Calibration curve adjustment - Page 1
Forum section: electronics / beginners

author: ARGLaser
author_rank: Contributor
timestamp: February 10, 2013, 01:55:54 am
content: Hey everyone,I'm creating a device that measures the power of a laser. I calibrated the sensor at 80mW, but the output is not linear. Here's the data I have:(Displayed power is Y axis, the real power is the x axis)How do I figure out an equation (or series of equations) to transform the Output line on to the Input line? Is there a way to do it easily in Excel?

author: amspire
author_rank: Super Contributor
timestamp: February 10, 2013, 03:12:40 am
content: You could do linear or polynomial curve fitting, but it probably wouldn't work great near zero.Excel has built in tools that can do this. You can do a Google search for LINEST and also EXCEL REGRESSION.This is reasonable concise:http://web.cecs.pdx.edu/~EAS199/A/notes/14/polynomial_curve_fit_notes.pdfSince you have all the calibration data, it may give a better result to use a piecewise linear interpolation.Say you have an output of 5. That is between the 2.25 and 6.5 calibration values, so you interpolate between the two:Input = 6.47 + (8.7-6.47)* (5-2.25)/(6.5-2.25) = 7.91This will probably need some VBA programming in a macro.http://www.tushar-mehta.com/excel/newsgroups/interpolation/index.htmlIf you go down the piecewise linear regression track, but you want a smoother curve, you can modify the VBA code for a Cubic Spline fit (search google) but be prepared for some mind numbing equations.The advantage of the piecewise linear or cubic spline interpolation is that the resultant curve passes exactly through all your calibration points. The LINEST type solutions creates a best fit curve that probably does not pass exactly through any calibration point including (0,0).

author: cwalex
author_rank: Frequent Contributor
timestamp: February 10, 2013, 04:53:10 am
content: Quote from: ARGLaser on February 10, 2013, 01:55:54 amDo you get the same results with different wavelength lasers? I have a couple of coherent thermopile sensors from ebay some years ago and made a laser power meter based on a amp circuit provided on laserpointer forums. I wonder if the sensor you are using is absorbant to different wavelengths? I was led to believe that the thermopiles I have are coated with a substance that is absorbent equally at most wavelengths, i lost interest in the project after using a crappy made prototype and confirming that it worked but had nothing to compare it to for accuracy. I lost interest in lasers at some point shortly after too.

author: ARGLaser
author_rank: Contributor
timestamp: February 10, 2013, 05:52:28 am
content: Quote from: cwalex on February 10, 2013, 04:53:10 amFor the most part; it's not perfect, but it's good enough to maintain 5% accuracy.Quote from: amspire on February 10, 2013, 03:12:40 amThank you! I had no idea what to Goggle for. You've given me lots to read and work with!

author: ARGLaser
author_rank: Contributor
timestamp: February 11, 2013, 04:05:45 am
content: I just had a thought, is there an easy way to do this without a polynomial in the programming?Using if statements for each number 1-3000 to multiple it to get the correct output? (without entering it by hand 3000 times)

author: amspire
author_rank: Super Contributor
timestamp: February 11, 2013, 05:53:04 am
content: Quote from: ARGLaser on February 11, 2013, 04:05:45 amNot sure what you mean, but both the solutions I mentioned are fairly straightforward. I would use the piecewise solution myself, unless my goal was to generate an approximation for use elsewhere. Whatever you are trying to achieve, the piecewise VBA solution probably achieves it.

author: GK
author_rank: Super Contributor
timestamp: February 11, 2013, 06:05:28 am
content: Quote from: ARGLaser on February 10, 2013, 01:55:54 amPerhaps I'm missing something here, but the biggest source of error I see is simply a scaling factor, rather than a severe non-linearity (the blue line is still straight).You just need to multiply the output by a number slightly less than one.

author: amspire
author_rank: Super Contributor
timestamp: February 11, 2013, 07:21:43 am
content: Quote from: GK on February 11, 2013, 06:05:28 amThe correction is very non-linear near zero. I did suggest a linear approximation if the values near zero did not matter. The LINEST function I mentioned will do a best fit linear approximation based on all the calibration points.For result that exactly matches the data points, a piecewise linear or cubic spline fit give the most accurate results, assuming the calibration readings are precise. A linear approximation will give less accurate results, but it may be adequate.

author: Rerouter
author_rank: Super Contributor
timestamp: February 11, 2013, 07:48:24 am
content: result 5 is your odd one out, you may wish to remeasure it, other than that, your correction factor is a small exponential, to make it more obvious, work out the percentage difference on each result, and graph that,

author: ARGLaser
author_rank: Contributor
timestamp: February 12, 2013, 10:07:11 pm
content: Yes, the values near 0 do matter in this. I would like to maintain accuracy across the whole range if possible, so that this will be usable for low power lasers as well as multi-watt lasers. Would I have to do multiple polynomial curve adjustments for the different ranges of power to maintain accuracy?@GKThe line is straight, but they intersect at 80, and at 0, a multiplying it by one value would give bad results at the high or low range.@ampsireWhat I am talking about is doing something like this:Code:if(power<1){power = power * 2.8; //The number to multiply by to get the correct value at the range}else}if(power<2)}power = power * 2.7; //The number to multiply by to get the correct value at the range}}Ect. ect. ect. up to 3000 using else if statements.Is there an easy way to do this?@RerouterThanks, I'll check that out.

author: baljemmett
author_rank: Unknown
timestamp: February 12, 2013, 10:44:10 pm
content: Quote from: ARGLaser on February 12, 2013, 10:07:11 pmIf your correction factors are at equally-spaced intervals, just store them in an array and index into it based on the integer truncation of your input value:Code:/* 0-1, 1-2, 2-3, 3-4 */static const float aFactors[] = { 2.9f, 2.8f, 2.7f, 2.6f };static const int nFactors = sizeof(aFactors) / sizeof(aFactors);if (power >= 0 && power < nFactors) {power *= aFactors[(int)power];} else {/* power was outside of the list of factors */}... which has the advantage that it will always take the same time to find the correction factor for any given value within the range. However, it gets a bit wasteful of space if you have long runs where the factors don't change, so you can trade that off against runtime with something like this:Code:static const struct {int UpperLimit;float Factor;} aIntervals[] = {/* Keep this list sorted by UpperLimit */{ 0, 2.9f },{ 1, 2.8f },{ 2, 2.7f },{ 5, 2.0f },};static const int nIntervals = sizeof(aIntervals) / sizeof(aIntervals);static float GetCorrectionFactor(float power) {for (int nInterval = 1; nInterval < nIntervals; nInterval++)if (power < aIntervals.UpperLimit)return aIntervals[nInterval - 1].Factor;return 1.0f; /* default factor if it ran off-scale*/}... which is a little slower than the array solution (each lookup takes a variable time based on how far down the list it had to look, just like your cascade of if()s) but takes up less space. Which one to use depends upon whether you have the space to spare and/or whether you need the constant lookup time of an array.(NB: this is totally untested code, written off the top of my head, but should illustrate two possible approaches regardless of any bugs!)

author: ToBeFrank
author_rank: Regular Contributor
timestamp: February 14, 2013, 03:12:05 pm
content: If you want to check out curve fitting, usezunzun.com. You can do all sort of different fits.