You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

188 lines
4.2 KiB

#include <corestats.h>
#include <Arduino.h>
#include <limits.h>
#include <math.h>
#include <float.h>
// //////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////
float Stats::stddev() const {
return sqrt(var());
}
float Stats::normalize(float value) const {
return ( value - mean() ) / (stddev() + FLT_MIN);
}
SimpleStats::SimpleStats(float startMean, float startVar) {
reset(startMean, startVar);
}
void SimpleStats::reset(float startMean, float startVar) {
_mean = startMean;
_mean2 = startVar + sq(_mean);
_nSamples = 0;
// _min = FLT_MAX;
// _max = -FLT_MAX;
}
float SimpleStats::update(float value) {
if (_nSamples == ULONG_MAX)
_nSamples = (ULONG_MAX / 4) * 3; // simple trick that makes sure we don't overflow
// Add one to number of samples
_nSamples++;
// Update mean and mean2
float prop = (float)(_nSamples-1) / (float)_nSamples;
_mean = _mean * prop + value / _nSamples;
_mean2 = _mean2 * prop + sq(value) / _nSamples;
// Update min and max
// _min = min(_min, value);
// _max = max(_max, value);
return normalize(value);
}
float SimpleStats::var() const {
float v = (_mean2 - sq(_mean));
return max(v, (float)0); // make sure the result is >= 0
}
// //////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////
MovingAverage::MovingAverage(float alphaOrN) : _value(0.5f) {
setAlphaOrN(alphaOrN);
reset();
}
MovingAverage::MovingAverage(float alphaOrN, float startValue) : _value(startValue) {
setAlphaOrN(alphaOrN);
}
void MovingAverage::setAlphaOrN(float alphaOrN)
{
alphaOrN = max(alphaOrN, 0); // make sure factor >= 0
_alpha = (alphaOrN > 1 ?
2 / (alphaOrN + 1) :
alphaOrN);
}
void MovingAverage::reset() {
_setStarted(false);
}
void MovingAverage::reset(float startValue) {
_value = startValue;
_setStarted(true);
}
float MovingAverage::update(float v) {
if (!isStarted()) {
_value = v;
_setStarted(true); // start
return _value;
}
else
return (_value -= _alpha * (_value - v));
}
bool MovingAverage::isStarted() const {
return _alpha >= 0;
}
void MovingAverage::_setStarted(bool start) {
_alpha = (start ? +1 : -1) * abs(_alpha);
}
MovingStats::MovingStats(float alphaOrN) : avg(alphaOrN) { }
MovingStats::MovingStats(float alphaOrN, float startMean, float startVar)
: avg(alphaOrN, startMean), _var(startVar) {
reset(startMean, startVar);
}
void MovingStats::reset() {
avg.reset();
_var = 0;
}
void MovingStats::reset(float startMean, float startVar) {
avg.reset(startMean);
_var = startVar;
}
float MovingStats::update(float value)
{
avg.update(value);
if (!isStarted())
_var = 0;
else {
float diff = value - avg.get();
_var -= avg.alpha() * (_var - sq(diff));
}
return normalize(value);
}
bool MovingStats::isStarted() const {
return avg.isStarted();
}
// //////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////
AdaptiveNormalizer::AdaptiveNormalizer(float smoothFactor)
: MovingStats(smoothFactor),
_value(0.5f),
_mean(0.5f),
_stddev(0.25f)
{}
AdaptiveNormalizer::AdaptiveNormalizer(float mean, float stddev, float smoothFactor)
: MovingStats(smoothFactor),
_value(mean),
_mean(mean),
_stddev(abs(stddev))
{}
float AdaptiveNormalizer::put(float value) {
return (_value = MovingStats::update(value) * _stddev + _mean);
}
Normalizer::Normalizer()
: SimpleStats(),
_value(0.5f),
_mean(0.5f),
_stddev(0.25f)
{}
Normalizer::Normalizer(float mean, float stddev)
: SimpleStats(),
_value(mean),
_mean(mean),
_stddev(abs(stddev))
{}
float Normalizer::put(float value) {
return (_value = SimpleStats::update(value) * _stddev + _mean);
}
MinMaxScaler::MinMaxScaler()
: _value(0.5f),
_minValue(FLT_MAX),
_maxValue(FLT_MIN)
{}
float MinMaxScaler::put(float value)
{
_minValue = min(value, _minValue);
_maxValue = max(value, _maxValue);
_value = (_minValue == _maxValue ? 0.5f : map(value, _minValue, _maxValue, 0.0f, 1.0f));
return _value;
}