From a168e81cca6447019019a2b621308f82ba56b5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Fri, 27 Nov 2020 16:31:05 +0100 Subject: [PATCH] minimal median filter implementation for math testing --- Software/PC_Application/Application.pro | 2 + .../Traces/Math/medianfilter.cpp | 65 +++++++++++++++++++ .../PC_Application/Traces/Math/medianfilter.h | 33 ++++++++++ .../PC_Application/Traces/Math/tracemath.cpp | 7 +- .../PC_Application/Traces/Math/tracemath.h | 11 ++-- .../Traces/Math/tracematheditdialog.cpp | 12 ++++ .../Traces/Math/tracematheditdialog.h | 1 + Software/PC_Application/Traces/trace.cpp | 17 ++--- .../PC_Application/Traces/tracexyplot.cpp | 10 +-- 9 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 Software/PC_Application/Traces/Math/medianfilter.cpp create mode 100644 Software/PC_Application/Traces/Math/medianfilter.h diff --git a/Software/PC_Application/Application.pro b/Software/PC_Application/Application.pro index 9f00806..90b6b5c 100644 --- a/Software/PC_Application/Application.pro +++ b/Software/PC_Application/Application.pro @@ -25,6 +25,7 @@ HEADERS += \ SpectrumAnalyzer/tracewidgetsa.h \ Tools/eseries.h \ Tools/impedancematchdialog.h \ + Traces/Math/medianfilter.h \ Traces/Math/tracemath.h \ Traces/Math/tracematheditdialog.h \ Traces/fftcomplex.h \ @@ -79,6 +80,7 @@ SOURCES += \ SpectrumAnalyzer/tracewidgetsa.cpp \ Tools/eseries.cpp \ Tools/impedancematchdialog.cpp \ + Traces/Math/medianfilter.cpp \ Traces/Math/tracemath.cpp \ Traces/Math/tracematheditdialog.cpp \ Traces/fftcomplex.cpp \ diff --git a/Software/PC_Application/Traces/Math/medianfilter.cpp b/Software/PC_Application/Traces/Math/medianfilter.cpp new file mode 100644 index 0000000..c91937f --- /dev/null +++ b/Software/PC_Application/Traces/Math/medianfilter.cpp @@ -0,0 +1,65 @@ +#include "medianfilter.h" + +using namespace Math; +using namespace std; + +MedianFilter::MedianFilter() +{ + kernelSize = 3; + order = Order::AbsoluteValue; +} + +TraceMath::DataType MedianFilter::outputType(TraceMath::DataType inputType) +{ + // domain stays the same + return inputType; +} + +QString MedianFilter::description() +{ + return "Median filter"; +} + +void MedianFilter::inputSamplesChanged(unsigned int begin, unsigned int end) { + if(data.size() != input->rData().size()) { + data.resize(input->rData().size()); + } + int start = (int) begin - (kernelSize-1)/2; + unsigned int stop = (int) end + (kernelSize-1)/2; + if(start < 0) { + start = 0; + } + if(stop >= input->rData().size()) { + stop = input->rData().size(); + } + for(unsigned int i=start;i> values; + for(int i=index - (kernelSize-1)/2;i<=index+(kernelSize-1)/2;i++) { + unsigned int inputSample; + if(i<0) { + inputSample = 0; + } else if(i>=(int) input->rData().size()) { + inputSample = input->rData().size() - 1; + } else { + inputSample = i; + } + values.push_back(input->rData().at(inputSample).y); + } + sort(values.begin(), values.end(), [=](const complex&a, const complex&b){ + switch(order) { + case Order::AbsoluteValue: return abs(a) > abs(b); + case Order::Phase: return arg(a) > arg(b); + case Order::Real: return real(a) > real(b); + case Order::Imag: return imag(a) > imag(b); + } + }); + data.at(index).y = values[(kernelSize-1)/2]; + data.at(index).x = input->rData().at(index).x; +} diff --git a/Software/PC_Application/Traces/Math/medianfilter.h b/Software/PC_Application/Traces/Math/medianfilter.h new file mode 100644 index 0000000..fa70e1f --- /dev/null +++ b/Software/PC_Application/Traces/Math/medianfilter.h @@ -0,0 +1,33 @@ +#ifndef MEDIANFILTER_H +#define MEDIANFILTER_H + +#include "tracemath.h" + +namespace Math { + +class MedianFilter : public TraceMath +{ +public: + MedianFilter(); + + virtual DataType outputType(DataType inputType) override; + virtual QString description() override; + +public slots: + // a single value of the input data has changed, index determines which sample has changed + virtual void inputSamplesChanged(unsigned int begin, unsigned int end) override; + +private: + void updateSample(int index); + int kernelSize; + enum class Order { + AbsoluteValue, + Phase, + Real, + Imag, + } order; +}; + +} + +#endif // MEDIANFILTER_H diff --git a/Software/PC_Application/Traces/Math/tracemath.cpp b/Software/PC_Application/Traces/Math/tracemath.cpp index 32ffcfb..743de67 100644 --- a/Software/PC_Application/Traces/Math/tracemath.cpp +++ b/Software/PC_Application/Traces/Math/tracemath.cpp @@ -36,10 +36,9 @@ void TraceMath::assignInput(TraceMath *input) this->input = input; inputTypeChanged(input->dataType); // do initial calculation - inputDataChanged(); + inputSamplesChanged(0, input->data.size()); // connect to input - connect(input, &TraceMath::outputDataChanged, this, &TraceMath::inputDataChanged); - connect(input, &TraceMath::outputSampleChanged, this, &TraceMath::inputSampleChanged); + connect(input, &TraceMath::outputSamplesChanged, this, &TraceMath::inputSamplesChanged); connect(input, &TraceMath::outputTypeChanged, this, &TraceMath::inputTypeChanged); } } @@ -50,7 +49,7 @@ void TraceMath::inputTypeChanged(TraceMath::DataType type) if(newType != dataType) { dataType = newType; data.clear(); - inputDataChanged(); + inputSamplesChanged(0, input->data.size()); emit outputTypeChanged(dataType); } } diff --git a/Software/PC_Application/Traces/Math/tracemath.h b/Software/PC_Application/Traces/Math/tracemath.h index c6b78cf..dfc20c3 100644 --- a/Software/PC_Application/Traces/Math/tracemath.h +++ b/Software/PC_Application/Traces/Math/tracemath.h @@ -27,8 +27,8 @@ public: // indicate whether this function produces time or frequency domain data virtual DataType outputType(DataType inputType) = 0; - virtual QString description() = 0; + virtual void edit(){}; void removeInput(); void assignInput(TraceMath *input); @@ -37,17 +37,14 @@ public: std::vector& rData() { return data;}; public slots: - // a single value of the input data has changed, index determines which sample has changed - virtual void inputSampleChanged(unsigned int index){Q_UNUSED(index)}; - // the complete input data has changed (e.g. cleared or all data modified by some operation) - virtual void inputDataChanged(){}; + // some values of the input data have changed, begin/end determine which sample(s) has changed + virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)}; void inputTypeChanged(DataType type); signals: // emit this whenever a sample changed (alternatively, if all samples are about to change, emit outputDataChanged after they have changed) - void outputSampleChanged(unsigned int index); - void outputDataChanged(); + void outputSamplesChanged(unsigned int begin, unsigned int end); // emit when the output type changed void outputTypeChanged(DataType type); diff --git a/Software/PC_Application/Traces/Math/tracematheditdialog.cpp b/Software/PC_Application/Traces/Math/tracematheditdialog.cpp index db9531c..3d93335 100644 --- a/Software/PC_Application/Traces/Math/tracematheditdialog.cpp +++ b/Software/PC_Application/Traces/Math/tracematheditdialog.cpp @@ -1,6 +1,8 @@ #include "tracematheditdialog.h" #include "ui_tracematheditdialog.h" +#include "medianfilter.h" + TraceMathEditDialog::TraceMathEditDialog(Trace &t, QWidget *parent) : QDialog(parent), ui(new Ui::TraceMathEditDialog) @@ -21,6 +23,9 @@ TraceMathEditDialog::TraceMathEditDialog(Trace &t, QWidget *parent) : } }); + connect(ui->bAdd, &QPushButton::clicked, [=](){ + model->addOperation(new Math::MedianFilter); + }); connect(ui->bDelete, &QPushButton::clicked, [=](){ model->deleteRow(ui->view->currentIndex().row()); }); @@ -110,6 +115,13 @@ Qt::ItemFlags MathModel::flags(const QModelIndex &index) const return (Qt::ItemFlags) flags; } +void MathModel::addOperation(TraceMath *math) +{ + beginInsertRows(QModelIndex(), t.getMathOperations().size(), t.getMathOperations().size()); + t.addMathOperation(math); + endInsertRows(); +} + void MathModel::deleteRow(unsigned int row) { beginRemoveRows(QModelIndex(), row, row); diff --git a/Software/PC_Application/Traces/Math/tracematheditdialog.h b/Software/PC_Application/Traces/Math/tracematheditdialog.h index 167ae57..3423093 100644 --- a/Software/PC_Application/Traces/Math/tracematheditdialog.h +++ b/Software/PC_Application/Traces/Math/tracematheditdialog.h @@ -27,6 +27,7 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; + void addOperation(TraceMath *math); void deleteRow(unsigned int row); void rowsSwapped(unsigned int top); diff --git a/Software/PC_Application/Traces/trace.cpp b/Software/PC_Application/Traces/trace.cpp index 4a7a1b0..933f679 100644 --- a/Software/PC_Application/Traces/trace.cpp +++ b/Software/PC_Application/Traces/trace.cpp @@ -22,9 +22,6 @@ Trace::Trace(QString name, QColor color, LiveParameter live) updateLastMath(mathOps.rbegin()); self.enabled = false; - mathOps.push_back(self); - mathOps.push_back(self); - mathOps.push_back(self); } Trace::~Trace() @@ -39,7 +36,7 @@ void Trace::clear() { data.clear(); settings.valid = false; emit cleared(this); - emit outputDataChanged(); + emit outputSamplesChanged(0, 0); } void Trace::addData(const Trace::Data& d) { @@ -74,7 +71,7 @@ void Trace::addData(const Trace::Data& d) { // insert at this position data.insert(lower, d); } - emit outputSampleChanged(lower - data.begin()); + emit outputSamplesChanged(lower - data.begin(), lower - data.begin() + 1); if(lower == data.begin()) { // received the first point, which means the last sweep just finished if(tdr_users) { @@ -173,7 +170,7 @@ void Trace::removeMarker(TraceMarker *m) void Trace::updateTimeDomainData() { - if(_data.size() < 2) { + if(data.size() < 2) { // can't compute anything timeDomain.clear(); return; @@ -258,13 +255,11 @@ void Trace::updateLastMath(vector::reverse_iterator start) Q_ASSERT(newLast != nullptr); if(newLast != lastMath) { if(lastMath != nullptr) { - disconnect(lastMath, &TraceMath::outputDataChanged, this, nullptr); - disconnect(lastMath, &TraceMath::outputSampleChanged, this, nullptr); + disconnect(lastMath, &TraceMath::outputSamplesChanged, this, nullptr); } lastMath = newLast; // relay signals of end of math chain - connect(lastMath, &TraceMath::outputDataChanged, this, &Trace::dataChanged); - connect(lastMath, &TraceMath::outputSampleChanged, this, &Trace::dataChanged); + connect(lastMath, &TraceMath::outputSamplesChanged, this, &Trace::dataChanged); } } @@ -419,7 +414,7 @@ bool Trace::hasMathOperations() void Trace::enableMath(bool enable) { - auto start = enable ? mathOps.rbegin() : make_reverse_iterator(mathOps.begin()); + auto start = enable ? mathOps.rbegin() : make_reverse_iterator(mathOps.begin() + 1); updateLastMath(start); } diff --git a/Software/PC_Application/Traces/tracexyplot.cpp b/Software/PC_Application/Traces/tracexyplot.cpp index 3212508..f5eb30c 100644 --- a/Software/PC_Application/Traces/tracexyplot.cpp +++ b/Software/PC_Application/Traces/tracexyplot.cpp @@ -666,8 +666,8 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo case YAxisType::Phase: case YAxisType::VSWR: { auto d = t->sample(sample); - ret.setY(traceToCoordinate(d.S, type)); - ret.setX(d.frequency); + ret.setY(traceToCoordinate(d.y, type)); + ret.setX(d.x); } break; case YAxisType::Impulse: @@ -714,12 +714,12 @@ unsigned int TraceXYPlot::numTraceSamples(Trace *t) QPoint TraceXYPlot::dataToPixel(Trace::Data d) { - if(d.frequency < XAxis.rangeMin || d.frequency > XAxis.rangeMax) { + if(d.x < XAxis.rangeMin || d.x > XAxis.rangeMax) { return QPoint(); } - auto y = traceToCoordinate(d.S, YAxis[0].type); + auto y = traceToCoordinate(d.y, YAxis[0].type); QPoint p; - p.setX(Util::Scale(d.frequency, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth)); + p.setX(Util::Scale(d.x, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth)); p.setY(Util::Scale(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0)); return p; }