From aa066bdd4622d4f6824fee864f6be6806813f04d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 30 Oct 2015 07:37:41 +0100 Subject: move to subdirectory-based build system Closes #224 --- filter-ewma2/CMakeLists.txt | 1 + filter-ewma2/ftnoir_ewma_filtercontrols.ui | 372 ++++++++++++++++++++++++++++ filter-ewma2/ftnoir_filter_ewma2.cpp | 81 ++++++ filter-ewma2/ftnoir_filter_ewma2.h | 66 +++++ filter-ewma2/ftnoir_filter_ewma2_dialog.cpp | 43 ++++ 5 files changed, 563 insertions(+) create mode 100644 filter-ewma2/CMakeLists.txt create mode 100644 filter-ewma2/ftnoir_ewma_filtercontrols.ui create mode 100644 filter-ewma2/ftnoir_filter_ewma2.cpp create mode 100644 filter-ewma2/ftnoir_filter_ewma2.h create mode 100644 filter-ewma2/ftnoir_filter_ewma2_dialog.cpp (limited to 'filter-ewma2') diff --git a/filter-ewma2/CMakeLists.txt b/filter-ewma2/CMakeLists.txt new file mode 100644 index 00000000..af786487 --- /dev/null +++ b/filter-ewma2/CMakeLists.txt @@ -0,0 +1 @@ +opentrack_boilerplate(opentrack-filter-ewma) diff --git a/filter-ewma2/ftnoir_ewma_filtercontrols.ui b/filter-ewma2/ftnoir_ewma_filtercontrols.ui new file mode 100644 index 00000000..9387f0d5 --- /dev/null +++ b/filter-ewma2/ftnoir_ewma_filtercontrols.ui @@ -0,0 +1,372 @@ + + + UICFilterControls + + + Qt::NonModal + + + + 0 + 0 + 448 + 380 + + + + EWMA2 filter settings + + + + :/images/filter-16.png:/images/filter-16.png + + + Qt::LeftToRight + + + false + + + + + + + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + Min + + + + + + + + 0 + 0 + + + + 1 + + + 100 + + + 5 + + + 2 + + + Qt::Horizontal + + + QSlider::NoTicks + + + + + + + + 0 + 0 + + + + background:none; + + + true + + + QAbstractSpinBox::PlusMinus + + + 1 + + + 120 + + + 5 + + + 2 + + + + + + + + 0 + 0 + + + + + + + Max + + + + + + + + 0 + 0 + + + + 1 + + + 100 + + + 5 + + + 10 + + + Qt::Horizontal + + + QSlider::NoTicks + + + + + + + + 0 + 0 + + + + background:none; + + + true + + + QAbstractSpinBox::PlusMinus + + + 1 + + + 120 + + + 5 + + + 10 + + + + + + + + 0 + 0 + + + + + + + Curve + + + + + + + + 0 + 0 + + + + 1 + + + 100 + + + 5 + + + 10 + + + Qt::Horizontal + + + QSlider::NoTicks + + + + + + + + 0 + 0 + + + + background:none; + + + true + + + QAbstractSpinBox::PlusMinus + + + 100 + + + 5 + + + 10 + + + + + + + + + + background-color: rgb(214, 214, 214); +border-color: rgb(0, 0, 0); + + + QFrame::Box + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Min:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Defines the way the filter responds to fast movements;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Higher value: slower response;</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Max:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Defines the way the filter responds to slow movements;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Higher value: slower response;</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Pow:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Defines the filters 'readiness' to respond to speed changes;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">Higher value = </span><span style=" font-family:'MS Shell Dlg 2'; font-weight:600;">faster</span><span style=" font-family:'MS Shell Dlg 2';"> response;</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + 5 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + 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() + cameraSettingsClicked() + + diff --git a/filter-ewma2/ftnoir_filter_ewma2.cpp b/filter-ewma2/ftnoir_filter_ewma2.cpp new file mode 100644 index 00000000..c09fb912 --- /dev/null +++ b/filter-ewma2/ftnoir_filter_ewma2.cpp @@ -0,0 +1,81 @@ +/* Copyright (c) 2014 Donovan Baarda + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ +#include "ftnoir_filter_ewma2.h" +#include +#include +#include +#include "opentrack/plugin-api.hpp" +#include +#include + +// Exponentially Weighted Moving Average (EWMA) Filter with dynamic smoothing. +// +// This filter tries to adjust the amount of filtering to minimize lag when +// moving, and minimize noise when still. It uses the delta filtered over the +// last 1/60sec (16ms) compared to the delta's average noise variance over +// the last 60sec to try and detect movement vs noise. As the delta increases +// from 0 to 3 stdevs of the noise, the filtering scales down from maxSmooth +// to minSmooth at a rate controlled by the powCurve setting. + + +FTNoIR_Filter::FTNoIR_Filter() +{ + 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()) { + timer.start(); + for (int i=0;i<6;i++) { + last_output[i] = input[i]; + last_delta[i] = 0.0; + last_noise[i] = 0.0; + } + } + // Get the time in seconds since last run and restart the timer. + auto dt = timer.restart() / 1000.0f; + // Calculate delta_alpha and noise_alpha from dt. + double delta_alpha = dt/(dt + delta_RC); + double noise_alpha = dt/(dt + noise_RC); + // Calculate the new camera position. + for (int i=0;i<6;i++) { + // 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]; + // Calculate the current and smoothed noise variance. + 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; + // 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; + // Calculate the dynamic alpha. + double alpha = dt/(dt + RC); + // Calculate the new output position. + output[i] = last_output[i] = alpha*input[i] + (1.0-alpha)*last_output[i]; + } +} + +OPENTRACK_DECLARE_FILTER(FTNoIR_Filter, FilterControls, FTNoIR_FilterDll) diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h new file mode 100644 index 00000000..bf4e83ad --- /dev/null +++ b/filter-ewma2/ftnoir_filter_ewma2.h @@ -0,0 +1,66 @@ +#pragma once + +#include "opentrack/plugin-api.hpp" +#include "ui_ftnoir_ewma_filtercontrols.h" +#include +#include +#include +#include "opentrack/options.hpp" +using namespace options; + +struct settings : opts { + // these are sadly sliders for now due to int/double mismatch -sh + value kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve; + settings() : + opts("ewma-filter"), + kMinSmoothing(b, "min-smoothing", 15), + kMaxSmoothing(b, "max-smoothing", 50), + kSmoothingScaleCurve(b, "smoothing-scale-curve", 10) + {} +}; + + +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; + // 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; + settings s; +}; + +class FilterControls: public IFilterDialog +{ + Q_OBJECT +public: + FilterControls(); + void register_filter(IFilter* flt); + void unregister_filter(); + +private: + Ui::UICFilterControls ui; + void save(); + settings s; + FTNoIR_Filter* pFilter; + +private slots: + void doOK(); + void doCancel(); +}; + +class FTNoIR_FilterDll : public Metadata +{ +public: + QString name() { return QString("EWMA"); } + QIcon icon() { return QIcon(":/images/filter-16.png"); } +}; diff --git a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp new file mode 100644 index 00000000..30fb6003 --- /dev/null +++ b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp @@ -0,0 +1,43 @@ +#include "ftnoir_filter_ewma2.h" +#include +#include +#include "opentrack/plugin-api.hpp" +#include "ui_ftnoir_ewma_filtercontrols.h" + +FilterControls::FilterControls() : pFilter(NULL) +{ + ui.setupUi( this ); + + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); + + 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; +} + +void FilterControls::unregister_filter() +{ + pFilter = NULL; +} + +void FilterControls::doOK() { + save(); + this->close(); +} + +void FilterControls::doCancel() { + s.b->reload(); + this->close(); +} + +void FilterControls::save() { + s.b->save(); + if (pFilter) + pFilter->receiveSettings(); +} -- cgit v1.2.3