summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-06-20 11:19:33 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-06-20 11:19:33 +0200
commitaaf7965df8b423bcacd411931d4cb0bb238ced61 (patch)
tree8c0cfe7dcb2816870405742c16bb5bb64ec95a2a
parentafb4f51a5526822681b147d5cbf37b6f818c49ca (diff)
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
-rw-r--r--filter-ewma2/ftnoir_ewma_filtercontrols.ui250
-rw-r--r--filter-ewma2/ftnoir_filter_ewma2.cpp50
-rw-r--r--filter-ewma2/ftnoir_filter_ewma2.h26
-rw-r--r--filter-ewma2/ftnoir_filter_ewma2_dialog.cpp38
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 @@
<height>380</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="windowTitle">
- <string>EWMA2 filter settings</string>
+ <string>EWMA filter settings</string>
</property>
<property name="windowIcon">
- <iconset resource="ewma-filter.qrc">
+ <iconset resource="../gui/ui-res.qrc">
<normaloff>:/images/filter-16.png</normaloff>:/images/filter-16.png</iconset>
</property>
<property name="layoutDirection">
@@ -39,30 +45,24 @@
<property name="bottomMargin">
<number>2</number>
</property>
- <item row="0" column="0">
- <widget class="QLabel" name="lblInvert1_6">
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblInvert1_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
- <string>Min</string>
+ <string>Max</string>
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QSlider" name="minSmooth">
+ <item row="1" column="1">
+ <widget class="QSlider" name="maxSmooth">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -70,16 +70,19 @@
</sizepolicy>
</property>
<property name="minimum">
- <number>1</number>
+ <number>0</number>
</property>
<property name="maximum">
- <number>100</number>
+ <number>1000</number>
</property>
- <property name="pageStep">
+ <property name="singleStep">
<number>5</number>
</property>
+ <property name="pageStep">
+ <number>50</number>
+ </property>
<property name="value">
- <number>2</number>
+ <number>1000</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -89,55 +92,30 @@
</property>
</widget>
</item>
- <item row="0" column="2">
- <widget class="QSpinBox" name="spinMinSmooth">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- <property name="buttonSymbols">
- <enum>QAbstractSpinBox::PlusMinus</enum>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>120</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="lblInvert1_7">
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblInvert1_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
- <string>Max</string>
+ <string>Min</string>
</property>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QSlider" name="maxSmooth">
+ <item row="0" column="1">
+ <widget class="QSlider" name="minSmooth">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -148,13 +126,16 @@
<number>1</number>
</property>
<property name="maximum">
- <number>100</number>
+ <number>1000</number>
</property>
- <property name="pageStep">
+ <property name="singleStep">
<number>5</number>
</property>
+ <property name="pageStep">
+ <number>50</number>
+ </property>
<property name="value">
- <number>10</number>
+ <number>1000</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -164,38 +145,7 @@
</property>
</widget>
</item>
- <item row="1" column="2">
- <widget class="QSpinBox" name="spinMaxSmooth">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- <property name="buttonSymbols">
- <enum>QAbstractSpinBox::PlusMinus</enum>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>120</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>10</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="lblInvert1_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@@ -211,7 +161,7 @@
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QSlider" name="powCurve">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
@@ -220,16 +170,19 @@
</sizepolicy>
</property>
<property name="minimum">
- <number>1</number>
+ <number>0</number>
</property>
<property name="maximum">
- <number>100</number>
+ <number>1000</number>
</property>
- <property name="pageStep">
+ <property name="singleStep">
<number>5</number>
</property>
+ <property name="pageStep">
+ <number>50</number>
+ </property>
<property name="value">
- <number>10</number>
+ <number>1000</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -239,31 +192,51 @@
</property>
</widget>
</item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="spinPowCurve">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item row="0" column="2">
+ <widget class="QLabel" name="min_label">
+ <property name="minimumSize">
+ <size>
+ <width>45</width>
+ <height>0</height>
+ </size>
</property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
+ <property name="text">
+ <string>100%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLabel" name="max_label">
+ <property name="minimumSize">
+ <size>
+ <width>45</width>
+ <height>0</height>
+ </size>
</property>
- <property name="readOnly">
- <bool>true</bool>
+ <property name="text">
+ <string>100%</string>
</property>
- <property name="buttonSymbols">
- <enum>QAbstractSpinBox::PlusMinus</enum>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
- <property name="maximum">
- <number>100</number>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QLabel" name="curve_label">
+ <property name="minimumSize">
+ <size>
+ <width>45</width>
+ <height>0</height>
+ </size>
</property>
- <property name="singleStep">
- <number>5</number>
+ <property name="text">
+ <string>100%</string>
</property>
- <property name="value">
- <number>10</number>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
@@ -312,58 +285,9 @@ p, li { white-space: pre-wrap; }
</layout>
</widget>
<resources>
- <include location="ewma-filter.qrc"/>
+ <include location="../gui/ui-res.qrc"/>
</resources>
- <connections>
- <connection>
- <sender>minSmooth</sender>
- <signal>valueChanged(int)</signal>
- <receiver>spinMinSmooth</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>303</x>
- <y>33</y>
- </hint>
- <hint type="destinationlabel">
- <x>391</x>
- <y>36</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>maxSmooth</sender>
- <signal>valueChanged(int)</signal>
- <receiver>spinMaxSmooth</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>281</x>
- <y>61</y>
- </hint>
- <hint type="destinationlabel">
- <x>390</x>
- <y>74</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>powCurve</sender>
- <signal>valueChanged(int)</signal>
- <receiver>spinPowCurve</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>236</x>
- <y>101</y>
- </hint>
- <hint type="destinationlabel">
- <x>391</x>
- <y>98</y>
- </hint>
- </hints>
- </connection>
- </connections>
+ <connections/>
<slots>
<slot>startEngineClicked()</slot>
<slot>stopEngineClicked()</slot>
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<slider_value>(s.kSmoothingScaleCurve);
+ // min/max smoothing .01->1
+ const double min_smoothing = static_cast<slider_value>(s.kMinSmoothing);
+ const double max_smoothing = std::max(min_smoothing, static_cast<slider_value>(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<double>(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<double>(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 <QElapsedTimer>
#include <QWidget>
#include <QMutex>
#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<int> kMinSmoothing, kMaxSmoothing, kSmoothingScaleCurve;
+ value<slider_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 <cmath>
#include <QDebug>
+#include <QString>
#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<slider_value>(s.kSmoothingScaleCurve).cur() * 100, 'f', 2) + "%");
+ ui.min_label->setText(QString::number(static_cast<slider_value>(s.kMinSmoothing).cur() * 100, 'f', 2) + "%");
+ ui.max_label->setText(QString::number(static_cast<slider_value>(s.kMaxSmoothing).cur() * 100, 'f', 2) + "%");
}