minimal median filter implementation for math testing
This commit is contained in:
parent
692bb85b5d
commit
a168e81cca
@ -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 \
|
||||
|
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Data>& 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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<MathInfo>::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);
|
||||
}
|
||||
|
||||
|
@ -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<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));
|
||||
return p;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user