Pages: [1]   Go Down
Author Topic: Average of a sensor  (Read 1396 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey im working on a project using a load cell to to turn voltages into weights. Im finished coding and everything is fine but the readings i get are not very stable, shifting slightly up and down for no reason. Is there a simple method where the only thing that appears on my serial monitor will be a more filtered result. I have looked through tons of filters on here but i cant seem to get it right. Any help is appreciated, thanks, Tom.
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How much variation are you getting in your readings?  Is it a stability or repeatability problem?  I like to take multiple samples and compute a simple average at the very least.
Logged

Experience, it's what you get when you were expecting something else.

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Something like this
126
126
126
126
125.5
125.5
126
125.5
126
126
126
Im not really how to code an average for this as its just constantly taking readings so do i need to place them in an array?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well first any averaging you do should be done with the raw integer values returned by analogRead() statements, not after you convert them (if you indeed do) to floating point numbers like the 125.5 example you posted. Anyway a simple averaging method might be to just add every four consecutive values in a row you read with a analogRead() statements and then divide the accumulated number by four. No need for an array.

Lefty
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I do this in one program, but you will always get some toggling of the last bit of the result.

Code:
// Sample the LM34 a bunch of times then compute a nice smooth average temperature

  temptot = 0;
  for(x = 0; x < 64; x++) {
    temptot += analogRead(LM34Pin);
  }
  temp = temptot >> 6;   // divide by 64

What you could do then is to build in some hysteresis into the software by only acknowledging changes above your "noise" threshold.  You could simply ignore the last bit.
Logged

Experience, it's what you get when you were expecting something else.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13707
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Well first any averaging you do should be done with the raw integer values returned by analogRead() statements, not after you convert them (if you indeed do) to floating point numbers like the 125.5 example you posted.
@lefty

I do not agree on this per se. Averaging of integer values have a truncating error that might be greater than when averaging the converted values.
you can minimize this with rounding.

Code:
temptot = 0;
  for(x = 0; x < 64; x++)
    temptot += analogRead(LM34Pin);
  temp = (temptot + 32) /64;   // rounding iso truncking
the number to add (32)  is half the number of samples you take (64)

BTW Averaging floats is definitely slower than averaging integers.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Well first any averaging you do should be done with the raw integer values returned by analogRead() statements, not after you convert them (if you indeed do) to floating point numbers like the 125.5 example you posted.
@lefty

I do not agree on this per se. Averaging of integer values have a truncating error that might be greater than when averaging the converted values.
you can minimize this with rounding.

Code:
temptot = 0;
  for(x = 0; x < 64; x++)
    temptot += analogRead(LM34Pin);
  temp = (temptot + 32) /64;   // rounding iso truncking
the number to add (32)  is half the number of samples you take (64)

BTW Averaging floats is definitely slower than averaging integers.

Well I do not agree per se back. I think as a general rule one should avoid using floating point math all together (if at all possible) on micro-controller applications, just too much code bloat and speed penalty to pay. For an applications like reading a load cell and converting to units of measurement it can all be done in integer math.

Lefty
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13707
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I think as a general rule one should avoid using floating point math all together (if at all possible) on micro-controller applications, just too much code bloat and speed penalty to pay. For an applications like reading a load cell and converting to units of measurement it can all be done in integer math.

Agree on these smiley-wink

However the point I wanted to make is that averaging the float values might be more accurate than the averaging the raw integers.
And sometimes one wants to trade speed for precision ...

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

alabama
Offline Offline
Full Member
***
Karma: 1
Posts: 183
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tom D,
Found this on this forum and I'm sorry to say I forgot to record the original senders ID, but it works well for me.
Changing the ratio of the decimal fractions changes the frequency of update.
TomJ
Code:
//Then I'd do a 'rolling average' of the form
//to smooth off the jitter.
//light1 is of type float)

Code:
light1 = light1 * 0.9 + float(analogRead(light1Pin)) * 0.1;
Logged

Einstein once said you don't really understand anything until you can explain it to your Grandmother

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Well first any averaging you do should be done with the raw integer values returned by analogRead() statements, not after you convert them (if you indeed do) to floating point numbers like the 125.5 example you posted.
@lefty

I do not agree on this per se. Averaging of integer values have a truncating error that might be greater than when averaging the converted values.
you can minimize this with rounding.

Code:
temptot = 0;
  for(x = 0; x < 64; x++)
    temptot += analogRead(LM34Pin);
  temp = (temptot + 32) /64;   // rounding iso truncking
the number to add (32)  is half the number of samples you take (64)

BTW Averaging floats is definitely slower than averaging integers.

Just in case, I didn't use any floats.  I also disagree with the rounding.  I don't believe it correct to do that, I believe truncation is better.  Here is my reference:
www.actel.com/documents/Improve_ADC_WP.pdf
Logged

Experience, it's what you get when you were expecting something else.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13707
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I don't believe it correct to do that, I believe truncation is better.

simple example, 10 measurements of an analogRead()

The integer average with truncating
{ 109 109 109 109 109  109 109 109 109 108 } = 1089/10 = 108 

The integer average with rounding
{ 109 109 109 109 109  109 109 109 109 108 } = (1089+5)/10 = 109 

The float average
{ 109 109 109 109 109  109 109 109 109 108 } = 1089/10 = 108.9 

(for above example)
with rounding the max error = 0.5 so the average error is 0.25
with truncating the max error = 0.9 the average error is 0.45
So there is a factor 1.8 difference in the max & avg error

However I do not know the requirements of your project, so I cannot say if rounding is correct or not.

// the numerical implication of error propagation in a rolling average are a bit more complex
// but it is a faster method than taking dozens of samples (when executed in integer domain)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I myself don't have a project, but the document I provided says that decimation is done by truncation.  Given that they (Actel) manufacture ADCs, I'm going to have to side with them.  No offense intended.  smiley

Maybe it's the number of samples, because to do true decimation requires more like 64 over samples.  At that point, I believe the truncation is truly just noise and not meaningful information as the "division" is just a simple shift removing noise bits that never were a part of the answer.  The assumption being that there is 1LSB of noise in the data that is randomly distributed white noise.

Logged

Experience, it's what you get when you were expecting something else.

Sydney, AUS
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In some cases (not all), a fairly simple 1nF capacitor can be placed between signal and ground, either on the sensor side or on the Arduino analog-in side. It will work as a low-pass filter, 'shorting' out possible high frequency disturbing crosstalk or noise, and stabilizing the measurements. Details depending on the actual measurements done, and works for analog sensors only.

Also, when using analogRead(), make sure to use the internal 3.3V reference source for scaling, it will produce more accurate digital readings.

Finally - make sure that the actual sensor is 'stable', e.g. it gets a stable power supply, stable as in when compared to the one that's powering the Arduino. Groundloops and all that...
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey thanks for everyone who posted a reply, alot of helpful information. Im having a little trouble with the how to program the arduino to separate ten samples to average from. Im including some code i found which i used some of in the project, if anyone could tell me the best way to include an average fileter into it i would be extremely greatful, sorry if this sounds stupid but im pretty crap at all this but im starting to cop on to how it all works.
I will also try the capacitor method when im next in the lab.
Apologies the original poster of this information but i couldnt find the name.
// Arduino with load cell

// Put two known loads on the sensor and take readings. Put those values
// here.
float aReading = 120.0;
float aLoad = 60.0; // lbs.
float bReading = 344.0;
float bLoad = 172.0; // lbs.

long time = 0;
int interval = 1000; // Take a reading every 500 ms

void setup() {
  Serial.begin(9600);
}

void loop() {
  float newReading = analogRead(0);
 
  // Calculate load based on A and B readings above
  float load = ((bLoad - aLoad)/(bReading - aReading)) * (newReading - aReading) + aLoad;
 
  // millis returns the number of milliseconds since the board started the current program
  if(millis() > time + interval) {
    Serial.print("Reading: ");
    Serial.print(newReading,1); // 1 decimal place
    Serial.print("  Load: ");
    Serial.println(load,1);  // 1 decimal place, println adds a carriage return
    time = millis();
  }
}
Logged

Pages: [1]   Go Up
Jump to: