Go Down

### Topic: Average of a sensor (Read 3324 times)previous topic - next topic

#### TomDev

##### Mar 06, 2013, 06:08 pm
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.

#### afremont

#1
##### Mar 06, 2013, 06:15 pm
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.
Experience, it's what you get when you were expecting something else.

#### TomDev

#2
##### Mar 06, 2013, 06:19 pm
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?

#### retrolefty

#3
##### Mar 06, 2013, 06:29 pm
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

#### afremont

#4
##### Mar 06, 2013, 06:30 pm
I do this in one program, but you will always get some toggling of the last bit of the result.

Code: [Select]
` // 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.
Experience, it's what you get when you were expecting something else.

#### robtillaart

#5
##### Mar 06, 2013, 07:26 pm
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: [Select]
`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.
Rob Tillaart

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

#### retrolefty

#6
##### Mar 06, 2013, 08:24 pm

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: [Select]
`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

#### robtillaart

#7
##### Mar 06, 2013, 08:42 pm
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

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

Rob Tillaart

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

#### Tumbleweed

#8
##### Mar 07, 2013, 12:09 am
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: [Select]
`//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;`
Einstein once said you don't really understand anything until you can explain it to your Grandmother

#### afremont

#9
##### Mar 07, 2013, 04:42 am

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: [Select]
`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:
Experience, it's what you get when you were expecting something else.

#### robtillaart

#10
##### Mar 07, 2013, 07:26 am
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)
Rob Tillaart

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

#### afremont

#11
##### Mar 07, 2013, 08:02 am
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.

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.

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

#### ottehoman

#12
##### Mar 07, 2013, 11:02 am
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...

#### TomDev

#13
##### Mar 07, 2013, 07:31 pm
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.

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

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

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

void loop() {

// millis returns the number of milliseconds since the board started the current program
if(millis() > time + interval) {
time = millis();
}
}

Go Up

Please enter a valid email to subscribe