esphome/components/nimble_distance/OneEuro.h
2023-12-02 12:01:23 +03:00

81 lines
1.7 KiB
C++

#ifndef ONEEURO_H
#define ONEEURO_H
/*
1-Euro Filter, template-compliant version
Jonathan Aceituno <join@oin.name>
25/04/14: fixed bug with last_time_ never updated on line 40
For details, see http://www.lifl.fr/~casiez/1euro
Updates:
- 23 May 2019 by Haimo Zhang <zh.hammer.dev@gmail.com>
- Included Arduino header
*/
#ifdef ARDUINO
/**
* cmath is not included in Arduino library, but we have the Arduino.h header
* which defines the abs macro.
*/
#include <Arduino.h>
#else
#include <cmath>
#endif
template <typename T = double>
struct low_pass_filter {
low_pass_filter() : hatxprev(0), xprev(0), hadprev(false) {}
T operator()(T x, T alpha) {
T hatx;
if(hadprev) {
hatx = alpha * x + (1-alpha) * hatxprev;
} else {
hatx = x;
hadprev = true;
}
hatxprev = hatx;
xprev = x;
return hatx;
}
T hatxprev;
T xprev;
bool hadprev;
};
template <typename T = double, typename timestamp_t = double>
struct one_euro_filter {
one_euro_filter(double _freq, T _mincutoff, T _beta, T _dcutoff) : freq(_freq), mincutoff(_mincutoff), beta(_beta), dcutoff(_dcutoff), last_time_(-1) {}
T operator()(T x, timestamp_t t = -1) {
T dx = 0;
if(last_time_ != -1 && t != -1 && t != last_time_) {
freq = 1.0 / (t - last_time_);
}
last_time_ = t;
if(xfilt_.hadprev)
dx = (x - xfilt_.xprev) * freq;
T edx = dxfilt_(dx, alpha(dcutoff));
T cutoff = mincutoff + beta * abs(static_cast<double>(edx));
return xfilt_(x, alpha(cutoff));
}
double freq;
T mincutoff, beta, dcutoff;
private:
T alpha(T cutoff) {
T tau = 1.0 / (2 * M_PI * cutoff);
T te = 1.0 / freq;
return 1.0 / (1.0 + tau / te);
}
timestamp_t last_time_;
low_pass_filter<T> xfilt_, dxfilt_;
};
#endif