Code Monkey home page Code Monkey logo

ewma's Introduction

EWMA

Exponentially Weighted Moving Average filter is used for smoothing data series readings. Unlike the method with a history buffer that calculates an average of the last N readings, this method consumes significantly less memory and works faster.

For example, if you have a wonky ADC, like the one in ESP8266, with a lot of noise, you will need a filter to smooth out the readings. Basically, EWMA filter allows you to specify the weight of the last reading versus the previous filtered value, by setting the alpha parameter. Roughly said, if you set alpha to, let's say, 0.1 it means that the result will be approximately the average of the last 10 readings.

output = alpha * reading + (1 - alpha) * lastOutput

  • alpha = Smoothing factor, in range [0,1]. Higher the value - less smoothing (higher the latest reading impact)
  • reading = current input value
  • lastOutput = last filter output value
  • output = filter output value after the last reading

EWMAT - Template for no-float filter

Exponentially Weighted Moving Average filter template that allows restriction to a specific data type (generally a non-floating-point data type), such as uint32_t. Avoiding floating point arithmetics can significantly decrease code footprint, especially in embeded devices, such as Arduino or STM32.

Note that the integer data type has to be as big as possible (32 bits at least, signed or unsinged), in order to allow internal calculations to be correctly performed, since the result will overflow in case when a too small data type is chosen.

The filtered value in this class is calculated as:

output = (alpha * reading + (alphaScale - alpha) * lastOutput) / alphaScale

If you want to create a filter for integers, with an alpha value of 0.03, you will just do the following:

EwmaT <int> filter(3, 100)

  • alpha = Smoothing factor in range [0,alphaScale]. Higher the value - less smoothing (higher the latest reading impact)
  • alphaScale = Number that will divide the alpha value, in order to get the actual alpha parameter of the filter (usually 10, 100, 1000 etc.)
  • lastOutput = last filter output value
  • output = filter output value after the last reading

Applications

Some sensors, like accelerometers or fast photoresistors that move a lot, give you quite noisy readings, meaning that two consecutive readings usually can differ up to 10%. These spikes make detection of movements (or whatever correlated events) impossible, so in order to smooth them out, you need to use a filter like this one.

Instantiate a filter, find an alpha value that meets the best your sampling frequency and noise level (the actual value is something you have to find out by trial and error) and feed it with readings from the sensor. Instead of using these readings directly in your further applications (calulations or whatever), read the .output value from the filter - and that's all.

Example

This example reads ADC input and filters it with two separate EWMA filters, each one with a different smoothing factor. You can observe how the first one is faster to detect changes, but more prone to noise, while the last one is less prone to noise, but slower to detect changes. The selection of the best alpha value depends on your actual application, the amount of noise and sampling frequency.

#include <Arduino.h>
#include <Ewma.h>

Ewma adcFilter1(0.1);   // Less smoothing - faster to detect changes, but more prone to noise
Ewma adcFilter2(0.01);  // More smoothing - less prone to noise, but slower to detect changes

void setup()
{
    Serial.begin(115200);
    pinMode(A0, INPUT);
}

void loop()
{
    int raw = analogRead(A0);
    float filtered1 = adcFilter1.filter(raw);
    float filtered2 = adcFilter2.filter(raw);
    Serial.printf("Raw=%d, Filter1=%.3f, Filter2=%.3f", raw, filtered1, filtered2);
    
    delay(100);
}

ewma's People

Contributors

jonniezg avatar rudex-it avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

ewma's Issues

EwmaT only handles unsigned?

This breaks (returns high numbers instead of negatives when the "average" goes negative) when fed negative values.

EwmaT <long int> diff_ewmat(3, 10, 500); 
...
filtered = diff_ewmat.filter(value); 

This works (add/subtract an offset to keep everything positive):

EwmaT <long int> diff_ewmat(3, 10, 1000500); 
...
filtered = diff_ewmat.filter(value+1000000)-1000000; 

Sorry, C++ isn't nearly my day job, so maybe I'm expecting too much, but there's nothing to indicate this shouldn't work with signed numbers.

Template version EWMAT

The argument of non-using float is false.
When you look at the code, there're at least 3 divisions, which are very slow !

Something must be wrong in the template...

As far as I've understood the doc, all these lines should be equivalent:
EwmaT<int32_t> ewmat_sliding_Average(1, 125, 0); => result is ok !
EwmaT<int32_t> ewmat_sliding_Average(4, 500, 0); => result is KO !
EwmaT<int32_t> ewmat_sliding_Average(8, 1000, 0); => result is KO !

But it looks like, at some time in the calculation, there's an overflow (I add only values between 0 and 30000).

Some compile-time validation or so should be implemented to know what is the limit, .... or at least documented !

example doesn't compile on Arduino Nano

Arduino Nano compile does not have Serial.printf and even sprintf() does not have %f

FilteredADC:29:12: error: 'class HardwareSerial' has no member named 'printf'; did you mean 'print'?
Serial.printf("Raw=%d, Filter1=%.3f, Filter2=%.3f", raw, filtered1, filtered2);
^~~~~~
print

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.