mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
170 lines
3.0 KiB
C++
170 lines
3.0 KiB
C++
#pragma once
|
|
//
|
|
// FILE: Gauss.h
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.2.1
|
|
// PURPOSE: Library for the Gauss probability math.
|
|
// DATE: 2023-07-06
|
|
|
|
|
|
#include "Arduino.h"
|
|
|
|
#define GAUSS_LIB_VERSION (F("0.2.1"))
|
|
|
|
|
|
class Gauss
|
|
{
|
|
public:
|
|
Gauss()
|
|
{
|
|
_mean = 0;
|
|
_reciprokeSD = 1; // math optimization.
|
|
}
|
|
|
|
// stddev should be positive.
|
|
bool begin(float mean = 0, float stddev = 1)
|
|
{
|
|
_mean = mean;
|
|
if (stddev == 0) _reciprokeSD = NAN;
|
|
else _reciprokeSD = 1.0 / stddev;
|
|
return (stddev > 0);
|
|
}
|
|
|
|
|
|
float getMean()
|
|
{
|
|
return _mean;
|
|
}
|
|
|
|
|
|
float getStdDev()
|
|
{
|
|
return 1.0 / _reciprokeSD;
|
|
}
|
|
|
|
|
|
float P_smaller(float value)
|
|
{
|
|
if (_reciprokeSD == NAN) return NAN;
|
|
return _P_smaller((value - _mean) * _reciprokeSD);
|
|
}
|
|
|
|
|
|
float P_larger(float value)
|
|
{
|
|
return 1.0 - P_smaller(value);
|
|
}
|
|
|
|
|
|
float P_between(float p, float q)
|
|
{
|
|
if (_reciprokeSD == NAN) return NAN;
|
|
if (p >= q) return 0;
|
|
return P_smaller(q) - P_smaller(p);
|
|
}
|
|
|
|
|
|
float P_outside(float p, float q)
|
|
{
|
|
return 1.0 - P_between(p, q);
|
|
}
|
|
|
|
|
|
float P_equal(float value)
|
|
{
|
|
if (_reciprokeSD == NAN) return NAN;
|
|
float n = (value - _mean) * _reciprokeSD;
|
|
// gain of ~10% if we allocate a global var for 'constant' c
|
|
float c = _reciprokeSD * (1.0 / sqrt(TWO_PI));
|
|
return c * exp(-0.5 * (n * n));
|
|
}
|
|
|
|
|
|
float stddevs(float value)
|
|
{
|
|
return normalize(value);
|
|
}
|
|
|
|
|
|
float normalize(float value)
|
|
{
|
|
return (value - _mean) * _reciprokeSD;
|
|
}
|
|
|
|
|
|
float denormalize(float value)
|
|
{
|
|
return value / _reciprokeSD + _mean;
|
|
}
|
|
|
|
|
|
float bellCurve(float value)
|
|
{
|
|
return P_equal(value);
|
|
}
|
|
|
|
|
|
float CDF(float value)
|
|
{
|
|
return P_smaller(value);
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
float _P_smaller(float x)
|
|
{
|
|
// NORM.DIST(mean, stddev, x, true)
|
|
// these points correspond with
|
|
// 0.0 .. 3.0 in steps of 0.1 followed by 4.0, 5.0 and 6.0
|
|
float __gauss[] = {
|
|
0.50000000, 0.53982784, 0.57925971, 0.61791142,
|
|
0.65542174, 0.69146246, 0.72574688, 0.75803635,
|
|
0.78814460, 0.81593987, 0.84134475, 0.86433394,
|
|
0.88493033, 0.90319952, 0.91924334, 0.93319280,
|
|
0.94520071, 0.95543454, 0.96406968, 0.97128344,
|
|
0.97724987, 0.98213558, 0.98609655, 0.98927589,
|
|
0.99180246, 0.99379033, 0.99533881, 0.99653303,
|
|
0.99744487, 0.99813419, 0.99865010, 0.99996833,
|
|
0.99999971, 1.00000000
|
|
};
|
|
|
|
bool neg = false;
|
|
if (x < 0)
|
|
{
|
|
neg = true;
|
|
x = -x;
|
|
}
|
|
|
|
if (x >= 6.0)
|
|
{
|
|
if (neg) return 0.0;
|
|
return 1.0;
|
|
}
|
|
|
|
if (x <= 3.0)
|
|
{
|
|
int idx = x * 10;
|
|
float rv = __gauss[idx] + ((x * 10) - idx) * (__gauss[idx+1] - __gauss[idx]);
|
|
if (neg) return 1.0 - rv;
|
|
return rv;
|
|
}
|
|
|
|
// 3.0 .. 6.0
|
|
int xint = x;
|
|
int idx = 27 + xint;
|
|
float rv = __gauss[idx] + (x - xint) * (__gauss[idx+1] - __gauss[idx]);
|
|
if (neg) return 1.0 - rv;
|
|
return rv;
|
|
}
|
|
|
|
float _mean = 0;
|
|
// reciprokeSD = 1.0 / stddev is faster in most math (MUL vs DIV)
|
|
float _reciprokeSD = 1;
|
|
};
|
|
|
|
|
|
// -- END OF FILE --
|
|
|