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