minimal median filter implementation for math testing
This commit is contained in:
parent
692bb85b5d
commit
a168e81cca
@ -25,6 +25,7 @@ HEADERS += \
|
|||||||
SpectrumAnalyzer/tracewidgetsa.h \
|
SpectrumAnalyzer/tracewidgetsa.h \
|
||||||
Tools/eseries.h \
|
Tools/eseries.h \
|
||||||
Tools/impedancematchdialog.h \
|
Tools/impedancematchdialog.h \
|
||||||
|
Traces/Math/medianfilter.h \
|
||||||
Traces/Math/tracemath.h \
|
Traces/Math/tracemath.h \
|
||||||
Traces/Math/tracematheditdialog.h \
|
Traces/Math/tracematheditdialog.h \
|
||||||
Traces/fftcomplex.h \
|
Traces/fftcomplex.h \
|
||||||
@ -79,6 +80,7 @@ SOURCES += \
|
|||||||
SpectrumAnalyzer/tracewidgetsa.cpp \
|
SpectrumAnalyzer/tracewidgetsa.cpp \
|
||||||
Tools/eseries.cpp \
|
Tools/eseries.cpp \
|
||||||
Tools/impedancematchdialog.cpp \
|
Tools/impedancematchdialog.cpp \
|
||||||
|
Traces/Math/medianfilter.cpp \
|
||||||
Traces/Math/tracemath.cpp \
|
Traces/Math/tracemath.cpp \
|
||||||
Traces/Math/tracematheditdialog.cpp \
|
Traces/Math/tracematheditdialog.cpp \
|
||||||
Traces/fftcomplex.cpp \
|
Traces/fftcomplex.cpp \
|
||||||
|
65
Software/PC_Application/Traces/Math/medianfilter.cpp
Normal file
65
Software/PC_Application/Traces/Math/medianfilter.cpp
Normal file
@ -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<stop;i++) {
|
||||||
|
updateSample(i);
|
||||||
|
}
|
||||||
|
emit outputSamplesChanged(start, stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MedianFilter::updateSample(int index)
|
||||||
|
{
|
||||||
|
vector<complex<double>> 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<double>&a, const complex<double>&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;
|
||||||
|
}
|
33
Software/PC_Application/Traces/Math/medianfilter.h
Normal file
33
Software/PC_Application/Traces/Math/medianfilter.h
Normal file
@ -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
|
@ -36,10 +36,9 @@ void TraceMath::assignInput(TraceMath *input)
|
|||||||
this->input = input;
|
this->input = input;
|
||||||
inputTypeChanged(input->dataType);
|
inputTypeChanged(input->dataType);
|
||||||
// do initial calculation
|
// do initial calculation
|
||||||
inputDataChanged();
|
inputSamplesChanged(0, input->data.size());
|
||||||
// connect to input
|
// connect to input
|
||||||
connect(input, &TraceMath::outputDataChanged, this, &TraceMath::inputDataChanged);
|
connect(input, &TraceMath::outputSamplesChanged, this, &TraceMath::inputSamplesChanged);
|
||||||
connect(input, &TraceMath::outputSampleChanged, this, &TraceMath::inputSampleChanged);
|
|
||||||
connect(input, &TraceMath::outputTypeChanged, this, &TraceMath::inputTypeChanged);
|
connect(input, &TraceMath::outputTypeChanged, this, &TraceMath::inputTypeChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +49,7 @@ void TraceMath::inputTypeChanged(TraceMath::DataType type)
|
|||||||
if(newType != dataType) {
|
if(newType != dataType) {
|
||||||
dataType = newType;
|
dataType = newType;
|
||||||
data.clear();
|
data.clear();
|
||||||
inputDataChanged();
|
inputSamplesChanged(0, input->data.size());
|
||||||
emit outputTypeChanged(dataType);
|
emit outputTypeChanged(dataType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ public:
|
|||||||
|
|
||||||
// indicate whether this function produces time or frequency domain data
|
// indicate whether this function produces time or frequency domain data
|
||||||
virtual DataType outputType(DataType inputType) = 0;
|
virtual DataType outputType(DataType inputType) = 0;
|
||||||
|
|
||||||
virtual QString description() = 0;
|
virtual QString description() = 0;
|
||||||
|
virtual void edit(){};
|
||||||
|
|
||||||
void removeInput();
|
void removeInput();
|
||||||
void assignInput(TraceMath *input);
|
void assignInput(TraceMath *input);
|
||||||
@ -37,17 +37,14 @@ public:
|
|||||||
std::vector<Data>& rData() { return data;};
|
std::vector<Data>& rData() { return data;};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// a single value of the input data has changed, index determines which sample has changed
|
// some values of the input data have changed, begin/end determine which sample(s) has changed
|
||||||
virtual void inputSampleChanged(unsigned int index){Q_UNUSED(index)};
|
virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)};
|
||||||
// the complete input data has changed (e.g. cleared or all data modified by some operation)
|
|
||||||
virtual void inputDataChanged(){};
|
|
||||||
|
|
||||||
void inputTypeChanged(DataType type);
|
void inputTypeChanged(DataType type);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// emit this whenever a sample changed (alternatively, if all samples are about to change, emit outputDataChanged after they have changed)
|
// 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 outputSamplesChanged(unsigned int begin, unsigned int end);
|
||||||
void outputDataChanged();
|
|
||||||
// emit when the output type changed
|
// emit when the output type changed
|
||||||
void outputTypeChanged(DataType type);
|
void outputTypeChanged(DataType type);
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "tracematheditdialog.h"
|
#include "tracematheditdialog.h"
|
||||||
#include "ui_tracematheditdialog.h"
|
#include "ui_tracematheditdialog.h"
|
||||||
|
|
||||||
|
#include "medianfilter.h"
|
||||||
|
|
||||||
TraceMathEditDialog::TraceMathEditDialog(Trace &t, QWidget *parent) :
|
TraceMathEditDialog::TraceMathEditDialog(Trace &t, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::TraceMathEditDialog)
|
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, [=](){
|
connect(ui->bDelete, &QPushButton::clicked, [=](){
|
||||||
model->deleteRow(ui->view->currentIndex().row());
|
model->deleteRow(ui->view->currentIndex().row());
|
||||||
});
|
});
|
||||||
@ -110,6 +115,13 @@ Qt::ItemFlags MathModel::flags(const QModelIndex &index) const
|
|||||||
return (Qt::ItemFlags) flags;
|
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)
|
void MathModel::deleteRow(unsigned int row)
|
||||||
{
|
{
|
||||||
beginRemoveRows(QModelIndex(), row, row);
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
|
@ -27,6 +27,7 @@ public:
|
|||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
void addOperation(TraceMath *math);
|
||||||
void deleteRow(unsigned int row);
|
void deleteRow(unsigned int row);
|
||||||
void rowsSwapped(unsigned int top);
|
void rowsSwapped(unsigned int top);
|
||||||
|
|
||||||
|
@ -22,9 +22,6 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
|
|||||||
updateLastMath(mathOps.rbegin());
|
updateLastMath(mathOps.rbegin());
|
||||||
|
|
||||||
self.enabled = false;
|
self.enabled = false;
|
||||||
mathOps.push_back(self);
|
|
||||||
mathOps.push_back(self);
|
|
||||||
mathOps.push_back(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace::~Trace()
|
Trace::~Trace()
|
||||||
@ -39,7 +36,7 @@ void Trace::clear() {
|
|||||||
data.clear();
|
data.clear();
|
||||||
settings.valid = false;
|
settings.valid = false;
|
||||||
emit cleared(this);
|
emit cleared(this);
|
||||||
emit outputDataChanged();
|
emit outputSamplesChanged(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::addData(const Trace::Data& d) {
|
void Trace::addData(const Trace::Data& d) {
|
||||||
@ -74,7 +71,7 @@ void Trace::addData(const Trace::Data& d) {
|
|||||||
// insert at this position
|
// insert at this position
|
||||||
data.insert(lower, d);
|
data.insert(lower, d);
|
||||||
}
|
}
|
||||||
emit outputSampleChanged(lower - data.begin());
|
emit outputSamplesChanged(lower - data.begin(), lower - data.begin() + 1);
|
||||||
if(lower == data.begin()) {
|
if(lower == data.begin()) {
|
||||||
// received the first point, which means the last sweep just finished
|
// received the first point, which means the last sweep just finished
|
||||||
if(tdr_users) {
|
if(tdr_users) {
|
||||||
@ -173,7 +170,7 @@ void Trace::removeMarker(TraceMarker *m)
|
|||||||
|
|
||||||
void Trace::updateTimeDomainData()
|
void Trace::updateTimeDomainData()
|
||||||
{
|
{
|
||||||
if(_data.size() < 2) {
|
if(data.size() < 2) {
|
||||||
// can't compute anything
|
// can't compute anything
|
||||||
timeDomain.clear();
|
timeDomain.clear();
|
||||||
return;
|
return;
|
||||||
@ -258,13 +255,11 @@ void Trace::updateLastMath(vector<MathInfo>::reverse_iterator start)
|
|||||||
Q_ASSERT(newLast != nullptr);
|
Q_ASSERT(newLast != nullptr);
|
||||||
if(newLast != lastMath) {
|
if(newLast != lastMath) {
|
||||||
if(lastMath != nullptr) {
|
if(lastMath != nullptr) {
|
||||||
disconnect(lastMath, &TraceMath::outputDataChanged, this, nullptr);
|
disconnect(lastMath, &TraceMath::outputSamplesChanged, this, nullptr);
|
||||||
disconnect(lastMath, &TraceMath::outputSampleChanged, this, nullptr);
|
|
||||||
}
|
}
|
||||||
lastMath = newLast;
|
lastMath = newLast;
|
||||||
// relay signals of end of math chain
|
// relay signals of end of math chain
|
||||||
connect(lastMath, &TraceMath::outputDataChanged, this, &Trace::dataChanged);
|
connect(lastMath, &TraceMath::outputSamplesChanged, this, &Trace::dataChanged);
|
||||||
connect(lastMath, &TraceMath::outputSampleChanged, this, &Trace::dataChanged);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +414,7 @@ bool Trace::hasMathOperations()
|
|||||||
|
|
||||||
void Trace::enableMath(bool enable)
|
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);
|
updateLastMath(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,8 +666,8 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo
|
|||||||
case YAxisType::Phase:
|
case YAxisType::Phase:
|
||||||
case YAxisType::VSWR: {
|
case YAxisType::VSWR: {
|
||||||
auto d = t->sample(sample);
|
auto d = t->sample(sample);
|
||||||
ret.setY(traceToCoordinate(d.S, type));
|
ret.setY(traceToCoordinate(d.y, type));
|
||||||
ret.setX(d.frequency);
|
ret.setX(d.x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case YAxisType::Impulse:
|
case YAxisType::Impulse:
|
||||||
@ -714,12 +714,12 @@ unsigned int TraceXYPlot::numTraceSamples(Trace *t)
|
|||||||
|
|
||||||
QPoint TraceXYPlot::dataToPixel(Trace::Data d)
|
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();
|
return QPoint();
|
||||||
}
|
}
|
||||||
auto y = traceToCoordinate(d.S, YAxis[0].type);
|
auto y = traceToCoordinate(d.y, YAxis[0].type);
|
||||||
QPoint p;
|
QPoint p;
|
||||||
p.setX(Util::Scale<double>(d.frequency, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
p.setX(Util::Scale<double>(d.x, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
||||||
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user