diff --git a/Software/PC_Application/Calibration/CalStandardLoadEditDialog.ui b/Software/PC_Application/Calibration/CalStandardLoadEditDialog.ui new file mode 100644 index 0000000..b3fc7b9 --- /dev/null +++ b/Software/PC_Application/Calibration/CalStandardLoadEditDialog.ui @@ -0,0 +1,244 @@ + + + CalStandardLoadEditDialog + + + + 0 + 0 + 349 + 355 + + + + Edit Load Standard + + + true + + + + + + + + Name: + + + + + + + + + + + + + + Coefficients + + + buttonGroup + + + + + + + Measurement file + + + buttonGroup + + + + + + + + + 0 + + + + + + + + + Resistance: + + + + + + + + + + Z0: + + + + + + + true + + + + + + + Offset delay [ps]: + + + + + + + + + + Parallel C: + + + + + + + + + + Series L: + + + + + + + + + + + + Load Parameter Model + + + + + + Series L first + + + buttonGroup_2 + + + + + + + Shunt C first + + + buttonGroup_2 + + + + + + + + + + + + + + + + + + + + + false + + + Update from file + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+ + TouchstoneImport + QWidget +
CustomWidgets/touchstoneimport.h
+ 1 +
+
+ + + + buttonBox + accepted() + CalStandardLoadEditDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CalStandardLoadEditDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + + +
diff --git a/Software/PC_Application/Calibration/CalStandardOpenEditDialog.ui b/Software/PC_Application/Calibration/CalStandardOpenEditDialog.ui new file mode 100644 index 0000000..a1dd1f9 --- /dev/null +++ b/Software/PC_Application/Calibration/CalStandardOpenEditDialog.ui @@ -0,0 +1,230 @@ + + + CalStandardOpenEditDialog + + + + 0 + 0 + 358 + 342 + + + + Edit Open Standard + + + true + + + + + + + + Name: + + + + + + + + + + + + + + Coefficients + + + buttonGroup + + + + + + + Measurement file + + + buttonGroup + + + + + + + + + 1 + + + + + + + Z0: + + + + + + + true + + + + + + + Offset delay [ps]: + + + + + + + + + + Offset loss [GΩ/s]: + + + + + + + + + + C0 [10<sup>-15</sup>F]: + + + + + + + + + + C1 [10<sup>-27</sup>F/Hz]: + + + + + + + + + + C2 [10<sup>-36</sup>F/Hz<sup>2</sup>]: + + + + + + + + + + <html><head/><body><p>C3 [10<span style=" vertical-align:super;">-45</span>F/Hz<span style=" vertical-align:super;">3</span>]:</p></body></html> + + + + + + + + + + + + + + + + + + + + + false + + + Update from file + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+ + TouchstoneImport + QWidget +
CustomWidgets/touchstoneimport.h
+ 1 +
+
+ + + + buttonBox + accepted() + CalStandardOpenEditDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CalStandardOpenEditDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + +
diff --git a/Software/PC_Application/Calibration/CalStandardShortEditDialog.ui b/Software/PC_Application/Calibration/CalStandardShortEditDialog.ui new file mode 100644 index 0000000..594cb06 --- /dev/null +++ b/Software/PC_Application/Calibration/CalStandardShortEditDialog.ui @@ -0,0 +1,230 @@ + + + CalStandardShortEditDialog + + + + 0 + 0 + 358 + 342 + + + + Edit Short Standard + + + true + + + + + + + + Name: + + + + + + + + + + + + + + Coefficients + + + buttonGroup + + + + + + + Measurement file + + + buttonGroup + + + + + + + + + 0 + + + + + + + Z0: + + + + + + + true + + + + + + + Offset delay [ps]: + + + + + + + + + + Offset loss [GΩ/s]: + + + + + + + + + + <html><head/><body><p>L0 [10<span style=" vertical-align:super;">-12</span>H]:</p></body></html> + + + + + + + + + + <html><head/><body><p>L1 [10<span style=" vertical-align:super;">-24</span>H/Hz]:</p></body></html> + + + + + + + + + + <html><head/><body><p>L2 [10<span style=" vertical-align:super;">-33</span>H/Hz<span style=" vertical-align:super;">2</span>]:</p></body></html> + + + + + + + + + + <html><head/><body><p>L3 [10<span style=" vertical-align:super;">-42</span>H/Hz<span style=" vertical-align:super;">3</span>]:</p></body></html> + + + + + + + + + + + + + + + + + + + + + false + + + Update from file + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+ + TouchstoneImport + QWidget +
CustomWidgets/touchstoneimport.h
+ 1 +
+
+ + + + buttonBox + accepted() + CalStandardShortEditDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CalStandardShortEditDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + +
diff --git a/Software/PC_Application/Calibration/calkitdialog.ui b/Software/PC_Application/Calibration/calkitdialog.ui index dee0f6d..e010eab 100644 --- a/Software/PC_Application/Calibration/calkitdialog.ui +++ b/Software/PC_Application/Calibration/calkitdialog.ui @@ -10,7 +10,7 @@ 0 0 1213 - 626 + 637 @@ -1505,14 +1505,14 @@ + - + + - - + - diff --git a/Software/PC_Application/Calibration/calstandard.cpp b/Software/PC_Application/Calibration/calstandard.cpp new file mode 100644 index 0000000..39ccf82 --- /dev/null +++ b/Software/PC_Application/Calibration/calstandard.cpp @@ -0,0 +1,540 @@ +#include "calstandard.h" +#include "ui_CalStandardOpenEditDialog.h" +#include "ui_CalStandardShortEditDialog.h" +#include "ui_CalStandardLoadEditDialog.h" +#include "unit.h" + +using namespace std; +using namespace CalStandard; + +QString Virtual::TypeToString(Virtual::Type type) +{ + switch(type) { + case Type::Open: return "Open"; + case Type::Short: return "Short"; + case Type::Load: return "Load"; + case Type::Through: return "Through"; + case Type::Line: return "Line"; + case Type::Last: return "Invalid"; + } +} + +Virtual::Type Virtual::TypeFromString(QString s) +{ + for(int i=0;i<(int) Type::Last;i++) { + if(TypeToString((Type) i) == s) { + return (Type) i; + } + } + return Type::Last; +} + +QString Virtual::getDescription() +{ + return TypeToString(getType())+", "+name; +} + +nlohmann::json Virtual::toJSON() +{ + nlohmann::json j; + j["name"] = name.toStdString(); + return j; +} + +void Virtual::fromJSON(nlohmann::json j) +{ + name = QString::fromStdString(j.value("name", "")); +} + +void OnePort::setMeasurement(const Touchstone &ts, int port) +{ + if(!touchstone) { + touchstone = new Touchstone(ts); + } else { + *touchstone = ts; + } + if(touchstone->ports() > 1) { + touchstone->reduceTo1Port(port); + } + minFreq = touchstone->minFreq(); + maxFreq = touchstone->maxFreq(); +} + +void OnePort::clearMeasurement() +{ + delete touchstone; + touchstone = nullptr; + minFreq = std::numeric_limits::lowest(); + minFreq = std::numeric_limits::max(); +} + +nlohmann::json OnePort::toJSON() +{ + auto j = Virtual::toJSON(); + if(touchstone) { + j["touchstone"] = touchstone->toJSON(); + } + return j; +} + +void OnePort::fromJSON(nlohmann::json j) +{ + Virtual::fromJSON(j); + if(j.contains("touchstone")) { + Touchstone ts(1); + ts.fromJSON(j["touchstone"]); + setMeasurement(ts); + } +} + +std::complex OnePort::addTransmissionLine(std::complex termination_reflection, double offset_impedance, double offset_delay, double offset_loss, double frequency) +{ + // nomenclature and formulas from https://loco.lab.asu.edu/loco-memos/edges_reports/report_20130807.pdf + auto Gamma_T = termination_reflection; + auto f = frequency; + auto w = 2.0 * M_PI * frequency; + auto f_sqrt = sqrt(f / 1e9); + + auto Z_c = complex(offset_impedance + (offset_loss / (2*w)) * f_sqrt, -(offset_loss / (2*w)) * f_sqrt); + auto gamma_l = complex(offset_loss*offset_delay/(2*offset_impedance)*f_sqrt, w*offset_delay+offset_loss*offset_delay/(2*offset_impedance)*f_sqrt); + + auto Z_r = complex(50.0); + + auto Gamma_1 = (Z_c - Z_r) / (Z_c + Z_r); + + auto Gamma_i = (Gamma_1*(1.0-exp(-2.0*gamma_l)-Gamma_1*Gamma_T)+exp(-2.0*gamma_l)*Gamma_T) + / (1.0-Gamma_1*(exp(-2.0*gamma_l)*Gamma_1+Gamma_T*(1.0-exp(-2.0*gamma_l)))); + + return Gamma_i; +} + +Open::Open() +{ + Z0 = 50.0; + delay = loss = C0 = C1 = C2 = C3 = 0.0; +} + +std::complex Open::toS11(double freq) +{ + if(touchstone) { + return touchstone->interpolate(freq).S[0]; + } else { + // calculate fringing capacitance for open + double Cfringing = C0 * 1e-15 + C1 * 1e-27 * freq + C2 * 1e-36 * pow(freq, 2) + C3 * 1e-45 * pow(freq, 3); + // convert to impedance + complex open; + if (Cfringing == 0) { + // special case to avoid issues with infinity + open = complex(1.0, 0); + } else { + auto imp_open = complex(0, -1.0 / (freq * 2 * M_PI * Cfringing)); + open = (imp_open - complex(50.0)) / (imp_open + complex(50.0)); + } + return addTransmissionLine(open, Z0, delay*1e-12, loss*1e9, freq); + } +} + +void Open::edit() +{ + auto d = new QDialog; + auto ui = new Ui::CalStandardOpenEditDialog; + ui->setupUi(d); + + ui->name->setText(name); + ui->Z0->setUnit("Ω"); + ui->Z0->setPrecision(2); + ui->Z0->setValue(Z0); + ui->delay->setValue(delay); + ui->loss->setValue(loss); + ui->C0->setValue(C0); + ui->C1->setValue(C1); + ui->C2->setValue(C2); + ui->C3->setValue(C3); + + auto updateMeasurementLabel = [=](){ + QString label; + if(touchstone) { + label = QString::number(touchstone->points())+" points from "+Unit::ToString(touchstone->minFreq(), "Hz", " kMG")+" to "+Unit::ToString(touchstone->maxFreq(), "Hz", " kMG"); + } else { + label = "No measurements stored yet"; + } + ui->measurementLabel->setText(label); + }; + + QObject::connect(ui->coefficients, &QRadioButton::toggled, [=](bool checked) { + if(checked) { + clearMeasurement(); + } + ui->stackedWidget->setCurrentIndex(checked ? 0 : 1); + }); + QObject::connect(ui->measurement, &QRadioButton::toggled, [=](bool checked) { + updateMeasurementLabel(); + ui->stackedWidget->setCurrentIndex(checked ? 1 : 0); + }); + + QObject::connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, ui->updateFile, &QPushButton::setEnabled); + + ui->touchstoneImport->setPorts(1); + if(touchstone) { + ui->measurement->setChecked(true); + ui->touchstoneImport->setFile(touchstone->getFilename()); + } else { + ui->coefficients->setChecked(true); + } + + QObject::connect(ui->updateFile, &QPushButton::clicked, [=](){ + setMeasurement(ui->touchstoneImport->getTouchstone(), ui->touchstoneImport->getPorts()[0]); + updateMeasurementLabel(); + }); + + QObject::connect(d, &QDialog::accepted, [=](){ + name = ui->name->text(); + Z0 = ui->Z0->value(); + delay = ui->delay->value(); + loss = ui->loss->value(); + C0 = ui->C0->value(); + C1 = ui->C1->value(); + C2 = ui->C2->value(); + C3 = ui->C3->value(); + }); + + d->show(); +} + +nlohmann::json Open::toJSON() +{ + auto j = OnePort::toJSON(); + j["Z0"] = Z0; + j["delay"] = delay; + j["loss"] = loss; + j["C0"] = C0; + j["C1"] = C1; + j["C2"] = C2; + j["C3"] = C3; + return j; +} + +void Open::fromJSON(nlohmann::json j) +{ + OnePort::fromJSON(j); + Z0 = j.value("Z0", 50.0); + delay = j.value("delay", 0.0); + loss = j.value("loss", 0.0); + C0 = j.value("C0", 0.0); + C1 = j.value("C1", 0.0); + C2 = j.value("C2", 0.0); + C3 = j.value("C3", 0.0); +} + +Short::Short() +{ + Z0 = 50.0; + delay = loss = L0 = L1 = L2 = L3 = 0.0; +} + +std::complex Short::toS11(double freq) +{ + if(touchstone) { + return touchstone->interpolate(freq).S[0]; + } else { + // calculate inductance for short + double Lseries = L0 * 1e-12 + L1 * 1e-24 * freq + L2 * 1e-33 * pow(freq, 2) + L3 * 1e-42 * pow(freq, 3); + // convert to impedance + auto imp_short = complex(0, freq * 2 * M_PI * Lseries); + complex _short = (imp_short - complex(50.0)) / (imp_short + complex(50.0)); + return addTransmissionLine(_short, Z0, delay*1e-12, loss*1e9, freq); + } +} + +void Short::edit() +{ + auto d = new QDialog; + auto ui = new Ui::CalStandardShortEditDialog; + ui->setupUi(d); + + ui->name->setText(name); + ui->Z0->setUnit("Ω"); + ui->Z0->setPrecision(2); + ui->Z0->setValue(Z0); + ui->delay->setValue(delay); + ui->loss->setValue(loss); + ui->L0->setValue(L0); + ui->L1->setValue(L1); + ui->L2->setValue(L2); + ui->L3->setValue(L3); + + auto updateMeasurementLabel = [=](){ + QString label; + if(touchstone) { + label = QString::number(touchstone->points())+" points from "+Unit::ToString(touchstone->minFreq(), "Hz", " kMG")+" to "+Unit::ToString(touchstone->maxFreq(), "Hz", " kMG"); + } else { + label = "No measurements stored yet"; + } + ui->measurementLabel->setText(label); + }; + + QObject::connect(ui->coefficients, &QRadioButton::toggled, [=](bool checked) { + if(checked) { + clearMeasurement(); + } + ui->stackedWidget->setCurrentIndex(checked ? 0 : 1); + }); + QObject::connect(ui->measurement, &QRadioButton::toggled, [=](bool checked) { + updateMeasurementLabel(); + ui->stackedWidget->setCurrentIndex(checked ? 1 : 0); + }); + + QObject::connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, ui->updateFile, &QPushButton::setEnabled); + + ui->touchstoneImport->setPorts(1); + if(touchstone) { + ui->measurement->setChecked(true); + ui->touchstoneImport->setFile(touchstone->getFilename()); + } else { + ui->coefficients->setChecked(true); + } + + QObject::connect(ui->updateFile, &QPushButton::clicked, [=](){ + setMeasurement(ui->touchstoneImport->getTouchstone(), ui->touchstoneImport->getPorts()[0]); + updateMeasurementLabel(); + }); + + QObject::connect(d, &QDialog::accepted, [=](){ + name = ui->name->text(); + Z0 = ui->Z0->value(); + delay = ui->delay->value(); + loss = ui->loss->value(); + L0 = ui->L0->value(); + L1 = ui->L1->value(); + L2 = ui->L2->value(); + L3 = ui->L3->value(); + }); + + d->show(); +} + +nlohmann::json Short::toJSON() +{ + auto j = OnePort::toJSON(); + j["Z0"] = Z0; + j["delay"] = delay; + j["loss"] = loss; + j["L0"] = L0; + j["L1"] = L1; + j["L2"] = L2; + j["L3"] = L3; + return j; +} + +void Short::fromJSON(nlohmann::json j) +{ + OnePort::fromJSON(j); + Z0 = j.value("Z0", 50.0); + delay = j.value("delay", 0.0); + loss = j.value("loss", 0.0); + L0 = j.value("L0", 0.0); + L1 = j.value("L1", 0.0); + L2 = j.value("L2", 0.0); + L3 = j.value("L3", 0.0); +} + +Load::Load() +{ + Z0 = 50.0; + resistance = 50.0; + delay = Cparallel = Lseries = 0; + Cfirst = true; +} + +std::complex Load::toS11(double freq) +{ + if(touchstone) { + return touchstone->interpolate(freq).S[0]; + } else { + auto imp_load = complex(resistance, 0); + if (Cfirst) { + // C is the first parameter starting from the VNA port. But the load is modeled here starting from + // the other end, so we need to start with the inductor + imp_load += complex(0, freq * 2 * M_PI * Lseries); + } + // Add parallel capacitor to impedance + if(Cparallel > 0) { + auto imp_C = complex(0, -1.0 / (freq * 2 * M_PI * Cparallel)); + imp_load = (imp_load * imp_C) / (imp_load + imp_C); + } + if (!Cfirst) { + // inductor not added yet, do so now + imp_load += complex(0, freq * 2 * M_PI * Lseries); + } + complex load = (imp_load - complex(50.0)) / (imp_load + complex(50.0)); + return addTransmissionLine(load, Z0, delay*1e-12, 0, freq); + } +} + +void Load::edit() +{ + auto d = new QDialog; + auto ui = new Ui::CalStandardLoadEditDialog; + ui->setupUi(d); + + ui->name->setText(name); + ui->resistance->setUnit("Ω"); + ui->resistance->setPrecision(2); + ui->resistance->setValue(resistance); + ui->Z0->setUnit("Ω"); + ui->Z0->setPrecision(2); + ui->Z0->setValue(Z0); + ui->delay->setValue(delay); + ui->parC->setUnit("F"); + ui->parC->setPrefixes("pnum "); + ui->parC->setPrecision(3); + ui->parC->setValue(Cparallel); + ui->serL->setUnit("H"); + ui->serL->setPrefixes("num "); + ui->serL->setPrecision(3); + ui->serL->setValue(Lseries); + + if(Cfirst) { + ui->C_first->setChecked(true); + } else { + ui->L_first->setChecked(true); + } + + auto updateMeasurementLabel = [=](){ + QString label; + if(touchstone) { + label = QString::number(touchstone->points())+" points from "+Unit::ToString(touchstone->minFreq(), "Hz", " kMG")+" to "+Unit::ToString(touchstone->maxFreq(), "Hz", " kMG"); + } else { + label = "No measurements stored yet"; + } + ui->measurementLabel->setText(label); + }; + + QObject::connect(ui->coefficients, &QRadioButton::toggled, [=](bool checked) { + if(checked) { + clearMeasurement(); + } + ui->stackedWidget->setCurrentIndex(checked ? 0 : 1); + }); + QObject::connect(ui->measurement, &QRadioButton::toggled, [=](bool checked) { + updateMeasurementLabel(); + ui->stackedWidget->setCurrentIndex(checked ? 1 : 0); + }); + + QObject::connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, ui->updateFile, &QPushButton::setEnabled); + + ui->touchstoneImport->setPorts(1); + if(touchstone) { + ui->measurement->setChecked(true); + ui->touchstoneImport->setFile(touchstone->getFilename()); + } else { + ui->coefficients->setChecked(true); + } + + QObject::connect(ui->updateFile, &QPushButton::clicked, [=](){ + setMeasurement(ui->touchstoneImport->getTouchstone(), ui->touchstoneImport->getPorts()[0]); + updateMeasurementLabel(); + }); + + QObject::connect(d, &QDialog::accepted, [=](){ + name = ui->name->text(); + resistance = ui->resistance->value(); + Z0 = ui->Z0->value(); + delay = ui->delay->value(); + Cparallel = ui->parC->value(); + Lseries = ui->serL->value(); + Cfirst = ui->C_first->isChecked(); + }); + + d->show(); +} + +nlohmann::json Load::toJSON() +{ + auto j = OnePort::toJSON(); + j["Z0"] = Z0; + j["delay"] = delay; + j["resistance"] = resistance; + j["Cparallel"] = Cparallel; + j["Lseries"] = Lseries; + j["Cfirst"] = Cfirst; + return j; +} + +void Load::fromJSON(nlohmann::json j) +{ + OnePort::fromJSON(j); + Z0 = j.value("Z0", 50.0); + delay = j.value("delay", 0.0); + resistance = j.value("resistance", 0.0); + Cparallel = j.value("Cparallel", 0.0); + Lseries = j.value("Lseries", 0.0); + Cfirst = j.value("Cfirst", true); +} + +void TwoPort::setMeasurement(const Touchstone &ts, int port1, int port2) +{ + if(!touchstone) { + touchstone = new Touchstone(ts); + } else { + *touchstone = ts; + } + if(touchstone->ports() > 2) { + touchstone->reduceTo2Port(port1, port2); + } + minFreq = touchstone->minFreq(); + maxFreq = touchstone->maxFreq(); +} + +void TwoPort::clearMeasurement() +{ + delete touchstone; + touchstone = nullptr; + minFreq = std::numeric_limits::lowest(); + minFreq = std::numeric_limits::max(); +} + +nlohmann::json TwoPort::toJSON() +{ + auto j = Virtual::toJSON(); + if(touchstone) { + j["touchstone"] = touchstone->toJSON(); + } + return j; +} + +void TwoPort::fromJSON(nlohmann::json j) +{ + Virtual::fromJSON(j); + if(j.contains("touchstone")) { + Touchstone ts(1); + ts.fromJSON(j["touchstone"]); + setMeasurement(ts); + } +} + +Sparam Through::toSparam(double freq) +{ + if(touchstone) { + auto interp = touchstone->interpolate(freq).S; + return Sparam(interp[0], interp[1], interp[2], interp[3]); + } else { + // calculate effect of through + double through_phaseshift = -2 * M_PI * freq * delay * 1e-12; + double through_att_db = loss * 1e9 * 4.3429 * delay * 1e-12 / Z0 * sqrt(freq / 1e9);; + double through_att = pow(10.0, -through_att_db / 10.0); + auto through = polar(through_att, through_phaseshift); + // Assume symmetric and perfectly matched through for other parameters + return Sparam(0.0, through, through, 0.0); + } +} + +nlohmann::json Through::toJSON() +{ + +} + +void Through::fromJSON(nlohmann::json j) +{ + +} diff --git a/Software/PC_Application/Calibration/calstandard.h b/Software/PC_Application/Calibration/calstandard.h new file mode 100644 index 0000000..2e00d63 --- /dev/null +++ b/Software/PC_Application/Calibration/calstandard.h @@ -0,0 +1,147 @@ +#ifndef CALSTANDARD_H +#define CALSTANDARD_H + +#include "savable.h" +#include "touchstone.h" +#include "Tools/parameters.h" + +#include + +namespace CalStandard +{ + +class Virtual : public Savable +{ +public: + Virtual() : + minFreq(std::numeric_limits::lowest()), + maxFreq(std::numeric_limits::max()){} + + enum class Type { + Open, + Short, + Load, + Through, + Line, + Last + }; + + static Virtual* create(Type type); + + static QString TypeToString(Type type); + static Type TypeFromString(QString s); + + virtual Type getType() = 0; + double minFrequency() {return minFreq;} + double maxFrequency() {return maxFreq;} + + virtual void edit() = 0; + virtual QString getDescription(); + + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; + +protected: + QString name; + double minFreq; + double maxFreq; +}; + +class OnePort : public Virtual +{ +public: + OnePort() : + touchstone(nullptr){} + + virtual std::complex toS11(double freq) = 0; + + void setMeasurement(const Touchstone &ts, int port = 0); + void clearMeasurement(); + + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; + +protected: + std::complex addTransmissionLine(std::complex termination_reflection, + double offset_impedance, double offset_delay, + double offset_loss, double frequency); + Touchstone *touchstone; +}; + +class Open : public OnePort +{ +public: + Open(); + + virtual std::complex toS11(double freq) override; + virtual void edit() override; + virtual Type getType() override {return Type::Open;} + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; +private: + double Z0, delay, loss, C0, C1, C2, C3; +}; + +class Short : public OnePort +{ +public: + Short(); + + virtual std::complex toS11(double freq) override; + virtual void edit() override; + virtual Type getType() override {return Type::Short;} + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; +private: + double Z0, delay, loss, L0, L1, L2, L3; +}; + +class Load : public OnePort +{ +public: + Load(); + + virtual std::complex toS11(double freq) override; + virtual void edit() override; + virtual Type getType() override {return Type::Load;} + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; +private: + double Z0, delay, resistance, Cparallel, Lseries; + bool Cfirst; +}; + +class TwoPort : public Virtual +{ +public: + TwoPort() : + touchstone(nullptr){} + + virtual Sparam toSparam(double freq) = 0; + + void setMeasurement(const Touchstone &ts, int port1 = 0, int port2 = 1); + void clearMeasurement(); + + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; + +protected: + Touchstone *touchstone; +}; + +class Through : public TwoPort +{ +public: + Through(); + + virtual Sparam toSparam(double freq) override; + virtual Type getType() override {return Type::Through;} + virtual nlohmann::json toJSON() override; + virtual void fromJSON(nlohmann::json j) override; +private: + double Z0, delay, loss; +}; + +} + +#endif // CALSTANDARD_H diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index 27bb59d..53599b6 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -5,6 +5,7 @@ HEADERS += \ Calibration/calibrationtracedialog.h \ Calibration/calkit.h \ Calibration/calkitdialog.h \ + Calibration/calstandard.h \ Calibration/frequencycaldialog.h \ Calibration/manualcalibrationdialog.h \ Calibration/measurementmodel.h \ @@ -144,6 +145,7 @@ SOURCES += \ Calibration/calibrationtracedialog.cpp \ Calibration/calkit.cpp \ Calibration/calkitdialog.cpp \ + Calibration/calstandard.cpp \ Calibration/frequencycaldialog.cpp \ Calibration/manualcalibrationdialog.cpp \ Calibration/measurementmodel.cpp \ @@ -272,6 +274,9 @@ osx:LIBS += $(shell pkg-config --libs libusb-1.0) QT += widgets network FORMS += \ + Calibration/CalStandardLoadEditDialog.ui \ + Calibration/CalStandardOpenEditDialog.ui \ + Calibration/CalStandardShortEditDialog.ui \ Calibration/addamplitudepointsdialog.ui \ Calibration/amplitudecaldialog.ui \ Calibration/automaticamplitudedialog.ui \ diff --git a/Software/PC_Application/Tools/parameters.h b/Software/PC_Application/Tools/parameters.h index 4850eb4..81ca684 100644 --- a/Software/PC_Application/Tools/parameters.h +++ b/Software/PC_Application/Tools/parameters.h @@ -8,8 +8,8 @@ using Type = std::complex; class Parameters { public: Parameters(Type m11, Type m12, Type m21, Type m22) - : m11(m11), m12(m12), m21(m21), m22(m22){}; - Parameters(){}; + : m11(m11), m12(m12), m21(m21), m22(m22){} + Parameters(){} Type m11, m12, m21, m22; }; diff --git a/Software/PC_Application/touchstone.h b/Software/PC_Application/touchstone.h index 3cdf1bd..10ae410 100644 --- a/Software/PC_Application/touchstone.h +++ b/Software/PC_Application/touchstone.h @@ -31,15 +31,15 @@ public: }; Touchstone(unsigned int m_ports); - virtual ~Touchstone(){}; + virtual ~Touchstone(){} void AddDatapoint(Datapoint p); void toFile(QString filename, Scale unit = Scale::GHz, Format format = Format::RealImaginary); std::stringstream toString(Scale unit = Scale::GHz, Format format = Format::RealImaginary); static Touchstone fromFile(std::string filename); double minFreq(); double maxFreq(); - unsigned int points() { return m_datapoints.size(); }; - Datapoint point(int index) { return m_datapoints.at(index); }; + unsigned int points() { return m_datapoints.size(); } + Datapoint point(int index) { return m_datapoints.at(index); } Datapoint interpolate(double frequency); // remove all paramaters except the ones regarding port1 and port2 (port cnt starts at 0) void reduceTo2Port(unsigned int port1, unsigned int port2);