Pages: [1] 2   Go Down
 Author Topic: ADC code needing more accurate results  (Read 1351 times) 0 Members and 1 Guest are viewing this topic.
0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « on: April 27, 2011, 05:12:21 pm » Bigger Smaller Reset

Dear all, as some of you might know (since i think i pissed many members here), I am design an automated refrigiration system for chargin an airconditioners (cars).
This system involves:
ARDUINO MEGA
POWER SUPPLY
SOLENOID VALVE
RELAY
OPAMP

All of these things have been succesfully tested and working as required

My procedure is this:
Basically I just put a gas cylinder on top of my mounted load cell, and depending on the weight of the gas cylinder (therefore depending on the amount of gas in it), it gives a voltage. This voltage is transferred to the Arduinos ADC.

Many tests have been made in order to have accurate results on the load cell....(For example a full load gives 4.6V while a half load gives 2.3V)
Attached I have a graph having the grams (amount of gas) vs voltage.  AND IT IS LINEAR

Therefore I have an equation of the line of the graph; then I can enter the voltage in the equation and giving an amount in grams.

y = 4621.2x - 281.96 (y- GRAMS. x - VOLT)

This is my code:
Code:
//Testing adc with load cell and having pin 13 actuing as relay
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

double maxvolt = 4.6;
int dec = 1023;

int gas_before;
double sensorValue = 0;        // value read from A0
double conversionvolt[10];      //array for average voltage

int conversiontogas;

void loop()
{
}

void setup()
{
lcd.begin(16,2);                              //initialise LCD
Serial.begin(9600);
setupA();
}

void setupA()
{
//TESTING
lcd.print("TESTING");                //display on lcd
delay(2000);                               //give some time for user to read

digitalWrite(13,LOW);                  //RELAY CLOSED
//READ AMOUNT OF GAS BEFORE RELAY IS OPENED, I.E. NO GAS ESCAPED

for(int x =0; x<10 ; x++)
{

conversionvolt[x] = sensorValue*(0.004643206);  //(conversionvolt of (4.7/1023)) + conversionvolt of (4.8/1023))/2  -NOTE THIS GIVES VERY GOOD RESULTS

}
//to find average
double conversionvoltaverage = ((conversionvolt[0] + conversionvolt[1] + conversionvolt[2] + conversionvolt[3] + conversionvolt[4] + conversionvolt[5] + conversionvolt[6] + conversionvolt[7] + conversionvolt[8] + conversionvolt[9]) / 10);
//To print the amount of voltage when cylinder is put on load cell
Serial.print("A-");
Serial.println(conversionvoltaverage);

//Display voltage on lcd
lcd.clear();
lcd.print(conversionvoltaverage);
delay(4000);
lcd.setCursor(0,1);

// Conversion from voltage to grams
double conversiontogasstep1 = ((4621.2)*(conversionvoltaverage));        //y = 4.621.2x (part of equation)
conversiontogasstep1 = (conversiontogasstep1 - 281.96);                     // - 281.96 (part of eqution)
double conversiontogasstep2 = (conversiontogasstep1 - 326);                //minus weight of steel base of loadcell
conversiontogas = (conversiontogasstep2 + 50);                                   //50 done under calibration since I put up a test and found that averagly there is a difference of -50grams than the origanal value of cylinder
Serial.println(conversiontogas);
//DISPLAY LCD
lcd.print(conversiontogas);
delay(4000);

}

Therefore my question is this:
The voltage displayed on the multimeter is approximatle equal to the ADC voltage
But when this voltage enters the equation y = 4621.2x - 281.96 (y- GRAMS. x - VOLT)[/b] It isn't calculated well.  I dont understand why this happens.

For example:
If the multimeter displays 1.775V the Arduino displays 1.76V
But then it doesnt work the calculation correct; y = 4621.2x - 281.96

Why is this???

tnx

 weightssuccesful.png (41.23 KB, 1199x867 - viewed 22 times.) « Last Edit: April 27, 2011, 05:16:43 pm by Daniel Formosa » Logged

Global Moderator
UK
Offline
Brattain Member
Karma: 290
Posts: 25802
I don't think you connected the grounds, Dave.
 « Reply #1 on: April 27, 2011, 05:22:16 pm » Bigger Smaller Reset

What happens if you do:
Code:
Serial.println(conversionvoltaverage, 5);
(for instance)?

(You do know that for the Arduino, a "double" is precisely the same as a "float"?)

Code:
double conversionvoltaverage = ((conversionvolt[0] + conversionvolt[1] + conversionvolt[2] + conversionvolt[3] + conversionvolt[4] + conversionvolt[5] + conversionvolt[6] + conversionvolt[7] + conversionvolt[8] + conversionvolt[9]) / 10);
What's wrong with a for loop?
Do you like typing or something?
 Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #2 on: April 27, 2011, 05:23:35 pm » Bigger Smaller Reset

So this gives 5 sig figures??
 Logged

Global Moderator
UK
Offline
Brattain Member
Karma: 290
Posts: 25802
I don't think you connected the grounds, Dave.
 « Reply #3 on: April 27, 2011, 05:24:27 pm » Bigger Smaller Reset

No, it just prints more.
 Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #4 on: April 27, 2011, 05:26:12 pm » Bigger Smaller Reset

KK didnt know that...

And yes i know, the code needs to be less.... but for now i just want to know why it doesnt correctly work out the equation.
tnx
 Logged

Left Coast, USA
Offline
Sr. Member
Karma: 5
Posts: 499
Sometimes I just can't help myself.
 « Reply #5 on: April 27, 2011, 06:34:03 pm » Bigger Smaller Reset

...just want to know why it doesnt correctly work out the equation.

You haven't told us a couple of important things:

Say you get a reading of 1.775 Volts on your multimeter and you see 1.76 on the first row of the LCD...

What output do you expect to see on the second row of the LCD?

What output do you see on the LCD?

I mean, it takes the calculation from the formula and subtracts something and adds something and truncates the floating point value to an integer, right?

Regards,

Dave
 « Last Edit: April 27, 2011, 06:36:56 pm by davekw7x » Logged

Ontario
Offline
God Member
Karma: 24
Posts: 860
 « Reply #6 on: April 27, 2011, 07:10:00 pm » Bigger Smaller Reset

I compiled your code for the final conversion and it converts 1.76 into 7,575 grams.  This looks like the right answer to me.  What does your program print?
 Logged

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #7 on: April 28, 2011, 03:36:55 am » Bigger Smaller Reset

davekw7x - Well if for example on the LCD i see 1.76V, then on the other row i need to see: y = 4621.2x - 281.96; i.e. 7851.32 (calculation).
But it doesnt give me this number. It gives me a number near to it but not good like 7950 for example.....I cant understand why...

gardner - How did you get that answer?? Is there something wrong with my code??

tnx
 Logged

0
Offline
Full Member
Karma: 2
Posts: 156
It was all digital
 « Reply #8 on: April 28, 2011, 05:47:31 am » Bigger Smaller Reset

Hi Daniel

Here you are makeing 10 superfast readings of the analog pin and calculate the average
Code:
for(int x =0; x<10 ; x++)
{

conversionvolt[x] = sensorValue*(0.004643206);  //(conversionvolt of (4.7/1023)) + conversionvolt of (4.8/1023))/2  -NOTE THIS GIVES VERY GOOD RESULTS

}
//to find average
double conversionvoltaverage = ((conversionvolt[0] + conversionvolt[1] + conversionvolt[2] + conversionvolt[3] + conversionvolt[4] + conversionvolt[5] + conversionvolt[6] + conversionvolt[7] + conversionvolt[8] + conversionvolt[9]) / 10);
Why? Have you seen instability in the voltage signal to justify an average calculation?

Here you are doing undocumentet manipulation with the equation:
Code:
double conversiontogasstep2 = (conversiontogasstep1 - 326);                //minus weight of steel base of loadcell
conversiontogas = (conversiontogasstep2 + 50);

I thought you were only interested in the weight change hence the absolute (true) weight value of the bottle with CFS gas is unimportent (unless it will run dry during the filling ofcorse). Furthermore you are storing a double (float) + 50 in a int construct:

Code:
int conversiontogas;

-Fletcher

 Logged

Left Coast, USA
Offline
Sr. Member
Karma: 5
Posts: 499
Sometimes I just can't help myself.
 « Reply #9 on: April 28, 2011, 08:01:29 am » Bigger Smaller Reset

davekw7x - Well if for example on the LCD i see 1.76V, then on the other row i need to see: y = 4621.2x - 281.96; i.e. 7851.32 (calculation).
But it doesnt give me this number.
No, it doesn't give you that number, and I would not expect it to.

Have you looked (yes looked) at the calculations in the program?

Well, without knowing what your real expectations from the program are, and without worrying about whether the program correctly implements what it needs to do to meet your expectations, and without caring about why it has been written the way that it was to do what it does, I'll step away from the Arduino for a minute, and I will go through the calculations that the program actually performs, but I will do them with my 10-digit calculator.  (See Footnote.)

The calculation in the program gives, approximately, the (truncated) integer value of (1.76*4621.1-281.96-326+50), so  I would expect to see something "in the neighborhood of" 7575 on the second line of the LCD.

In fact, if the number shown on the first line of the LCD is 1.76, it represents a number that was rounded to two significant digits, so the actual value could be anything between 1.755 and 1.765.  Repeat the actual calculation with these numbers, and you can see that value on the second row could be anything from 7552 to 7598.

Regards,

Dave

Footnote:
The floating point calculations in the Arduino are carried out with a precision of something like six or seven significant decimal digits. For this particular formula, roundoff error does not alter the results significantly, so I would expect the same output on the LCD that I show above for my calculator.

 « Last Edit: April 28, 2011, 09:08:00 am by davekw7x » Logged

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #10 on: April 28, 2011, 12:52:31 pm » Bigger Smaller Reset

Dear all, I made some arrangments.  First off all I didnot know that the arduino uses up to 6 or 7 sig fig...  Therefore this is what I came up with.  This all depends on this line:
Code:
Serial.print(sensorValue);
Serial.print("\n");
//AT THAT MOMENT THE VOLT ON MULTIMETER WAS 1.954V, THEREFORE BY LOOKING AT SERIAL.PRINT(SENSORVALUE), ONE FOUND (X/1023)TIMES 415.8 (AVERAGE ADC VALUE) = 1.954
conversionvolt[x] = sensorValue*(0.00469592);

The number 0.00469592 is the main thing I think, changing it to 0.00467351 will give A REALLY DIFFERENCE IN SHOWING THE VOLTAGE.
The number 0.00467351 came from doing various averaging of the analogvalue and that is the best I came up with.

Now I need to construct a loop because this is my new code for reading the voltage and averaging:
Code:
for(int y = 0; y<10;y++)
{
for(int x =0; x<10 ; x++)
{
Serial.print(sensorValue);
Serial.print("\n");
conversionvolt[x] = sensorValue*(0.00469592);  //Maxvoltafe/1023   4.782V Vmax 2 BESTTTTTTTTTTTTTTTTTTTTTTTTTT

Serial.print(conversionvolt[x], 3);
Serial.print("\n");
}
//to find average
conversionvoltaverage[y] = ((conversionvolt[0] + conversionvolt[1] + conversionvolt[2] + conversionvolt[3] + conversionvolt[4] + conversionvolt[5] + conversionvolt[6] + conversionvolt[7] + conversionvolt[8] + conversionvolt[9]
) / 10);
}
double conversionvoltaverageaverage = ((conversionvoltaverage[0] + conversionvoltaverage[1] + conversionvoltaverage[2] + conversionvoltaverage[3] + conversionvoltaverage[4] + conversionvoltaverage[5] + conversionvoltaverage[6] + conversionvoltaverage[7] + conversionvoltaverage[8] + conversionvoltaverage[9]
) / 10);

Serial.print("A-");
Serial.println(conversionvoltaverageaverage, 3);
Serial.print("\n");

I need help in such a simple loop since I need to take a lot of values to have an accurate reading.

double conversiontogasstep2 = (conversiontogasstep1 - 326);                //minus weight of steel base of loadcell  That is since the loadcells base (were the cylinder is put weighs 326g)

AND THE CODE
Code:
conversiontogas = (conversiontogasstep2 + 50);
IS WRONG, THAT WAS AN AVERAGE ERROR WHICH I THOUGHT WOULD HAVE HELPED ME, forget it...

Please I need help in reading more values; i.e. just a big loop which I think will help me more accurate

tnx
 Logged

Ontario
Offline
God Member
Karma: 24
Posts: 860
 « Reply #11 on: April 28, 2011, 01:44:38 pm » Bigger Smaller Reset

Please I need help in reading more values; i.e. just a big loop which I think will help me more accurate

How's this?

Code:
* return the floating point mean of the samples.
* The summing of samples is done using a long, which
* is subject to overflow for very large counts.
*/
{
int i;
long sum;

/* Impossible counts yield a reading of 0.0
*/
if (count < 1)
return 0.0;

sum = 0;
for (i = 0; i < count; i++)

return ((float) sum) / ((float) count);
}
 « Last Edit: April 28, 2011, 01:53:00 pm by gardner » Logged

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #12 on: April 28, 2011, 01:56:36 pm » Bigger Smaller Reset

I think I understood it..My question is this: uint8_t pin

tnx
 Logged

Ontario
Offline
God Member
Karma: 24
Posts: 860
 « Reply #13 on: April 28, 2011, 04:15:06 pm » Bigger Smaller Reset

uint8_t pin

Yes, this is the pin number that is being passed to analogRead().  Where you have:

Code:

You could do

Code:

Oversampling in this way would likely help with quantization noise and may help improve your overall accuracy.  The A2D only has a 1 part in 1024 resolution, and it's accuracy is +/-2 LSB -- this means about +/-10 mV in a range of 5 V.  And as davekw7x worked out earlier, this is an error of around +/-50 grams.  There are likely other accuracy effects to look out for -- temperature stability of the load cell and amplifier, hysteresis in the load cell and such -- that will knock another ~100 ppm off your accuracy.

I think you have some work to do to understand the simple arithmetic you are doing and the way in which that is implemented in C though.  Simple issues like using an integer when you wanted a float are going to mess you up until you get them right, and no amount of oversampling is going to fix it.
 Logged

0
Offline
Full Member
Karma: 1
Posts: 110
Arduino rocks
 « Reply #14 on: April 28, 2011, 04:27:49 pm » Bigger Smaller Reset

Yes I understant the %error.  As an amplifier I used a chopper opamp which has a very low offset volt so that change in temp doesnt effect the volt amplified...
Ok and I managed to get o how many averages as I want with this code
Code:
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
int count = 300;

void setup()
{
lcd.begin(16,2);                              //initialise LCD
Serial.begin(9600);
setupA();
}

void loop()
{
}

void setupA()
{
lcd.print("TESTING");                //display on lcd
delay(2000);
digitalWrite(13,LOW);                  //RELAY CLOSED
}

* return the floating point mean of the samples.
* The summing of samples is done using a long, which
* is subject to overflow for very large counts.
*/
{
int i;
double sum = 0;
double average;
double voltage;
double conversiontogas;
int gas;

sum = 0;
for (i = 0; i < count; i++)
{
Serial.print(sum, 3);
Serial.print("\n");
}

average = ((sum)/(count));
voltage = average*(0.00469592);
Serial.print("A");
Serial.println(average, 3);
Serial.println(voltage, 3);

conversiontogas = ((4621.2)*(voltage) - 607.96);
gas = conversiontogas;
Serial.println(conversiontogas);
Serial.println(gas);

return gas;
}

I havenet tried this in real becuse I dont have the system near me....

I was thinking: Since I am always using a tank; when empty the tank is approx 7kgs which gives 1.576V. Therefore can I trick the ADC of having a range of from 1.576 to 5V??

tnx
 Logged

 Pages: [1] 2   Go Up