median option for averaging
This commit is contained in:
parent
82891ac766
commit
dced1732d6
@ -265,6 +265,13 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
|||||||
|
|
||||||
// Set initial sweep settings
|
// Set initial sweep settings
|
||||||
auto pref = Preferences::getInstance();
|
auto pref = Preferences::getInstance();
|
||||||
|
|
||||||
|
if(pref.Acquisition.useMedianAveraging) {
|
||||||
|
average.setMode(Averaging::Mode::Median);
|
||||||
|
} else {
|
||||||
|
average.setMode(Averaging::Mode::Mean);
|
||||||
|
}
|
||||||
|
|
||||||
if(pref.Startup.RememberSweepSettings) {
|
if(pref.Startup.RememberSweepSettings) {
|
||||||
LoadSweepSettings();
|
LoadSweepSettings();
|
||||||
} else {
|
} else {
|
||||||
@ -1075,6 +1082,11 @@ void SpectrumAnalyzer::updateGraphColors()
|
|||||||
emit graphColorsChanged();
|
emit graphColorsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumAnalyzer::setAveragingMode(Averaging::Mode mode)
|
||||||
|
{
|
||||||
|
average.setMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
QString SpectrumAnalyzer::WindowToString(SpectrumAnalyzer::Window w)
|
QString SpectrumAnalyzer::WindowToString(SpectrumAnalyzer::Window w)
|
||||||
{
|
{
|
||||||
switch(w) {
|
switch(w) {
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
virtual void fromJSON(nlohmann::json j) override;
|
virtual void fromJSON(nlohmann::json j) override;
|
||||||
|
|
||||||
void updateGraphColors();
|
void updateGraphColors();
|
||||||
|
void setAveragingMode(Averaging::Mode mode);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -530,6 +530,12 @@ VNA::VNA(AppWindow *window)
|
|||||||
// Set initial sweep settings
|
// Set initial sweep settings
|
||||||
auto pref = Preferences::getInstance();
|
auto pref = Preferences::getInstance();
|
||||||
|
|
||||||
|
if(pref.Acquisition.useMedianAveraging) {
|
||||||
|
average.setMode(Averaging::Mode::Median);
|
||||||
|
} else {
|
||||||
|
average.setMode(Averaging::Mode::Mean);
|
||||||
|
}
|
||||||
|
|
||||||
if(pref.Startup.RememberSweepSettings) {
|
if(pref.Startup.RememberSweepSettings) {
|
||||||
LoadSweepSettings();
|
LoadSweepSettings();
|
||||||
} else {
|
} else {
|
||||||
@ -1466,6 +1472,11 @@ void VNA::updateGraphColors()
|
|||||||
emit graphColorsChanged();
|
emit graphColorsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNA::setAveragingMode(Averaging::Mode mode)
|
||||||
|
{
|
||||||
|
average.setMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
QString VNA::SweepTypeToString(VNA::SweepType sw)
|
QString VNA::SweepTypeToString(VNA::SweepType sw)
|
||||||
{
|
{
|
||||||
switch(sw) {
|
switch(sw) {
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
virtual void fromJSON(nlohmann::json j) override;
|
virtual void fromJSON(nlohmann::json j) override;
|
||||||
|
|
||||||
void updateGraphColors();
|
void updateGraphColors();
|
||||||
|
void setAveragingMode(Averaging::Mode mode);
|
||||||
|
|
||||||
enum class SweepType {
|
enum class SweepType {
|
||||||
Frequency = 0,
|
Frequency = 0,
|
||||||
|
@ -204,6 +204,14 @@ AppWindow::AppWindow(QWidget *parent)
|
|||||||
vna->updateGraphColors();
|
vna->updateGraphColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// averaging mode may have changed, update for all relevant modes
|
||||||
|
if(p.Acquisition.useMedianAveraging) {
|
||||||
|
spectrumAnalyzer->setAveragingMode(Averaging::Mode::Median);
|
||||||
|
vna->setAveragingMode(Averaging::Mode::Median);
|
||||||
|
} else {
|
||||||
|
spectrumAnalyzer->setAveragingMode(Averaging::Mode::Mean);
|
||||||
|
vna->setAveragingMode(Averaging::Mode::Mean);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->actionAbout, &QAction::triggered, [=](){
|
connect(ui->actionAbout, &QAction::triggered, [=](){
|
||||||
|
@ -5,6 +5,7 @@ using namespace std;
|
|||||||
Averaging::Averaging()
|
Averaging::Averaging()
|
||||||
{
|
{
|
||||||
averages = 1;
|
averages = 1;
|
||||||
|
mode = Mode::Mean;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Averaging::reset(unsigned int points)
|
void Averaging::reset(unsigned int points)
|
||||||
@ -45,6 +46,8 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
|
|||||||
deque->pop_front();
|
deque->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case Mode::Mean: {
|
||||||
// calculate average
|
// calculate average
|
||||||
complex<double> sum[4];
|
complex<double> sum[4];
|
||||||
for(auto s : *deque) {
|
for(auto s : *deque) {
|
||||||
@ -58,6 +61,43 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
|
|||||||
S21 = sum[2] / (double) (deque->size());
|
S21 = sum[2] / (double) (deque->size());
|
||||||
S22 = sum[3] / (double) (deque->size());
|
S22 = sum[3] / (double) (deque->size());
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case Mode::Median: {
|
||||||
|
auto size = deque->size();
|
||||||
|
// create sorted arrays
|
||||||
|
std::vector<complex<double>> S11sorted, S12sorted, S21sorted, S22sorted;
|
||||||
|
S11sorted.reserve(size);
|
||||||
|
S12sorted.reserve(size);
|
||||||
|
S21sorted.reserve(size);
|
||||||
|
S22sorted.reserve(size);
|
||||||
|
|
||||||
|
auto comp = [=](const complex<double>&a, const complex<double>&b){
|
||||||
|
return abs(a) < abs(b);
|
||||||
|
};
|
||||||
|
|
||||||
|
for(auto d : *deque) {
|
||||||
|
S11sorted.insert(upper_bound(S11sorted.begin(), S11sorted.end(), d[0], comp), d[0]);
|
||||||
|
S12sorted.insert(upper_bound(S12sorted.begin(), S12sorted.end(), d[1], comp), d[1]);
|
||||||
|
S21sorted.insert(upper_bound(S21sorted.begin(), S21sorted.end(), d[2], comp), d[2]);
|
||||||
|
S22sorted.insert(upper_bound(S22sorted.begin(), S22sorted.end(), d[3], comp), d[3]);
|
||||||
|
}
|
||||||
|
if(size & 0x01) {
|
||||||
|
// odd number of samples
|
||||||
|
S11 = S11sorted[size / 2];
|
||||||
|
S12 = S12sorted[size / 2];
|
||||||
|
S21 = S21sorted[size / 2];
|
||||||
|
S22 = S22sorted[size / 2];
|
||||||
|
} else {
|
||||||
|
// even number, use average of middle samples
|
||||||
|
S11 = (S11sorted[size / 2 - 1] + S11sorted[size / 2]) / 2.0;
|
||||||
|
S12 = (S12sorted[size / 2 - 1] + S12sorted[size / 2]) / 2.0;
|
||||||
|
S21 = (S21sorted[size / 2 - 1] + S21sorted[size / 2]) / 2.0;
|
||||||
|
S22 = (S22sorted[size / 2 - 1] + S22sorted[size / 2]) / 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d.real_S11 = S11.real();
|
d.real_S11 = S11.real();
|
||||||
d.imag_S11 = S11.imag();
|
d.imag_S11 = S11.imag();
|
||||||
@ -90,17 +130,41 @@ Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerRe
|
|||||||
deque->pop_front();
|
deque->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case Mode::Mean: {
|
||||||
// calculate average
|
// calculate average
|
||||||
complex<double> sum[4];
|
complex<double> sum[2];
|
||||||
for(auto s : *deque) {
|
for(auto s : *deque) {
|
||||||
sum[0] += s[0];
|
sum[0] += s[0];
|
||||||
sum[1] += s[1];
|
sum[1] += s[1];
|
||||||
sum[2] += s[2];
|
|
||||||
sum[3] += s[3];
|
|
||||||
}
|
}
|
||||||
d.port1 = abs(sum[0] / (double) (deque->size()));
|
d.port1 = abs(sum[0] / (double) (deque->size()));
|
||||||
d.port2 = abs(sum[1] / (double) (deque->size()));
|
d.port2 = abs(sum[1] / (double) (deque->size()));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case Mode::Median: {
|
||||||
|
auto size = deque->size();
|
||||||
|
// create sorted arrays
|
||||||
|
std::vector<double> port1, port2;
|
||||||
|
port1.reserve(size);
|
||||||
|
port2.reserve(size);
|
||||||
|
for(auto d : *deque) {
|
||||||
|
port1.insert(upper_bound(port1.begin(), port1.end(), abs(d[0])), abs(d[0]));
|
||||||
|
port2.insert(upper_bound(port2.begin(), port2.end(), abs(d[0])), abs(d[0]));
|
||||||
|
}
|
||||||
|
if(size & 0x01) {
|
||||||
|
// odd number of samples
|
||||||
|
d.port1 = port1[size / 2];
|
||||||
|
d.port2 = port1[size / 2];
|
||||||
|
} else {
|
||||||
|
// even number, use average of middle samples
|
||||||
|
d.port1 = (port1[size / 2 - 1] + port1[size / 2]) / 2;
|
||||||
|
d.port2 = (port2[size / 2 - 1] + port2[size / 2]) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@ -122,3 +186,13 @@ unsigned int Averaging::currentSweep()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Averaging::Mode Averaging::getMode() const
|
||||||
|
{
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Averaging::setMode(const Mode &value)
|
||||||
|
{
|
||||||
|
mode = value;
|
||||||
|
}
|
||||||
|
@ -10,6 +10,11 @@
|
|||||||
class Averaging
|
class Averaging
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class Mode {
|
||||||
|
Mean,
|
||||||
|
Median
|
||||||
|
};
|
||||||
|
|
||||||
Averaging();
|
Averaging();
|
||||||
void reset(unsigned int points);
|
void reset(unsigned int points);
|
||||||
void setAverages(unsigned int a);
|
void setAverages(unsigned int a);
|
||||||
@ -21,10 +26,14 @@ public:
|
|||||||
// Returns the number of the currently active sweep. Value is incremented whenever the the first point of the sweep is added
|
// Returns the number of the currently active sweep. Value is incremented whenever the the first point of the sweep is added
|
||||||
// Returned values are in range 0 (when no data has been added yet) to averages
|
// Returned values are in range 0 (when no data has been added yet) to averages
|
||||||
unsigned int currentSweep();
|
unsigned int currentSweep();
|
||||||
|
Mode getMode() const;
|
||||||
|
void setMode(const Mode &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::deque<std::array<std::complex<double>, 4>>> avg;
|
std::vector<std::deque<std::array<std::complex<double>, 4>>> avg;
|
||||||
int maxPoints;
|
int maxPoints;
|
||||||
unsigned int averages;
|
unsigned int averages;
|
||||||
|
Mode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AVERAGING_H
|
#endif // AVERAGING_H
|
||||||
|
@ -134,6 +134,7 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
|
|||||||
p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked();
|
p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked();
|
||||||
p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked();
|
p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked();
|
||||||
p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value();
|
p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value();
|
||||||
|
p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1;
|
||||||
p->Graphs.Color.background = ui->GraphsColorBackground->getColor();
|
p->Graphs.Color.background = ui->GraphsColorBackground->getColor();
|
||||||
p->Graphs.Color.axis = ui->GraphsColorAxis->getColor();
|
p->Graphs.Color.axis = ui->GraphsColorAxis->getColor();
|
||||||
p->Graphs.Color.Ticks.Background.enabled = ui->GraphsColorTicksBackgroundEnabled->isChecked();
|
p->Graphs.Color.Ticks.Background.enabled = ui->GraphsColorTicksBackgroundEnabled->isChecked();
|
||||||
@ -199,6 +200,7 @@ void PreferencesDialog::setInitialGUIState()
|
|||||||
ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing);
|
ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing);
|
||||||
ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode);
|
ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode);
|
||||||
ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT);
|
ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT);
|
||||||
|
ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0);
|
||||||
|
|
||||||
ui->GraphsColorBackground->setColor(p->Graphs.Color.background);
|
ui->GraphsColorBackground->setColor(p->Graphs.Color.background);
|
||||||
ui->GraphsColorAxis->setColor(p->Graphs.Color.axis);
|
ui->GraphsColorAxis->setColor(p->Graphs.Color.axis);
|
||||||
|
@ -66,6 +66,7 @@ public:
|
|||||||
bool harmonicMixing;
|
bool harmonicMixing;
|
||||||
bool useDFTinSAmode;
|
bool useDFTinSAmode;
|
||||||
double RBWLimitForDFT;
|
double RBWLimitForDFT;
|
||||||
|
bool useMedianAveraging;
|
||||||
} Acquisition;
|
} Acquisition;
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
@ -100,7 +101,7 @@ private:
|
|||||||
QString name;
|
QString name;
|
||||||
QVariant def;
|
QVariant def;
|
||||||
};
|
};
|
||||||
const std::array<SettingDescription, 37> descr = {{
|
const std::array<SettingDescription, 38> descr = {{
|
||||||
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
|
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
|
||||||
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
|
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
|
||||||
{&Startup.DefaultSweep.type, "Startup.DefaultSweep.type", "Frequency"},
|
{&Startup.DefaultSweep.type, "Startup.DefaultSweep.type", "Frequency"},
|
||||||
@ -128,6 +129,7 @@ private:
|
|||||||
{&Acquisition.harmonicMixing, "Acquisition.harmonicMixing", false},
|
{&Acquisition.harmonicMixing, "Acquisition.harmonicMixing", false},
|
||||||
{&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true},
|
{&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true},
|
||||||
{&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0},
|
{&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0},
|
||||||
|
{&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false},
|
||||||
{&Graphs.Color.background, "Graphs.Color.background", QColor(Qt::black)},
|
{&Graphs.Color.background, "Graphs.Color.background", QColor(Qt::black)},
|
||||||
{&Graphs.Color.axis, "Graphs.Color.axis", QColor(Qt::white)},
|
{&Graphs.Color.axis, "Graphs.Color.axis", QColor(Qt::white)},
|
||||||
{&Graphs.Color.Ticks.Background.enabled, "Graphs.Color.Ticks.Background.enabled", true},
|
{&Graphs.Color.Ticks.Background.enabled, "Graphs.Color.Ticks.Background.enabled", true},
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>2</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="Startup">
|
<widget class="QWidget" name="Startup">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
@ -637,6 +637,36 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_14">
|
||||||
|
<property name="title">
|
||||||
|
<string>Common</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_26">
|
||||||
|
<property name="text">
|
||||||
|
<string>Averaging mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="AcquisitionAveragingMode">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Mean</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Median</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer_2">
|
<spacer name="verticalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
Loading…
Reference in New Issue
Block a user