Pages: [1] 2   Go Down
Author Topic: ADC code needing more accurate results  (Read 1342 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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:
LOAD CELL
ARDUINO MEGA
POWER SUPPLY
SOLENOID VALVE
RELAY
OPAMP
LCD KEYPAD

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

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 smiley-grin

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;

const int analogInPin = A0;
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++)
 {
  sensorValue = analogRead(analogInPin);  
  
  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 smiley
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 Offline
Brattain Member
*****
Karma: 288
Posts: 25692
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So this gives 5 sig figures??
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 288
Posts: 25692
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Sr. Member
****
Karma: 5
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
God Member
*****
Karma: 24
Posts: 860
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Full Member
***
Karma: 2
Posts: 156
It was all digital
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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++)
 {
  sensorValue = analogRead(analogInPin);   
 
  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 Offline
Sr. Member
****
Karma: 5
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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:
sensorValue = analogRead(analogInPin);   
  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++)
 {
  sensorValue = analogRead(analogInPin);   
  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 Offline
God Member
*****
Karma: 24
Posts: 860
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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:
/* Sample analog in pin a given number of times and
 * 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.
 */
float read_average_analog(uint8_t pin, int count)
{
  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++)
      sum += analogRead(pin);

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

0
Offline Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Is that the pin in which the Analog input enters?
tnx
Logged

Ontario
Offline Offline
God Member
*****
Karma: 24
Posts: 860
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

uint8_t pin
Is that the pin in which the Analog input enters?

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

Code:
  sensorValue = analogRead(analogInPin);

You could do

Code:
  sensorValue = read_average_analog(analogInPin, 10);

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 Offline
Full Member
***
Karma: 1
Posts: 110
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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);
const int analogInPin = A0;
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
   read_average_analog(count);
}


/* Sample analog in pin a given number of times and
 * 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.
 */
double read_average_analog(int count)
{
  int i;
  double sum = 0;
  double average;
  double voltage;
  double conversiontogas;
  int gas;


 
    sum = 0;
    for (i = 0; i < count; i++)
    {
        sum += analogRead(analogInPin);
        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
Jump to: