I came here to look for an answer to a question I had about potentiometers giving values that vary too much. I've found that the answer is to smooth the data by taking an average of the last 10 samples or so. I only post here because I think that for continuous input data, the methods here are a bit simple, and don't quite achieve an efficient calculation of a moving average. The following code hasn't been tested on an arduino (or anywhere), and hence may have errors. But, I think it gives an idea on how (e.g.) an average can be taken from the last 10 input values without having to add up all the numbers each time.
BTW: I used round() to round the average, rather than truncate. I haven't looked in the arduino header files to check that I need to cast the result of round() or not.
int values[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Array with 10 zeroes. 10 pseduo-samples before the first one read.
int total = 0; // The total of the last 10 samples read
int next = 0; // The index of the oldest sample in the array
/*
* Function that accepts a new sample, and returns the average of the last 10 samples.
*/
int addValue( int newValue )
{
total = total - values[next] + newValue; // Update totla
values[next] = newValue; // Update array
next = ( next + 1 ) % 10; // move to new 'oldest sample in the array'
return (int) round( total / 10.0 ); // return average
}
Oh dear, now that I reread the OP, that doesn't solve the problem as it doesn't throw away values too far from the average. The following code might do, but it hasn't been debugged, or even compiled on an arduino. Note that the code watches out for situations where none of the values are in the range around the average, and takes the raw average in these situations.
#include <stdio.h>
#include <math.h>
int values[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int total = 0; // The total of the last 10 samples read
int next = 0; // The index of the oldest sample in the array
/*
* Function that accepts a new sample, and returns the average of the last 10 samples.
*
* A threshold of 0.5 means that the value must be between 1/2x - 2x the
* average. A threshold of 0.2 means that the value must be between 1/5x -
* 5x the average.
*/
int addValue( int newValue, double threshold )
{
int newTotal;
double newNum;
double average;
int index;
total = total - values[next] + newValue; // Update totla
values[next] = newValue; // Update array
next = ( next + 1 ) % 10; // move to new 'oldest sample in the array'
average = total / 10.0;
newTotal = 0;
newNum = 0;
for ( index = 0; index < 10; index++ )
{
if ( values[index] >= average * threshold &&
values[index] <= average / threshold )
{
newTotal += values[index];
newNum++;
}
}
if ( newNum > 0 )
{
return (int) round( newTotal / newNum );
}
else
{
return (int) round( total / 10.0 ); // return average
}
}