Smooth Averaging in Loop (simple advice)

Obviously most of us ever had a necessity to average continuous data reading, for example from temperature sensor, readings are jerky and to output steady indications, input data should be averaged. There is very simple method and I thought it was obvious to use but noticed unexpectedly many projects with different averaging method. Most of them just save reading in array and average them time by time. This method has at least two cons: array eats memory and first reading comes out only after several readings. So I think I should present that method I've using long time. Sure it was mentioned here many times and sorry for repeating but seems many Arduino fans missed it.
So, suppose we have reading: float r=ReadData(); (ReadData is some function to get data reading, change is by yours) and need to get smoothed value of r - avgr;
Each time we get new r value, we just need to modify already calculated avgr.
We need smoothing speed coefficient - k. It should be between 0 and 1.
If k is 0, we'll get constant data when reading is ignored;
If k is 1, we'll have no smoothing, so the less k is the smoother is output.
And finally, whole code:

float avgr=0;
float k=0.01;
float r=ReadData();
avgr = avgr * (1-k)+r*k;

How does it work? very simple, if reading is steady (therefore avgr = r) , then output also steady:
If reading changes rapidly, low k mixes is with small portions to averaged value and therefore output will be smooth. This method is very simple and resource-saving. It mimics analog devices like analog voltmeter or thermometer, also electrical condenser, so I call it condenser method (of course method isn't exact condenser simulation but with such small expenses we have very nice close results).

As noted in comments, there is way to do all this via integer types:

int avgr=0;
int Scale=1000;
int k=10; //0-1000
float r=ReadData();
avgr = (avgr * (Scale-k)+r*k)/Scale;

And another little improvement that I like more:

int avg=0;
int avgr;
int Scale=1000;
int k=10; //0-1000
float r=ReadData();
avg = avg * (Scale-k)/Scale+r*k; //avg is scalled for better precision
avgr = avg/Scale;

If you have time-dependent data, you may need to have variable k that will be depend on time passed from previous reading.

I'd never really considered floating point calculations on a family of processors not noted for their floating point performance as "small expenses", but, OK

You can scale all calculations to int or long.
I used that way also many times.

That's what most digital implementations of low-pass filters do.

A low pass digital filter is often implemented without using multiplication or division as described here or better, here. Very fast!

Try this:

// y(n) = (1-alpha)*y(n-1) + alpha*x(n)
// fast implementation with shifts

unsigned int data = 0, filtered=0;
unsigned long sum = 0;
unsigned int beta = 6;  //alpha = 1/2^beta

void setup() {

void loop() {
  //uniformly distributed random data from 0 to 1023
data = random(0,1024);  
sum = sum - filtered + data;
filtered = sum>>beta;
Serial.print(data); Serial.print(", "); 

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.