From 4307a392fbe76c3c95c9fa203723a056d336ba77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Thu, 17 Mar 2022 18:24:18 +0100 Subject: [PATCH] Impedance renormalization moved to de-embedding --- .../Calibration/calibration.cpp | 165 ++++++++---------- .../PC_Application/Calibration/calibration.h | 11 +- Software/PC_Application/LibreVNA-GUI.pro | 4 + .../Tools/impedancematchdialog.cpp | 5 +- .../PC_Application/Traces/Marker/marker.cpp | 24 +-- .../PC_Application/Traces/smithchartdialog.ui | 27 ++- Software/PC_Application/Traces/trace.cpp | 32 +++- Software/PC_Application/Traces/trace.h | 13 +- Software/PC_Application/Traces/traceaxis.cpp | 8 +- .../PC_Application/Traces/traceeditdialog.cpp | 3 + .../PC_Application/Traces/traceeditdialog.ui | 24 ++- Software/PC_Application/Traces/tracemodel.cpp | 12 +- Software/PC_Application/Traces/tracemodel.h | 3 +- Software/PC_Application/Traces/traceplot.cpp | 6 + .../PC_Application/Traces/tracesmithchart.cpp | 82 +++++++-- .../PC_Application/Traces/tracesmithchart.h | 6 +- .../Traces/tracetouchstoneexport.cpp | 4 +- .../Traces/tracetouchstoneexport.h | 1 + Software/PC_Application/Util/util.cpp | 6 +- Software/PC_Application/Util/util.h | 14 +- .../VNA/Deembedding/deembedding.cpp | 2 +- .../VNA/Deembedding/deembedding.h | 4 +- .../VNA/Deembedding/deembeddingoption.cpp | 5 + .../VNA/Deembedding/deembeddingoption.h | 6 +- .../impedancenormalizationdialog.ui | 88 ++++++++++ .../Deembedding/impedancerenormalization.cpp | 57 ++++++ .../Deembedding/impedancerenormalization.h | 29 +++ .../VNA/Deembedding/matchingnetwork.cpp | 21 +-- .../VNA/Deembedding/matchingnetwork.h | 4 +- .../VNA/Deembedding/portextension.cpp | 34 ++-- .../VNA/Deembedding/portextension.h | 4 +- .../VNA/Deembedding/twothru.cpp | 68 +++----- .../PC_Application/VNA/Deembedding/twothru.h | 14 +- Software/PC_Application/VNA/vna.cpp | 27 +-- Software/PC_Application/VNA/vnadata.h | 29 +++ Software/PC_Application/averaging.cpp | 19 +- Software/PC_Application/averaging.h | 3 +- Software/PC_Application/preferences.cpp | 5 - Software/PC_Application/preferences.h | 2 - Software/PC_Application/preferencesdialog.ui | 18 -- Software/PC_Application/touchstone.cpp | 21 ++- Software/PC_Application/touchstone.h | 4 + 42 files changed, 584 insertions(+), 330 deletions(-) create mode 100644 Software/PC_Application/VNA/Deembedding/impedancenormalizationdialog.ui create mode 100644 Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp create mode 100644 Software/PC_Application/VNA/Deembedding/impedancerenormalization.h create mode 100644 Software/PC_Application/VNA/vnadata.h diff --git a/Software/PC_Application/Calibration/calibration.cpp b/Software/PC_Application/Calibration/calibration.cpp index 1737f9d..96d5b95 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, Protocol::Datapoint &d) +void Calibration::addMeasurement(Calibration::Measurement type, VNAData &d) { measurements[type].datapoints.push_back(d); measurements[type].timestamp = QDateTime::currentDateTime(); } -void Calibration::addMeasurements(std::set types, Protocol::Datapoint &d) +void Calibration::addMeasurements(std::set types, VNAData &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 = complex(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); - auto S11_short = complex(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); - auto S11_load = complex(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11); - auto S22_open = complex(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); - auto S22_short = complex(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); - auto S22_load = complex(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22); + 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 S21_isolation = complex(0,0); auto S12_isolation = complex(0,0); if(isolation_measured) { - S21_isolation = complex(measurements[Measurement::Isolation].datapoints[i].real_S21, measurements[Measurement::Isolation].datapoints[i].imag_S21); - S12_isolation = complex(measurements[Measurement::Isolation].datapoints[i].real_S12, measurements[Measurement::Isolation].datapoints[i].imag_S12); + S21_isolation = measurements[Measurement::Isolation].datapoints[i].S.m21; + S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12; } - auto S11_through = complex(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11); - auto S21_through = complex(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21); - auto S22_through = complex(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22); - auto S12_through = complex(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_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 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 = complex(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); - auto S11_short = complex(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); - auto S11_load = complex(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11); + 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; // 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 = complex(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); - auto S22_short = complex(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); - auto S22_load = complex(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22); + 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; // 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 = complex(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21); - auto S12_through = complex(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12); + auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; + auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; 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 = complex(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11); - auto S21_through = complex(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21); - auto S22_through = complex(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22); - auto S12_through = complex(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12); - auto S11_line = complex(measurements[Measurement::Line].datapoints[i].real_S11, measurements[Measurement::Line].datapoints[i].imag_S11); - auto S21_line = complex(measurements[Measurement::Line].datapoints[i].real_S21, measurements[Measurement::Line].datapoints[i].imag_S21); - auto S22_line = complex(measurements[Measurement::Line].datapoints[i].real_S22, measurements[Measurement::Line].datapoints[i].imag_S22); - auto S12_line = complex(measurements[Measurement::Line].datapoints[i].real_S12, measurements[Measurement::Line].datapoints[i].imag_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_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 trl = kit.toTRL(p.frequency); complex S11_reflection, S22_reflection; if(trl.reflectionIsNegative) { // used short - S11_reflection = complex(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); - S22_reflection = complex(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); + S11_reflection = measurements[Measurement::Port1Short].datapoints[i].S.m11; + S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22; } else { // used open - S11_reflection = complex(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); - S22_reflection = complex(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); + S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11; + S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22; } // 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(Protocol::Datapoint &d) +void Calibration::correctMeasurement(VNAData &d) { if(type == Type::None) { // No calibration data, do nothing return; } // Convert measurements to complex variables - auto S11m = complex(d.real_S11, d.imag_S11); - auto S21m = complex(d.real_S21, d.imag_S21); - auto S22m = complex(d.real_S22, d.imag_S22); - auto S12m = complex(d.real_S12, d.imag_S12); + auto S11m = d.S.m11; + auto S21m = d.S.m21; + auto S22m = d.S.m22; + auto S12m = d.S.m12; // find correct entry auto p = getCalibrationPoint(d); @@ -459,14 +459,7 @@ void Calibration::correctMeasurement(Protocol::Datapoint &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.real_S11 = S11.real(); - d.imag_S11 = S11.imag(); - d.real_S12 = S12.real(); - d.imag_S12 = S12.imag(); - d.real_S21 = S21.real(); - d.imag_S21 = S21.imag(); - d.real_S22 = S22.real(); - d.imag_S22 = S22.imag(); + d.S = Sparam(S11, S12, S21, S22); } void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22) @@ -741,13 +734,13 @@ std::vector Calibration::getMeasurementTraces() Trace::Data d; d.x = p.frequency; if(prefix == "S11") { - d.y = complex(p.real_S11, p.imag_S11); + d.y = p.S.m11; } else if(prefix == "S12") { - d.y = complex(p.real_S12, p.imag_S12); + d.y = p.S.m12; } else if(prefix == "S21") { - d.y = complex(p.real_S21, p.imag_S21); + d.y = p.S.m21; } else { - d.y = complex(p.real_S22, p.imag_S22); + d.y = p.S.m22; } t->addData(d, TraceMath::DataType::Frequency); } @@ -916,14 +909,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.real_S11; - j_point["S11_imag"] = p.imag_S11; - j_point["S12_real"] = p.real_S12; - j_point["S12_imag"] = p.imag_S12; - j_point["S21_real"] = p.real_S21; - j_point["S21_imag"] = p.imag_S21; - j_point["S22_real"] = p.real_S22; - j_point["S22_imag"] = p.imag_S22; + 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_points.push_back(j_point); } j_measurement["points"] = j_points; @@ -964,17 +957,13 @@ void Calibration::fromJSON(nlohmann::json j) } int pointNum = 0; for(auto j_p : j_m["points"]) { - Protocol::Datapoint p; + VNAData p; p.pointNum = pointNum++; p.frequency = j_p.value("frequency", 0.0); - p.real_S11 = j_p.value("S11_real", 0.0); - p.imag_S11 = j_p.value("S11_imag", 0.0); - p.real_S12 = j_p.value("S12_real", 0.0); - p.imag_S12 = j_p.value("S12_imag", 0.0); - p.real_S21 = j_p.value("S21_real", 0.0); - p.imag_S21 = j_p.value("S21_imag", 0.0); - p.real_S22 = j_p.value("S22_real", 0.0); - p.imag_S22 = j_p.value("S22_imag", 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)); measurements[m].datapoints.push_back(p); } } @@ -997,24 +986,6 @@ QString Calibration::getCurrentCalibrationFile(){ return this->currentCalFile; } -ostream& operator<<(ostream &os, const Calibration &c) -{ - for(auto m : c.measurements) { - if(m.second.datapoints.size() > 0) { - os << c.MeasurementToString(m.first).toStdString() << endl; - os << m.second.timestamp.toSecsSinceEpoch() << endl; - os << m.second.datapoints.size() << endl; - for(auto p : m.second.datapoints) { - os << p.pointNum << " " << p.frequency << " "; - os << p.imag_S11 << " " << p.real_S11 << " " << p.imag_S21 << " " << p.real_S21 << " " << p.imag_S12 << " " << p.real_S12 << " " << p.imag_S22 << " " << p.real_S22; - os << endl; - } - } - } - os << Calibration::TypeToString(c.getType()).toStdString() << endl; - return os; -} - istream& operator >>(istream &in, Calibration &c) { // old file format did not contain port standard gender, set default @@ -1039,7 +1010,7 @@ istream& operator >>(istream &in, Calibration &c) Protocol::Datapoint p; in >> 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(p); + 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."); @@ -1097,7 +1068,7 @@ bool Calibration::SanityCheckSamples(const std::vector return true; } -Calibration::Point Calibration::getCalibrationPoint(Protocol::Datapoint &d) +Calibration::Point Calibration::getCalibrationPoint(VNAData &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 fba9643..bc48f3d 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, Protocol::Datapoint &d); - void addMeasurements(std::set types, Protocol::Datapoint &d); + void addMeasurement(Measurement type, VNAData &d); + void addMeasurements(std::set types, VNAData &d); enum class Type { Port1SOL, @@ -63,7 +63,7 @@ public: bool constructErrorTerms(Type type); void resetErrorTerms(); - void correctMeasurement(Protocol::Datapoint &d); + void correctMeasurement(VNAData &d); void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22); enum class InterpolationType { @@ -93,7 +93,6 @@ public: const std::vector Measurements(Type type = Type::None, bool optional_included = true); MeasurementInfo getMeasurementInfo(Measurement m); - friend std::ostream& operator<<(std::ostream& os, const Calibration& c); friend std::istream& operator >> (std::istream &in, Calibration& c); int nPoints() { return points.size(); @@ -142,7 +141,7 @@ private: // Reverse error terms std::complex re33, re11, re23e32, re23e01, re22, re03, rex; }; - Point getCalibrationPoint(Protocol::Datapoint &d); + Point getCalibrationPoint(VNAData &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). @@ -174,7 +173,7 @@ private: class MeasurementData { public: QDateTime timestamp; - std::vector datapoints; + std::vector datapoints; }; Type type; diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index 4052967..48cc28b 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -110,12 +110,14 @@ HEADERS += \ VNA/Deembedding/deembedding.h \ VNA/Deembedding/deembeddingdialog.h \ VNA/Deembedding/deembeddingoption.h \ + VNA/Deembedding/impedancerenormalization.h \ VNA/Deembedding/manualdeembeddingdialog.h \ VNA/Deembedding/matchingnetwork.h \ VNA/Deembedding/portextension.h \ VNA/Deembedding/twothru.h \ VNA/tracewidgetvna.h \ VNA/vna.h \ + VNA/vnadata.h \ about.h \ appwindow.h \ averaging.h \ @@ -228,6 +230,7 @@ SOURCES += \ VNA/Deembedding/deembedding.cpp \ VNA/Deembedding/deembeddingdialog.cpp \ VNA/Deembedding/deembeddingoption.cpp \ + VNA/Deembedding/impedancerenormalization.cpp \ VNA/Deembedding/manualdeembeddingdialog.cpp \ VNA/Deembedding/matchingnetwork.cpp \ VNA/Deembedding/portextension.cpp \ @@ -293,6 +296,7 @@ FORMS += \ Traces/waterfallaxisdialog.ui \ Traces/xyplotaxisdialog.ui \ VNA/Deembedding/deembeddingdialog.ui \ + VNA/Deembedding/impedancenormalizationdialog.ui \ VNA/Deembedding/manualdeembeddingdialog.ui \ VNA/Deembedding/matchingnetworkdialog.ui \ VNA/Deembedding/measurementdialog.ui \ diff --git a/Software/PC_Application/Tools/impedancematchdialog.cpp b/Software/PC_Application/Tools/impedancematchdialog.cpp index 2618804..eb06da6 100644 --- a/Software/PC_Application/Tools/impedancematchdialog.cpp +++ b/Software/PC_Application/Tools/impedancematchdialog.cpp @@ -13,7 +13,7 @@ ImpedanceMatchDialog::ImpedanceMatchDialog(MarkerModel &model, Marker *marker, Q { ui->setupUi(this); - Z0 = Preferences::getInstance().Acquisition.refImp; + Z0 = 50.0; // set SI units and prefixes ui->zReal->setUnit("Ohm"); @@ -70,10 +70,13 @@ void ImpedanceMatchDialog::on_cSource_currentIndexChanged(int index) auto m = qvariant_cast(ui->cSource->itemData(index)); ui->rbSeries->setChecked(true); auto data = m->getData(); + Z0 = m->getTrace()->getReferenceImpedance(); auto reflection = Z0 * (1.0 + data) / (1.0 - data); ui->zReal->setValue(reflection.real()); ui->zImag->setValue(reflection.imag()); ui->zFreq->setValue(m->getPosition()); + } else { + Z0 = 50.0; } } diff --git a/Software/PC_Application/Traces/Marker/marker.cpp b/Software/PC_Application/Traces/Marker/marker.cpp index ecaec13..25c6c63 100644 --- a/Software/PC_Application/Traces/Marker/marker.cpp +++ b/Software/PC_Application/Traces/Marker/marker.cpp @@ -275,7 +275,7 @@ QString Marker::readableData(Format f) return Unit::ToString(data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag(), "", " ", 5)+"j"; case Format::Impedance: { auto step = parentTrace->sample(parentTrace->index(position), true).y.real(); - auto impedance = Util::SparamToImpedance(step).real(); + auto impedance = Util::SparamToImpedance(step, trace()->getReferenceImpedance()).real(); return Unit::ToString(impedance, "Ω", "m kM", 3); } break; @@ -294,8 +294,8 @@ QString Marker::readableData(Format f) case Format::Impedance: { auto step = parentTrace->sample(parentTrace->index(position), true).y.real(); auto stepDelta = delta->parentTrace->sample(delta->parentTrace->index(delta->position), true).y.real(); - auto impedance = Util::SparamToImpedance(step).real(); - auto impedanceDelta = Util::SparamToImpedance(stepDelta).real(); + auto impedance = Util::SparamToImpedance(step, trace()->getReferenceImpedance()).real(); + auto impedanceDelta = Util::SparamToImpedance(stepDelta, trace()->getReferenceImpedance()).real(); return "Δ:"+Unit::ToString(impedance - impedanceDelta, "Ω", "m kM", 3); } break; @@ -330,13 +330,13 @@ QString Marker::readableData(Format f) } case Format::RealImag: return "Δ:"+Unit::ToString(data.real() - delta->data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag() - delta->data.imag(), "", " ", 5)+"j"; case Format::Impedance: { - auto impedance = Util::SparamToImpedance(data); - auto delta_impedance = Util::SparamToImpedance(delta->data); + auto impedance = Util::SparamToImpedance(data, trace()->getReferenceImpedance()); + auto delta_impedance = Util::SparamToImpedance(delta->data, trace()->getReferenceImpedance()); return "Δ:"+Unit::ToString(impedance.real() - delta_impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag() - delta_impedance.imag(), "Ω", "m k", 5)+"j"; } - case Format::SeriesR: return "Δ:"+Unit::ToString(Util::SparamToResistance(data) - Util::SparamToResistance(delta->data), "Ω", "m kM", 4); - case Format::Capacitance: return "Δ:"+Unit::ToString(Util::SparamToCapacitance(data, position) - Util::SparamToCapacitance(delta->data, delta->position), "F", "pnum ", 4); - case Format::Inductance: return "Δ:"+Unit::ToString(Util::SparamToInductance(data, position) - Util::SparamToInductance(delta->data, delta->position), "H", "pnum ", 4); + case Format::SeriesR: return "Δ:"+Unit::ToString(Util::SparamToResistance(data, trace()->getReferenceImpedance()) - Util::SparamToResistance(delta->data, trace()->getReferenceImpedance()), "Ω", "m kM", 4); + case Format::Capacitance: return "Δ:"+Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()) - Util::SparamToCapacitance(delta->data, delta->position, trace()->getReferenceImpedance()), "F", "pnum ", 4); + case Format::Inductance: return "Δ:"+Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()) - Util::SparamToInductance(delta->data, delta->position, trace()->getReferenceImpedance()), "H", "pnum ", 4); case Format::QualityFactor: return "ΔQ:" + Unit::ToString(Util::SparamToQualityFactor(data) - Util::SparamToQualityFactor(delta->data), "", " ", 3); case Format::Noise: return "Δ:"+Unit::ToString(parentTrace->getNoise(position) - delta->parentTrace->getNoise(delta->position), "dbm/Hz", " ", 3); default: return "Invalid"; @@ -355,9 +355,9 @@ QString Marker::readableData(Format f) return "VSWR: NaN"; } break; - case Format::SeriesR: return Unit::ToString(Util::SparamToResistance(data), "Ω", "m kM", 4); - case Format::Capacitance: return Unit::ToString(Util::SparamToCapacitance(data, position), "F", "pnum ", 4); - case Format::Inductance: return Unit::ToString(Util::SparamToInductance(data, position), "H", "pnum ", 4); + case Format::SeriesR: return Unit::ToString(Util::SparamToResistance(data, trace()->getReferenceImpedance()), "Ω", "m kM", 4); + case Format::Capacitance: return Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()), "F", "pnum ", 4); + case Format::Inductance: return Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()), "H", "pnum ", 4); case Format::QualityFactor: return "Q:" + Unit::ToString(Util::SparamToQualityFactor(data), "", " ", 3); case Format::Noise: return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3); case Format::TOI: { @@ -396,7 +396,7 @@ QString Marker::readableData(Format f) } break; case Format::Impedance: { - auto impedance = Util::SparamToImpedance(data); + auto impedance = Util::SparamToImpedance(data, trace()->getReferenceImpedance()); return Unit::ToString(impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag(), "Ω", "m k", 5)+"j"; } case Format::CenterBandwidth: diff --git a/Software/PC_Application/Traces/smithchartdialog.ui b/Software/PC_Application/Traces/smithchartdialog.ui index d45bb05..7843bad 100644 --- a/Software/PC_Application/Traces/smithchartdialog.ui +++ b/Software/PC_Application/Traces/smithchartdialog.ui @@ -6,8 +6,8 @@ 0 0 - 856 - 259 + 881 + 334 @@ -16,11 +16,11 @@ true - + - + @@ -72,6 +72,25 @@ + + + + Reference Impedance + + + + + + + + + Impedance: + + + + + + diff --git a/Software/PC_Application/Traces/trace.cpp b/Software/PC_Application/Traces/trace.cpp index c191804..ab20e28 100644 --- a/Software/PC_Application/Traces/trace.cpp +++ b/Software/PC_Application/Traces/trace.cpp @@ -19,6 +19,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live) _liveParam(live), vFactor(0.66), reflection(true), + reference_impedance(50.0), visible(true), paused(false), createdFromFile(false), @@ -61,7 +62,7 @@ void Trace::clear() { emit outputSamplesChanged(0, 0); } -void Trace::addData(const Trace::Data& d, DataType domain) { +void Trace::addData(const Trace::Data& d, DataType domain, double reference_impedance) { if(this->domain != domain) { clear(); this->domain = domain; @@ -100,6 +101,10 @@ void Trace::addData(const Trace::Data& d, DataType domain) { // insert at this position data.insert(lower, d); } + if(this->reference_impedance != reference_impedance) { + this->reference_impedance = reference_impedance; + emit typeChanged(this); + } success(); emit outputSamplesChanged(index, index + 1); } @@ -154,6 +159,7 @@ void Trace::fillFromTouchstone(Touchstone &t, unsigned int parameter) reflection = false; } createdFromFile = true; + reference_impedance = t.getReferenceImpedance(); emit typeChanged(this); emit outputSamplesChanged(0, data.size()); } @@ -233,7 +239,7 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter) return traceName; } -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(); @@ -242,13 +248,13 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c for(auto d : data) { Trace::Data td; td.x = d.frequency; - td.y = complex(d.real_S11, d.imag_S11); + td.y = d.S.m11; S11.addData(td, DataType::Frequency); - td.y = complex(d.real_S12, d.imag_S12); + td.y = d.S.m12; S12.addData(td, DataType::Frequency); - td.y = complex(d.real_S21, d.imag_S21); + td.y = d.S.m21; S21.addData(td, DataType::Frequency); - td.y = complex(d.real_S22, d.imag_S22); + td.y = d.S.m22; S22.addData(td, DataType::Frequency); } } @@ -287,6 +293,11 @@ void Trace::removeMarker(Marker *m) emit markerRemoved(m); } +double Trace::getReferenceImpedance() const +{ + return reference_impedance; +} + const std::vector& Trace::getMathOperations() const { return mathOps; @@ -474,12 +485,13 @@ 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(); + auto impedance = S11.getReferenceImpedance(); vector traces; traces.push_back(&S11); traces.push_back(&S12); @@ -491,6 +503,10 @@ std::vector Trace::assembleDatapoints(const Trace &S11, con qWarning() << "Selected traces do not have the same size"; return ret; } + if(t->getReferenceImpedance() != impedance) { + qWarning() << "Selected traces do not have the same reference impedance"; + return ret; + } if(t->outputType() != Trace::DataType::Frequency) { qWarning() << "Selected trace not in frequency domain"; return ret; diff --git a/Software/PC_Application/Traces/trace.h b/Software/PC_Application/Traces/trace.h index e6cd72a..2576847 100644 --- a/Software/PC_Application/Traces/trace.h +++ b/Software/PC_Application/Traces/trace.h @@ -5,6 +5,9 @@ #include "csv.h" #include "Device/device.h" #include "Math/tracemath.h" +#include "Tools/parameters.h" +#include "tracemodel.h" +#include "VNA/vnadata.h" #include #include @@ -41,15 +44,14 @@ public: Invalid, }; - void clear(); - void addData(const Data& d, DataType domain); + void addData(const Data& d, DataType domain, double reference_impedance = 50.0); void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s); 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); + static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector &data); void fromLivedata(LivedataType type, LiveParameter param); QString name() { return _name; }; QColor color() { return _color; }; @@ -134,7 +136,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 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); @@ -144,6 +146,8 @@ public: static LivedataType TypeFromString(QString s); static QString TypeToString(LivedataType t); + double getReferenceImpedance() const; + public slots: void setVisible(bool visible); void setColor(QColor color); @@ -174,6 +178,7 @@ private: bool paused; bool createdFromFile; bool calibration; + double reference_impedance; DataType domain; QString filename; unsigned int fileParameter; diff --git a/Software/PC_Application/Traces/traceaxis.cpp b/Software/PC_Application/Traces/traceaxis.cpp index e7be30b..cf22ced 100644 --- a/Software/PC_Application/Traces/traceaxis.cpp +++ b/Software/PC_Application/Traces/traceaxis.cpp @@ -109,11 +109,11 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample case YAxis::Type::Imaginary: return data.y.imag(); case YAxis::Type::SeriesR: - return Util::SparamToResistance(data.y); + return Util::SparamToResistance(data.y, t->getReferenceImpedance()); case YAxis::Type::Reactance: - return Util::SparamToImpedance(data.y).imag(); + return Util::SparamToImpedance(data.y, t->getReferenceImpedance()).imag(); case YAxis::Type::Capacitance: - return Util::SparamToCapacitance(data.y, data.x); + return Util::SparamToCapacitance(data.y, data.x, t->getReferenceImpedance()); case YAxis::Type::Inductance: return Util::SparamToInductance(data.y, data.x); case YAxis::Type::QualityFactor: @@ -164,7 +164,7 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample } double step = t->sample(sample, true).y.real(); if(abs(step) < 1.0) { - return Util::SparamToImpedance(step).real(); + return Util::SparamToImpedance(step, t->getReferenceImpedance()).real(); } } break; diff --git a/Software/PC_Application/Traces/traceeditdialog.cpp b/Software/PC_Application/Traces/traceeditdialog.cpp index 089540b..d49c625 100644 --- a/Software/PC_Application/Traces/traceeditdialog.cpp +++ b/Software/PC_Application/Traces/traceeditdialog.cpp @@ -22,6 +22,9 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : ui->name->setText(t.name()); ui->color->setColor(trace.color()); ui->vFactor->setValue(t.velocityFactor()); + ui->impedance->setUnit("Ω"); + ui->impedance->setPrecision(3); + ui->impedance->setValue(t.getReferenceImpedance()); connect(ui->bLive, &QPushButton::clicked, [=](bool live) { if(live) { diff --git a/Software/PC_Application/Traces/traceeditdialog.ui b/Software/PC_Application/Traces/traceeditdialog.ui index bf8c507..35e283c 100644 --- a/Software/PC_Application/Traces/traceeditdialog.ui +++ b/Software/PC_Application/Traces/traceeditdialog.ui @@ -9,8 +9,8 @@ 0 0 - 1038 - 365 + 931 + 392 @@ -21,7 +21,7 @@ - + @@ -112,6 +112,24 @@ + + + + + + Reference impedance: + + + + + + + false + + + + + diff --git a/Software/PC_Application/Traces/tracemodel.cpp b/Software/PC_Application/Traces/tracemodel.cpp index ac4a387..29bfe89 100644 --- a/Software/PC_Application/Traces/tracemodel.cpp +++ b/Software/PC_Application/Traces/tracemodel.cpp @@ -207,7 +207,7 @@ void TraceModel::clearLiveData() } } -void TraceModel::addVNAData(const Protocol::Datapoint &d, TraceMath::DataType datatype) +void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype) { source = DataSource::VNA; for(auto t : traces) { @@ -225,15 +225,15 @@ void TraceModel::addVNAData(const Protocol::Datapoint &d, TraceMath::DataType da return; } switch(t->liveParameter()) { - case Trace::LiveParameter::S11: td.y = complex(d.real_S11, d.imag_S11); break; - case Trace::LiveParameter::S12: td.y = complex(d.real_S12, d.imag_S12); break; - case Trace::LiveParameter::S21: td.y = complex(d.real_S21, d.imag_S21); break; - case Trace::LiveParameter::S22: td.y = complex(d.real_S22, d.imag_S22); break; + 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 continue; } - t->addData(td, datatype); + t->addData(td, datatype, d.reference_impedance); } } } diff --git a/Software/PC_Application/Traces/tracemodel.h b/Software/PC_Application/Traces/tracemodel.h index f55d3c2..07ea83a 100644 --- a/Software/PC_Application/Traces/tracemodel.h +++ b/Software/PC_Application/Traces/tracemodel.h @@ -4,6 +4,7 @@ #include "Device/device.h" #include "savable.h" #include "trace.h" +#include "VNA/vnadata.h" #include #include @@ -64,7 +65,7 @@ signals: public slots: void clearLiveData(); - void addVNAData(const Protocol::Datapoint& d, TraceMath::DataType datatype); + void addVNAData(const VNAData& d, TraceMath::DataType datatype); void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings); private: diff --git a/Software/PC_Application/Traces/traceplot.cpp b/Software/PC_Application/Traces/traceplot.cpp index 227bdbc..f4ebba1 100644 --- a/Software/PC_Application/Traces/traceplot.cpp +++ b/Software/PC_Application/Traces/traceplot.cpp @@ -460,6 +460,12 @@ void TracePlot::checkIfStillSupported(Trace *t) if(!configureForTrace(t)) { enableTrace(t, false); } + // remove non-supported traces after graph has been adjusted + for(auto t : activeTraces()) { + if(!supported(t)) { + enableTrace(t, false); + } + } break; } diff --git a/Software/PC_Application/Traces/tracesmithchart.cpp b/Software/PC_Application/Traces/tracesmithchart.cpp index 408cf7d..4071bfa 100644 --- a/Software/PC_Application/Traces/tracesmithchart.cpp +++ b/Software/PC_Application/Traces/tracesmithchart.cpp @@ -7,6 +7,7 @@ #include "QFileDialog" #include "Util/util.h" #include "appwindow.h" +#include "CustomWidgets/informationbox.h" #include #include @@ -22,6 +23,7 @@ TraceSmithChart::TraceSmithChart(TraceModel &model, QWidget *parent) limitToSpan = true; limitToEdge = true; edgeReflection = 1.0; + Z0 = 50.0; initializeTraceInfo(); } @@ -31,6 +33,7 @@ nlohmann::json TraceSmithChart::toJSON() j["limit_to_span"] = limitToSpan; j["limit_to_edge"] = limitToEdge; j["edge_reflection"] = edgeReflection; + j["Z0"] = Z0; nlohmann::json jtraces; for(auto t : traces) { if(t.second) { @@ -51,6 +54,7 @@ void TraceSmithChart::fromJSON(nlohmann::json j) limitToSpan = j.value("limit_to_span", true); limitToEdge = j.value("limit_to_edge", false); edgeReflection = j.value("edge_reflection", 1.0); + Z0 = j.value("Z0", 50.0); for(unsigned int hash : j["traces"]) { // attempt to find the traces with this hash bool found = false; @@ -107,6 +111,10 @@ void TraceSmithChart::axisSetupDialog() ui->zoomReflection->setValue(edgeReflection); ui->zoomFactor->setValue(1.0/edgeReflection); + ui->impedance->setUnit("Ω"); + ui->impedance->setPrecision(3); + ui->impedance->setValue(Z0); + auto model = new SmithChartContantLineModel(*this); ui->lineTable->setModel(model); ui->lineTable->setItemDelegateForColumn(SmithChartContantLineModel::ColIndexType, new SmithChartTypeDelegate); @@ -125,6 +133,15 @@ void TraceSmithChart::axisSetupDialog() edgeReflection = ui->zoomReflection->value(); ui->zoomFactor->setValueQuiet(1.0 / edgeReflection); }); + connect(ui->impedance, &SIUnitEdit::valueChanged, [=](){ + Z0 = ui->impedance->value(); + for(auto t : traces) { + if(t.second) { + checkIfStillSupported(t.first); + } + } + ui->impedance->setValueQuiet(Z0); + }); connect(ui->lineTable, &QTableView::clicked, [=](const QModelIndex &index){ if(index.column() == SmithChartContantLineModel::ColIndexColor) { auto line = &constantLines[index.row()]; @@ -182,8 +199,7 @@ QPoint TraceSmithChart::dataToPixel(Trace::Data d) if(d.x < sweep_fmin || d.x > sweep_fmax) { return QPoint(); } - return dataToPixel(d.y); -} + return dataToPixel(d.y);} std::complex TraceSmithChart::pixelToData(QPoint p) { @@ -265,6 +281,20 @@ bool TraceSmithChart::markerVisible(double x) } } +bool TraceSmithChart::configureForTrace(Trace *t) +{ + if(dropSupported(t)) { + Z0 = t->getReferenceImpedance(); + for(auto t : traces) { + if(t.second && t.first->getReferenceImpedance() != Z0) { + enableTrace(t.first, false); + } + } + return true; + } + return false; +} + void TraceSmithChart::draw(QPainter &p) { auto pref = Preferences::getInstance(); @@ -306,7 +336,7 @@ void TraceSmithChart::draw(QPainter &p) { p.drawLine(dataToPixel(complex(edgeReflection,0)),dataToPixel(complex(-edgeReflection,0))); constexpr std::array impedanceLines = {10, 25, 50, 100, 250}; for(auto z : impedanceLines) { - z /= Preferences::getInstance().Acquisition.refImp; + z /= Z0; auto radius = 1.0/z; drawArc(SmithChartArc(QPointF(1.0, radius), radius, 0, 2*M_PI)); drawArc(SmithChartArc(QPointF(1.0, -radius), radius, 0, 2*M_PI)); @@ -317,7 +347,7 @@ void TraceSmithChart::draw(QPainter &p) { pen = QPen(line.getColor(), pref.Graphs.lineWidth); pen.setCosmetic(true); p.setPen(pen); - for(auto arc : line.getArcs()) { + for(auto arc : line.getArcs(Z0)) { drawArc(arc); } } @@ -397,11 +427,40 @@ void TraceSmithChart::draw(QPainter &p) { } } +void TraceSmithChart::traceDropped(Trace *t, QPoint position) +{ + if(!supported(t) && dropSupported(t)) { + // needs to switch to a different domain for the graph + if(!InformationBox::AskQuestion("Reference impedance change", "You dropped a trace that is not supported with the currently selected reference impedance." + " Do you want to remove all traces and change the graph to the correct reference imppedance?", true, "ReferenceImpedanceChangeRequest")) { + // user declined to change domain, to not add change impedance + return; + } + // attempt to configure for this trace + configureForTrace(t); + } + TracePlot::traceDropped(t, position); +} + +bool TraceSmithChart::dropSupported(Trace *t) +{ + if(!t->isReflection()) { + return false; + } + switch(t->outputType()) { + case Trace::DataType::Frequency: + case Trace::DataType::Power: + return true; + default: + return false; + } +} + QString TraceSmithChart::mouseText(QPoint pos) { auto data = pixelToData(pos); if(abs(data) <= edgeReflection) { - data = Preferences::getInstance().Acquisition.refImp * (1.0 + data) / (1.0 - data); + data = Z0 * (1.0 + data) / (1.0 - data); auto ret = Unit::ToString(data.real(), "", " ", 3); if(data.imag() >= 0) { ret += "+"; @@ -478,16 +537,10 @@ void TraceSmithChart::updateContextMenu() bool TraceSmithChart::supported(Trace *t) { - if(!t->isReflection()) { - return false; - } - switch(t->outputType()) { - case Trace::DataType::Frequency: - case Trace::DataType::Power: - return true; - default: + if(t->getReferenceImpedance() != Z0) { return false; } + return dropSupported(t); } SmithChartArc::SmithChartArc(QPointF center, double radius, double startAngle, double spanAngle) @@ -571,9 +624,8 @@ SmithChartConstantLine::SmithChartConstantLine() color = Qt::darkRed; } -std::vector SmithChartConstantLine::getArcs() +std::vector SmithChartConstantLine::getArcs(double Z0) { - double Z0 = Preferences::getInstance().Acquisition.refImp; std::vector arcs; switch(type) { case Type::VSWR: diff --git a/Software/PC_Application/Traces/tracesmithchart.h b/Software/PC_Application/Traces/tracesmithchart.h index c591763..c8f9276 100644 --- a/Software/PC_Application/Traces/tracesmithchart.h +++ b/Software/PC_Application/Traces/tracesmithchart.h @@ -33,7 +33,7 @@ public: }; SmithChartConstantLine(); - std::vector getArcs(); + std::vector getArcs(double Z0); QColor getColor() const; void setColor(const QColor &value); @@ -126,13 +126,17 @@ protected: virtual bool markerVisible(double x); //void paintEvent(QPaintEvent *event) override; + virtual bool configureForTrace(Trace *t); virtual void updateContextMenu() override; bool supported(Trace *t) override; virtual void draw(QPainter& painter) override; + virtual void traceDropped(Trace *t, QPoint position) override; + virtual bool dropSupported(Trace *t) override; QString mouseText(QPoint pos) override; bool limitToSpan; bool limitToEdge; double edgeReflection; // magnitude of reflection coefficient at the edge of the smith chart (zoom factor) + double Z0; QTransform transform; std::vector constantLines; }; diff --git a/Software/PC_Application/Traces/tracetouchstoneexport.cpp b/Software/PC_Application/Traces/tracetouchstoneexport.cpp index dbaebfe..9f0c44c 100644 --- a/Software/PC_Application/Traces/tracetouchstoneexport.cpp +++ b/Software/PC_Application/Traces/tracetouchstoneexport.cpp @@ -68,6 +68,7 @@ void TraceTouchstoneExport::on_buttonBox_accepted() if(filename.length() > 0) { auto ports = ui->sbPorts->value(); auto t = Touchstone(ports); + t.setReferenceImpedance(referenceImpedance); // add trace points to touchstone for(unsigned int s=0;s(w->itemData(w->currentIndex())); points = t->size(); + referenceImpedance = t->getReferenceImpedance(); ui->points->setText(QString::number(points)); if(points > 0) { lowerFreq = t->minX(); @@ -179,7 +181,7 @@ void TraceTouchstoneExport::selectionChanged(QComboBox *w) for(auto c : v1) { for(int i=1;icount();i++) { Trace *t = qvariant_cast(c->itemData(i)); - if(t->size() != points || (points > 0 && (t->minX() != lowerFreq || t->maxX() != upperFreq))) { + if(t->getReferenceImpedance() != referenceImpedance || t->size() != points || (points > 0 && (t->minX() != lowerFreq || t->maxX() != upperFreq))) { // this trace is not available anymore c->removeItem(i); // decrement to check the next index in the next loop iteration diff --git a/Software/PC_Application/Traces/tracetouchstoneexport.h b/Software/PC_Application/Traces/tracetouchstoneexport.h index e095df2..db28e9d 100644 --- a/Software/PC_Application/Traces/tracetouchstoneexport.h +++ b/Software/PC_Application/Traces/tracetouchstoneexport.h @@ -34,6 +34,7 @@ private: unsigned int ports; unsigned int points; double lowerFreq, upperFreq; + double referenceImpedance; bool freqsSet; }; diff --git a/Software/PC_Application/Util/util.cpp b/Software/PC_Application/Util/util.cpp index 627f2de..f42c0b6 100644 --- a/Software/PC_Application/Util/util.cpp +++ b/Software/PC_Application/Util/util.cpp @@ -62,13 +62,13 @@ double Util::distanceToLine(QPointF point, QPointF l1, QPointF l2, QPointF *clos return orthVect.length(); } -std::complex Util::SparamToImpedance(std::complex d) { - return Preferences::getInstance().Acquisition.refImp * (1.0 + d) / (1.0 - d); +std::complex Util::SparamToImpedance(std::complex d, std::complex Z0) { + return Z0 * (1.0 + d) / (1.0 - d); } double Util::dBmTodBuV(double dBm) { - double uVpower = 0.000001*0.000001/Preferences::getInstance().Acquisition.refImp; + double uVpower = 0.000001*0.000001/50.0; double dBdiff = 10*log10(uVpower*1000); return dBm - dBdiff; } diff --git a/Software/PC_Application/Util/util.h b/Software/PC_Application/Util/util.h index ab47357..d04a3d8 100644 --- a/Software/PC_Application/Util/util.h +++ b/Software/PC_Application/Util/util.h @@ -45,16 +45,16 @@ namespace Util { static inline double SparamToVSWR(std::complex d) { return SparamToVSWR(abs(d)); } - std::complex SparamToImpedance(std::complex d); + std::complex SparamToImpedance(std::complex d, std::complex Z0 = 50.0); // all these conversions assume series connection of real and imag part - static inline double SparamToResistance(std::complex d) { - return SparamToImpedance(d).real(); + static inline double SparamToResistance(std::complex d, std::complex Z0 = 50.0) { + return SparamToImpedance(d, Z0).real(); } - static inline double SparamToCapacitance(std::complex d, double freq) { - return -1.0 / (SparamToImpedance(d).imag() * 2.0 * M_PI * freq); + static inline double SparamToCapacitance(std::complex d, double freq, std::complex Z0 = 50.0) { + return -1.0 / (SparamToImpedance(d, Z0).imag() * 2.0 * M_PI * freq); } - static inline double SparamToInductance(std::complex d, double freq) { - return SparamToImpedance(d).imag() / (2.0 * M_PI * freq); + static inline double SparamToInductance(std::complex d, double freq, std::complex Z0 = 50.0) { + return SparamToImpedance(d, Z0).imag() / (2.0 * M_PI * freq); } static inline double SparamToQualityFactor(std::complex d) { return abs(d.imag()) / d.real(); diff --git a/Software/PC_Application/VNA/Deembedding/deembedding.cpp b/Software/PC_Application/VNA/Deembedding/deembedding.cpp index 919c495..752c3db 100644 --- a/Software/PC_Application/VNA/Deembedding/deembedding.cpp +++ b/Software/PC_Application/VNA/Deembedding/deembedding.cpp @@ -120,7 +120,7 @@ Deembedding::Deembedding(TraceModel &tm) } -void Deembedding::Deembed(Protocol::Datapoint &d) +void Deembedding::Deembed(VNAData &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 462d85f..dfa1f83 100644 --- a/Software/PC_Application/VNA/Deembedding/deembedding.h +++ b/Software/PC_Application/VNA/Deembedding/deembedding.h @@ -19,7 +19,7 @@ public: Deembedding(TraceModel &tm); ~Deembedding(){}; - void Deembed(Protocol::Datapoint &d); + void Deembed(VNAData &d); void Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22); void removeOption(unsigned int index); @@ -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.cpp b/Software/PC_Application/VNA/Deembedding/deembeddingoption.cpp index 1ec89c4..1e17300 100644 --- a/Software/PC_Application/VNA/Deembedding/deembeddingoption.cpp +++ b/Software/PC_Application/VNA/Deembedding/deembeddingoption.cpp @@ -3,6 +3,7 @@ #include "portextension.h" #include "twothru.h" #include "matchingnetwork.h" +#include "impedancerenormalization.h" DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type) { @@ -13,6 +14,8 @@ DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type) return new TwoThru(); case Type::MatchingNetwork: return new MatchingNetwork(); + case Type::ImpedanceRenormalization: + return new ImpedanceRenormalization(); default: return nullptr; } @@ -27,6 +30,8 @@ QString DeembeddingOption::getName(DeembeddingOption::Type type) return "2xThru"; case Type::MatchingNetwork: return "Matching Network"; + case Type::ImpedanceRenormalization: + return "Impedance Renormalization"; default: return ""; } diff --git a/Software/PC_Application/VNA/Deembedding/deembeddingoption.h b/Software/PC_Application/VNA/Deembedding/deembeddingoption.h index 86177a0..3cad265 100644 --- a/Software/PC_Application/VNA/Deembedding/deembeddingoption.h +++ b/Software/PC_Application/VNA/Deembedding/deembeddingoption.h @@ -3,6 +3,7 @@ #include "savable.h" #include "Device/device.h" +#include "Traces/tracemodel.h" #include @@ -14,6 +15,7 @@ public: PortExtension, TwoThru, MatchingNetwork, + ImpedanceRenormalization, // Add new deembedding options here, do not explicitly assign values and keep the Last entry at the last position Last, }; @@ -21,12 +23,12 @@ public: static DeembeddingOption *create(Type type); static QString getName(Type type); - virtual void transformDatapoint(Protocol::Datapoint &p) = 0; + virtual void transformDatapoint(VNAData &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/impedancenormalizationdialog.ui b/Software/PC_Application/VNA/Deembedding/impedancenormalizationdialog.ui new file mode 100644 index 0000000..01a7f99 --- /dev/null +++ b/Software/PC_Application/VNA/Deembedding/impedancenormalizationdialog.ui @@ -0,0 +1,88 @@ + + + ImpedanceRenormalizationDialog + + + + 0 + 0 + 241 + 76 + + + + S parameter renormalization + + + true + + + + + + + + Normalize to: + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+
+ + + + buttonBox + accepted() + ImpedanceRenormalizationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ImpedanceRenormalizationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp new file mode 100644 index 0000000..ba935f9 --- /dev/null +++ b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp @@ -0,0 +1,57 @@ +#include "impedancerenormalization.h" + +#include "ui_impedancenormalizationdialog.h" +#include "Tools/parameters.h" +#include "appwindow.h" + +#include + +using namespace std; + +ImpedanceRenormalization::ImpedanceRenormalization() + : DeembeddingOption(), + impedance(50.0) +{ + +} + +void ImpedanceRenormalization::transformDatapoint(VNAData &p) +{ + p.S = Sparam(ABCDparam(p.S, p.reference_impedance), impedance); + p.reference_impedance = impedance; +} + +nlohmann::json ImpedanceRenormalization::toJSON() +{ + nlohmann::json j; + j["impedance"] = impedance; + return j; +} + +void ImpedanceRenormalization::fromJSON(nlohmann::json j) +{ + impedance = j.value("impedance", impedance); +} + +void ImpedanceRenormalization::edit() +{ + auto dialog = new QDialog(); + ui = new Ui::ImpedanceRenormalizationDialog(); + ui->setupUi(dialog); + connect(dialog, &QDialog::finished, [=](){ + delete ui; + }); + + // set initial values + ui->impedance->setUnit("Ω"); + ui->impedance->setPrecision(3); + ui->impedance->setValue(impedance); + + connect(ui->impedance, &SIUnitEdit::valueChanged, [&](double newval){ + impedance = newval; + }); + + if(AppWindow::showGUI()) { + dialog->show(); + } +} diff --git a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h new file mode 100644 index 0000000..a0784d6 --- /dev/null +++ b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.h @@ -0,0 +1,29 @@ +#ifndef IMPEDANCERENORMALIZATION_H +#define IMPEDANCERENORMALIZATION_H + +#include "deembeddingoption.h" + +namespace Ui { +class ImpedanceRenormalizationDialog; +} + +class ImpedanceRenormalization : public DeembeddingOption +{ + Q_OBJECT +public: + ImpedanceRenormalization(); + + void transformDatapoint(VNAData &p) override; + Type getType() override { return Type::ImpedanceRenormalization;} + nlohmann::json toJSON() override; + void fromJSON(nlohmann::json j) override; + +public slots: + virtual void edit() override; +private: + double impedance; + + Ui::ImpedanceRenormalizationDialog *ui; +}; + +#endif // IMPEDANCERENORMALIZATION_H diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp index 3458b99..b49f578 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp @@ -26,13 +26,10 @@ MatchingNetwork::MatchingNetwork() addNetwork = true; } -void MatchingNetwork::transformDatapoint(Protocol::Datapoint &p) +void MatchingNetwork::transformDatapoint(VNAData &p) { - auto S = Sparam(complex(p.real_S11, p.imag_S11), - complex(p.real_S12, p.imag_S12), - complex(p.real_S21, p.imag_S21), - complex(p.real_S22, p.imag_S22)); - auto measurement = ABCDparam(S, Preferences::getInstance().Acquisition.refImp); + auto S = p.S; + auto measurement = ABCDparam(S, p.reference_impedance); if(matching.count(p.frequency) == 0) { // this point is not calculated yet MatchingPoint m; @@ -56,15 +53,7 @@ void MatchingNetwork::transformDatapoint(Protocol::Datapoint &p) // at this point the map contains the matching network effect auto m = matching[p.frequency]; auto corrected = m.p1 * measurement * m.p2; - S = Sparam(corrected, Preferences::getInstance().Acquisition.refImp); - p.real_S11 = real(S.m11); - p.imag_S11 = imag(S.m11); - p.real_S12 = real(S.m12); - p.imag_S12 = imag(S.m12); - p.real_S21 = real(S.m21); - p.imag_S21 = imag(S.m21); - p.real_S22 = real(S.m22); - p.imag_S22 = imag(S.m22); + p.S = Sparam(corrected, p.reference_impedance); } void MatchingNetwork::edit() @@ -541,7 +530,7 @@ ABCDparam MatchingComponent::parameters(double freq) } else { auto d = touchstone->interpolate(freq); auto S = Sparam(d.S[0], d.S[1], d.S[2], d.S[3]); - return ABCDparam(S, Preferences::getInstance().Acquisition.refImp); + return ABCDparam(S, 50.0); } default: return ABCDparam(1.0, 0.0, 0.0, 1.0); diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h index afc1fc7..5d206ab 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h @@ -64,9 +64,9 @@ public: // DeembeddingOption interface public: - void transformDatapoint(Protocol::Datapoint &p) override; + void transformDatapoint(VNAData &p) override; void edit() override; - Type getType() override {return Type::MatchingNetwork;}; + Type getType() override {return Type::MatchingNetwork;} nlohmann::json toJSON() override; void fromJSON(nlohmann::json j) override; private: diff --git a/Software/PC_Application/VNA/Deembedding/portextension.cpp b/Software/PC_Application/VNA/Deembedding/portextension.cpp index 125b709..c5b9064 100644 --- a/Software/PC_Application/VNA/Deembedding/portextension.cpp +++ b/Software/PC_Application/VNA/Deembedding/portextension.cpp @@ -29,15 +29,9 @@ PortExtension::PortExtension() kit = nullptr; } -void PortExtension::transformDatapoint(Protocol::Datapoint &d) +void PortExtension::transformDatapoint(VNAData &d) { if(port1.enabled || port2.enabled) { - // Convert measurements to complex variables - auto S11 = complex(d.real_S11, d.imag_S11); - auto S21 = complex(d.real_S21, d.imag_S21); - auto S22 = complex(d.real_S22, d.imag_S22); - auto S12 = complex(d.real_S12, d.imag_S12); - if(port1.enabled) { auto phase = -2 * M_PI * port1.delay * d.frequency; auto db_attennuation = port1.DCloss; @@ -47,9 +41,9 @@ void PortExtension::transformDatapoint(Protocol::Datapoint &d) // convert from db to factor auto att = pow(10.0, -db_attennuation / 20.0); auto correction = polar(att, phase); - S11 /= correction * correction; - S21 /= correction; - S12 /= correction; + d.S.m11 /= correction * correction; + d.S.m21 /= correction; + d.S.m12 /= correction; } if(port2.enabled) { auto phase = -2 * M_PI * port2.delay * d.frequency; @@ -60,18 +54,10 @@ void PortExtension::transformDatapoint(Protocol::Datapoint &d) // convert from db to factor auto att = pow(10.0, -db_attennuation / 20.0); auto correction = polar(att, phase); - S22 /= correction * correction; - S21 /= correction; - S12 /= correction; + d.S.m22 /= correction * correction; + d.S.m21 /= correction; + d.S.m12 /= correction; } - d.real_S11 = S11.real(); - d.imag_S11 = S11.imag(); - d.real_S12 = S12.real(); - d.imag_S12 = S12.imag(); - d.real_S21 = S21.real(); - d.imag_S21 = S21.imag(); - d.real_S22 = S22.real(); - d.imag_S22 = S22.imag(); } } @@ -208,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; @@ -219,9 +205,9 @@ void PortExtension::measurementCompleted(std::vector m) // grab correct measurement complex reflection; if(isPort1) { - reflection = complex(p.real_S11, p.imag_S11); + reflection = p.S.m11; } else { - reflection = complex(p.real_S22, p.imag_S22); + reflection = p.S.m22; } // 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 28fd17e..1b88700 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(Protocol::Datapoint& d) override; + void transformDatapoint(VNAData& 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 a961318..0785a12 100644 --- a/Software/PC_Application/VNA/Deembedding/twothru.cpp +++ b/Software/PC_Application/VNA/Deembedding/twothru.cpp @@ -12,19 +12,14 @@ using namespace std; TwoThru::TwoThru() { - Z0 = Preferences::getInstance().Acquisition.refImp; + Z0 = 50.0; } -void TwoThru::transformDatapoint(Protocol::Datapoint &p) +void TwoThru::transformDatapoint(VNAData &p) { // correct measurement if(points.size() > 0) { - auto S11 = complex(p.real_S11, p.imag_S11); - auto S12 = complex(p.real_S12, p.imag_S12); - auto S21 = complex(p.real_S21, p.imag_S21); - auto S22 = complex(p.real_S22, p.imag_S22); - Sparam S(S11, S12, S21, S22); - Tparam meas(S); + Tparam meas(p.S); Tparam inv1, inv2; if(p.frequency < points.front().freq) { @@ -54,15 +49,7 @@ void TwoThru::transformDatapoint(Protocol::Datapoint &p) // perform correction Tparam corrected = inv1*meas*inv2; // transform back into S parameters - S = Sparam(corrected); - p.real_S11 = real(S.m11); - p.imag_S11 = imag(S.m11); - p.real_S12 = real(S.m12); - p.imag_S12 = imag(S.m12); - p.real_S21 = real(S.m21); - p.imag_S21 = imag(S.m21); - p.real_S22 = real(S.m22); - p.imag_S22 = imag(S.m22); + p.S = Sparam(corrected); } } @@ -112,7 +99,7 @@ void TwoThru::updateGUI() } } -void TwoThru::measurementCompleted(std::vector m) +void TwoThru::measurementCompleted(std::vector m) { if (measuring2xthru) { measurements2xthru = m; @@ -223,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 @@ -242,10 +229,10 @@ std::vector TwoThru::calculateErrorBoxes(std::vector(m.real_S11, m.imag_S11)); - S12.push_back(complex(m.real_S12, m.imag_S12)); - S21.push_back(complex(m.real_S21, m.imag_S21)); - S22.push_back(complex(m.real_S22, m.imag_S22)); + S11.push_back(m.S.m11); + S12.push_back(m.S.m12); + S21.push_back(m.S.m21); + S22.push_back(m.S.m22); f.push_back(m.frequency); } auto n = f.size(); @@ -403,7 +390,7 @@ std::vector TwoThru::calculateErrorBoxes(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; @@ -427,19 +414,13 @@ std::vector TwoThru::calculateErrorBoxes(std::vector p; vector f; for(auto d : data_2xthru) { - p.push_back(Sparam(complex(d.real_S11, d.imag_S11), - complex(d.real_S12, d.imag_S12), - complex(d.real_S21, d.imag_S21), - complex(d.real_S22, d.imag_S22))); + p.push_back(d.S); 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(Sparam(complex(d.real_S11, d.imag_S11), - complex(d.real_S12, d.imag_S12), - complex(d.real_S21, d.imag_S21), - complex(d.real_S22, d.imag_S22))); + data_fix_dut_fix_Sparam.push_back(d.S); } // grabbing S21 @@ -682,9 +663,9 @@ std::vector TwoThru::calculateErrorBoxes(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; @@ -706,8 +687,8 @@ std::vector TwoThru::interpolateEvenFrequencySteps(std::vec // needs to interpolate double freq = freqStep; while(freq <= input.back().frequency) { - Protocol::Datapoint interp; - auto it = lower_bound(input.begin(), input.end(), freq, [](const Protocol::Datapoint &lhs, const double f) -> bool { + VNAData interp; + auto it = lower_bound(input.begin(), input.end(), freq, [](const VNAData &lhs, const double f) -> bool { return lhs.frequency < f; }); if(it->frequency == freq) { @@ -718,15 +699,14 @@ std::vector TwoThru::interpolateEvenFrequencySteps(std::vec it--; auto low = *it; double alpha = (freq - low.frequency) / (high.frequency - low.frequency); - interp.real_S11 = low.real_S11 * (1.0 - alpha) + high.real_S11 * alpha; - interp.imag_S11 = low.imag_S11 * (1.0 - alpha) + high.imag_S11 * alpha; - interp.real_S12 = low.real_S12 * (1.0 - alpha) + high.real_S12 * alpha; - interp.imag_S12 = low.imag_S12 * (1.0 - alpha) + high.imag_S12 * alpha; - interp.real_S21 = low.real_S21 * (1.0 - alpha) + high.real_S21 * alpha; - interp.imag_S21 = low.imag_S21 * (1.0 - alpha) + high.imag_S21 * alpha; - interp.real_S22 = low.real_S22 * (1.0 - alpha) + high.real_S22 * alpha; - interp.imag_S22 = low.imag_S22 * (1.0 - alpha) + high.imag_S22 * alpha; + 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.pointNum = it->pointNum; interp.frequency = freq; ret.push_back(interp); freq += freqStep; diff --git a/Software/PC_Application/VNA/Deembedding/twothru.h b/Software/PC_Application/VNA/Deembedding/twothru.h index 0f56cd7..db1e376 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(Protocol::Datapoint &p) override; + virtual void transformDatapoint(VNAData& 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/vna.cpp b/Software/PC_Application/VNA/vna.cpp index 85bef89..955ad53 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -21,6 +21,7 @@ #include "Deembedding/manualdeembeddingdialog.h" #include "Calibration/manualcalibrationdialog.h" #include "Util/util.h" +#include "Tools/parameters.h" #include #include @@ -812,28 +813,30 @@ void VNA::NewDatapoint(Protocol::Datapoint d) return; } - d = average.process(d); + auto vd = VNAData(d); + + vd = average.process(vd); if(calMeasuring) { if(average.currentSweep() == averages) { // this is the last averaging sweep, use values for calibration - if(!calWaitFirst || d.pointNum == 0) { + if(!calWaitFirst || vd.pointNum == 0) { calWaitFirst = false; - cal.addMeasurements(calMeasurements, d); - if(d.pointNum == settings.npoints - 1) { + cal.addMeasurements(calMeasurements, vd); + if(vd.pointNum == settings.npoints - 1) { calMeasuring = false; emit CalibrationMeasurementsComplete(calMeasurements); } } } - int percentage = (((average.currentSweep() - 1) * 100) + (d.pointNum + 1) * 100 / settings.npoints) / averages; + int percentage = (((average.currentSweep() - 1) * 100) + (vd.pointNum + 1) * 100 / settings.npoints) / averages; calDialog.setValue(percentage); } if(calValid) { - cal.correctMeasurement(d); + cal.correctMeasurement(vd); } if(deembedding_active) { - deembedding.Deembed(d); + deembedding.Deembed(vd); } TraceMath::DataType type; @@ -847,17 +850,17 @@ void VNA::NewDatapoint(Protocol::Datapoint d) break; } - traceModel.addVNAData(d, type); + traceModel.addVNAData(vd, type); emit dataChanged(); - if(d.pointNum == settings.npoints - 1) { + if(vd.pointNum == settings.npoints - 1) { UpdateAverageCount(); markerModel->updateMarkers(); } static unsigned int lastPoint = 0; - if(d.pointNum > 0 && d.pointNum != lastPoint + 1) { - qWarning() << "Got point" << d.pointNum << "but last received point was" << lastPoint << "("<<(d.pointNum-lastPoint-1)<<"missed points)"; + if(vd.pointNum > 0 && vd.pointNum != lastPoint + 1) { + qWarning() << "Got point" << vd.pointNum << "but last received point was" << lastPoint << "("<<(vd.pointNum-lastPoint-1)<<"missed points)"; } - lastPoint = d.pointNum; + lastPoint = vd.pointNum; if (needsSegmentUpdate) { changingSettings = true; diff --git a/Software/PC_Application/VNA/vnadata.h b/Software/PC_Application/VNA/vnadata.h new file mode 100644 index 0000000..3031e8b --- /dev/null +++ b/Software/PC_Application/VNA/vnadata.h @@ -0,0 +1,29 @@ +#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; + cdbm = d.cdbm; + pointNum = d.pointNum; + reference_impedance = 50.0; + } + double frequency; + 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 1eeb004..5705b46 100644 --- a/Software/PC_Application/averaging.cpp +++ b/Software/PC_Application/averaging.cpp @@ -22,12 +22,12 @@ void Averaging::setAverages(unsigned int a) reset(avg.size()); } -Protocol::Datapoint Averaging::process(Protocol::Datapoint d) +VNAData Averaging::process(VNAData d) { - auto S11 = complex(d.real_S11, d.imag_S11); - auto S12 = complex(d.real_S12, d.imag_S12); - auto S21 = complex(d.real_S21, d.imag_S21); - auto S22 = complex(d.real_S22, d.imag_S22); + 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 @@ -99,14 +99,7 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d) } } - d.real_S11 = S11.real(); - d.imag_S11 = S11.imag(); - d.real_S12 = S12.real(); - d.imag_S12 = S12.imag(); - d.real_S21 = S21.real(); - d.imag_S21 = S21.imag(); - d.real_S22 = S22.real(); - d.imag_S22 = S22.imag(); + d.S = Sparam(S11, S12, S21, S22); return d; } diff --git a/Software/PC_Application/averaging.h b/Software/PC_Application/averaging.h index 84dc68e..ffea038 100644 --- a/Software/PC_Application/averaging.h +++ b/Software/PC_Application/averaging.h @@ -2,6 +2,7 @@ #define AVERAGING_H #include "Device/device.h" +#include "VNA/vnadata.h" #include #include @@ -18,7 +19,7 @@ public: Averaging(); void reset(unsigned int points); void setAverages(unsigned int a); - Protocol::Datapoint process(Protocol::Datapoint d); + VNAData process(VNAData d); Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult 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 diff --git a/Software/PC_Application/preferences.cpp b/Software/PC_Application/preferences.cpp index 470e630..efa9fac 100644 --- a/Software/PC_Application/preferences.cpp +++ b/Software/PC_Application/preferences.cpp @@ -88,9 +88,6 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : ui->StartupSARBW->setPrefixes(" k"); // Acquisition page - ui->AcquisitionReferenceImpedance->setUnit("Ω"); - ui->AcquisitionReferenceImpedance->setPrefixes(" "); - ui->AcquisitionReferenceImpedance->setPrecision(3); ui->AcquisitionDFTlimitRBW->setUnit("Hz"); ui->AcquisitionDFTlimitRBW->setPrefixes(" k"); connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) { @@ -237,7 +234,6 @@ void PreferencesDialog::setInitialGUIState() ui->AcquisitionAdjustPowerLevel->setChecked(p->Acquisition.adjustPowerLevel); ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing); ui->AcquisitionAllowSegmentedSweep->setChecked(p->Acquisition.allowSegmentedSweep); - ui->AcquisitionReferenceImpedance->setValue(p->Acquisition.refImp); ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode); ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT); ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0); @@ -298,7 +294,6 @@ void PreferencesDialog::updateFromGUI() p->Acquisition.adjustPowerLevel = ui->AcquisitionAdjustPowerLevel->isChecked(); p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked(); p->Acquisition.allowSegmentedSweep = ui->AcquisitionAllowSegmentedSweep->isChecked(); - p->Acquisition.refImp = ui->AcquisitionReferenceImpedance->value(); p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked(); p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value(); p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1; diff --git a/Software/PC_Application/preferences.h b/Software/PC_Application/preferences.h index f70327b..67a28c4 100644 --- a/Software/PC_Application/preferences.h +++ b/Software/PC_Application/preferences.h @@ -73,7 +73,6 @@ public: bool useDFTinSAmode; double RBWLimitForDFT; bool useMedianAveraging; - double refImp; // reference impedance // advanced, hardware specific settings double IF1; @@ -153,7 +152,6 @@ private: {&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true}, {&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0}, {&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false}, - {&Acquisition.refImp, "Acquisition.referenceImpedance", 50.0}, {&Acquisition.IF1, "Acquisition.IF1", 62000000}, {&Acquisition.ADCprescaler, "Acquisition.ADCprescaler", 128}, {&Acquisition.DFTPhaseInc, "Acquisition.DFTPhaseInc", 1280}, diff --git a/Software/PC_Application/preferencesdialog.ui b/Software/PC_Application/preferencesdialog.ui index 1687165..5cfa158 100644 --- a/Software/PC_Application/preferencesdialog.ui +++ b/Software/PC_Application/preferencesdialog.ui @@ -745,24 +745,6 @@
- - - - - - Reference impedance: - - - - - - - <html><head/><body><p>Frequency of the first IF</p></body></html> - - - - -
diff --git a/Software/PC_Application/touchstone.cpp b/Software/PC_Application/touchstone.cpp index c592fec..2afdb87 100644 --- a/Software/PC_Application/touchstone.cpp +++ b/Software/PC_Application/touchstone.cpp @@ -16,6 +16,7 @@ using namespace std; Touchstone::Touchstone(unsigned int ports) { this->m_ports = ports; + referenceImpedance = 50.0; m_datapoints.clear(); } @@ -74,8 +75,8 @@ stringstream Touchstone::toString(Touchstone::Scale unit, Touchstone::Format for case Format::RealImaginary: s << "RI "; break; case Format::MagnitudeAngle: s << "MA "; break; } - // reference impedance is always 50 ohm - s << "R 50\n"; + // reference impedance + s << "R " << referenceImpedance << "\n"; auto printParameter = [format](ostream &out, complex &c) { switch (format) { @@ -192,10 +193,8 @@ Touchstone Touchstone::fromFile(string filename) for(;iss>>s;) { if(last_R) { last_R = false; - // check reference impedance - if (stoi(s, nullptr, 10) != 50) { - throw runtime_error("Invalid reference impedance, only 50Ohm is supported"); - } + // read reference impedance + ret.referenceImpedance = stod(s, nullptr); break; } if (!s.compare("HZ")) { @@ -438,3 +437,13 @@ void Touchstone::fromJSON(nlohmann::json j) m_datapoints.push_back(d); } } + +double Touchstone::getReferenceImpedance() const +{ + return referenceImpedance; +} + +void Touchstone::setReferenceImpedance(double value) +{ + referenceImpedance = value; +} diff --git a/Software/PC_Application/touchstone.h b/Software/PC_Application/touchstone.h index daa9dd7..3cdf1bd 100644 --- a/Software/PC_Application/touchstone.h +++ b/Software/PC_Application/touchstone.h @@ -51,8 +51,12 @@ public: virtual nlohmann::json toJSON(); virtual void fromJSON(nlohmann::json j); + double getReferenceImpedance() const; + void setReferenceImpedance(double value); + private: unsigned int m_ports; + double referenceImpedance; std::vector m_datapoints; QString filename; };