median option for averaging

This commit is contained in:
Jan Käberich 2021-12-01 22:11:50 +01:00
parent 82891ac766
commit dced1732d6
10 changed files with 172 additions and 22 deletions

View File

@ -265,6 +265,13 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
// Set initial sweep settings
auto pref = Preferences::getInstance();
if(pref.Acquisition.useMedianAveraging) {
average.setMode(Averaging::Mode::Median);
} else {
average.setMode(Averaging::Mode::Mean);
}
if(pref.Startup.RememberSweepSettings) {
LoadSweepSettings();
} else {
@ -1075,6 +1082,11 @@ void SpectrumAnalyzer::updateGraphColors()
emit graphColorsChanged();
}
void SpectrumAnalyzer::setAveragingMode(Averaging::Mode mode)
{
average.setMode(mode);
}
QString SpectrumAnalyzer::WindowToString(SpectrumAnalyzer::Window w)
{
switch(w) {

View File

@ -26,6 +26,7 @@ public:
virtual void fromJSON(nlohmann::json j) override;
void updateGraphColors();
void setAveragingMode(Averaging::Mode mode);
private:

View File

@ -530,6 +530,12 @@ VNA::VNA(AppWindow *window)
// Set initial sweep settings
auto pref = Preferences::getInstance();
if(pref.Acquisition.useMedianAveraging) {
average.setMode(Averaging::Mode::Median);
} else {
average.setMode(Averaging::Mode::Mean);
}
if(pref.Startup.RememberSweepSettings) {
LoadSweepSettings();
} else {
@ -1466,6 +1472,11 @@ void VNA::updateGraphColors()
emit graphColorsChanged();
}
void VNA::setAveragingMode(Averaging::Mode mode)
{
average.setMode(mode);
}
QString VNA::SweepTypeToString(VNA::SweepType sw)
{
switch(sw) {

View File

@ -29,6 +29,7 @@ public:
virtual void fromJSON(nlohmann::json j) override;
void updateGraphColors();
void setAveragingMode(Averaging::Mode mode);
enum class SweepType {
Frequency = 0,

View File

@ -204,6 +204,14 @@ AppWindow::AppWindow(QWidget *parent)
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, [=](){

View File

@ -5,6 +5,7 @@ using namespace std;
Averaging::Averaging()
{
averages = 1;
mode = Mode::Mean;
}
void Averaging::reset(unsigned int points)
@ -45,18 +46,57 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
deque->pop_front();
}
// calculate average
complex<double> sum[4];
for(auto s : *deque) {
sum[0] += s[0];
sum[1] += s[1];
sum[2] += s[2];
sum[3] += s[3];
switch(mode) {
case Mode::Mean: {
// calculate average
complex<double> sum[4];
for(auto s : *deque) {
sum[0] += s[0];
sum[1] += s[1];
sum[2] += s[2];
sum[3] += s[3];
}
S11 = sum[0] / (double) (deque->size());
S12 = sum[1] / (double) (deque->size());
S21 = sum[2] / (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;
}
S11 = sum[0] / (double) (deque->size());
S12 = sum[1] / (double) (deque->size());
S21 = sum[2] / (double) (deque->size());
S22 = sum[3] / (double) (deque->size());
}
d.real_S11 = S11.real();
@ -90,16 +130,40 @@ Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerRe
deque->pop_front();
}
// calculate average
complex<double> sum[4];
for(auto s : *deque) {
sum[0] += s[0];
sum[1] += s[1];
sum[2] += s[2];
sum[3] += s[3];
switch(mode) {
case Mode::Mean: {
// calculate average
complex<double> sum[2];
for(auto s : *deque) {
sum[0] += s[0];
sum[1] += s[1];
}
d.port1 = abs(sum[0] / (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;
}
d.port1 = abs(sum[0] / (double) (deque->size()));
d.port2 = abs(sum[1] / (double) (deque->size()));
}
return d;
@ -122,3 +186,13 @@ unsigned int Averaging::currentSweep()
return 0;
}
}
Averaging::Mode Averaging::getMode() const
{
return mode;
}
void Averaging::setMode(const Mode &value)
{
mode = value;
}

View File

@ -10,6 +10,11 @@
class Averaging
{
public:
enum class Mode {
Mean,
Median
};
Averaging();
void reset(unsigned int points);
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
// Returned values are in range 0 (when no data has been added yet) to averages
unsigned int currentSweep();
Mode getMode() const;
void setMode(const Mode &value);
private:
std::vector<std::deque<std::array<std::complex<double>, 4>>> avg;
int maxPoints;
unsigned int averages;
Mode mode;
};
#endif // AVERAGING_H

View File

@ -134,6 +134,7 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked();
p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked();
p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value();
p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1;
p->Graphs.Color.background = ui->GraphsColorBackground->getColor();
p->Graphs.Color.axis = ui->GraphsColorAxis->getColor();
p->Graphs.Color.Ticks.Background.enabled = ui->GraphsColorTicksBackgroundEnabled->isChecked();
@ -199,6 +200,7 @@ void PreferencesDialog::setInitialGUIState()
ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing);
ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode);
ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT);
ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0);
ui->GraphsColorBackground->setColor(p->Graphs.Color.background);
ui->GraphsColorAxis->setColor(p->Graphs.Color.axis);

View File

@ -66,6 +66,7 @@ public:
bool harmonicMixing;
bool useDFTinSAmode;
double RBWLimitForDFT;
bool useMedianAveraging;
} Acquisition;
struct {
struct {
@ -100,7 +101,7 @@ private:
QString name;
QVariant def;
};
const std::array<SettingDescription, 37> descr = {{
const std::array<SettingDescription, 38> descr = {{
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
{&Startup.DefaultSweep.type, "Startup.DefaultSweep.type", "Frequency"},
@ -128,6 +129,7 @@ private:
{&Acquisition.harmonicMixing, "Acquisition.harmonicMixing", false},
{&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true},
{&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0},
{&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false},
{&Graphs.Color.background, "Graphs.Color.background", QColor(Qt::black)},
{&Graphs.Color.axis, "Graphs.Color.axis", QColor(Qt::white)},
{&Graphs.Color.Ticks.Background.enabled, "Graphs.Color.Ticks.Background.enabled", true},

View File

@ -78,7 +78,7 @@
</size>
</property>
<property name="currentIndex">
<number>2</number>
<number>1</number>
</property>
<widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4">
@ -637,6 +637,36 @@
</layout>
</widget>
</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>
<spacer name="verticalSpacer_2">
<property name="orientation">