Go Down

Topic: Non-linear interpolation table help needed (Read 1 time) previous topic - next topic

Lsnyman

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

Graynomad

#1
Jan 23, 2012, 02:14 pm Last Edit: Jan 23, 2012, 02:19 pm by Graynomad Reason: 1
You have an array of (in your case) 10 values and use the sensor value to index into that array.

Code: [Select]
int table [10] = {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.

Quote
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
Rob Gray aka the GRAYnomad www.robgray.com

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.

cr0sh


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 will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Grumpy_Mike

Quote
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
Code: [Select]
value = table[6];
Will return the sixth value in your array. Or if your reading was in a variable called "reading" then
Code: [Select]
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.


Lsnyman

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.

GoForSmoke

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[0]) 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.

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Lsnyman

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

PeterH

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.
I only provide help via the forum - please do not contact me for private consultancy.

GoForSmoke

How does that work out for a non-linear table of say, sine values 0 - pi/2?
I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

PeterH


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.

I only provide help via the forum - please do not contact me for private consultancy.

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 find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

PeterH


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?
I only provide help via the forum - please do not contact me for private consultancy.

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.

Grumpy_Mike

Quote
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.

Go Up