diff --git a/Software/PC_Application/Calibration/calibration.cpp b/Software/PC_Application/Calibration/calibration.cpp index 1645447..7cce183 100644 --- a/Software/PC_Application/Calibration/calibration.cpp +++ b/Software/PC_Application/Calibration/calibration.cpp @@ -15,15 +15,15 @@ using namespace std; Calibration::Calibration() { // Create vectors for measurements - measurements[Measurement::Port1Open].datapoints = vector(); - measurements[Measurement::Port1Short].datapoints = vector(); - measurements[Measurement::Port1Load].datapoints = vector(); - measurements[Measurement::Port2Open].datapoints = vector(); - measurements[Measurement::Port2Short].datapoints = vector(); - measurements[Measurement::Port2Load].datapoints = vector(); - measurements[Measurement::Isolation].datapoints = vector(); - measurements[Measurement::Through].datapoints = vector(); - measurements[Measurement::Line].datapoints = vector(); + measurements[Measurement::Port1Open].datapoints = vector(); + measurements[Measurement::Port1Short].datapoints = vector(); + measurements[Measurement::Port1Load].datapoints = vector(); + measurements[Measurement::Port2Open].datapoints = vector(); + measurements[Measurement::Port2Short].datapoints = vector(); + measurements[Measurement::Port2Load].datapoints = vector(); + measurements[Measurement::Isolation].datapoints = vector(); + measurements[Measurement::Through].datapoints = vector(); + measurements[Measurement::Line].datapoints = vector(); type = Type::None; port1Standard = port2Standard = PortStandard::Male; @@ -84,13 +84,13 @@ void Calibration::clearMeasurement(Calibration::Measurement type) qDebug() << "Deleted" << MeasurementToString(type) << "measurement"; } -void Calibration::addMeasurement(Calibration::Measurement type, VNAData &d) +void Calibration::addMeasurement(Calibration::Measurement type, VirtualDevice::VNAMeasurement &d) { measurements[type].datapoints.push_back(d); measurements[type].timestamp = QDateTime::currentDateTime(); } -void Calibration::addMeasurements(std::set types, VNAData &d) +void Calibration::addMeasurements(std::set types, VirtualDevice::VNAMeasurement &d) { for(auto t : types) { addMeasurement(t, d); @@ -176,22 +176,22 @@ void Calibration::construct12TermPoints() Point p; p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency; // extract required complex reflection/transmission factors from datapoints - auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11; - auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11; - auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11; - auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22; - auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22; - auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22; + auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"]; + auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"]; + auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"]; + auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"]; + auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"]; + auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"]; auto S21_isolation = complex(0,0); auto S12_isolation = complex(0,0); if(isolation_measured) { - S21_isolation = measurements[Measurement::Isolation].datapoints[i].S.m21; - S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12; + S21_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S21"]; + S12_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S12"]; } - auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11; - auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; - auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22; - auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; + auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"]; + auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"]; + auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"]; + auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"]; auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); // Forward calibration @@ -232,9 +232,9 @@ void Calibration::constructPort1SOL() Point p; p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency; // extract required complex reflection/transmission factors from datapoints - auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11; - auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11; - auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11; + auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"]; + auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"]; + auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"]; // OSL port1 auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); // See page 13 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf @@ -262,9 +262,9 @@ void Calibration::constructPort2SOL() Point p; p.frequency = measurements[Measurement::Port2Open].datapoints[i].frequency; // extract required complex reflection/transmission factors from datapoints - auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22; - auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22; - auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22; + auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"]; + auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"]; + auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"]; // OSL port2 auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); // See page 19 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf @@ -292,8 +292,8 @@ void Calibration::constructTransmissionNormalization() Point p; p.frequency = measurements[Measurement::Through].datapoints[i].frequency; // extract required complex reflection/transmission factors from datapoints - auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; - auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; + auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"]; + auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"]; auto actual = kit.toSOLT(p.frequency); p.fe10e32 = S21_through / actual.ThroughS21; p.re23e01 = S12_through / actual.ThroughS12; @@ -329,24 +329,24 @@ void Calibration::constructTRL() p.frequency = measurements[Measurement::Through].datapoints[i].frequency; // grab raw measurements - auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11; - auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; - auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22; - auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; - auto S11_line = measurements[Measurement::Line].datapoints[i].S.m11; - auto S21_line = measurements[Measurement::Line].datapoints[i].S.m21; - auto S22_line = measurements[Measurement::Line].datapoints[i].S.m22; - auto S12_line = measurements[Measurement::Line].datapoints[i].S.m12; + auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"]; + auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"]; + auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"]; + auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"]; + auto S11_line = measurements[Measurement::Line].datapoints[i].measurements["S11"]; + auto S21_line = measurements[Measurement::Line].datapoints[i].measurements["S21"]; + auto S22_line = measurements[Measurement::Line].datapoints[i].measurements["S22"]; + auto S12_line = measurements[Measurement::Line].datapoints[i].measurements["S12"]; auto trl = kit.toTRL(p.frequency); complex S11_reflection, S22_reflection; if(trl.reflectionIsNegative) { // used short - S11_reflection = measurements[Measurement::Port1Short].datapoints[i].S.m11; - S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22; + S11_reflection = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"]; + S22_reflection = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"]; } else { // used open - S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11; - S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22; + S11_reflection = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"]; + S22_reflection = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"]; } // calculate TRL calibration // variable names and formulas according to http://emlab.uiuc.edu/ece451/notes/new_TRL.pdf @@ -432,17 +432,17 @@ void Calibration::constructTRL() } } -void Calibration::correctMeasurement(VNAData &d) +void Calibration::correctMeasurement(VirtualDevice::VNAMeasurement &d) { if(type == Type::None) { // No calibration data, do nothing return; } - // Convert measurements to complex variables - auto S11m = d.S.m11; - auto S21m = d.S.m21; - auto S22m = d.S.m22; - auto S12m = d.S.m12; + // Extract measurement S parameters + auto S11m = d.measurements["S11"]; + auto S21m = d.measurements["S21"]; + auto S22m = d.measurements["S22"]; + auto S12m = d.measurements["S12"]; // find correct entry auto p = getCalibrationPoint(d); @@ -459,7 +459,11 @@ void Calibration::correctMeasurement(VNAData &d) - p.re11 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom; S12 = ((S12m - p.re03) / p.re23e01 * (1.0 + (S11m - p.fe00) / p.fe10e01 * (p.fe11 - p.re11))) / denom; - d.S = Sparam(S11, S12, S21, S22); + auto S = Sparam(S11, S12, S21, S22); + d.measurements["S11"] = S.m11; + d.measurements["S12"] = S.m12; + d.measurements["S21"] = S.m21; + d.measurements["S22"] = S.m22; } void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22) @@ -733,15 +737,7 @@ std::vector Calibration::getMeasurementTraces() for(auto p : m.second.datapoints) { Trace::Data d; d.x = p.frequency; - if(prefix == "S11") { - d.y = p.S.m11; - } else if(prefix == "S12") { - d.y = p.S.m12; - } else if(prefix == "S21") { - d.y = p.S.m21; - } else { - d.y = p.S.m22; - } + d.y = p.measurements[prefix]; t->addData(d, TraceMath::DataType::Frequency); } traces.push_back(t); @@ -803,19 +799,9 @@ bool Calibration::openFromFile(QString filename) file >> j; fromJSON(j); } catch(exception &e) { - // json parsing failed, probably using a legacy file format - try { - file.clear(); - file.seekg(0); - file >> *this; - InformationBox::ShowMessage("Loading calibration file", "The file \"" + filename + "\" is stored in a deprecated" - " calibration format. Future versions of this application might not support" - " it anymore. Please save the calibration to update to the new format"); - } catch(exception &e) { - InformationBox::ShowError("File parsing error", e.what()); - qWarning() << "Calibration file parsing failed: " << e.what(); - return false; - } + InformationBox::ShowError("File parsing error", e.what()); + qWarning() << "Calibration file parsing failed: " << e.what(); + return false; } this->currentCalFile = filename; // if all ok, remember this @@ -909,14 +895,14 @@ nlohmann::json Calibration::toJSON() for(auto p : m.second.datapoints) { nlohmann::json j_point; j_point["frequency"] = p.frequency; - j_point["S11_real"] = p.S.m11.real(); - j_point["S11_imag"] = p.S.m11.imag(); - j_point["S12_real"] = p.S.m12.real(); - j_point["S12_imag"] = p.S.m12.imag(); - j_point["S21_real"] = p.S.m21.real(); - j_point["S21_imag"] = p.S.m21.imag(); - j_point["S22_real"] = p.S.m22.real(); - j_point["S22_imag"] = p.S.m22.imag(); + j_point["S11_real"] = p.measurements["S11"].real(); + j_point["S11_imag"] = p.measurements["S11"].imag(); + j_point["S12_real"] = p.measurements["S12"].real(); + j_point["S12_imag"] = p.measurements["S12"].imag(); + j_point["S21_real"] = p.measurements["S21"].real(); + j_point["S21_imag"] = p.measurements["S21"].imag(); + j_point["S22_real"] = p.measurements["S22"].real(); + j_point["S22_imag"] = p.measurements["S22"].imag(); j_points.push_back(j_point); } j_measurement["points"] = j_points; @@ -957,13 +943,14 @@ void Calibration::fromJSON(nlohmann::json j) } int pointNum = 0; for(auto j_p : j_m["points"]) { - VNAData p; + VirtualDevice::VNAMeasurement p; p.pointNum = pointNum++; p.frequency = j_p.value("frequency", 0.0); - p.S.m11 = complex(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0)); - p.S.m12 = complex(j_p.value("S12_real", 0.0), j_p.value("S12_imag", 0.0)); - p.S.m21 = complex(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0)); - p.S.m22 = complex(j_p.value("S22_real", 0.0), j_p.value("S22_imag", 0.0)); + p.Z0 = 50.0; + p.measurements["S11"] = complex(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0)); + p.measurements["S12"] = complex(j_p.value("S12_real", 0.0), j_p.value("S12_imag", 0.0)); + p.measurements["S21"] = complex(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0)); + p.measurements["S22"] = complex(j_p.value("S22_real", 0.0), j_p.value("S22_imag", 0.0)); measurements[m].datapoints.push_back(p); } } @@ -986,56 +973,6 @@ QString Calibration::getCurrentCalibrationFile(){ return this->currentCalFile; } -istream& operator >>(istream &in, Calibration &c) -{ - // old file format did not contain port standard gender, set default - c.port1Standard = Calibration::PortStandard::Male; - c.port2Standard = Calibration::PortStandard::Male; - c.throughZeroLength = false; - - std::string line; - while(getline(in, line)) { - QString qLine = QString::fromStdString(line).simplified(); - for(auto m : c.Measurements()) { - if(Calibration::MeasurementToString(m) == qLine) { - // this is the correct measurement - c.measurements[m].datapoints.clear(); - uint timestamp; - in >> timestamp; - c.measurements[m].timestamp = QDateTime::fromSecsSinceEpoch(timestamp); - unsigned int points; - in >> points; - qDebug() << "Found measurement" << Calibration::MeasurementToString(m) << ", containing" << points << "points"; - for(unsigned int i=0;i> p.pointNum >> p.frequency; - in >> p.imag_S11 >> p.real_S11 >> p.imag_S21 >> p.real_S21 >> p.imag_S12 >> p.real_S12 >> p.imag_S22 >> p.real_S22; - c.measurements[m].datapoints.push_back(VNAData(p)); - if(in.eof() || in.bad() || in.fail()) { - c.clearMeasurement(m); - throw runtime_error("Failed to parse measurement \"" + line + "\", aborting calibration data import."); - } - } - break; - } - } - for(auto t : Calibration::Types()) { - if(Calibration::TypeToString(t) == qLine) { - // try to apply this calibration type - qDebug() << "Specified calibration in file is" << Calibration::TypeToString(t); - if(c.calculationPossible(t)) { - c.constructErrorTerms(t); - } else { - throw runtime_error("Incomplete calibration data, the requested \"" + line + "\"-Calibration could not be performed."); - } - break; - } - } - } - qDebug() << "Calibration file parsing complete"; - return in; -} - bool Calibration::SanityCheckSamples(const std::vector &requiredMeasurements) { // sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty) @@ -1068,7 +1005,7 @@ bool Calibration::SanityCheckSamples(const std::vector return true; } -Calibration::Point Calibration::getCalibrationPoint(VNAData &d) +Calibration::Point Calibration::getCalibrationPoint(VirtualDevice::VNAMeasurement &d) { if(!points.size()) { throw runtime_error("No calibration points available"); diff --git a/Software/PC_Application/Calibration/calibration.h b/Software/PC_Application/Calibration/calibration.h index bc48f3d..f202fd7 100644 --- a/Software/PC_Application/Calibration/calibration.h +++ b/Software/PC_Application/Calibration/calibration.h @@ -45,8 +45,8 @@ public: void clearMeasurements(); void clearMeasurements(std::set types); void clearMeasurement(Measurement type); - void addMeasurement(Measurement type, VNAData &d); - void addMeasurements(std::set types, VNAData &d); + void addMeasurement(Measurement type, VirtualDevice::VNAMeasurement &d); + void addMeasurements(std::set types, VirtualDevice::VNAMeasurement &d); enum class Type { Port1SOL, @@ -63,7 +63,7 @@ public: bool constructErrorTerms(Type type); void resetErrorTerms(); - void correctMeasurement(VNAData &d); + void correctMeasurement(VirtualDevice::VNAMeasurement &d); void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22); enum class InterpolationType { @@ -141,7 +141,7 @@ private: // Reverse error terms std::complex re33, re11, re23e32, re23e01, re22, re03, rex; }; - Point getCalibrationPoint(VNAData &d); + Point getCalibrationPoint(VirtualDevice::VNAMeasurement &d); /* * Constructs directivity, match and tracking correction factors from measurements of three distinct impedances * Normally, an open, short and load are used (with ideal reflection coefficients of 1, -1 and 0 respectively). @@ -173,7 +173,7 @@ private: class MeasurementData { public: QDateTime timestamp; - std::vector datapoints; + std::vector datapoints; }; Type type; diff --git a/Software/PC_Application/Device/virtualdevice.cpp b/Software/PC_Application/Device/virtualdevice.cpp index d4762f5..30982a0 100644 --- a/Software/PC_Application/Device/virtualdevice.cpp +++ b/Software/PC_Application/Device/virtualdevice.cpp @@ -190,6 +190,7 @@ VirtualDevice::VirtualDevice(QString serial) connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){ VNAMeasurement m; m.pointNum = res.pointNum; + m.Z0 = 50.0; if(zerospan) { m.us = res.us; } else { @@ -486,3 +487,48 @@ VirtualDevice *VirtualDevice::getConnected() { return connected; } + +Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2) +{ + Sparam S; + S.m11 = measurements["S"+QString::number(port1)+QString::number(port1)]; + S.m12 = measurements["S"+QString::number(port1)+QString::number(port2)]; + S.m21 = measurements["S"+QString::number(port2)+QString::number(port1)]; + S.m22 = measurements["S"+QString::number(port2)+QString::number(port2)]; + return S; +} + +void VirtualDevice::VNAMeasurement::fromSparam(Sparam S, int port1, int port2) +{ + QString s11 = "S"+QString::number(port1)+QString::number(port1); + QString s12 = "S"+QString::number(port1)+QString::number(port2); + QString s21 = "S"+QString::number(port2)+QString::number(port1); + QString s22 = "S"+QString::number(port2)+QString::number(port2); + if(measurements.count(s11)) { + measurements[s11] = S.m11; + } + if(measurements.count(s12)) { + measurements[s12] = S.m12; + } + if(measurements.count(s21)) { + measurements[s21] = S.m21; + } + if(measurements.count(s22)) { + measurements[s22] = S.m22; + } +} + +VirtualDevice::VNAMeasurement VirtualDevice::VNAMeasurement::interpolateTo(const VirtualDevice::VNAMeasurement &to, double a) +{ + VNAMeasurement ret; + ret.frequency = frequency * (1.0 - a) + to.frequency * a; + ret.dBm = dBm * (1.0 - a) + to.dBm * a; + ret.Z0 = Z0 * (1.0 - a) + to.Z0 * a; + for(auto m : measurements) { + if(to.measurements.count(m.first) == 0) { + throw runtime_error("Nothing to interpolate to, expected measurement +\""+m.first.toStdString()+"\""); + } + ret.measurements[m.first] = measurements[m.first] * (1.0 - a) + to.measurements.at(m.first) * a; + } + return ret; +} diff --git a/Software/PC_Application/Device/virtualdevice.h b/Software/PC_Application/Device/virtualdevice.h index 638693a..b9e2d83 100644 --- a/Software/PC_Application/Device/virtualdevice.h +++ b/Software/PC_Application/Device/virtualdevice.h @@ -2,6 +2,7 @@ #define VIRTUALDEVICE_H #include "device.h" +#include "Tools/parameters.h" #include #include @@ -66,6 +67,7 @@ public: class VNAMeasurement { public: int pointNum; + double Z0; union { struct { // for non-zero span @@ -78,6 +80,10 @@ public: }; }; std::map> measurements; + + Sparam toSparam(int port1, int port2); + void fromSparam(Sparam S, int port1, int port2); + VNAMeasurement interpolateTo(const VNAMeasurement &to, double a); }; QStringList availableVNAMeasurements(); diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index 7d2a041..5113fc1 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -118,7 +118,6 @@ HEADERS += \ VNA/Deembedding/twothru.h \ VNA/tracewidgetvna.h \ VNA/vna.h \ - VNA/vnadata.h \ about.h \ appwindow.h \ averaging.h \ diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index 923f4b3..05c5e03 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -61,10 +61,10 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name) // Create default traces auto tPort1 = new Trace("Port1", Qt::yellow); - tPort1->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port1); + tPort1->fromLivedata(Trace::LivedataType::Overwrite, "PORT1"); traceModel.addTrace(tPort1); auto tPort2 = new Trace("Port2", Qt::blue); - tPort2->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port2); + tPort2->fromLivedata(Trace::LivedataType::Overwrite, "PORT2"); traceModel.addTrace(tPort2); auto traceXY = new TraceXYPlot(traceModel); diff --git a/Software/PC_Application/SpectrumAnalyzer/tracewidgetsa.h b/Software/PC_Application/SpectrumAnalyzer/tracewidgetsa.h index 43ba7a9..7a610e2 100644 --- a/Software/PC_Application/SpectrumAnalyzer/tracewidgetsa.h +++ b/Software/PC_Application/SpectrumAnalyzer/tracewidgetsa.h @@ -12,7 +12,7 @@ protected slots: virtual void importDialog() override; protected: - virtual Trace::LiveParameter defaultParameter() override {return Trace::LiveParameter::Port1;}; + virtual QString defaultParameter() override {return "PORT1";} }; #endif // TRACEWIDGETSA_H diff --git a/Software/PC_Application/Traces/Marker/marker.cpp b/Software/PC_Application/Traces/Marker/marker.cpp index 055960a..a25a1b8 100644 --- a/Software/PC_Application/Traces/Marker/marker.cpp +++ b/Software/PC_Application/Traces/Marker/marker.cpp @@ -184,7 +184,7 @@ std::vector Marker::applicableFormats() case Type::Maximum: case Type::Minimum: case Type::PeakTable: - if(Trace::isSAParamater(parentTrace->liveParameter())) { + if(Trace::isSAParameter(parentTrace->liveParameter())) { ret.push_back(Format::dBm); ret.push_back(Format::dBuV); } else { @@ -217,7 +217,7 @@ std::vector Marker::applicableFormats() case Type::Maximum: case Type::Minimum: case Type::PeakTable: - if(Trace::isSAParamater(parentTrace->liveParameter())) { + if(Trace::isSAParameter(parentTrace->liveParameter())) { ret.push_back(Format::dBm); ret.push_back(Format::dBuV); } else { @@ -871,20 +871,13 @@ std::set Marker::getSupportedTypes() supported.insert(Type::Bandpass); } if(parentTrace->getSource() == Trace::Source::Live) { - switch(parentTrace->liveParameter()) { - case Trace::LiveParameter::S11: - case Trace::LiveParameter::S12: - case Trace::LiveParameter::S21: - case Trace::LiveParameter::S22: + if(Trace::isVNAParameter(parentTrace->liveParameter())) { // no special marker types for VNA yet - break; - case Trace::LiveParameter::Port1: - case Trace::LiveParameter::Port2: + } + if(Trace::isSAParameter(parentTrace->liveParameter())) { // special SA marker types supported.insert(Type::TOI); supported.insert(Type::PhaseNoise); - break; - default: break; } } break; diff --git a/Software/PC_Application/Traces/trace.cpp b/Software/PC_Application/Traces/trace.cpp index eeb79eb..a28f11b 100644 --- a/Software/PC_Application/Traces/trace.cpp +++ b/Software/PC_Application/Traces/trace.cpp @@ -16,7 +16,7 @@ using namespace std; using namespace mup; -Trace::Trace(QString name, QColor color, LiveParameter live) +Trace::Trace(QString name, QColor color, QString live) : model(nullptr), _name(name), _color(color), @@ -25,7 +25,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live) hashSet(false), JSONskipHash(false), _liveType(LivedataType::Overwrite), - _liveParam(live), + liveParam(live), vFactor(0.66), reflection(true), visible(true), @@ -130,12 +130,12 @@ void Trace::addData(const Trace::Data& d, DataType domain, double reference_impe emit outputSamplesChanged(index, index + 1); } -void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettings &s, int index) +void Trace::addData(const Trace::Data &d, const VirtualDevice::SASettings &s, int index) { settings.SA = s; settings.valid = true; auto domain = DataType::Frequency; - if (s.f_start == s.f_stop) { + if (s.freqStart == s.freqStop) { // in zerospan mode domain = DataType::TimeZeroSpan; } @@ -143,7 +143,7 @@ void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettin } void Trace::setName(QString name) { - _name = name; + name = name; emit nameChanged(); } @@ -259,7 +259,7 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter) return lastTraceName; } -void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector &data) +void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector &data) { S11.clear(); S12.clear(); @@ -267,25 +267,26 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c S22.clear(); for(auto d : data) { Trace::Data td; + auto S = d.toSparam(1, 2); td.x = d.frequency; - td.y = d.S.m11; + td.y = S.m11; S11.addData(td, DataType::Frequency); - td.y = d.S.m12; + td.y = S.m12; S12.addData(td, DataType::Frequency); - td.y = d.S.m21; + td.y = S.m21; S21.addData(td, DataType::Frequency); - td.y = d.S.m22; + td.y = S.m22; S22.addData(td, DataType::Frequency); } } -void Trace::fromLivedata(Trace::LivedataType type, LiveParameter param) +void Trace::fromLivedata(Trace::LivedataType type, QString param) { clearMathSources(); source = Source::Live; _liveType = type; - _liveParam = param; - if(param == LiveParameter::S11 || param == LiveParameter::S22) { + liveParam = param; + if(param.length() == 3 && param[0] == 'S' && param[1].isDigit() && param[1] == param[2]) { reflection = true; } else { reflection = false; @@ -305,8 +306,8 @@ void Trace::fromMath() } void Trace::setColor(QColor color) { - if(_color != color) { - _color = color; + if(color != color) { + color = color; emit colorChanged(this); } } @@ -637,6 +638,16 @@ const std::vector& Trace::getMathOperations() const return mathOps; } +bool Trace::isSAParameter(QString param) +{ + return param.length() == 5 && param.startsWith("PORT") && param[4].isDigit(); +} + +bool Trace::isVNAParameter(QString param) +{ + return param.length() == 3 && param[0] == 'S' && param[1].isDigit() && param[2].isDigit(); +} + double Trace::velocityFactor() { return vFactor; @@ -678,7 +689,7 @@ nlohmann::json Trace::toJSON() switch(source) { case Source::Live: j["type"] = "Live"; - j["parameter"] = _liveParam; + j["parameter"] = liveParam.toStdString(); j["livetype"] = _liveType; j["paused"] = paused; break; @@ -737,7 +748,7 @@ void Trace::fromJSON(nlohmann::json j) visible = j.value("visible", true); auto type = QString::fromStdString(j.value("type", "Live")); if(type == "Live") { - _liveParam = j.value("parameter", LiveParameter::S11); + liveParam = QString::fromStdString(j.value("parameter", "S11")); _liveType = j.value("livetype", LivedataType::Overwrite); paused = j.value("paused", false); } else if(type == "Touchstone" || type == "File") { @@ -862,9 +873,9 @@ std::vector Trace::createFromCSV(CSV &csv) return traces; } -std::vector Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22) +std::vector Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22) { - vector ret; + vector ret; // Sanity check traces unsigned int samples = S11.size(); @@ -906,15 +917,11 @@ std::vector Trace::assembleDatapoints(const Trace &S11, const Trace &S1 // Checks passed, assemble datapoints for(unsigned int i=0;i Trace::assembleDatapoints(const Trace &S11, const Trace &S1 return ret; } -Trace::LiveParameter Trace::ParameterFromString(QString s) -{ - s = s.toUpper(); - if(s == "S11") { - return LiveParameter::S11; - } else if(s == "S12") { - return LiveParameter::S12; - } else if(s == "S21") { - return LiveParameter::S21; - } else if(s == "S22") { - return LiveParameter::S22; - } else if(s == "PORT1") { - return LiveParameter::Port1; - } else if(s == "PORT2") { - return LiveParameter::Port2; - } else { - return LiveParameter::Invalid; - } -} - -QString Trace::ParameterToString(LiveParameter p) -{ - switch(p) { - case Trace::LiveParameter::S11: return "S11"; - case Trace::LiveParameter::S12: return "S12"; - case Trace::LiveParameter::S21: return "S21"; - case Trace::LiveParameter::S22: return "S22"; - case Trace::LiveParameter::Port1: return "Port1"; - case Trace::LiveParameter::Port2: return "Port2"; - default: return "Invalid"; - } -} - -bool Trace::isVNAParameter(Trace::LiveParameter p) -{ - switch(p) { - case Trace::LiveParameter::S11: - case Trace::LiveParameter::S12: - case Trace::LiveParameter::S21: - case Trace::LiveParameter::S22: - return true; - case Trace::LiveParameter::Port1: - case Trace::LiveParameter::Port2: - default: - return false; - } -} - -bool Trace::isSAParamater(Trace::LiveParameter p) -{ - switch(p) { - case Trace::LiveParameter::S11: - case Trace::LiveParameter::S12: - case Trace::LiveParameter::S21: - case Trace::LiveParameter::S22: - return false; - case Trace::LiveParameter::Port1: - case Trace::LiveParameter::Port2: - return true; - default: - return false; - } -} - Trace::LivedataType Trace::TypeFromString(QString s) { s = s.toUpper(); @@ -1365,7 +1308,7 @@ unsigned int Trace::getFileParameter() const double Trace::getNoise(double frequency) { - if(source != Trace::Source::Live || !settings.valid || (_liveParam != LiveParameter::Port1 && _liveParam != LiveParameter::Port2) || lastMath->getDataType() != DataType::Frequency) { + if(source != Trace::Source::Live || !settings.valid || !liveParam.startsWith("PORT") || lastMath->getDataType() != DataType::Frequency) { // data not suitable for noise calculation return std::numeric_limits::quiet_NaN(); } diff --git a/Software/PC_Application/Traces/trace.h b/Software/PC_Application/Traces/trace.h index 059987c..442eb84 100644 --- a/Software/PC_Application/Traces/trace.h +++ b/Software/PC_Application/Traces/trace.h @@ -3,10 +3,9 @@ #include "touchstone.h" #include "csv.h" -#include "Device/device.h" +#include "Device/virtualdevice.h" #include "Math/tracemath.h" #include "Tools/parameters.h" -#include "VNA/vnadata.h" #include #include @@ -33,17 +32,7 @@ public: Last, }; - enum class LiveParameter { - S11, - S12, - S21, - S22, - Port1, - Port2, - Invalid, - }; - - Trace(QString name = QString(), QColor color = Qt::darkYellow, LiveParameter live = LiveParameter::S11); + Trace(QString name = QString(), QColor color = Qt::darkYellow, QString live = "S11"); ~Trace(); enum class LivedataType { @@ -55,13 +44,13 @@ public: void clear(bool force = false); void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1); - void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s, int index = -1); + void addData(const Data& d, const VirtualDevice::SASettings &s, int index = -1); void setName(QString name); void setVelocityFactor(double v); void fillFromTouchstone(Touchstone &t, unsigned int parameter); QString fillFromCSV(CSV &csv, unsigned int parameter); // returns the suggested trace name (not yet set in member data) - static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector &data); - void fromLivedata(LivedataType type, LiveParameter param); + static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector &data); + void fromLivedata(LivedataType type, QString param); void fromMath(); QString name() { return _name; } QColor color() { return _color; } @@ -72,7 +61,7 @@ public: bool isPaused(); Source getSource() {return source;} bool isReflection(); - LiveParameter liveParameter() { return _liveParam; } + QString liveParameter() { return liveParam; } LivedataType liveType() { return _liveType; } TraceMath::DataType outputType() const { return lastMath->getDataType(); } unsigned int size() const; @@ -125,6 +114,9 @@ public: }; const std::vector& getMathOperations() const; + static bool isSAParameter(QString param); + static bool isVNAParameter(QString param); + double velocityFactor(); double timeToDistance(double time); double distanceToTime(double distance); @@ -145,12 +137,7 @@ public: // Assembles datapoints as received from the VNA from four S parameter traces. Requires that all traces are in the frequency domain, // have the same number of samples and their samples must be at the same frequencies across all traces - static std::vector assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22); - - static LiveParameter ParameterFromString(QString s); - static QString ParameterToString(LiveParameter p); - static bool isVNAParameter(LiveParameter p); - static bool isSAParamater(LiveParameter p); + static std::vector assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22); static LivedataType TypeFromString(QString s); static QString TypeToString(LivedataType t); @@ -247,7 +234,7 @@ private: // Members for when source == Source::Live LivedataType _liveType; - LiveParameter _liveParam; + QString liveParam; // Members for when source == Source::File QString filename; @@ -273,7 +260,7 @@ private: std::set markers; struct { union { - Protocol::SpectrumAnalyzerSettings SA; + VirtualDevice::SASettings SA; }; bool valid; } settings; diff --git a/Software/PC_Application/Traces/traceeditdialog.cpp b/Software/PC_Application/Traces/traceeditdialog.cpp index 853f8c7..2196758 100644 --- a/Software/PC_Application/Traces/traceeditdialog.cpp +++ b/Software/PC_Application/Traces/traceeditdialog.cpp @@ -124,25 +124,15 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : } VNAtrace = Trace::isVNAParameter(t.liveParameter()); - if(VNAtrace) { - ui->CLiveParam->addItem("S11"); - ui->CLiveParam->addItem("S12"); - ui->CLiveParam->addItem("S21"); - ui->CLiveParam->addItem("S22"); - } else { - ui->CLiveParam->addItem("Port 1"); - ui->CLiveParam->addItem("Port 2"); + if(VirtualDevice::getConnected()) { + if(VNAtrace) { + ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableVNAMeasurements()); + } else { + ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableSAMeasurements()); + } } - switch(t.liveParameter()) { - case Trace::LiveParameter::S11: ui->CLiveParam->setCurrentIndex(0); break; - case Trace::LiveParameter::S12: ui->CLiveParam->setCurrentIndex(1); break; - case Trace::LiveParameter::S21: ui->CLiveParam->setCurrentIndex(2); break; - case Trace::LiveParameter::S22: ui->CLiveParam->setCurrentIndex(3); break; - case Trace::LiveParameter::Port1: ui->CLiveParam->setCurrentIndex(0); break; - case Trace::LiveParameter::Port2: ui->CLiveParam->setCurrentIndex(1); break; - default: break; - } + ui->CLiveParam->setCurrentText(t.liveParameter()); connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateTouchstoneFileStatus); connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateTouchstoneFileStatus); @@ -354,26 +344,12 @@ void TraceEditDialog::on_buttonBox_accepted() } } else if(ui->bLive->isChecked()) { Trace::LivedataType type = Trace::LivedataType::Overwrite; - Trace::LiveParameter param = Trace::LiveParameter::S11; switch(ui->CLiveType->currentIndex()) { case 0: type = Trace::LivedataType::Overwrite; break; case 1: type = Trace::LivedataType::MaxHold; break; case 2: type = Trace::LivedataType::MinHold; break; } - if(VNAtrace) { - switch(ui->CLiveParam->currentIndex()) { - case 0: param = Trace::LiveParameter::S11; break; - case 1: param = Trace::LiveParameter::S12; break; - case 2: param = Trace::LiveParameter::S21; break; - case 3: param = Trace::LiveParameter::S22; break; - } - } else { - switch(ui->CLiveParam->currentIndex()) { - case 0: param = Trace::LiveParameter::Port1; break; - case 1: param = Trace::LiveParameter::Port2; break; - } - } - trace.fromLivedata(type, param); + trace.fromLivedata(type, ui->CLiveParam->currentText()); } else { // math operation trace trace.fromMath(); diff --git a/Software/PC_Application/Traces/tracemodel.cpp b/Software/PC_Application/Traces/tracemodel.cpp index e1a31cb..079b57e 100644 --- a/Software/PC_Application/Traces/tracemodel.cpp +++ b/Software/PC_Application/Traces/tracemodel.cpp @@ -1,4 +1,4 @@ -#include "tracemodel.h" +#include "tracemodel.h" #include #include @@ -161,9 +161,7 @@ bool TraceModel::PortExcitationRequired(int port) if(t->getSource() == Trace::Source::Live && !t->isPaused()) { // this trace needs measurements from VNA, check if port has to be excited for its measurement auto param = t->liveParameter(); - if(port == 1 && (param == Trace::LiveParameter::S11 || param == Trace::LiveParameter::S21)) { - return true; - } else if(port == 2 && (param == Trace::LiveParameter::S22 || param == Trace::LiveParameter::S12)) { + if(port == QString(param[2]).toInt()) { return true; } } @@ -214,7 +212,7 @@ void TraceModel::clearLiveData() } } -void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype) +void TraceModel::addVNAData(const VirtualDevice::VNAMeasurement& d, TraceMath::DataType datatype) { source = DataSource::VNA; for(auto t : traces) { @@ -226,31 +224,28 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype) td.x = d.frequency; break; case TraceMath::DataType::Power: - td.x = (double) d.cdbm / 100.0; + td.x = d.dBm; break; case TraceMath::DataType::TimeZeroSpan: - td.x = d.time; + td.x = d.us; index = d.pointNum; break; default: // invalid type, can not add return; } - switch(t->liveParameter()) { - case Trace::LiveParameter::S11: td.y = d.S.m11; break; - case Trace::LiveParameter::S12: td.y = d.S.m12; break; - case Trace::LiveParameter::S21: td.y = d.S.m21; break; - case Trace::LiveParameter::S22: td.y = d.S.m22; break; - default: - // not a VNA trace, skip + if(d.measurements.count(t->liveParameter())) { + td.y = d.measurements.at(t->liveParameter()); + } else { + // parameter not included in data, skip continue; } - t->addData(td, datatype, d.reference_impedance, index); + t->addData(td, datatype, d.Z0, index); } } } -void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings) +void TraceModel::addSAData(const VirtualDevice::SAMeasurement& d, const VirtualDevice::SASettings &settings) { source = DataSource::SA; for(auto t : traces) { @@ -264,11 +259,10 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot } else { td.x = d.frequency; } - switch(t->liveParameter()) { - case Trace::LiveParameter::Port1: td.y = complex(d.port1, 0); break; - case Trace::LiveParameter::Port2: td.y = complex(d.port2, 0); break; - default: - // not a SA trace, skip + if(d.measurements.count(t->liveParameter())) { + td.y = d.measurements.at(t->liveParameter()); + } else { + // parameter not included in data, skip continue; } t->addData(td, settings, index); diff --git a/Software/PC_Application/Traces/tracemodel.h b/Software/PC_Application/Traces/tracemodel.h index 07ea83a..83a4eb4 100644 --- a/Software/PC_Application/Traces/tracemodel.h +++ b/Software/PC_Application/Traces/tracemodel.h @@ -4,7 +4,6 @@ #include "Device/device.h" #include "savable.h" #include "trace.h" -#include "VNA/vnadata.h" #include #include @@ -65,8 +64,8 @@ signals: public slots: void clearLiveData(); - void addVNAData(const VNAData& d, TraceMath::DataType datatype); - void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings); + void addVNAData(const VirtualDevice::VNAMeasurement& d, TraceMath::DataType datatype); + void addSAData(const VirtualDevice::SAMeasurement &d, const VirtualDevice::SASettings &settings); private: DataSource source; diff --git a/Software/PC_Application/Traces/tracewidget.cpp b/Software/PC_Application/Traces/tracewidget.cpp index 082944b..fe29c0e 100644 --- a/Software/PC_Application/Traces/tracewidget.cpp +++ b/Software/PC_Application/Traces/tracewidget.cpp @@ -180,7 +180,7 @@ void TraceWidget::SetupSCPI() }; auto createStringFromData = [](Trace *t, const Trace::Data &d) -> QString { - if(Trace::isSAParamater(t->liveParameter())) { + if(Trace::isSAParameter(t->liveParameter())) { if(std::isnan(d.x)) { return "NaN"; } @@ -373,7 +373,7 @@ void TraceWidget::SetupSCPI() if(!t || params.size() < 2) { return "ERROR"; } - auto newparam = Trace::ParameterFromString(params[1]); + auto newparam = params[1]; if((Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam)) || (Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))) { t->fromLivedata(t->liveType(), newparam); @@ -386,7 +386,7 @@ void TraceWidget::SetupSCPI() if(!t) { return "ERROR"; } - return Trace::ParameterToString(t->liveParameter()); + return t->liveParameter(); })); add(new SCPICommand("TYPE", [=](QStringList params) -> QString { auto t = findTrace(params); diff --git a/Software/PC_Application/Traces/tracewidget.h b/Software/PC_Application/Traces/tracewidget.h index a668276..73ea81b 100644 --- a/Software/PC_Application/Traces/tracewidget.h +++ b/Software/PC_Application/Traces/tracewidget.h @@ -31,7 +31,7 @@ protected: void SetupSCPI(); void contextMenuEvent(QContextMenuEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override; - virtual Trace::LiveParameter defaultParameter() = 0; + virtual QString defaultParameter() = 0; QPoint dragStartPosition; Trace *dragTrace; Ui::TraceWidget *ui; diff --git a/Software/PC_Application/VNA/Deembedding/deembedding.cpp b/Software/PC_Application/VNA/Deembedding/deembedding.cpp index 752c3db..1c8a8f9 100644 --- a/Software/PC_Application/VNA/Deembedding/deembedding.cpp +++ b/Software/PC_Application/VNA/Deembedding/deembedding.cpp @@ -76,31 +76,26 @@ void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22) auto S21 = t[2]; auto S22 = t[3]; for(unsigned int i=0;igetPoints();i++) { - Protocol::Datapoint p; + VirtualDevice::VNAMeasurement p; p.pointNum = i; + p.Z0 = 0; + p.dBm = 0; + Sparam S; if(S11) { - auto sample = S11->sample(i); - p.imag_S11 = sample.y.imag(); - p.real_S11 = sample.y.real(); - p.frequency = sample.x; + S.m11 = S11->sample(i).y; + p.frequency = S11->sample(i).x; } if(S12) { - auto sample = S12->sample(i); - p.imag_S12 = sample.y.imag(); - p.real_S12 = sample.y.real(); - p.frequency = sample.x; + S.m12 = S12->sample(i).y; + p.frequency = S11->sample(i).x; } if(S21) { - auto sample = S21->sample(i); - p.imag_S21 = sample.y.imag(); - p.real_S21 = sample.y.real(); - p.frequency = sample.x; + S.m21 = S21->sample(i).y; + p.frequency = S11->sample(i).x; } if(S22) { - auto sample = S22->sample(i); - p.imag_S22 = sample.y.imag(); - p.real_S22 = sample.y.real(); - p.frequency = sample.x; + S.m22 = S22->sample(i).y; + p.frequency = S11->sample(i).x; } measurements.push_back(p); } @@ -120,7 +115,7 @@ Deembedding::Deembedding(TraceModel &tm) } -void Deembedding::Deembed(VNAData &d) +void Deembedding::Deembed(VirtualDevice::VNAMeasurement &d) { // figure out the point in one sweep based on the incomig pointNums static unsigned lastPointNum; diff --git a/Software/PC_Application/VNA/Deembedding/deembedding.h b/Software/PC_Application/VNA/Deembedding/deembedding.h index dfa1f83..f7163ac 100644 --- a/Software/PC_Application/VNA/Deembedding/deembedding.h +++ b/Software/PC_Application/VNA/Deembedding/deembedding.h @@ -17,15 +17,15 @@ class Deembedding : public QObject, public Savable Q_OBJECT public: Deembedding(TraceModel &tm); - ~Deembedding(){}; + ~Deembedding(){} - void Deembed(VNAData &d); + void Deembed(VirtualDevice::VNAMeasurement &d); void Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22); void removeOption(unsigned int index); void addOption(DeembeddingOption* option); void swapOptions(unsigned int index); - std::vector& getOptions() {return options;}; + std::vector& getOptions() {return options;} nlohmann::json toJSON() override; void fromJSON(nlohmann::json j) override; public slots: @@ -42,7 +42,7 @@ private: TraceModel &tm; bool measuring; - std::vector measurements; + std::vector measurements; QDialog *measurementDialog; Ui_DeembeddingMeasurementDialog *measurementUI; diff --git a/Software/PC_Application/VNA/Deembedding/deembeddingoption.h b/Software/PC_Application/VNA/Deembedding/deembeddingoption.h index 3cad265..5d69846 100644 --- a/Software/PC_Application/VNA/Deembedding/deembeddingoption.h +++ b/Software/PC_Application/VNA/Deembedding/deembeddingoption.h @@ -23,12 +23,12 @@ public: static DeembeddingOption *create(Type type); static QString getName(Type type); - virtual void transformDatapoint(VNAData &p) = 0; - virtual void edit(){}; + virtual void transformDatapoint(VirtualDevice::VNAMeasurement &p) = 0; + virtual void edit(){} virtual Type getType() = 0; public slots: - virtual void measurementCompleted(std::vector m){Q_UNUSED(m)}; + virtual void measurementCompleted(std::vector m){Q_UNUSED(m)} signals: // Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself void deleted(DeembeddingOption *option); diff --git a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp index ba935f9..4bcea37 100644 --- a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp +++ b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp @@ -15,10 +15,11 @@ ImpedanceRenormalization::ImpedanceRenormalization() } -void ImpedanceRenormalization::transformDatapoint(VNAData &p) +void ImpedanceRenormalization::transformDatapoint(VirtualDevice::VNAMeasurement &p) { - p.S = Sparam(ABCDparam(p.S, p.reference_impedance), impedance); - p.reference_impedance = impedance; + //p.S = Sparam(ABCDparam(p.S, p.Z0), impedance); + // TODO + p.Z0 = impedance; } nlohmann::json ImpedanceRenormalization::toJSON() diff --git a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h index a0784d6..e461c45 100644 --- a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h +++ b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h @@ -13,7 +13,7 @@ class ImpedanceRenormalization : public DeembeddingOption public: ImpedanceRenormalization(); - void transformDatapoint(VNAData &p) override; + void transformDatapoint(VirtualDevice::VNAMeasurement &p) override; Type getType() override { return Type::ImpedanceRenormalization;} nlohmann::json toJSON() override; void fromJSON(nlohmann::json j) override; diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp index b49f578..9521f10 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp @@ -26,10 +26,10 @@ MatchingNetwork::MatchingNetwork() addNetwork = true; } -void MatchingNetwork::transformDatapoint(VNAData &p) +void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p) { - auto S = p.S; - auto measurement = ABCDparam(S, p.reference_impedance); + auto S = p.toSparam(1, 2); + auto measurement = ABCDparam(S, p.Z0); if(matching.count(p.frequency) == 0) { // this point is not calculated yet MatchingPoint m; @@ -53,7 +53,7 @@ void MatchingNetwork::transformDatapoint(VNAData &p) // at this point the map contains the matching network effect auto m = matching[p.frequency]; auto corrected = m.p1 * measurement * m.p2; - p.S = Sparam(corrected, p.reference_impedance); + p.fromSparam(Sparam(corrected, p.Z0), 1, 2); } void MatchingNetwork::edit() diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h index 5d206ab..e881a76 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h @@ -64,7 +64,7 @@ public: // DeembeddingOption interface public: - void transformDatapoint(VNAData &p) override; + void transformDatapoint(VirtualDevice::VNAMeasurement &p) override; void edit() override; Type getType() override {return Type::MatchingNetwork;} nlohmann::json toJSON() override; diff --git a/Software/PC_Application/VNA/Deembedding/portextension.cpp b/Software/PC_Application/VNA/Deembedding/portextension.cpp index c5b9064..8c45140 100644 --- a/Software/PC_Application/VNA/Deembedding/portextension.cpp +++ b/Software/PC_Application/VNA/Deembedding/portextension.cpp @@ -29,7 +29,7 @@ PortExtension::PortExtension() kit = nullptr; } -void PortExtension::transformDatapoint(VNAData &d) +void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d) { if(port1.enabled || port2.enabled) { if(port1.enabled) { @@ -41,9 +41,9 @@ void PortExtension::transformDatapoint(VNAData &d) // convert from db to factor auto att = pow(10.0, -db_attennuation / 20.0); auto correction = polar(att, phase); - d.S.m11 /= correction * correction; - d.S.m21 /= correction; - d.S.m12 /= correction; + d.measurements["S11"] /= correction * correction; + d.measurements["S21"] /= correction; + d.measurements["S12"] /= correction; } if(port2.enabled) { auto phase = -2 * M_PI * port2.delay * d.frequency; @@ -54,9 +54,9 @@ void PortExtension::transformDatapoint(VNAData &d) // convert from db to factor auto att = pow(10.0, -db_attennuation / 20.0); auto correction = polar(att, phase); - d.S.m22 /= correction * correction; - d.S.m21 /= correction; - d.S.m12 /= correction; + d.measurements["S22"] /= correction * correction; + d.measurements["S21"] /= correction; + d.measurements["S12"] /= correction; } } } @@ -194,7 +194,7 @@ void PortExtension::edit() } } -void PortExtension::measurementCompleted(std::vector m) +void PortExtension::measurementCompleted(std::vector m) { if(m.size() > 0) { double last_phase = 0.0; @@ -205,9 +205,9 @@ void PortExtension::measurementCompleted(std::vector m) // grab correct measurement complex reflection; if(isPort1) { - reflection = p.S.m11; + reflection = p.measurements["S11"]; } else { - reflection = p.S.m22; + reflection = p.measurements["S22"]; } // remove calkit if specified if(!isIdeal) { diff --git a/Software/PC_Application/VNA/Deembedding/portextension.h b/Software/PC_Application/VNA/Deembedding/portextension.h index 1b88700..fa649df 100644 --- a/Software/PC_Application/VNA/Deembedding/portextension.h +++ b/Software/PC_Application/VNA/Deembedding/portextension.h @@ -18,14 +18,14 @@ class PortExtension : public DeembeddingOption Q_OBJECT public: PortExtension(); - void transformDatapoint(VNAData& d) override; + void transformDatapoint(VirtualDevice::VNAMeasurement& d) override; void setCalkit(Calkit *kit); Type getType() override {return Type::PortExtension;} nlohmann::json toJSON() override; void fromJSON(nlohmann::json j) override; public slots: void edit() override; - void measurementCompleted(std::vector m) override; + void measurementCompleted(std::vector m) override; private: void startMeasurement(); diff --git a/Software/PC_Application/VNA/Deembedding/twothru.cpp b/Software/PC_Application/VNA/Deembedding/twothru.cpp index 0785a12..6af2cc0 100644 --- a/Software/PC_Application/VNA/Deembedding/twothru.cpp +++ b/Software/PC_Application/VNA/Deembedding/twothru.cpp @@ -15,11 +15,11 @@ TwoThru::TwoThru() Z0 = 50.0; } -void TwoThru::transformDatapoint(VNAData &p) +void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p) { // correct measurement if(points.size() > 0) { - Tparam meas(p.S); + Tparam meas(p.toSparam(1,2)); Tparam inv1, inv2; if(p.frequency < points.front().freq) { @@ -49,7 +49,7 @@ void TwoThru::transformDatapoint(VNAData &p) // perform correction Tparam corrected = inv1*meas*inv2; // transform back into S parameters - p.S = Sparam(corrected); + p.fromSparam(Sparam(corrected), 1, 2); } } @@ -99,7 +99,7 @@ void TwoThru::updateGUI() } } -void TwoThru::measurementCompleted(std::vector m) +void TwoThru::measurementCompleted(std::vector m) { if (measuring2xthru) { measurements2xthru = m; @@ -210,7 +210,7 @@ void TwoThru::fromJSON(nlohmann::json j) } } -std::vector TwoThru::calculateErrorBoxes(std::vector data_2xthru) +std::vector TwoThru::calculateErrorBoxes(std::vector data_2xthru) { // calculate error boxes, see https://www.freelists.org/post/si-list/IEEE-P370-Opensource-Deembedding-MATLAB-functions // create vectors of S parameters @@ -229,10 +229,10 @@ std::vector TwoThru::calculateErrorBoxes(std::vector da // ignore possible DC point continue; } - S11.push_back(m.S.m11); - S12.push_back(m.S.m12); - S21.push_back(m.S.m21); - S22.push_back(m.S.m22); + S11.push_back(m.measurements["S11"]); + S12.push_back(m.measurements["S12"]); + S21.push_back(m.measurements["S21"]); + S22.push_back(m.measurements["S22"]); f.push_back(m.frequency); } auto n = f.size(); @@ -390,7 +390,7 @@ std::vector TwoThru::calculateErrorBoxes(std::vector da return ret; } -std::vector TwoThru::calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0) +std::vector TwoThru::calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0) { vector ret; @@ -414,13 +414,13 @@ std::vector TwoThru::calculateErrorBoxes(std::vector da vector p; vector f; for(auto d : data_2xthru) { - p.push_back(d.S); + p.push_back(d.toSparam(1, 2)); f.push_back(d.frequency); } auto data_2xthru_Sparam = p; vector data_fix_dut_fix_Sparam; for(auto d : data_fix_dut_fix) { - data_fix_dut_fix_Sparam.push_back(d.S); + data_fix_dut_fix_Sparam.push_back(d.toSparam(1, 2)); } // grabbing S21 @@ -663,9 +663,9 @@ std::vector TwoThru::calculateErrorBoxes(std::vector da return ret; } -std::vector TwoThru::interpolateEvenFrequencySteps(std::vector input) +std::vector TwoThru::interpolateEvenFrequencySteps(std::vector input) { - vector ret; + vector ret; if(input.size() > 1) { int size = input.size(); double freqStep = 0.0; @@ -687,8 +687,8 @@ std::vector TwoThru::interpolateEvenFrequencySteps(std::vector // needs to interpolate double freq = freqStep; while(freq <= input.back().frequency) { - VNAData interp; - auto it = lower_bound(input.begin(), input.end(), freq, [](const VNAData &lhs, const double f) -> bool { + VirtualDevice::VNAMeasurement interp; + auto it = lower_bound(input.begin(), input.end(), freq, [](const VirtualDevice::VNAMeasurement &lhs, const double f) -> bool { return lhs.frequency < f; }); if(it->frequency == freq) { @@ -699,12 +699,7 @@ std::vector TwoThru::interpolateEvenFrequencySteps(std::vector it--; auto low = *it; double alpha = (freq - low.frequency) / (high.frequency - low.frequency); - interp.S.m11 = low.S.m11 * (1.0 - alpha) + high.S.m11 * alpha; - interp.S.m12 = low.S.m12 * (1.0 - alpha) + high.S.m12 * alpha; - interp.S.m21 = low.S.m21 * (1.0 - alpha) + high.S.m21 * alpha; - interp.S.m22 = low.S.m22 * (1.0 - alpha) + high.S.m22 * alpha; - interp.cdbm = low.cdbm * (1.0 - alpha) + high.cdbm * alpha; - interp.reference_impedance = low.reference_impedance * (1.0 - alpha) + high.reference_impedance * alpha; + interp = low.interpolateTo(high, alpha); } interp.pointNum = it->pointNum; interp.frequency = freq; diff --git a/Software/PC_Application/VNA/Deembedding/twothru.h b/Software/PC_Application/VNA/Deembedding/twothru.h index db1e376..aec4bf7 100644 --- a/Software/PC_Application/VNA/Deembedding/twothru.h +++ b/Software/PC_Application/VNA/Deembedding/twothru.h @@ -16,7 +16,7 @@ class TwoThru : public DeembeddingOption public: TwoThru(); - virtual void transformDatapoint(VNAData& p) override; + virtual void transformDatapoint(VirtualDevice::VNAMeasurement& p) override; virtual void edit() override; virtual Type getType() override {return DeembeddingOption::Type::TwoThru;} nlohmann::json toJSON() override; @@ -25,19 +25,19 @@ public: private slots: void startMeasurement(); void updateGUI(); - void measurementCompleted(std::vector m) override; + void measurementCompleted(std::vector m) override; private: using Point = struct { double freq; Tparam inverseP1, inverseP2; }; - static std::vector interpolateEvenFrequencySteps(std::vector input); - static std::vector calculateErrorBoxes(std::vector data_2xthru); - static std::vector calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0); + static std::vector interpolateEvenFrequencySteps(std::vector input); + static std::vector calculateErrorBoxes(std::vector data_2xthru); + static std::vector calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0); - std::vector measurements2xthru; - std::vector measurementsDUT; + std::vector measurements2xthru; + std::vector measurementsDUT; double Z0; std::vector points; bool measuring2xthru; diff --git a/Software/PC_Application/VNA/tracewidgetvna.h b/Software/PC_Application/VNA/tracewidgetvna.h index 242969e..304ed3a 100644 --- a/Software/PC_Application/VNA/tracewidgetvna.h +++ b/Software/PC_Application/VNA/tracewidgetvna.h @@ -10,11 +10,11 @@ class TraceWidgetVNA : public TraceWidget public: TraceWidgetVNA(TraceModel &model, Calibration &cal, Deembedding &deembed, QWidget *parent = nullptr); protected slots: - virtual void exportDialog() override {}; + virtual void exportDialog() override {} virtual void importDialog() override; protected: - virtual Trace::LiveParameter defaultParameter() override {return Trace::LiveParameter::S11;}; + virtual QString defaultParameter() override {return "S11";} // These can optionally be applied when importing an s2p file Calibration &cal; Deembedding &deembed; diff --git a/Software/PC_Application/VNA/vnadata.h b/Software/PC_Application/VNA/vnadata.h deleted file mode 100644 index ad4aea9..0000000 --- a/Software/PC_Application/VNA/vnadata.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef VNADATA_H -#define VNADATA_H - -#include "Tools/parameters.h" - -#include - -class VNAData { -public: - VNAData() = default; - VNAData(const Protocol::Datapoint &d) { - S = Sparam(std::complex(d.real_S11, d.imag_S11), - std::complex(d.real_S12, d.imag_S12), - std::complex(d.real_S21, d.imag_S21), - std::complex(d.real_S22, d.imag_S22)); - frequency = d.frequency; - time = (double) d.us / 1000000.0; - cdbm = d.cdbm; - pointNum = d.pointNum; - reference_impedance = 50.0; - } - double frequency; - double time; - int cdbm; - Sparam S; - unsigned int pointNum; - double reference_impedance; -}; - - -#endif // VNADATA_H diff --git a/Software/PC_Application/averaging.cpp b/Software/PC_Application/averaging.cpp index 4a4324a..27100d2 100644 --- a/Software/PC_Application/averaging.cpp +++ b/Software/PC_Application/averaging.cpp @@ -12,7 +12,7 @@ void Averaging::reset(unsigned int points) { avg.clear(); for(unsigned int i = 0;i, 4>>()); + avg.push_back(deque>>()); } } @@ -22,162 +22,41 @@ void Averaging::setAverages(unsigned int a) reset(avg.size()); } -VNAData Averaging::process(VNAData d) +VirtualDevice::VNAMeasurement Averaging::process(VirtualDevice::VNAMeasurement d) { - auto S11 = d.S.m11; - auto S12 = d.S.m12; - auto S21 = d.S.m21; - auto S22 = d.S.m22; - - if (d.pointNum == avg.size()) { - // add moving average entry - deque, 4>> deque; - avg.push_back(deque); + if(d.measurements.size() != numMeasurements) { + numMeasurements = d.measurements.size(); + reset(avg.size()); } - if (d.pointNum < avg.size()) { - // can compute average - // get correct queue - auto deque = &avg[d.pointNum]; - // add newest sample to queue - array, 4> sample = {S11, S12, S21, S22}; - deque->push_back(sample); - if(deque->size() > averages) { - deque->pop_front(); - } - - switch(mode) { - case Mode::Mean: { - // calculate average - complex 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> S11sorted, S12sorted, S21sorted, S22sorted; - S11sorted.reserve(size); - S12sorted.reserve(size); - S21sorted.reserve(size); - S22sorted.reserve(size); - - auto comp = [=](const complex&a, const complex&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; - } + vector> data; + for(auto m : d.measurements) { + data.push_back(m.second); + } + process(d.pointNum, data); + int i=0; + for(auto &m : d.measurements) { + m.second = data[i++]; } - - d.S = Sparam(S11, S12, S21, S22); - return d; } VirtualDevice::SAMeasurement Averaging::process(VirtualDevice::SAMeasurement d) { if(d.measurements.size() != numMeasurements) { + numMeasurements = d.measurements.size(); reset(avg.size()); } - if (d.pointNum == avg.size()) { - // add moving average entry - deque>> deque; - avg.push_back(deque); + vector> data; + for(auto m : d.measurements) { + data.push_back(m.second); } - - if (d.pointNum < avg.size()) { - // can compute average - // get correct queue - auto deque = &avg[d.pointNum]; - // add newest sample to queue - vector> sample; - for(auto m : d.measurements) { - sample.push_back(m.second); - } - deque->push_back(sample); - if(deque->size() > averages) { - deque->pop_front(); - } - - deque averagedResults; - - switch(mode) { - case Mode::Mean: { - // calculate average - complex sum[numMeasurements]; - for(auto s : *deque) { - for(int i=0;isize()))); - } - } - break; - case Mode::Median: { - auto size = deque->size(); - // create sorted vectors - array, numMeasurements> vectors; - for(auto &v : vectors) { - v.reserve(size); - } - for(auto d : *deque) { - for(auto &v : vectors) { - v.insert(upper_bound(v.begin(), v.end(), abs(d[0])), abs(d[0])); - } - } - if(size & 0x01) { - // odd number of samples - for(auto v : vectors) { - averagedResults.push_back(v[size / 2]); - } - } else { - // even number, use average of middle samples - for(auto v : vectors) { - averagedResults.push_back((v[size / 2 - 1] + v[size / 2]) / 2); - } - } - } - break; - } - - for(auto &m : d.measurements) { - m.second = averagedResults.pop_front(); - } + process(d.pointNum, data); + int i=0; + for(auto &m : d.measurements) { + m.second = data[i++].real(); } - return d; } @@ -208,3 +87,80 @@ void Averaging::setMode(const Mode &value) { mode = value; } + +void Averaging::process(int pointNum, std::vector> &data) +{ + if(data.size() != numMeasurements) { + numMeasurements = data.size(); + reset(avg.size()); + } + + if (pointNum == avg.size()) { + // add moving average entry + deque>> deque; + avg.push_back(deque); + } + + if (pointNum < avg.size()) { + // can compute average + // get correct queue + auto deque = &avg[pointNum]; + // add newest sample to queue + deque->push_back(data); + // remove oldest sample if required number of averages reached + if(deque->size() > averages) { + deque->pop_front(); + } + + std::deque> averagedResults = {}; + + switch(mode) { + case Mode::Mean: { + // calculate average + complex sum[numMeasurements]; + for(auto s : *deque) { + for(int i=0;isize()))); + } + } + break; + case Mode::Median: { + auto size = deque->size(); + // create sorted vectors + vector>> vectors(numMeasurements); + + auto comp = [=](const complex&a, const complex&b){ + return abs(a) < abs(b); + }; + for(auto d : *deque) { + int i=0; + for(auto &v : vectors) { + v.insert(upper_bound(v.begin(), v.end(), d[i], comp), d[i]); + i++; + } + } + if(size & 0x01) { + // odd number of samples + for(auto v : vectors) { + averagedResults.push_back(v[size / 2]); + } + } else { + // even number, use average of middle samples + for(auto v : vectors) { + averagedResults.push_back((v[size / 2 - 1] + v[size / 2]) / 2.0); + } + } + } + break; + } + + for(auto &m : data) { + m = averagedResults.front(); + averagedResults.pop_front(); + } + } +} diff --git a/Software/PC_Application/averaging.h b/Software/PC_Application/averaging.h index 6cc377b..f97a44c 100644 --- a/Software/PC_Application/averaging.h +++ b/Software/PC_Application/averaging.h @@ -1,8 +1,7 @@ #ifndef AVERAGING_H #define AVERAGING_H -#include "Device/virtualdevice.h".h" -#include "VNA/vnadata.h" +#include "Device/virtualdevice.h" #include #include @@ -19,7 +18,7 @@ public: Averaging(); void reset(unsigned int points); void setAverages(unsigned int a); - VNAData process(VNAData d); + VirtualDevice::VNAMeasurement process(VirtualDevice::VNAMeasurement d); VirtualDevice::SAMeasurement process(VirtualDevice::SAMeasurement d); // Returns the number of averaged sweeps. Value is incremented whenever the last point of the sweep is added. // Returned values are in range 0 to averages @@ -31,6 +30,8 @@ public: void setMode(const Mode &value); private: + void process(int pointNum, std::vector > &data); + std::vector>>> avg; int maxPoints; int numMeasurements;