Go Down

Topic: RunningAverage Class on playground (updated) (Read 9614 times) previous topic - next topic

robtillaart

The RA lib uses floats which are on an AVR based Arduino 32bits IEEE754 floats. This means a 23 bit mantissa which equals about 7 significant digits.

If you are using an ARM based Arduino, which supports 64 bit double you could patch the library by replacing all float types with double. Should be a good change anyway. On my todo list.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

updated Running Average Library to version 0.2.05 on GITHUB
- https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -

changed float to double
==> support for double on ARM of the Arduino DUE ...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

GPSJay

Thanks Rob.

BTW I'm using a MEGA with GPS engines running at 4Hz...

robtillaart

updated Running Average Library to version 0.2.06 on GITHUB

- https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -

+ minor edits
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#34
Apr 10, 2015, 09:29 pm Last Edit: Apr 10, 2015, 09:30 pm by robtillaart
skip version 0.2.07 (contained typos)

updated Running Average Library to version 0.2.08 on GITHUB
- https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -

since 0.2.06
+ added getMin() and getMax() - thanks to Eric M.
+ refactored

Note getMin() and getMax() gives the minimum/maximum since last call to clear(),
==> so it is not the min/max of the internal buffer.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Sembazuru

Do you have any plans on getting your libraries added to the 1.6.2+ library manager? I imagine it would take quite a bit of work because it seems at first brush that each library should be it's own repository (instead of how you have several libraries in one repository).

I think AdaFruit has published a script to help mass publishing of libraries.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

robtillaart

No I do not have such plans in near future as my time is quite limited.

And I am using 1.5.8 which works quite well for me.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Sembazuru

No I do not have such plans in near future as my time is quite limited.

And I am using 1.5.8 which works quite well for me.
OK. Fair answer.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

aaronblanchard

One thing to be wary of when using this library is floating point imprecision.

I left a unit running for a week sampling 10 times a second and was very confused when I came back as to why my average (over the last 50 samples) was very different to the actual current input.

Looking into the code, the RunningAverage::addValue function subtracts a Double and then adds a Double.  Adding and subtracting of Doubles (and Floats) can lead to a huge degree of imprecision. 

I'm not sure what the best solution is here, calculating the sum total every time getAverage() is called is the obvious one, but that leads to somewhat more function overhead.

robtillaart

You are completely right. Thanks for this observation.

10 samples/second = 864.000 /day = 6 million per week.

The number of samples is approaching the accuracy of the (IEEE754) float (7 digits) when one reaches 1 million samples (1 day in your case) . This means if the average sample has 3 digits, one will loose 2 digits every time.

The "trick" of remove one double and add one double is an efficient way to calculate the sum of the array of samples. And yes when using this trick the error will add up in sum. In theory after 100 samples the last two digits are suspected to be incorrect. Need to investigate the effect.

Solution is to (sort and) add all elements of the array every time, giving a constant error. Consequence is a slower execution. The sorting will improve the sum when the dynamic range of the numbers is large.

A practical solution for the library might be to do a proper sum e.g. every 100 or 1000 times a value is added (new parameter?). The lower this number the more accurate the sum. The price is a performance penalty once every 100 / 1000 times. There are several variations possible.
A good value for the number will also depend on the size of the numbers added. Ideally one would like to have a sort of error counter that makes an estimate of the max error and when a threshold is reached do a recalculation of sum.

The easiest solution is to redo the function Average() and rename the current one to fastAverage();

in short food for thought.

thanks




Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart


quick patch:
Code: (snippet for runningAverage.cpp) [Select]

// returns the average of the data-set added sofar
double RunningAverage::getAverage() const
{
    if (_cnt == 0) return NAN;
    double sum = 0;
    for (uint8_t i = 0; i < _cnt; i++)
    {
        sum += _ar[i];
    }
    return sum / _cnt;
}

double RunningAverage::getFastAverage() const
{
    if (_cnt == 0) return NAN;
    return _sum / _cnt;
}

the .h file must add a signature for

double getFastAverage() const;
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up