 # Non-linear interpolation table help needed

I am a newbie and struggling to understand tables and the code to use them. I have about 10 sample analog values from 600 to 990 that represent different distances from the sensor. Problem is it is not linear. Can someone give me a simple explanation of how a table works and the code to implement it? I just want to write the distance out to the monitor.

I have looked at some recipes that implement tables but I am confused.

Thanks in advance

You have an array of (in your case) 10 values and use the sensor value to index into that array.

``````int table  = {1,2,4,7,10,15,20,27,35,45}; // example non-linear values

sensor_linearized_val = table[sensor_val];
``````

Actually that changes linear to non-linear but the principle is the same.

10 sample analog values from 600 to 990

Do you get the same 10 values or 10 ranges of values? That would be different.

Rob

Sorry I was not clear. The 10 values are hust arbitrary measurements of anakog input A1 at a few different distances from the sensor. It is not linear in that a 1cm distance change does not produce a linear change in sensor output v. I tried to follow the recipe for “Measuring distance accurately” im the arduino cookbook but I am confused.
So the measured values are not equidistant but break up the log curve into smaller chunks. I want the code to substitute any read analog value into a real distance.
I am just unclear on how the actual table functions and how it determines a value to be returned.

I guess I could write 100 code lines tonsay if the value is >x but <y then distance = 1cm etc but it seems the table should do this much easier.

Lsnyman:
Sorry I was not clear. The 10 values are hust arbitrary measurements of anakog input A1 at a few different distances from the sensor. It is not linear in that a 1cm distance change does not produce a linear change in sensor output v. I tried to follow the recipe for “Measuring distance accurately” im the arduino cookbook but I am confused.
So the measured values are not equidistant but break up the log curve into smaller chunks. I want the code to substitute any read analog value into a real distance.
I am just unclear on how the actual table functions and how it determines a value to be returned.

I guess I could write 100 code lines tonsay if the value is >x but <y then distance = 1cm etc but it seems the table should do this much easier.

You’ve been given the basics by Graynomad on converting a linear value (1-10) into a non-linear value from a table; you should be able to figure out the inverse. Just realize that this could take up a lot of memory (and you might have to do some interpolation to figure out “in-between” values or such).

What would take less memory than a table would be to figure out what your non-linear curve is (ie - graph it), then fit an equation to match it (as close as possible); unless the curve is really complex (and from a distance sensor, it shouldn’t be), the equation should be fairly simple. Or, you could make your table smaller, and use interpolation along with curve fitting to potentially speed things up (while keeping the table size small).

I am just unclear on how the actual table functions and how it determines a value to be returned.

It functions by using an array to fetch values given to it in the form of an array index. So if you the array table, as shown above and have a reading of 6 then

``````value = table;
``````

Will return the sixth value in your array. Or if your reading was in a variable called "reading" then

``````value = table[reading];
``````

Would give you the appropriate value in your array.

Note here you have to have one array element for every reading you are going to get, so for an analogue input you would require an array with 1024 values in it. This is too big most of the time so there are tricks to reduce this. However you just want a restricted range of reading from 600 to 990, that is just 390 elements in your array. So you take your reading and subtract 600 from it to get the array element to use.

Even that may be too big an array, in which case you break it up into ranges and do an linear interpolation between the readings.

That is exactly what I intend. I am breaking the curve into 10 ranges and need to interpolate the values. So if the value is example 800, the range above is 830 (10cm) and below is 790 (7.2cm), then the interpolation should return 8.5 cm ( just example). This is the explanation given in the Arduino Cookbook forthe recipe "measuring distance more accurately". But I am lost as to how it works.

Have you ever interpolated tabled values by hand before? Like a sine table?

Basically your table would have an entry (array element) for each unit of range, possibly 1 per foot or meter. and you would compare your analog input to each entry in turn until you found the first entry bigger than your input. If the first bigger than your input is the first entry (array) then you're out of range as would be the case where your input is bigger than the last entry but in between you can interpolate.

Say your input reads 780 (call it R) and there are table values 740 (call it L) and 800 (call it H).

The percentage of the range between L and H that R falls on is ((100 x (R - L)) / (H - L)). If you want to get 3 places then multiply by 1000 to get 10ths of a percent, etc. Then you have distance corresponding to L plus percentage times 1 unit for your interpolated answer. Just take care about your units if you use integers or use floating-point since exactness isn't really any issue. With FP fastest processing shouldn't be either, it's your choice.

Thank you Now I understand the function. Do you have a code example with explanation?

I would suggest a slightly different approach.

Use DIV and MOD operations to convert your input value into an array index, and a remainder.

Use the array index to look up two adjacent values in the array. Use the remainder to interpolate between these two values.

The result of the interpolation is your answer.

How does that work out for a non-linear table of say, sine values 0 - pi/2?

GoForSmoke: How does that work out for a non-linear table of say, sine values 0 - pi/2?

The problem is to calculate an output value which is related in a non-linear but monotonic way to the input value. In this case the input is the signal amplitude and the output is the corresponding range.

The two approaches we've described are similar and both work in the same situations, but in the scheme I'm proposing the interpolation points are equally space in the input domain, and in the other they aren't. Since they're equally spaced, the interpolation points can be calculated (by a simple div) rather than needing to be found by a search through the array. This also simplifies the interpolation since the distance between the two interpolation points is also known.

So for a sine table with values of 0.0 to 1.0 I might have 11 array elements where each holds the angle corresponding to sine = 0, .1, .2, ... 1.0 rather than array elements for angles with values = sine of those. More of an arcsine table.

GoForSmoke: So for a sine table with values of 0.0 to 1.0 I might have 11 array elements where each holds the angle corresponding to sine = 0, .1, .2, ... 1.0 rather than array elements for angles with values = sine of those. More of an arcsine table.

I haven't fully understood your example. Are you starting with an angle and trying to estimate its sine, or starting with a sine and trying to estimate the angle?

Can you give a code example of the DIV MOD method? I am struggling to understand how to reference the correct range and how the MOD gets you closer to the correct value. I guess my main battle is that my analog voltage increases as my distance decreases so its inversed as well as non linear.

Can you give a code example of the DIV MOD method?

If you actually try and write it yourself you will learn a lot more. Programming is just doing stuff one step at a time.
If you get stuck post what you have and people will help, but don’t do this helpless “can someone post an example” business all the time.

PeterH:

GoForSmoke: So for a sine table with values of 0.0 to 1.0 I might have 11 array elements where each holds the angle corresponding to sine = 0, .1, .2, ... 1.0 rather than array elements for angles with values = sine of those. More of an arcsine table.

I haven't fully understood your example. Are you starting with an angle and trying to estimate its sine, or starting with a sine and trying to estimate the angle?

Yes.

If my data is sine and I want to use your method to look up then the array would be arranged by sine values and give angles to be interpolated. But if my data were angle then it would work the other way around.

So yes either way, I would pick the way to suit the incoming data. It's much better than what I suggested which is how some of use used trig tables back before scientific calculators.

Lsnyman: Can you give a code example of the DIV MOD method? I am struggling to understand how to reference the correct range and how the MOD gets you closer to the correct value. I guess my main battle is that my analog voltage increases as my distance decreases so its inversed as well as non linear.

Maybe when I've got more time and energy I can make something to show -how I see it- but really just as Mike tells I would probably not be doing you any favor in the process. And I am one of those who takes the view that code mostly comments itself, but what is as obvious to me as 1 + 1 = 2 isn't so clear to everyone else.

Your best action would be to sit down with a pencil and start working it out. Draw some diagrams from what has been written, make boxes for array elements and put values in them then work out how it should work.

It's YOUR project. Do something besides asking other people to get on with it.

Simple truth is that if your data is inverse square with distance then a simple function beats a small table for accuracy if not speed.