Go Down

Topic: Help mapping analog value from sensor (Read 3 times) previous topic - next topic

avrguy

Feb 14, 2010, 04:57 am Last Edit: Feb 14, 2010, 04:59 am by avrguy Reason: 1
I'm having trouble understanding how to get an analog value mapped to an actual value.

I'm testing with a MPX4250AP that I had from a previous project and this code below seems to work but it does not seem to work for
other sensors.

KPA = (analogRead(13)*(.00488) / (.02246)+20);

.00488 is 5/1024
.02246 is the range of the sensor divided by 1024 (230 kPa / 1024)
20 is the lowest kPa value

The data sheet says it has a range of 20 to 250 kPa.
http://www.freescale.com/files/sensors/doc/data_sheet/MPX4250A.pdf

I thought that I could use this code:

KPA = map(analogRead(13), 0, 1023, 20, 250);

But it seems to be off about 5% from actual values.

I can use:

VIN = .00488 * analogRead(13);

And the voltage is exactly what the mpx4250ap is putting out.

Can someone shed some light on the most accurate way to
map the incoming value to the actual value?


retrolefty

#1
Feb 14, 2010, 06:30 am Last Edit: Feb 14, 2010, 06:31 am by retrolefty Reason: 1
Looking at the graph in figure 4 of the linked datasheet I would suggest using mapping as:  KPA = map(analogRead(13), 0, 1023, 0, 260);

The fact that the sensor does not continue to give linear responses below 20 or above 250 kPa does not change the fact that the response curve is shown to be a 0-5vdc = 0-260 kPa linear relationship. Try it and see if you don't get more accurate results for valid pressure inputs between 20-250 Kpa.

Lefty


SRyLul

Its always nice to use engineering units as values.
About the first example, you are almost right in the formula.
Here is the calc, a little bit cleaned, from my lib FloatRamp:
Code: [Select]
Out =  OutMin + ( OutMax - OutMin ) * ( float(In) - InMin ) / (InMax - InMin)  ;

Note the conversion of the input to float, just to stay accurate. All other variables are floats.

avrguy

Quote
Looking at the graph in figure 4 of the linked datasheet I would suggest using mapping as:  KPA = map(analogRead(13), 0, 1023, 0, 260);


That looks to give a reading about 9% low. I was going by page 2 of the datasheet that said the min was 20 and max was 250. I understand what your saying about the graph though.

Quote
Out =  OutMin + ( OutMax - OutMin ) * ( float(In) - InMin ) / (InMax - InMin)  ;


I tried to work this out but I guess I'm not clear on what is In and what is Out? Is In 0-1023 and out 20 to 250?

avrguy

I tried this:

//Out =  OutMin + ( OutMax - OutMin ) * ( float(In) - InMin ) / (InMax - InMin)  ;

float RAW = analogRead();
KPA =  20 + ( 250 - 20 ) * ( RAW - 0 ) / (1023 - 0)  ;

I left the zeros in just to make it easier to relate back to the formula given. The result seems to be about 5% high.

SRyLul

What if you try this:
20kPa = 0.204V = 41.8 as InMin.
250kpa = 4.896V = 1002.7 as InMax.
About zeros, I dont have the knowledge of Arduino to tell if it matters. I just love them.  ;)

dilbert98122

Note that the datasheet gives you the formula:
Quote
Nominal Transfer Value:  VOUT = VS (P × 0.004 - 0.04)


If Vs = 5v, and you use the default reference voltage (5v) on the analog inputs, the Vout/Vs = (P x 0.004 - 0.04).

The value you get from analogRead is equal to (Vout/Vs)*1023.  (Let's call this IN).

Now just do some algebra:
IN/1023 = P * 0.004 - 0.04;
P = (IN/1023 + 0.04)/0.004;

Cleaning this up a bit:
1/0.004 = 250;
250 * 0.04 = 10;

P = 250 * (IN/1023 + 0.04)
P = 250 * IN / 1023 + 10

Be sure in your code to force this to be floating-point math:
Code: [Select]

float P;
int IN;
IN = analogRead(pin);
P = 250 * IN / 1023[glow].0[/glow] + 10; // the .0 forces floating-point math instead of integer math.



BTW:
Quote
.00488 is 5/1024

This is a common mistake because indeed a 1-bit ADC has 1024 possible values.   But keep in mind:
0V = 0
5V = 1023, NOT 1024.
Granted the error is small enough that most people wouldn't notice but it is additional error in the calculations.

avrguy

Quote
What if you try this:
20kPa = 0.204V = 41.8 as InMin.
250kpa = 4.896V = 1002.7 as InMax.


It's about 19% off if I did it correctly.

Quote
IN = analogRead(pin);
P = 250 * IN / 1023.0 + 10; // the .0 forces floating-point math instead of integer math.


I think that's it Dilbert! Seems to be very close, less than 1% off
in my inital tests.  Simple to implement and understand too. I totally missed the formula in the datasheet.

I'll do more testing and report back.

dilbert98122

I used the same technique with a MPX4115A.  It has a similar formula, but the constants don't come out to such nice numbers.

avrguy

#9
Feb 15, 2010, 03:12 am Last Edit: Feb 15, 2010, 03:14 am by avrguy Reason: 1
I was just trying to work out the same thing for the MPX4115AP and the MPXV5004DP:

The formula for the:
MPXA5004DP  VS * (P * .2 - .2)
MPX4115AP is VS * (P * .009 - .095)


I'm having a problem with this, can you explain that part a little more:

Quote
Cleaning this up a bit:
1/0.004 = 250;
250 * 0.04 = 10;


I may have been looking at this for too long but I'm not seeing
the relationship 1/0.004 = 250;  :-?

Seems like for the MPXV5004DP it would be .784 but the pressure seems
to be off by that amount.


dilbert98122

I was simplifying the constants a little bit.

P = (IN/1023 + 0.04)/0.004;

The divide by 0.004 is algebraically the same as multiplying by 1/0.004 which is 250.  Then the 250 can be distributed across the equation so that 250 * 0.04 becomes 10.   It's not necessary to do this.  The equation above will work just fine too, but in the CPU, it's easier and faster to multiply than to divide.

The MXP4115's constants don't come out so nice, but the technique works the same.

Code: [Select]
P = (IN/1023.0 + 0.095) / 0.009;  // Optionally simplify constants as desired.

MPXA5004DP... left as an exercise for the reader.   ;)

avrguy

Quote
P = (IN/1023 + 0.04)/0.004;


I don't think the formula works for the MPX5004AP,

Consider a reading of 1023 from the input pin:

P = (1023/1023 + .2) / .2;
P = 1.2 / .2;
P = 6; // Should be 3.92;

The formula below works but is different than your formula and I
don't understand the difference because it looks like
we should be subtracting .784 as yours does.

P = 3.92 * IN / 1023.0;
P = 3.92;




avrguy

OK, I see now. The formula in the datasheet for the MPX5004 is slightly
different.

It should be P = (1023/1023 - .2) / .2;

And it works fine now. Thanks for the lesson!   :) :) :)

SRyLul

#13
Feb 15, 2010, 08:16 am Last Edit: Feb 15, 2010, 08:18 am by srylul Reason: 1
I went a little bit concerned over your statement:
Quote
It's about 19% off if I did it correctly.

because I use that formula in my working life to. Am I wrong?
But after checking the specs and consulted mr Excel, Im back on track.
Actually, my formula is just like the other, its called "straight-line equation". Its just another way of config it.
But: If you needs precision, the Vs is critical. Especially at lower pressures.
My values was at TypVs, 5.1V. MinVs gives 16,4 kPa instead of 20 at TypVs. 18%.
My suggestion is to read Vs on another pin and compensate for the diff.

dilbert98122

That's probably what threw it off by such a high percentage.  If the device is being powered by the Arduino's voltage regulator, then it is running on 5V.

BTW: It should be noted that the formulas that I gave are assuming that the Vs to the sensor, and the Vref to the ADC are equal, as is the case when using the Arduino's voltage regulator and the default reference voltage.  As long as that is the case, it shouldn't be necessary to make any compensation for Vs.

Go Up