Go Down

Topic: RunningAverage Class on playground (updated) (Read 20539 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)

robtillaart

#41
Sep 05, 2015, 12:24 pm Last Edit: Sep 05, 2015, 12:35 pm by robtillaart
updated Running Average Library to version 0.2.11 on GITHUB
https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -

The following changes were made since 0.2.08
(request aaronblanchard)
+ getAverage() renamed to getFastAverage() as it is fast but less accurate.
+ reimplemented getAverage() to be accurate, but a bit slower.
getAverage() sums all elements in the internal buffer and average them. This solves the remark from  aaronblanchard a few posts ago that the fastAverage() drifts from the real value. An example sketch is included to show this drift.

(request by mail)
+ added GetMinInBuffer() to make difference with getMin()
+ added GetMaxInBuffer() to make difference with getMin()
Note getMin() and getMax() gives the minimum/maximum since last call to clear(). An example sketch shows the differences between the methods.

+ refactored

snippet from drift test (included as example)
Code: [Select]

COUNT       AVG         FASTAVG     DIFF        MAXDIFF sofar
30750000 0.5153000 0.5152977 0.0000023 0.0000522
30760000 0.5241000 0.5240974 0.0000026 0.0000522

The sample sketch adds values between 0.0 and 0.999 in a loop. The maximum difference after 30 million++ additions is relative still low. There will be input streams which are more sensitive for the fastAverage algorithm. So when max accuracy is a requirement please use getAverage().

as always remarks and bug reports are welcome,
Rob
Rob Tillaart

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

Leonas

updated Running Average Library to version 0.2.11 on GITHUB
https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -
Maybe a stupid question but where is the download button for this library? I must be missing something.   :-[ 

robtillaart

#43
Jan 30, 2016, 02:18 pm Last Edit: Jan 30, 2016, 02:20 pm by robtillaart
No stupid question, the [download zip] button is two levels up (right side)

https://github.com/RobTillaart/Arduino

or use

https://github.com/RobTillaart/Arduino/archive/master.zip
Rob Tillaart

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

Leonas

No stupid question, the [download zip] button is two levels up (right side)

https://github.com/RobTillaart/Arduino
OK, thanks, sorry that I missed that. I was too deep. ;)

Go Up