From 8269fdfa57b4be8c079c85fbc416de6afa15a7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Sat, 27 Nov 2021 19:11:45 +0100 Subject: [PATCH] de-embed touchstone-defined through --- .../SpectrumAnalyzer/spectrumanalyzer.cpp | 2 +- .../PC_Application/Traces/Marker/marker.cpp | 2 +- .../VNA/Deembedding/matchingnetwork.cpp | 208 ++++- .../VNA/Deembedding/matchingnetwork.h | 15 +- .../VNA/Deembedding/matchingnetworkdialog.ui | 738 +++++++++--------- Software/PC_Application/icons.qrc | 8 + .../PC_Application/icons/definedThrough.png | Bin 0 -> 884 bytes .../PC_Application/icons/definedThrough.svg | 44 ++ Software/PC_Application/icons/parallelC.png | Bin 0 -> 466 bytes Software/PC_Application/icons/parallelL.png | Bin 0 -> 1064 bytes Software/PC_Application/icons/parallelR.png | Bin 0 -> 1077 bytes Software/PC_Application/icons/port1.svg | 31 + Software/PC_Application/icons/port2.svg | 31 + Software/PC_Application/icons/seriesC.png | Bin 0 -> 361 bytes Software/PC_Application/icons/seriesL.png | Bin 0 -> 808 bytes Software/PC_Application/icons/seriesR.png | Bin 0 -> 759 bytes Software/PC_Application/touchstone.cpp | 54 ++ Software/PC_Application/touchstone.h | 8 +- 18 files changed, 744 insertions(+), 397 deletions(-) create mode 100644 Software/PC_Application/icons/definedThrough.png create mode 100644 Software/PC_Application/icons/definedThrough.svg create mode 100644 Software/PC_Application/icons/parallelC.png create mode 100644 Software/PC_Application/icons/parallelL.png create mode 100644 Software/PC_Application/icons/parallelR.png create mode 100644 Software/PC_Application/icons/seriesC.png create mode 100644 Software/PC_Application/icons/seriesL.png create mode 100644 Software/PC_Application/icons/seriesR.png diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index b66be51..1f497d4 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -315,7 +315,7 @@ nlohmann::json SpectrumAnalyzer::toJSON() tracking["enabled"] = settings.trackingGenerator ? true : false; tracking["port"] = settings.trackingGeneratorPort ? 2 : 1; tracking["offset"] = settings.trackingGeneratorOffset; - tracking["power"] = settings.trackingPower; + tracking["power"] = (double) settings.trackingPower / 100.0; // convert to dBm sweep["trackingGenerator"] = tracking; if(normalize.active) { diff --git a/Software/PC_Application/Traces/Marker/marker.cpp b/Software/PC_Application/Traces/Marker/marker.cpp index 0111c05..1e76a93 100644 --- a/Software/PC_Application/Traces/Marker/marker.cpp +++ b/Software/PC_Application/Traces/Marker/marker.cpp @@ -1560,7 +1560,7 @@ bool Marker::isMovable() // helper traces are never movable by the user return false; } - if(trace()->size() == 0) { + if(!parentTrace || parentTrace->size() == 0) { return false; } switch(type) { diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp index f6592c0..3b08796 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp @@ -1,6 +1,8 @@ #include "matchingnetwork.h" #include "ui_matchingnetworkdialog.h" +#include "unit.h" +#include "CustomWidgets/informationbox.h" #include #include @@ -11,6 +13,7 @@ #include #include #include +#include using namespace std; @@ -83,24 +86,25 @@ void MatchingNetwork::edit() ui->lParallelC->installEventFilter(this); ui->lParallelL->installEventFilter(this); ui->lParallelR->installEventFilter(this); + ui->lDefinedThrough->installEventFilter(this); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); layout->addStretch(1); auto p1 = new QWidget(); - p1->setMinimumSize(portWidth, 150); - p1->setMaximumSize(portWidth, 150); + p1->setMinimumSize(portWidth, 151); + p1->setMaximumSize(portWidth, 151); p1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - p1->setStyleSheet("image: url(:/icons/port1.svg);"); + p1->setStyleSheet("image: url(:/icons/port1.png);"); auto DUT = new QWidget(); - DUT->setMinimumSize(DUTWidth, 150); - DUT->setMaximumSize(DUTWidth, 150); + DUT->setMinimumSize(DUTWidth, 151); + DUT->setMaximumSize(DUTWidth, 151); DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - DUT->setStyleSheet("image: url(:/icons/DUT.svg);"); + DUT->setStyleSheet("image: url(:/icons/DUT.png);"); auto p2 = new QWidget(); - p2->setMinimumSize(portWidth, 150); - p2->setMaximumSize(portWidth, 150); + p2->setMinimumSize(portWidth, 151); + p2->setMaximumSize(portWidth, 151); p2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - p2->setStyleSheet("image: url(:/icons/port2.svg);"); + p2->setStyleSheet("image: url(:/icons/port2.png);"); layout->addWidget(p1); for(auto w : p1Network) { layout->addWidget(w); @@ -136,27 +140,31 @@ void MatchingNetwork::edit() nlohmann::json MatchingNetwork::toJSON() { nlohmann::json j; - for(int i=0;i<2;i++) { - auto network = i==0 ? p1Network : p2Network; - nlohmann::json jn; - for(auto c : network) { - nlohmann::json jc; - jc["component"] = c->getName().toStdString(); - jc["params"] = c->toJSON(); - jn.push_back(jc); - } - j.push_back(jn); + nlohmann::json jn1, jn2; + for(auto c : p1Network) { + nlohmann::json jc; + jc["component"] = c->getName().toStdString(); + jc["params"] = c->toJSON(); + jn1.push_back(jc); } + for(auto c : p2Network) { + nlohmann::json jc; + jc["component"] = c->getName().toStdString(); + jc["params"] = c->toJSON(); + jn2.push_back(jc); + } + j["port1"] = jn1; + j["port2"] = jn2; + j["addNetwork"] = addNetwork; return j; } void MatchingNetwork::fromJSON(nlohmann::json j) { - for(int i=0;i<2;i++) { - auto jn = j[i]; - auto &network = i==0 ? p1Network : p2Network; - network.clear(); - for(auto jc : jn) { + p1Network.clear(); + p2Network.clear(); + if(j.contains("port1")) { + for(auto jc : j["port1"]) { if(!jc.contains("component")) { continue; } @@ -165,9 +173,23 @@ void MatchingNetwork::fromJSON(nlohmann::json j) continue; } c->fromJSON(jc["params"]); - network.push_back(c); + p1Network.push_back(c); } } + if(j.contains("port2")) { + for(auto jc : j["port2"]) { + if(!jc.contains("component")) { + continue; + } + auto c = MatchingComponent::createFromName(QString::fromStdString(jc["component"])); + if(!c) { + continue; + } + c->fromJSON(jc["params"]); + p2Network.push_back(c); + } + } + addNetwork = j.value("addNetwork", true); matching.clear(); } @@ -329,8 +351,8 @@ bool MatchingNetwork::eventFilter(QObject *object, QEvent *event) dropComponent = (MatchingComponent*) dropPtr; dragEvent->acceptProposedAction(); insertIndicator = new QWidget(); - insertIndicator->setMinimumSize(2, 150); - insertIndicator->setMaximumSize(2, 150); + insertIndicator->setMinimumSize(2, imageHeight); + insertIndicator->setMaximumSize(2, imageHeight); insertIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); insertIndicator->setStyleSheet("background-color:red;"); updateInsertIndicator(dragEvent->pos().x()); @@ -368,6 +390,8 @@ bool MatchingNetwork::eventFilter(QObject *object, QEvent *event) dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelL); } else if(object->objectName() == "lParallelR") { dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelR); + } else if(object->objectName() == "lDefinedThrough") { + dragComponent = new MatchingComponent(MatchingComponent::Type::DefinedThrough); } else { dragComponent = nullptr; } @@ -397,18 +421,21 @@ bool MatchingNetwork::eventFilter(QObject *object, QEvent *event) MatchingComponent::MatchingComponent(Type type) { this->type = type; - setMinimumSize(150, 150); - setMaximumSize(150, 150); + eValue = nullptr; + touchstone = nullptr; + touchstoneLabel = nullptr; + setMinimumSize(151, 151); + setMaximumSize(151, 151); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - eValue = new SIUnitEdit(); - eValue->setPrecision(4); - eValue->setPrefixes("fpnum k"); - connect(eValue, &SIUnitEdit::valueChanged, this, &MatchingComponent::valueChanged); setFocusPolicy(Qt::FocusPolicy::ClickFocus); switch(type) { case Type::SeriesR: case Type::SeriesL: case Type::SeriesC: { + eValue = new SIUnitEdit(); + eValue->setPrecision(4); + eValue->setPrefixes("fpnum k"); + connect(eValue, &SIUnitEdit::valueChanged, this, &MatchingComponent::valueChanged); auto layout = new QVBoxLayout(); layout->addWidget(eValue); setLayout(layout); @@ -417,13 +444,16 @@ MatchingComponent::MatchingComponent(Type type) case Type::ParallelR: case Type::ParallelL: case Type::ParallelC: { + eValue = new SIUnitEdit(); + eValue->setPrecision(4); + eValue->setPrefixes("fpnum k"); + connect(eValue, &SIUnitEdit::valueChanged, this, &MatchingComponent::valueChanged); auto layout = new QVBoxLayout(); layout->addWidget(eValue); layout->addStretch(1); layout->setContentsMargins(9, 5, 9, 9); setLayout(layout); } - break; default: break; } @@ -431,38 +461,58 @@ MatchingComponent::MatchingComponent(Type type) case Type::SeriesR: eValue->setUnit("Ω"); eValue->setValue(50); - setStyleSheet("image: url(:/icons/seriesR.svg);"); + setStyleSheet("image: url(:/icons/seriesR.png);"); break; case Type::SeriesL: eValue->setUnit("H"); eValue->setValue(1e-9); - setStyleSheet("image: url(:/icons/seriesL.svg);"); + setStyleSheet("image: url(:/icons/seriesL.png);"); break; case Type::SeriesC: eValue->setUnit("F"); eValue->setValue(1e-12); - setStyleSheet("image: url(:/icons/seriesC.svg);"); + setStyleSheet("image: url(:/icons/seriesC.png);"); break; case Type::ParallelR: eValue->setUnit("Ω"); eValue->setValue(50); - setStyleSheet("image: url(:/icons/parallelR.svg);"); + setStyleSheet("image: url(:/icons/parallelR.png);"); break; case Type::ParallelL: eValue->setUnit("H"); eValue->setValue(1e-9); - setStyleSheet("image: url(:/icons/parallelL.svg);"); + setStyleSheet("image: url(:/icons/parallelL.png);"); break; case Type::ParallelC: eValue->setUnit("F"); eValue->setValue(1e-12); - setStyleSheet("image: url(:/icons/parallelC.svg);"); + setStyleSheet("image: url(:/icons/parallelC.png);"); + break; + case Type::DefinedThrough: { + touchstone = new Touchstone(2); + touchstoneLabel = new QLabel(); + touchstoneLabel->setWordWrap(true); + touchstoneLabel->setAlignment(Qt::AlignCenter); + auto layout = new QVBoxLayout(); + layout->addWidget(touchstoneLabel); + layout->setContentsMargins(0, 0, 0, 0); + setLayout(layout); + setStyleSheet("image: url(:/icons/definedThrough.png);"); + updateTouchstoneLabel(); + } break; default: break; } } +MatchingComponent::~MatchingComponent() +{ + delete eValue; + delete touchstone; + delete touchstoneLabel; +} + ABCDparam MatchingComponent::parameters(double freq) { switch(type) { @@ -478,6 +528,15 @@ ABCDparam MatchingComponent::parameters(double freq) return ABCDparam(1.0, 0.0, 1.0/complex(0, freq * 2 * M_PI * eValue->value()), 1.0); case Type::ParallelC: return ABCDparam(1.0, 0.0, 1.0/complex(0, -1.0 / (freq * 2 * M_PI * eValue->value())), 1.0); + case Type::DefinedThrough: + if(touchstone->points() == 0 || freq < touchstone->minFreq() || freq > touchstone->maxFreq()) { + // outside of provided frequency range, pass through unchanged + return ABCDparam(1.0, 0.0, 0.0, 1.0); + } else { + auto d = touchstone->interpolate(freq); + auto S = Sparam(d.S[0], d.S[1], d.S[2], d.S[3]); + return ABCDparam(S, 50.0); + } default: return ABCDparam(1.0, 0.0, 0.0, 1.0); } @@ -485,7 +544,9 @@ ABCDparam MatchingComponent::parameters(double freq) void MatchingComponent::MatchingComponent::setValue(double v) { - eValue->setValue(v); + if(eValue) { + eValue->setValue(v); + } } MatchingComponent *MatchingComponent::createFromName(QString name) @@ -507,13 +568,73 @@ QString MatchingComponent::getName() nlohmann::json MatchingComponent::toJSON() { nlohmann::json j; - j["value"] = eValue->value(); + switch(type) { + case Type::SeriesC: + case Type::SeriesR: + case Type::SeriesL: + case Type::ParallelC: + case Type::ParallelR: + case Type::ParallelL: + j["value"] = eValue->value(); + break; + case Type::DefinedThrough: + j["touchstone"] = touchstone->toJSON(); + break; + case Type::Last: + break; + } return j; } void MatchingComponent::fromJSON(nlohmann::json j) { - eValue->setValue(j.value("value", 1e-12)); + switch(type) { + case Type::SeriesC: + case Type::SeriesR: + case Type::SeriesL: + case Type::ParallelC: + case Type::ParallelR: + case Type::ParallelL: + eValue->setValue(j.value("value", 1e-12)); + break; + case Type::DefinedThrough: + touchstone->fromJSON(j["touchstone"]); + updateTouchstoneLabel(); + break; + case Type::Last: + break; + } +} + +void MatchingComponent::mouseDoubleClickEvent(QMouseEvent *e) +{ + Q_UNUSED(e); + if(type == Type::DefinedThrough) { + // select new touchstone file + auto filename = QFileDialog::getOpenFileName(nullptr, "Open measurement file", "", "Touchstone files (*.s2p)", nullptr, QFileDialog::DontUseNativeDialog); + if (!filename.isEmpty()) { + try { + *touchstone = Touchstone::fromFile(filename.toStdString()); + } catch(const std::exception& e) { + InformationBox::ShowError("Failed to load file", QString("Attempt to load file ended with error: \"") + e.what()+"\""); + } + updateTouchstoneLabel(); + } + } +} + +void MatchingComponent::updateTouchstoneLabel() +{ + if(!touchstone || !touchstoneLabel) { + return; + } + if(touchstone->points() == 0) { + touchstoneLabel->setText("No data. Double-click to select touchstone file"); + } else { + QString text = QString::number(touchstone->points()) + " points from "+Unit::ToString(touchstone->minFreq(), "Hz", " kMG", 4) + + " to "+Unit::ToString(touchstone->maxFreq(), "Hz", " kMG", 4); + touchstoneLabel->setText(text); + } } QString MatchingComponent::typeToName(MatchingComponent::Type type) @@ -525,6 +646,7 @@ QString MatchingComponent::typeToName(MatchingComponent::Type type) case Type::ParallelR: return "ParallelR"; case Type::ParallelL: return "ParallelL"; case Type::ParallelC: return "ParallelC"; + case Type::DefinedThrough: return "Touchstone Through"; default: return ""; } } diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h index 7ea983e..afc1fc7 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h @@ -5,8 +5,10 @@ #include "deembeddingoption.h" #include "Tools/parameters.h" #include "savable.h" +#include "touchstone.h" #include +#include #include @@ -21,11 +23,13 @@ public: ParallelR, ParallelL, ParallelC, + DefinedThrough, // Add new matching components here, do not explicitly assign values and keep the Last entry at the last position Last, }; MatchingComponent(Type type); + ~MatchingComponent(); ABCDparam parameters(double freq); void setValue(double v); @@ -40,7 +44,11 @@ signals: void deleted(MatchingComponent* m); protected: SIUnitEdit *eValue; + Touchstone *touchstone; + QLabel *touchstoneLabel; private: + void mouseDoubleClickEvent(QMouseEvent *e) override; + void updateTouchstoneLabel(); static QString typeToName(Type type); Type type; void keyPressEvent(QKeyEvent *event) override; @@ -62,9 +70,10 @@ public: nlohmann::json toJSON() override; void fromJSON(nlohmann::json j) override; private: - static constexpr int componentWidth = 150; - static constexpr int DUTWidth = 150; - static constexpr int portWidth = 75; + static constexpr int imageHeight = 151; + static constexpr int componentWidth = 151; + static constexpr int DUTWidth = 151; + static constexpr int portWidth = 76; MatchingComponent *componentAtPosition(int pos); unsigned int findInsertPosition(int xcoord); void addComponentAtPosition(int pos, MatchingComponent *c); diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui b/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui index 2a52e6f..a1c67f3 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui +++ b/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui @@ -7,7 +7,7 @@ 0 0 772 - 442 + 443 @@ -131,20 +131,8 @@ Matching Components - - - 0 - - - 0 - - - 0 - - - 0 - - + + @@ -159,369 +147,423 @@ - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/seriesC.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + Series C - - 0 + + Qt::AlignCenter - - - - border-image: url(:/icons/seriesC.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Series C - - - Qt::AlignCenter - - - - - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/seriesL.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + Series L - - 0 + + Qt::AlignCenter - - - - border-image: url(:/icons/seriesL.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Series L - - - Qt::AlignCenter - - - - - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/seriesR.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + Series R - - 0 + + Qt::AlignCenter - - - - border-image: url(:/icons/seriesR.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Series R - - - Qt::AlignCenter - - - - - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/definedThrough.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + <html><head/><body><p align="center"><br/><br/>Defined<br/>Through</p></body></html> - - 0 + + Qt::AlignHCenter|Qt::AlignTop - - - - border-image: url(:/icons/parallelC.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Parallel C - - - Qt::AlignHCenter|Qt::AlignTop - - - - - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/parallelC.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + Parallel C - - 0 + + Qt::AlignHCenter|Qt::AlignTop - - - - - 0 - 0 - - - - border-image: url(:/icons/parallelL.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Parallel L - - - Qt::AlignHCenter|Qt::AlignTop - - - - - - - - - - - 0 - 0 - - - - - 80 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + - - 0 + + border-image: url(:/icons/parallelL.svg); - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - 0 + + Parallel L - - - - border-image: url(:/icons/parallelR.svg); - - - QFrame::NoFrame - - - QFrame::Plain - - - Parallel R - - - Qt::AlignHCenter|Qt::AlignTop - - - - - - - + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border-image: url(:/icons/parallelR.svg); + + + QFrame::NoFrame + + + QFrame::Plain + + + Parallel R + + + Qt::AlignHCenter|Qt::AlignTop + + + + + diff --git a/Software/PC_Application/icons.qrc b/Software/PC_Application/icons.qrc index b4b2c2f..148fb55 100644 --- a/Software/PC_Application/icons.qrc +++ b/Software/PC_Application/icons.qrc @@ -50,5 +50,13 @@ icons/down.png icons/up.png icons/chainlink.png + icons/definedThrough.svg + icons/seriesR.png + icons/seriesL.png + icons/seriesC.png + icons/parallelR.png + icons/parallelL.png + icons/parallelC.png + icons/definedThrough.png diff --git a/Software/PC_Application/icons/definedThrough.png b/Software/PC_Application/icons/definedThrough.png new file mode 100644 index 0000000000000000000000000000000000000000..71b41820ecdae0060c2d1119bae058ae29474e2f GIT binary patch literal 884 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn2}J&l(*shR1s;*b3=Dj8K$wwzO7L9<24*!+ z7srr_TW@dg_qIxuIq>oMK8;I@+`Kh%)%8> zQCjGsvB*P12*@J9u{~-0V|s>!TfKh5hyN3vTzs_o+VR3Sztb}+MCvaeJ$m%>=g*ff zU;gr?#A(%wIU%#F>abj;T@A1M#7grpA92pby3zaqG+T^4|UV zGiT=t$Mx&iFAdTZ;o7-wwug$Dx%up~Y30*XBR59)Xih!~k9yos2ms&q2t6VT@D-I=o{PoCWCc6ieoucebtrttCcxjcFGN^ADn zZ?E3eN-t6jj){z%IdkUC`}gy=M#W3p+u2Q%!IQq&4+Y zT;U0^9>3+m8X}KA{`mB%sJ#32uAMRK;?{Scxc>Uho1F6Z*REZ=ckiCO)Plyj-P5N} z-#oNZ`uh6q?d?iMMMazT?$uRV8%8t;_ZQ#VHur3ryuAF>AfN{xKYn~QYioqgvm(o-S8m?CdF$4#BS%`Uzm}DjerHp?`7s!;r)_A%C Qn2i`bUHx3vIVCg!0L&+y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/PC_Application/icons/parallelC.png b/Software/PC_Application/icons/parallelC.png new file mode 100644 index 0000000000000000000000000000000000000000..9acfd382dad616d1c6147d3451ec1b79d74fef5e GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn2}J&l(*shR1s;*b3=Dj8K$wwzO7L9<2F4ao z7srr_TW{~~&OK}(;t*(9pzgcS@W@LGmg9+&&SJ)6Hj69^D-4HR+hTBOmn$OFg-6ww5+l|X`lOMrqJU0?+;@uLS{?cIK@=-k?^ z_o`ElS?4XCaz1rh5YzfACS3tsIx~yy`X2xNwk`MfzUp|H^--^Pt-EZp_H|Ttsb1fn zLn8IP`!b2OPoB5ZHqh(kbGbh@=PT!Fo^la|JMyc1RnLzlf6G39ZMd=Z1W~6FbG&u zx&Mdg0uK$Lt`;RATIiv%h!AIC2S}Mvmqu2Y086i%@_+aqp$%8)L%#a=5jOro@=&gi!4zc9((Eldh* zJ=|Q7TmIH><7|$JjXj%Uw0QAiZ*T8yxyIsOv$L~L7tV=VyKU1ZBSXW7yVmWwEIrL~ z{`c>{|E^xW`tIGkD_5?p+N+lt6t!&btq-;KV%?n0TX<}$AOHS$`BK`kKFU!emm4_?%cUkPe0W^_O4aIj?syz29~8{87K}B)}prE)I+tjVzxT ze#@r@eg6DeBP(+C)md}r=5D_|@42VdmXD`dEU%ZAmzAZZrA<2d1qWtsx&nu=+pML1v;v%y-vKDtYCN4Y z`@equ`riC7@XFTZ%hk`dy`H=0{nyVuyz5p(U48#O_WD%!6+RZ_oA>UuH8FYeyKZX~ zZ~Ni)_V$}OVK=_@3R)NJjPd(c{NTrZvpxEtRECn|@Nhu6;(u7tKGAFMzq`A+{rmG= zwO01rk>$oGydQ~Y*W2v#|D%(lS5)pC6ZrpHY3Qrgc5SWj5T}U&Dk6a@BAl*Hg02Y8 cugi7Jw=x1YL|QL#1ZI5(Pgg&ebxsLQ0P5NMNB{r; literal 0 HcmV?d00001 diff --git a/Software/PC_Application/icons/parallelR.png b/Software/PC_Application/icons/parallelR.png new file mode 100644 index 0000000000000000000000000000000000000000..78feadccda33054d4653dd0676d7169dd0fe4461 GIT binary patch literal 1077 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn2}J&l(*shR1s;*b3=Dj8K$wwzO7L9<2Il9U zE{-7;x8BY*^mrX0;t+3t_tw@R^^L19^faBk;3$6GZ{q_!Cz(5~JFKT{+rfSE!M!Gr zmy=5JV_KhU6#6b_`_=BCS^w+y|M&Zf)!3&$|G2mM{@$IQxx4Rb8O(|Q!?}SYf<=c( zY$MSWV>eg>kTU7nr1Sjq&eyv>|JO# zK&JiQqJurhA1~7Q^>^R%%B0x5wF@=66gZ{?-OV%i6!P@mtg$=OMC$Ovfb80$qDPhY z?%tJEUo~+`>dqKF@$S~3S6{wN5x%% zax>@2+Q3hpvzEO)di3bWj~~yU_n)M)`s%A!uU5saFTQM`{Nrfh8;ic@m21Piv;Y44 z_iop^Ck^^KKYHC3m+f9Vh3jxY#D~pFdTxOss`^3A^F<3ke*PS+Sz1s~P*S2|^dnMG zTwYFY%eB36=RfZ`eE6_MU#tJ_w~8NLe*aqa_sf?rfBvkQvTNtgo%{Fan@Alp_2Lzs zeO9e&k=A9-CWma_vSb6#NhP~umri;A`%u>dvCzZ7a9tY~mAy3N>YQ0;(=ItJ3ze*# z_k4HOs}ieJeJRh?S9k5(XJ>E!|KGp5>gvbK5(^?t&wp0&Y&)zd=Bu^(T-xTpn_gvY zofH-}^=|N%C2Lk4NjD4>>D2G`-aI4q<~sE`DxIpSg_eaMA3r`^IOkPU{MVM)>sy!V z=so+t@mABm_qQ*HiR=)MkBeKR5v3z`HtjPo#9qHXy{LP`9;F|34^2)ReOpv{<@MK9 z1+!8kr#=qx|N1%2xA|h!`*_PG%hrU296lQVU-wmJNbTd;6H~63Z(D5~y7SIm&kY$* zcJ8WfQ|38rbADsS4EuwN%|7YA>%Zl*Jb0z$svG~3W-aS`{HFg_OkA9o?rN{iJM6PA zzy7*LV(Y|`*Xx_+w=OnY^e9R6f0M$7+$(NVj@th^9ARRuxi+pn=_<#ZGx@%6`0srA z{r6*qj`hxoe~wPrq!S+>&)$46?9cT0Z8f*sek&yi0&~L=qA3=gB*A~`PkdU}UVojo z`RDij`k69*|8nN@a@2JDuMOLrF1|_pWL|^t*Z8@sgZSnALi|DwfDG?&#iagCyZ`K+ WN7!^$Q()d_VDNPHb6Mw<&;$U5@CQQx literal 0 HcmV?d00001 diff --git a/Software/PC_Application/icons/port1.svg b/Software/PC_Application/icons/port1.svg index c93f08d..12252e3 100644 --- a/Software/PC_Application/icons/port1.svg +++ b/Software/PC_Application/icons/port1.svg @@ -1,6 +1,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -12,6 +32,17 @@ + + + + + + + + + + + diff --git a/Software/PC_Application/icons/port2.svg b/Software/PC_Application/icons/port2.svg index f98b346..9ead629 100644 --- a/Software/PC_Application/icons/port2.svg +++ b/Software/PC_Application/icons/port2.svg @@ -1,12 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/PC_Application/icons/seriesC.png b/Software/PC_Application/icons/seriesC.png new file mode 100644 index 0000000000000000000000000000000000000000..3e5155aaaa02383b1c9e45892f6044cb02f85158 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn2}J&l(*shR1s;*b3=Dj8K$wwzO7L9<21aR5 z7srr_TW{|eavd<>aJU#z^Ki(YQH_EO>qg8<$eE=Q=@B^VNs+EoVM&1x zw_jmlM=;mUhmI4L?X`ZFm+|nkte4Ncl}|2DmzTB4x^4F2!0(3w0V1w}BCcJFG`bdf z02zTInjp3kNHA~-P*9@_B=|L6O6J1-Umrhy{PgM5&!3g0rKOdXmJ&R_nCH!#=fq)d zZZ0k^{?}G#`swG-p9>s%`}S>t#hn|w;@024cP}nJ-rwJU{rdI4nZIrS<}k}|xnhgX z>7<^_g{xNOWnVVA`^)D1Z{}62PHoa@nee9IC_p-b|vJdy=mtO+-{45j>-OQO* zx8}8#?CU2}I5z8OpWdYW(@uf&sD$mP&@M&p&Ni4CbHT zzuu>)a-RC*-kH~VCHjx&-tIdNVxLr94zh0BKK-NnbG8$ElO=kx<7Q#O@4 zgod&k%6|XrnY=aXs6_c)y?giXw+px}4*Xwd`t`$y3w!f+I?D3^`P=8$9e!wVY)8~u z8~uO5-A5mZm;X^$S66J=y?b{o^SSfqcVAz-^uF)!o2)w{bZjR5%Z^@Oc~|q}@4eak zH|aQY+y&Alfpg)f% zZCD#G_~+#A;3@9|T_=JfS0e~VM7KBKl}4lkeCY#f2S&QVv>TG1VB%Nez6*0zoced@ T{Kpbt(r55=^>bP0l+XkKScrBm literal 0 HcmV?d00001 diff --git a/Software/PC_Application/icons/seriesR.png b/Software/PC_Application/icons/seriesR.png new file mode 100644 index 0000000000000000000000000000000000000000..f4028ee5caad60f23902da00a8af4df74002e636 GIT binary patch literal 759 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn2}J&l(*shR1s;*b3=Dj8K$wwzO7L9<2Bwvs zE{-7;x8B~_*!##qqT%Ar)k&*nXl>&(cjRB!DCNT*z{sg7!eD6V!dG+9xwq@~SS%HB+7Y*2 ze*K!)RxKAye78RfTO1J@y6xus?@zV+k0*ayw`x^Q>g{ccEmJO?IqF#0=x8I?UmCl7 zid|KB=u}<#e)or`mSraOeE(g0?$LrB2Nde+>&s)mSJ)V(-~3%;_xyQQ?Df|EUc+bH z&vf{@xOpCBPp_n5b0|Gf)2ugbpruMJ*zI5_*@)JI8sZS7BQ z-~IoO&i>U;%uif@G~-r-re4^8o#1_U|872Wr80eoMOewb$c>M(S3SG)?#~|G{ndMP z`#yDR9#uVVxYXo%*>m@IWxN0GIREtM#P4^v*6?r0J8IKfoL4^Ykieli%+J#{pS(Y* z`t|?f`)|(dxm&sCnT*BfM-dmlKaQXK|KyAOzwp=+(FDbu685OYC5{y3c#{IeaLgov gY3ZUL`d@@2CM^EEq%i0?FeNj1y85}Sb4q9e0K+3<*#H0l literal 0 HcmV?d00001 diff --git a/Software/PC_Application/touchstone.cpp b/Software/PC_Application/touchstone.cpp index 555667e..5525dbe 100644 --- a/Software/PC_Application/touchstone.cpp +++ b/Software/PC_Application/touchstone.cpp @@ -384,3 +384,57 @@ QString Touchstone::getFilename() const { return filename; } + +nlohmann::json Touchstone::toJSON() +{ + nlohmann::json j; + j["ports"] = m_ports; + j["filename"] = filename.toStdString(); + if(m_datapoints.size() > 0) { + nlohmann::json json_points; + for(auto d : m_datapoints) { + nlohmann::json point; + point["frequency"] = d.frequency; + nlohmann::json sparams; + for(auto s : d.S) { + nlohmann::json sparam; + sparam["real"] = s.real(); + sparam["imag"] = s.imag(); + sparams.push_back(sparam); + } + point["Sparams"] = sparams; + json_points.push_back(point); + } + j["datapoints"] = json_points; + } + return j; +} + +void Touchstone::fromJSON(nlohmann::json j) +{ + m_datapoints.clear(); + filename = QString::fromStdString(j.value("filename", "")); + m_ports = j.value("ports", 0); + if(!m_ports || !j.contains("datapoints")) { + return; + } + auto json_points = j["datapoints"]; + for(auto point : json_points) { + Datapoint d; + if(!point.contains("frequency") || !point.contains("Sparams")) { + // missing data, abort here + qWarning() << "Touchstone data point does not contain frequency or S parameters"; + break; + } + d.frequency = point["frequency"]; + if(point["Sparams"].size() != m_ports * m_ports) { + // invalid number of Sparams, abort here + qWarning() << "Invalid number of S parameters, got" << point["Sparams"].size() << "expected" << m_ports*m_ports; + break; + } + for(auto Sparam : point["Sparams"]) { + d.S.push_back(complex(Sparam.value("real", 0.0), Sparam.value("imag", 0.0))); + } + m_datapoints.push_back(d); + } +} diff --git a/Software/PC_Application/touchstone.h b/Software/PC_Application/touchstone.h index a73b4ce..fa34fa1 100644 --- a/Software/PC_Application/touchstone.h +++ b/Software/PC_Application/touchstone.h @@ -1,12 +1,14 @@ #ifndef TOUCHSTONE_H #define TOUCHSTONE_H +#include "savable.h" + #include #include #include #include -class Touchstone +class Touchstone : public Savable { public: enum class Scale { @@ -29,6 +31,7 @@ public: }; Touchstone(unsigned int m_ports); + virtual ~Touchstone(){}; void AddDatapoint(Datapoint p); void toFile(std::string filename, Scale unit = Scale::GHz, Format format = Format::RealImaginary); std::stringstream toString(Scale unit = Scale::GHz, Format format = Format::RealImaginary); @@ -45,6 +48,9 @@ public: unsigned int ports() { return m_ports; } QString getFilename() const; + virtual nlohmann::json toJSON(); + virtual void fromJSON(nlohmann::json j); + private: unsigned int m_ports; std::vector m_datapoints;