Averaging an analog signal with a long loop time / Low Acquisition Frequency

Hi everyone,

While I thought that I had finally finished my data acquisition setup, it turned out that the torquemeter signal I'm logging (0-5V) is very noisy and the reading (at least on the LCD) is jumping +- 10 values (on the 1024/10-bit scale).

I'm currently trying to log it at 10Hz even though it's more of 5Hz since my main loop has a delay in it and the loop time I measured are along the lines of 200mS...

Anyway, this has nothing to do with the noisy signal but it does forbid me to do high Frequency acquisition...

So I tried to a very crude moving average with the code below :

for(i=0; i<49; i++)
{
Cdata=AnalogRead(A0);
}
Cdata=Cdata/i

Basically it's converting 50 values as fast as it can (in a row in order to not be stuck with the 200mS main loop time) and then averages them.

But it didn't give me any results... It's still jumping up and down (much to my surprise!).

Would there be a method to average/smooth this analog signal with the constraint of this long loop time? The value will only be of interest on stabilised phase so a slow dynamic is not a problem... But accuracy is, obviously!

Thanks for the help,

Marc

What you have isn't a moving average, it's just an average of groups of 50. A moving average would gain one, drop one, not just take the next 50.

I'm pretty sure someone posted code for that recently, for someone with exactly your problem. So wait a while and if they see this they'll post it. It might have been robtillaart but I'm not 100% sure.

That said, I would have thought a normal average of 50 would have helped.

I recall that someone said each time you take an average you should drop the highest and lowest; I'm not sure if that is statistically valid, though.

Hi Jimbo,

Thanks for the help,

I've been looking for robitllaart posts but didn't find anything relating to my problem...

Any idea where it might be / what the topic would be named?

The code you posted is missing a "+" and is not an average. You need something like:

float Cdata=0.
Nsample = 50;
for(i=0; i<Nsample; i++)
{
Cdata += AnalogRead(A0);
}
Cdata=Cdata/Nsample;

I would use a low pass filter instead.

jremington:
The code you posted is missing a "+" and is not an average

Crap, I missed that.....

Oops... yes it does lack a +!

Though the real code (I retyped it for the forum) is correct, I was monitoring the final value via a serial.print and it was adding up 50 values...

About the low pass filter, how would I do that via software (granted it is possible with an arduino...)?

My favorite bit of rolling average code goes something like this. It only requires one variable which makes it great for embedded stuff.

const double W = 0.95;
double average;
average = average * W + newValue * (1 - W);

W is a weight constant between 0 and 1 which in the example above means the average takes roughly 95% of the old values and 5% of the new value. Smaller W means a quicker change while a W close to 1 makes the average roll very slowly. This is basically a mathematically continuous version of the 50 bucket average.

+1 for tripphippie

note that formula can be rewritten as:

average = newValue + (average - newValue) * W;

using one float operations less :wink: