Analog Smoothing Algorithm

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