## Exponential Moving Average

The exponential moving average is a type of IIR filter that is easy to implement in C and uses minimal resources. Unlike a simple moving average, it does not require a RAM buffer to store previous samples. It just has to store one value (the previous average).

An exponential moving average is expressed as the following equation: avg[n] = (in * alpha) + avg[n-1]*(1-alpha). Implementing this equation using floating point math is straightforward but using fixed point variables is a little tricky. The code snippet here use 32-bit signed integers for the average and input values. Intermediate values need to use 64-bit math to avoid overflow errors.

Alpha values close to zero represent heavy averaging while an alpha value of one has no averaging.

```
//This macros defines an alpha value between 0 and 1
#define DSP_EMA_I32_ALPHA(x) ( (uint16_t)(x * 65535) )
int32_t dsp_ema_i32(int32_t in, int32_t average, uint16_t alpha){
int64_t tmp0; //calcs must be done in 64-bit math to avoid overflow
tmp0 = (int64_t)in * (alpha) + (int64_t)average * (65536 - alpha);
return (int32_t)((tmp0 + 32768) / 65536); //scale back to 32-bit (with rounding)
}
//here is a function that uses the averaging code
int32_t my_avg_func(void){
static int32_t average = 0;
int32_t adc_value;
adc_value = read_the_adc_value();
average = dsp_ema_i32(adc_value, average, DSP_EMA_I32_ALPHA(0.1));
return average;
}
```

## Comments:

To see this, lets choose alpha to be 1024.

We start with adc_value = 0, then dsp_ema_i32 will return 0 as expected.

Then raise adc_value to 1. tmp0 in dsp_ema_i32 will be:

tmp0 = (int64_t)1 * (1024) + (int64_t)0 * (65536 - 1024)

= 1024 + 0 * 64512

= 1024

so the returned value is:

(int32_t)((tmp0 + 32768) / 65536) = (1024 + 32768) / 65536

= 33792 / 65536

= 0

So dsp_ema_i32 will keep on returning 0, while it should (after long enough filtering time) in the end return 1.

The code effectively implements a filter with a "dead zone", not changing until the input differs from the average by 32768/alpha or more, or differs by -(32768/alpha) or less.

Following the above example, raise adc_value to 31 (which is less than 32768/alpha). tmp0 in dsp_ema_i32 will be:

tmp0 = (int64_t)31 * (1024) + (int64_t)0 * (65536 - 1024)

= 31744 + 0 * 64512

= 31744

so the returned value is:

(int32_t)((tmp0 + 32768) / 65536) = (31744 + 32768) / 65536

= 64512 / 65536

= 0

So dsp_ema_i32 will keep on returning 0.

When raising adc_value to 32 instead, tmp0 in dsp_ema_i32 will be:

tmp0 = (int64_t)32 * (1024) + (int64_t)0 * (65536 - 1024)

= 32768 + 0 * 64512

= 32768

so the returned value is:

(int32_t)((tmp0 + 32768) / 65536) = (32768 + 32768) / 65536

= 65536 / 65536

= 1

So at least the average is moving toward the input value by 1. That is good.

But then:

tmp0 = (int64_t)32 * (1024) + (int64_t)1 * (65536 - 1024)

= 32768 + 1 * 64512

= 97280

so the returned value is:

(int32_t)((tmp0 + 97280) / 65536) = (97280 + 32768) / 65536

= 130048 / 65536

= 1

So dsp_ema_i32 will keep on returning 1, never reaching the input value of 32. Not good.

The second bug is the integer division (tmp0 + 32768) / 65536 . In C / C++, integer division will round toward 0, so in that situation, the dead zone is even larger.

Much better (and much simpler) is the algorithm as shown by david.prentice on http://www.avrfreaks.net/comment/824765#comment-824765 :

long total = 0;

int average = 0;

int N = 0; // working number of samples

...

total += ADCW; // add to running total

if (N >= MAX_SAMPLES) // enough samples ?

total -= average; // remove one

else N++; //

average = total / N; // integer

(65535 - alpha)

Otherwise an alpha of 1 would improperly include the previous average as well as the new value.