machines/components/pid-controller/firmware/ppmath_statistics.h
2024-01-20 15:04:46 +01:00

116 lines
3.0 KiB
C++

#ifndef PPMATH_STATISTICS_H
#define PPMATH_STATISTICS_H
#include <Arduino.h>
#include <math.h>
#define STAT_USE_STDEV
#ifdef __cplusplus
// C++11 solution that is standards compliant. Return type is deduced automatically
template <class L, class R>
static inline constexpr auto MIN(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
return lhs < rhs ? lhs : rhs;
}
template <class L, class R>
static inline constexpr auto MAX(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
return lhs > rhs ? lhs : rhs;
}
template <class T>
static inline constexpr const T ABS(const T v)
{
return v >= 0 ? v : -v;
}
#else
// Using GCC extensions, but Travis GCC version does not like it and gives
// "error: statement-expressions are not allowed outside functions nor in template-argument lists"
#define MIN(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; })
#define MAX(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; })
#define ABS(a) \
({__typeof__(a) _a = (a); \
_a >= 0 ? _a : -_a; })
#endif
class Statistic
{
public:
Statistic(); // "switches on/off" stdev run time
void clear(); // "switches on/off" stdev run time
void add(const float);
// returns the number of values added
uint32_t count() const { return _cnt; }; // zero if empty
float sum() const { return _sum; }; // zero if empty
float minimum() const { return _min; }; // zero if empty
float maximum() const { return _max; }; // zero if empty
float average() const; // NAN if empty
float mean() const; // zero if empty
#ifdef STAT_USE_STDEV
float variance() const; // NAN if empty
float pop_stdev() const; // population stdev // NAN if empty
float unbiased_stdev() const; // NAN if empty
#endif
protected:
uint32_t _cnt;
float _sum;
float _min;
float _max;
#ifdef STAT_USE_STDEV
float _ssqdif; // sum of squares difference
#endif
};
/**
* Returns the kth q-quantile.
* @link http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population
* ie: median is 1st 2-quantile
* ie: upper quartile is 3rd 4-quantile
* @return {Number} q-quantile of values.
*/
/*
const quantile = (arr: number[], i: number, n: number) => {
if (i === 0) return Math.min.apply(null, arr);
if (i === n) return Math.max.apply(null, arr);
let sorted = arr.slice(0);
sorted.sort((a, b) => a - b);
let index = sorted.length * i / n;
if (index % 1 === 0) {
return 0.5 * sorted[index - 1] + 0.5 * sorted[index];
}
return sorted[~~index];
};
export const median = (arr: number[]) => quantile(arr, 1, 2);
export const sum = (arr: number[]) => arr.reduce((a, b) => a + b, 0);
export const mean = (arr: number[]) => sum(arr) / arr.length;
// sqare errors along mean
const sdiff = (arr: number[], mean: number) => arr.map((v) =>
Math.pow(v - mean, 2)
);
export const standardDeviation = (arr: number[]) =>
Math.sqrt(mean(sdiff(arr, mean(arr))));
*/
#endif