Here’s another simple algorithm for smothing analog values. This one was posted by Brian Taylor on the PicBasic list.
Adjust alpha for more or less smoothing. A large alpha takes much longer to reach final value. 1 = no smoothing. 4 or 5 would typically give good results, but your mileage may vary.
newVal var word ' the value from the ADC
smoothed var word ' a nicely smoothed result
if newval > smoothed then
smoothed = smoothed + (newval - smoothed)/alpha
else
smoothed = smoothed - (smoothed - newval)/alpha
endif
Here’s a more fully-developed example of it in Wiring syntax (tested on an Arduino board):
/*
Analog smoothing algorithm
by Tom Igoe
This program reads an analog input and smooths out the result by averaging
the result with past values of the analog input.
uses a potentiometer on analog in 2 to generate the value for alpha,
the number of samples to average.
n.b. the variable "smoothed" needs to be a global, since it's modified
each time a new smoothing is done. So if you want to use this for multiple
inputs, you'll need a "smoothed" variable for each input.
Created 17 October 2005
Updated 24 March 2006
*/
int analogVal = 0; // the value from the ADC
int smoothed = 0; // a nicely smoothed result. This needs to be a global variable
int alpha = 4; // the number of past samples to average by
// function prototypes:
void blink(int howManyTimes);
void smoothValue(int rawValue);
void setup() {
Serial.begin(9600);
blink(3);
}
void loop() {
// read the trimmer pot, use it to generate alpha:
alpha = (analogRead(1) /114) + 1;
// get an analog reading:
analogVal = analogRead(0);
// smooth it:
smoothValue(analogVal);
// to see the difference, try outputting analogVal
// instead of smoothed here, and graph the difference.
// divide by 4 to print the result as a byte:
Serial.print(smoothed/4, BYTE);
// delay before next reading
delay(10);
}
// Blink the reset LED:
void blink(int howManyTimes) {
int i;
for (i=0; i< howManyTimes; i++) {
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13, LOW);
delay(200);
}
}
// Smooth out an analog reading:
void smoothValue(int rawValue) {
if (rawValue > smoothed) {
smoothed = smoothed + (rawValue - smoothed)/alpha;
}
else {
smoothed = smoothed - (smoothed - rawValue)/alpha;
}
}
Written in PicBasic Pro, tested on a PIC 18F252:
' Analog smoothing algorithm
' by Tom Igoe
' This program reads an analog input and smooths out the result by averaging
' the result with past values of the analog input.
' uses a potentiometer on analog in 2 to generate the value for alpha,
' the number of samples to average.
' n.b. the variable "smoothed" needs to be a global, since it's modified
' each time a new smoothing is done. So if you want to use this for multiple
' inputs, you'll need a "smoothed" variable for each input.
' Created 17 October 2005
' Updated 27 March 2006
' Define ADCIN parameters
DEFINE ADC_BITS 10 ' Set number of bits in result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS
TRISA = %11111111 ' Set PORTA to all input
ADCON1 = %10000010 ' Set PORTA analog and right justify result
analogVal var word ' the value from the ADC
smoothed var word ' a nicely smoothed result. This needs to be a global variable
byteVar var byte ' a byte variable to send out serially
alpha var byte ' the number of past samples to average by
trimPotValue var word ' the trimmer pot input
' serial variables and constants:
tx var portc.6
rx var portc.7
inv9600 con 16468
' Variables for subroutines:
i var byte
LEDPin var portb.7
gosub blink
main:
' read the trim pot to determine alpha between 1 and 10:
adcin 1, trimPotValue
alpha = (trimPotValue / 114) + 1
' get an analog reading:
adcin 0, analogVal
' smooth it:
gosub smoothValue
' to see the difference, try outputting analogVal
' instead of smoothed here, and graph the difference.
' divide by 4 to print the result as a byte:
byteVar = smoothed /4
serout2 tx, inv9600, [byteVar]
' delay before next reading
pause 10
goto main
' Blink the reset LED:
blink:
for i=0 to 3
high LEDPin
pause 200
low LEDPin
pause 200
next
return
' Smooth out an analog reading:
smoothValue:
if (analogVal > smoothed) then
smoothed = smoothed + (analogVal - smoothed)/alpha
else
smoothed = smoothed - (smoothed - analogVal)/alpha
endif
return