From aaf7965df8b423bcacd411931d4cb0bb238ced61 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Mon, 20 Jun 2016 11:19:33 +0200 Subject: filter/ewma: cleanup, update - switch to our timer since it has more than millisecond precision - use slider_value for settings - sanitize allowed scaling curve bounds - ensure min <= max in dialog - ensure min <= max at filter runtime - check for NaN taking -ffast-math into account - simplify dialog logic - change delta smoothing constant --- filter-ewma2/ftnoir_ewma_filtercontrols.ui | 250 ++++++++++------------------ filter-ewma2/ftnoir_filter_ewma2.cpp | 50 +++--- filter-ewma2/ftnoir_filter_ewma2.h | 26 ++- filter-ewma2/ftnoir_filter_ewma2_dialog.cpp | 38 +++-- 4 files changed, 145 insertions(+), 219 deletions(-) diff --git a/filter-ewma2/ftnoir_ewma_filtercontrols.ui b/filter-ewma2/ftnoir_ewma_filtercontrols.ui index 9387f0d5..36826c2d 100644 --- a/filter-ewma2/ftnoir_ewma_filtercontrols.ui +++ b/filter-ewma2/ftnoir_ewma_filtercontrols.ui @@ -13,11 +13,17 @@ 380 + + + 0 + 0 + + - EWMA2 filter settings + EWMA filter settings - + :/images/filter-16.png:/images/filter-16.png @@ -39,30 +45,24 @@ 2 - - + + 0 0 - - - 0 - 0 - - - Min + Max - - + + 0 @@ -70,16 +70,19 @@ - 1 + 0 - 100 + 1000 - + 5 + + 50 + - 2 + 1000 Qt::Horizontal @@ -89,55 +92,30 @@ - - - - - 0 - 0 - - - - background:none; - - - true - - - QAbstractSpinBox::PlusMinus - - - 1 - - - 120 - - - 5 - - - 2 - - - - - + + 0 0 + + + 0 + 0 + + - Max + Min - - + + 0 @@ -148,13 +126,16 @@ 1 - 100 + 1000 - + 5 + + 50 + - 10 + 1000 Qt::Horizontal @@ -164,38 +145,7 @@ - - - - - 0 - 0 - - - - background:none; - - - true - - - QAbstractSpinBox::PlusMinus - - - 1 - - - 120 - - - 5 - - - 10 - - - - + @@ -211,7 +161,7 @@ - + @@ -220,16 +170,19 @@ - 1 + 0 - 100 + 1000 - + 5 + + 50 + - 10 + 1000 Qt::Horizontal @@ -239,31 +192,51 @@ - - - - - 0 - 0 - + + + + + 45 + 0 + - - background:none; + + 100% + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 45 + 0 + - - true + + 100% - - QAbstractSpinBox::PlusMinus + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - 100 + + + + + + + 45 + 0 + - - 5 + + 100% - - 10 + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -312,58 +285,9 @@ p, li { white-space: pre-wrap; } - + - - - minSmooth - valueChanged(int) - spinMinSmooth - setValue(int) - - - 303 - 33 - - - 391 - 36 - - - - - maxSmooth - valueChanged(int) - spinMaxSmooth - setValue(int) - - - 281 - 61 - - - 390 - 74 - - - - - powCurve - valueChanged(int) - spinPowCurve - setValue(int) - - - 236 - 101 - - - 391 - 98 - - - - + startEngineClicked() stopEngineClicked() diff --git a/filter-ewma2/ftnoir_filter_ewma2.cpp b/filter-ewma2/ftnoir_filter_ewma2.cpp index bf4b1083..7229c6d6 100644 --- a/filter-ewma2/ftnoir_filter_ewma2.cpp +++ b/filter-ewma2/ftnoir_filter_ewma2.cpp @@ -22,39 +22,42 @@ // to minSmooth at a rate controlled by the powCurve setting. -FTNoIR_Filter::FTNoIR_Filter() +FTNoIR_Filter::FTNoIR_Filter() : first_run(true) { - reset(); -} - -void FTNoIR_Filter::receiveSettings() -{ - s.b->reload(); -} - -void FTNoIR_Filter::reset() -{ - timer.invalidate(); } void FTNoIR_Filter::filter(const double *input, double *output) { // Start the timer and initialise filter state if it's not running. - if (!timer.isValid()) { + if (first_run) + { + first_run = false; timer.start(); - for (int i=0;i<6;i++) { + for (int i=0;i<6;i++) + { last_output[i] = input[i]; - last_delta[i] = 0.0; - last_noise[i] = 0.0; + last_delta[i] = 0; + last_noise[i] = 0; } } // Get the time in seconds since last run and restart the timer. - const double dt = timer.restart() / 1000.; + const double dt = timer.elapsed_seconds(); + timer.start(); // Calculate delta_alpha and noise_alpha from dt. double delta_alpha = dt/(dt + delta_RC); double noise_alpha = dt/(dt + noise_RC); + + // scale curve .01->1 where 1.0 is sqrt(norm_noise). + const double smoothing_scale_curve = static_cast(s.kSmoothingScaleCurve); + // min/max smoothing .01->1 + const double min_smoothing = static_cast(s.kMinSmoothing); + const double max_smoothing = std::max(min_smoothing, static_cast(s.kMaxSmoothing).cur()); + // Calculate the new camera position. - for (int i=0;i<6;i++) { + for (int i=0;i<6;i++) + { + using std::pow; + // Calculate the current and smoothed delta. double delta = input[i] - last_output[i]; last_delta[i] = delta_alpha*delta + (1.0-delta_alpha)*last_delta[i]; @@ -62,15 +65,10 @@ void FTNoIR_Filter::filter(const double *input, double *output) double noise = last_delta[i]*last_delta[i]; last_noise[i] = noise_alpha*noise + (1.0-noise_alpha)*last_noise[i]; // Normalise the noise between 0->1 for 0->9 variances (0->3 stddevs). - double norm_noise = std::min(noise/(9.0*last_noise[i]), 1.0); - if (std::isnan(norm_noise)) - norm_noise = 0; + double norm_noise = last_noise[i] < 1e-10 ? 0 : std::min(noise/(9.0*last_noise[i]), 1.0); // Calculate the smoothing 0.0->1.0 from the normalized noise. - // TODO(abo): change kSmoothingScaleCurve to a float where 1.0 is sqrt(norm_noise). - double smoothing = 1.0 - pow(norm_noise, s.kSmoothingScaleCurve/20.0); - // Currently min/max smoothing are ints 0->100. We want 0.0->3.0 seconds. - // TODO(abo): Change kMinSmoothing, kMaxSmoothing to floats 0.0->3.0 seconds RC. - double RC = 3.0*(s.kMinSmoothing + smoothing*(s.kMaxSmoothing - s.kMinSmoothing))/100.0; + double smoothing = 1.0 - pow(norm_noise, smoothing_scale_curve); + double RC = (min_smoothing + smoothing*(max_smoothing - min_smoothing)); // Calculate the dynamic alpha. double alpha = dt/(dt + RC); // Calculate the new output position. diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h index bdb9cedc..328279ac 100644 --- a/filter-ewma2/ftnoir_filter_ewma2.h +++ b/filter-ewma2/ftnoir_filter_ewma2.h @@ -2,20 +2,20 @@ #include "opentrack/plugin-api.hpp" #include "ui_ftnoir_ewma_filtercontrols.h" -#include #include #include #include "opentrack-compat/options.hpp" +#include "opentrack-compat/timer.hpp" using namespace options; struct settings : opts { // these are sadly sliders for now due to int/double mismatch -sh - value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; + value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; settings() : opts("ewma-filter"), - kMinSmoothing(b, "min-smoothing", 15), - kMaxSmoothing(b, "max-smoothing", 50), - kSmoothingScaleCurve(b, "smoothing-scale-curve", 10) + kMinSmoothing(b, "min-smoothing", slider_value(.02, .01, 1)), + kMaxSmoothing(b, "max-smoothing", slider_value(.7, .01, 1)), + kSmoothingScaleCurve(b, "smoothing-scale-curve", slider_value(.7, .01, 1)) {} }; @@ -24,19 +24,18 @@ class FTNoIR_Filter : public IFilter { public: FTNoIR_Filter(); - void reset(); void filter(const double *input, double *output); - void receiveSettings(); private: - // Deltas are smoothed over the last 1/60sec (16ms). - const double delta_RC = 0.016; + // Deltas are smoothed over the last 1/20sec. + const double delta_RC = 1./20; // Noise is smoothed over the last 60sec. const double noise_RC = 60.0; double last_delta[6]; double last_noise[6]; double last_output[6]; - QElapsedTimer timer; + Timer timer; settings s; + bool first_run; }; class FilterControls: public IFilterDialog @@ -44,18 +43,17 @@ class FilterControls: public IFilterDialog Q_OBJECT public: FilterControls(); - void register_filter(IFilter* flt); - void unregister_filter(); + void register_filter(IFilter*) override {} + void unregister_filter() override {} private: Ui::UICFilterControls ui; - void save(); settings s; - FTNoIR_Filter* pFilter; private slots: void doOK(); void doCancel(); + void update_labels(int); }; class FTNoIR_FilterDll : public Metadata diff --git a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp index 5425fada..fca1d0ff 100644 --- a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp +++ b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp @@ -1,12 +1,13 @@ #include "ftnoir_filter_ewma2.h" #include #include +#include #include "opentrack/plugin-api.hpp" #include "ui_ftnoir_ewma_filtercontrols.h" -FilterControls::FilterControls() : pFilter(NULL) +FilterControls::FilterControls() { - ui.setupUi( this ); + ui.setupUi(this); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); @@ -14,20 +15,24 @@ FilterControls::FilterControls() : pFilter(NULL) tie_setting(s.kMaxSmoothing, ui.maxSmooth); tie_setting(s.kMinSmoothing, ui.minSmooth); tie_setting(s.kSmoothingScaleCurve, ui.powCurve); -} -void FilterControls::register_filter(IFilter* flt) -{ - pFilter = (FTNoIR_Filter*) flt; -} + connect(ui.powCurve, &QSlider::valueChanged, this, &FilterControls::update_labels); + connect(ui.minSmooth, &QSlider::valueChanged, this, &FilterControls::update_labels); + connect(ui.maxSmooth, &QSlider::valueChanged, this, &FilterControls::update_labels); -void FilterControls::unregister_filter() -{ - pFilter = NULL; + using std::min; + using std::max; + + connect(ui.minSmooth, &QSlider::valueChanged, this, + [&](int v) -> void { if (ui.maxSmooth->value() < v) ui.maxSmooth->setValue(v); }); + + connect(ui.maxSmooth, &QSlider::valueChanged, this, + [&](int v) -> void { if (ui.minSmooth->value() > v) ui.minSmooth->setValue(v); }); } -void FilterControls::doOK() { - save(); +void FilterControls::doOK() +{ + s.b->save(); close(); } @@ -36,8 +41,9 @@ void FilterControls::doCancel() close(); } -void FilterControls::save() { - s.b->save(); - if (pFilter) - pFilter->receiveSettings(); +void FilterControls::update_labels(int) +{ + ui.curve_label->setText(QString::number(static_cast(s.kSmoothingScaleCurve).cur() * 100, 'f', 2) + "%"); + ui.min_label->setText(QString::number(static_cast(s.kMinSmoothing).cur() * 100, 'f', 2) + "%"); + ui.max_label->setText(QString::number(static_cast(s.kMaxSmoothing).cur() * 100, 'f', 2) + "%"); } -- cgit v1.2.3