C++ Implementation
Pieter PTable of Contents list
Simplifying the Difference Equation
Recall the Simple Moving Average difference equation:
However, we can do much better if we notice how only two terms of the sum change
each time:
C++ Implementation
We can now implement Equation
The previous inputs
SMA.cpp
#include <stdint.h>
template <uint8_t N, class input_t = uint16_t, class sum_t = uint32_t>
class SMA {
public:
input_t operator()(input_t input) {
sum -= previousInputs[index];
sum += input;
previousInputs[index] = input;
if (++index == N)
index = 0;
return (sum + (N / 2)) / N;
}
static_assert(
sum_t(0) < sum_t(-1), // Check that `sum_t` is an unsigned type
"Error: sum data type should be an unsigned integer, otherwise, "
"the rounding operation in the return statement is invalid.");
private:
uint8_t index = 0;
input_t previousInputs[N] = {};
sum_t sum = 0;
};
Arduino Example
As a basic example, you can use this filter for smoothing analog inputs on
microcontrollers. Keep in mind that an exponential moving average filter is
often more appropriate than a simple moving average filter.
The SMA uses much more memory, and is much slower than the EMA.
The exponential impulse response of the EMA may be better as well.
You can find an Arduino example using an EMA
here.
template <uint8_t N, class input_t = uint16_t, class sum_t = uint32_t>
class SMA {
public:
input_t operator()(input_t input) {
sum -= previousInputs[index];
sum += input;
previousInputs[index] = input;
if (++index == N)
index = 0;
return (sum + (N / 2)) / N;
}
static_assert(
sum_t(0) < sum_t(-1), // Check that `sum_t` is an unsigned type
"Error: sum data type should be an unsigned integer, otherwise, "
"the rounding operation in the return statement is invalid.");
private:
uint8_t index = 0;
input_t previousInputs[N] = {};
sum_t sum = 0;
};
void setup() {
Serial.begin(115200);
while (!Serial);
}
const unsigned long interval = 10000; // 100 Hz
void loop() {
static SMA<20> filter;
static unsigned long prevMicros = micros();
if (micros() - prevMicros >= interval) {
int rawValue = analogRead(A0);
int filteredValue = filter(rawValue);
Serial.print(rawValue);
Serial.print('\t');
Serial.println(filteredValue);
prevMicros += interval;
}
}