Skip to content

Commit

Permalink
add moving variance
Browse files Browse the repository at this point in the history
  • Loading branch information
facontidavide committed Jan 4, 2024
1 parent 8fee659 commit 730172e
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 2 deletions.
2 changes: 2 additions & 0 deletions plotjuggler_app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ QT5_WRAP_UI ( UI_SRC

transforms/first_derivative.ui
transforms/moving_average_filter.ui
transforms/moving_variance.ui
transforms/moving_rms.ui
transforms/outlier_removal.ui
transforms/integral_transform.ui
Expand Down Expand Up @@ -79,6 +80,7 @@ SET( PLOtJUGGLER_SRC
transforms/lua_custom_function.cpp
transforms/moving_average_filter.cpp
transforms/moving_rms.cpp
transforms/moving_variance.cpp
transforms/outlier_removal.cpp
transforms/integral_transform.cpp
transforms/absolute_transform.cpp
Expand Down
6 changes: 4 additions & 2 deletions plotjuggler_app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "transforms/first_derivative.h"
#include "transforms/scale_transform.h"
#include "transforms/moving_average_filter.h"
#include "transforms/moving_variance.h"
#include "transforms/moving_rms.h"
#include "transforms/outlier_removal.h"
#include "transforms/integral_transform.h"
Expand Down Expand Up @@ -217,11 +218,12 @@ int main(int argc, char* argv[])
TransformFactory::registerTransform<OutlierRemovalFilter>();
TransformFactory::registerTransform<IntegralTransform>();
TransformFactory::registerTransform<AbsoluteTransform>();
TransformFactory::registerTransform<MovingVarianceFilter>();
//---------------------------

QCommandLineParser parser;
parser.setApplicationDescription("PlotJuggler: the time series visualization tool that "
"you deserve ");
parser.setApplicationDescription("PlotJuggler: the time series visualization"
" tool that you deserve ");
parser.addVersionOption();
parser.addHelpOption();

Expand Down
95 changes: 95 additions & 0 deletions plotjuggler_app/transforms/moving_variance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "moving_variance.h"
#include "ui_moving_variance.h"
#include <QCheckBox>

MovingVarianceFilter::MovingVarianceFilter()
: ui(new Ui::MovingVarianceFilter)
, _widget(new QWidget())
, _buffer(1)
, _ring_view(_buffer.begin(), _buffer.end())
{
ui->setupUi(_widget);

connect(ui->spinBoxSamples, qOverload<int>(&QSpinBox::valueChanged), this,
[=](int) { emit parametersChanged(); });

connect(ui->checkBoxStdDev, &QCheckBox::toggled, this,
[=]() { emit parametersChanged(); });
}

MovingVarianceFilter::~MovingVarianceFilter()
{
delete ui;
delete _widget;
}

void MovingVarianceFilter::reset()
{
_buffer.clear();
TransformFunction_SISO::reset();
}

std::optional<PlotData::Point> MovingVarianceFilter::calculateNextPoint(size_t index)
{
size_t buffer_size =
std::min(size_t(ui->spinBoxSamples->value()), size_t(dataSource()->size()));
if (buffer_size != _buffer.size())
{
_buffer.resize(buffer_size);
_ring_view = nonstd::ring_span<PlotData::Point>(_buffer.begin(), _buffer.end());
}

const auto& p = dataSource()->at(index);
_ring_view.push_back(p);

while (_ring_view.size() < buffer_size)
{
_ring_view.push_back(p);
}

double total = 0;
for (const auto& point: _ring_view)
{
total += point.y;
}
const double N = double(_ring_view.size());
const double avg = total / N;

double total_sqr = 0;
for (const auto& point: _ring_view)
{
const auto v = point.y - avg;
total_sqr += v*v;
}

if(ui->checkBoxStdDev->isChecked())
{
return PlotData::Point{ p.x, std::sqrt(total_sqr / N)};
}
return PlotData::Point{ p.x, total_sqr / N};
}

QWidget* MovingVarianceFilter::optionsWidget()
{
return _widget;
}

bool MovingVarianceFilter::xmlSaveState(QDomDocument& doc,
QDomElement& parent_element) const
{
QDomElement widget_el = doc.createElement("options");
widget_el.setAttribute("value", ui->spinBoxSamples->value());
widget_el.setAttribute("apply_sqrt",
ui->checkBoxStdDev->isChecked() ? "true" : "false");
parent_element.appendChild(widget_el);
return true;
}

bool MovingVarianceFilter::xmlLoadState(const QDomElement& parent_element)
{
QDomElement widget_el = parent_element.firstChildElement("options");
ui->spinBoxSamples->setValue(widget_el.attribute("value").toInt());
bool checked = widget_el.attribute("apply_sqrt") == "true";
ui->checkBoxStdDev->setChecked(checked);
return true;
}
44 changes: 44 additions & 0 deletions plotjuggler_app/transforms/moving_variance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <QRadioButton>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include "PlotJuggler/transform_function.h"
#include "ui_moving_variance.h"
#include "PlotJuggler/ring_span.hpp"

using namespace PJ;

namespace Ui
{
class MovingVarianceFilter;
}

class MovingVarianceFilter : public TransformFunction_SISO
{
public:
explicit MovingVarianceFilter();

~MovingVarianceFilter() override;

void reset() override;

const char* name() const override
{
return "Moving Variance";
}

QWidget* optionsWidget() override;

bool xmlSaveState(QDomDocument& doc, QDomElement& parent_element) const override;

bool xmlLoadState(const QDomElement& parent_element) override;

private:
Ui::MovingVarianceFilter* ui;
QWidget* _widget;
std::vector<PlotData::Point> _buffer;
nonstd::ring_span_lite::ring_span<PlotData::Point> _ring_view;

std::optional<PlotData::Point> calculateNextPoint(size_t index) override;
};
90 changes: 90 additions & 0 deletions plotjuggler_app/transforms/moving_variance.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MovingVarianceFilter</class>
<widget class="QWidget" name="MovingVarianceFilter">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>425</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Select the size of the window</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxSamples">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Window size:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxStdDev">
<property name="text">
<string>Apply square root</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>(i.e., convert to standard deviation)</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

0 comments on commit 730172e

Please sign in to comment.