2011-10-09 16:06:19 -04:00
|
|
|
|
//
|
|
|
|
|
// FILE: Statistic.cpp
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// AUTHOR: Rob dot Tillaart at gmail dot com
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// modified at 0.3 by Gil Ross at physics dot org
|
2017-09-27 02:42:54 -04:00
|
|
|
|
// VERSION: 0.3.5
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// PURPOSE: Recursive statistical library for Arduino
|
|
|
|
|
//
|
|
|
|
|
// NOTE: 2011-01-07 Gill Ross
|
|
|
|
|
// Rob Tillaart's Statistic library uses one-pass of the data (allowing
|
|
|
|
|
// each value to be discarded), but expands the Sum of Squares Differences to
|
|
|
|
|
// difference the Sum of Squares and the Average Squared. This is susceptible
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// to bit length precision errors with the float type (only 5 or 6 digits
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// absolute precision) so for long runs and high ratios of
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// the average value to standard deviation the estimate of the
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// standard error (deviation) becomes the difference of two large
|
|
|
|
|
// numbers and will tend to zero.
|
|
|
|
|
//
|
|
|
|
|
// For small numbers of iterations and small Average/SE th original code is
|
|
|
|
|
// likely to work fine.
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// It should also be recognised that for very large samples, questions
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// of stability of the sample assume greater importance than the
|
2013-08-17 09:44:20 -04:00
|
|
|
|
// correctness of the asymptotic estimators.
|
2011-10-09 16:06:19 -04:00
|
|
|
|
//
|
|
|
|
|
// This recursive algorithm, which takes slightly more computation per
|
|
|
|
|
// iteration is numerically stable.
|
|
|
|
|
// It updates the number, mean, max, min and SumOfSquaresDiff each step to
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// deliver max min average, population standard error (standard deviation) and
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// unbiassed SE.
|
|
|
|
|
// -------------
|
|
|
|
|
//
|
|
|
|
|
// HISTORY:
|
|
|
|
|
// 0.1 - 2010-10-29 initial version
|
|
|
|
|
// 0.2 - 2010-10-29 stripped to minimal functionality
|
|
|
|
|
// 0.2.01 - 2010-10-30
|
|
|
|
|
// added minimim, maximum, unbiased stdev,
|
|
|
|
|
// changed counter to long -> int overflows @32K samples
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// 0.3 - 2011-01-07
|
2013-08-17 09:44:20 -04:00
|
|
|
|
// branched from 0.2.01 version of Rob Tillaart's code
|
2013-08-17 09:08:50 -04:00
|
|
|
|
// 0.3.1 - minor edits
|
2013-08-17 09:44:20 -04:00
|
|
|
|
// 0.3.2 - 2012-11-10
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// minor edits
|
2013-08-17 09:44:20 -04:00
|
|
|
|
// changed count -> unsigned long allows for 2^32 samples
|
|
|
|
|
// added variance()
|
2015-03-07 14:32:51 -05:00
|
|
|
|
// 0.3.3 - 2015-03-07
|
|
|
|
|
// float -> double to support ARM (compiles)
|
|
|
|
|
// moved count() sum() min() max() to .h; for optimizing compiler
|
2017-07-31 15:40:26 -04:00
|
|
|
|
// 0.3.4 - 2017-07-31
|
|
|
|
|
// Refactored const in many places
|
|
|
|
|
// [reverted] double to float on request as float is 99.99% of the cases
|
|
|
|
|
// good enough and float(32 bit) is supported in HW for some processors.
|
2017-09-27 02:42:54 -04:00
|
|
|
|
// 0.3.5 - 2017-09-27
|
|
|
|
|
// Added #include <Arduino.h> to fix uint32_t bug
|
2013-08-17 09:08:50 -04:00
|
|
|
|
//
|
2011-10-09 16:06:19 -04:00
|
|
|
|
// Released to the public domain
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "Statistic.h"
|
|
|
|
|
|
|
|
|
|
Statistic::Statistic()
|
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
clear();
|
2011-10-09 16:06:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resets all counters
|
|
|
|
|
void Statistic::clear()
|
2015-03-07 14:32:51 -05:00
|
|
|
|
{
|
|
|
|
|
_cnt = 0;
|
2017-07-31 15:40:26 -04:00
|
|
|
|
_sum = 0;
|
|
|
|
|
_min = 0;
|
|
|
|
|
_max = 0;
|
2011-10-09 16:06:19 -04:00
|
|
|
|
#ifdef STAT_USE_STDEV
|
2015-03-07 14:32:51 -05:00
|
|
|
|
_ssqdif = 0.0; // not _ssq but sum of square differences
|
|
|
|
|
// which is SUM(from i = 1 to N) of
|
|
|
|
|
// (f(i)-_ave_N)**2
|
2011-10-09 16:06:19 -04:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// adds a new value to the data-set
|
2017-07-31 15:40:26 -04:00
|
|
|
|
void Statistic::add(const float value)
|
2011-10-09 16:06:19 -04:00
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
if (_cnt == 0)
|
|
|
|
|
{
|
|
|
|
|
_min = value;
|
|
|
|
|
_max = value;
|
|
|
|
|
} else {
|
|
|
|
|
if (value < _min) _min = value;
|
|
|
|
|
else if (value > _max) _max = value;
|
2013-08-17 09:08:50 -04:00
|
|
|
|
}
|
2015-03-07 14:32:51 -05:00
|
|
|
|
_sum += value;
|
|
|
|
|
_cnt++;
|
2017-07-31 15:40:26 -04:00
|
|
|
|
|
2015-03-07 14:32:51 -05:00
|
|
|
|
#ifdef STAT_USE_STDEV
|
|
|
|
|
if (_cnt > 1)
|
|
|
|
|
{
|
2017-07-31 15:40:26 -04:00
|
|
|
|
float _store = (_sum / _cnt - value);
|
2013-08-17 09:08:50 -04:00
|
|
|
|
_ssqdif = _ssqdif + _cnt * _store * _store / (_cnt-1);
|
2017-07-31 15:40:26 -04:00
|
|
|
|
// ~10% faster but limits the amount of samples to 65K as _cnt*_cnt overflows
|
|
|
|
|
// float _store = _sum - _cnt * value;
|
|
|
|
|
// _ssqdif = _ssqdif + _store * _store / (_cnt*_cnt - _cnt);
|
2015-03-07 14:32:51 -05:00
|
|
|
|
}
|
2011-10-09 16:06:19 -04:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// returns the average of the data-set added sofar
|
2017-07-31 15:40:26 -04:00
|
|
|
|
float Statistic::average() const
|
2011-10-09 16:06:19 -04:00
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
if (_cnt == 0) return NAN; // original code returned 0
|
|
|
|
|
return _sum / _cnt;
|
2011-10-09 16:06:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Population standard deviation = s = sqrt [ S ( Xi - <20> )2 / N ]
|
|
|
|
|
// http://www.suite101.com/content/how-is-standard-deviation-used-a99084
|
2015-03-07 14:32:51 -05:00
|
|
|
|
#ifdef STAT_USE_STDEV
|
2013-08-17 09:44:20 -04:00
|
|
|
|
|
2017-07-31 15:40:26 -04:00
|
|
|
|
float Statistic::variance() const
|
2013-08-17 09:44:20 -04:00
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
if (_cnt == 0) return NAN; // otherwise DIV0 error
|
|
|
|
|
return _ssqdif / _cnt;
|
2013-08-17 09:44:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-31 15:40:26 -04:00
|
|
|
|
float Statistic::pop_stdev() const
|
2011-10-09 16:06:19 -04:00
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
if (_cnt == 0) return NAN; // otherwise DIV0 error
|
|
|
|
|
return sqrt( _ssqdif / _cnt);
|
2011-10-09 16:06:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-31 15:40:26 -04:00
|
|
|
|
float Statistic::unbiased_stdev() const
|
2011-10-09 16:06:19 -04:00
|
|
|
|
{
|
2015-03-07 14:32:51 -05:00
|
|
|
|
if (_cnt < 2) return NAN; // otherwise DIV0 error
|
|
|
|
|
return sqrt( _ssqdif / (_cnt - 1));
|
2011-10-09 16:06:19 -04:00
|
|
|
|
}
|
2013-08-17 09:44:20 -04:00
|
|
|
|
|
2011-10-09 16:06:19 -04:00
|
|
|
|
#endif
|
2013-08-17 09:08:50 -04:00
|
|
|
|
// END OF FILE
|