diff --git a/Software/PC_Application/Application.pro b/Software/PC_Application/Application.pro index c1a8681..28a273d 100644 --- a/Software/PC_Application/Application.pro +++ b/Software/PC_Application/Application.pro @@ -33,6 +33,7 @@ HEADERS += \ Traces/tracewidget.h \ Traces/tracexyplot.h \ Traces/xyplotaxisdialog.h \ + VNA/portextension.h \ VNA/vna.h \ appwindow.h \ averaging.h \ @@ -78,6 +79,7 @@ SOURCES += \ Traces/tracewidget.cpp \ Traces/tracexyplot.cpp \ Traces/xyplotaxisdialog.cpp \ + VNA/portextension.cpp \ VNA/vna.cpp \ appwindow.cpp \ averaging.cpp \ @@ -111,6 +113,7 @@ FORMS += \ Traces/traceimportdialog.ui \ Traces/tracewidget.ui \ Traces/xyplotaxisdialog.ui \ + VNA/portextensioneditdialog.ui \ main.ui \ preferencesdialog.ui diff --git a/Software/PC_Application/Calibration/calibration.cpp b/Software/PC_Application/Calibration/calibration.cpp index 77c5a2d..dc62c9f 100644 --- a/Software/PC_Application/Calibration/calibration.cpp +++ b/Software/PC_Application/Calibration/calibration.cpp @@ -44,7 +44,7 @@ bool Calibration::calculationPossible(Calibration::Type type) { return SanityCheckSamples(Measurements(type, false)); } - +#include bool Calibration::constructErrorTerms(Calibration::Type type) { if(!calculationPossible(type)) { @@ -700,7 +700,7 @@ istream& operator >>(istream &in, Calibration &c) } for(auto t : Calibration::Types()) { if(Calibration::TypeToString(t) == QString::fromStdString(line)) { - // try to apply this calibration type + // try to P2 this calibration type if(c.calculationPossible(t)) { c.constructErrorTerms(t); } else { diff --git a/Software/PC_Application/Calibration/calkit.cpp b/Software/PC_Application/Calibration/calkit.cpp index 6f06f01..970267b 100644 --- a/Software/PC_Application/Calibration/calkit.cpp +++ b/Software/PC_Application/Calibration/calkit.cpp @@ -239,7 +239,7 @@ double Calkit::minFreq(bool TRL) return TRL_line_minfreq; } else { fillTouchstoneCache(); - double min = std::numeric_limits::min(); + double min = 0; array ts_list = {ts_open, ts_short, ts_load, ts_through}; // find the highest minimum frequency in all measurement files for(auto ts : ts_list) { diff --git a/Software/PC_Application/VNA/portextension.cpp b/Software/PC_Application/VNA/portextension.cpp new file mode 100644 index 0000000..6558261 --- /dev/null +++ b/Software/PC_Application/VNA/portextension.cpp @@ -0,0 +1,233 @@ +#include "portextension.h" +#include "ui_portextensioneditdialog.h" +#include +#include + +using namespace std; + +PortExtension::PortExtension() + : QObject() +{ + port1.enabled = false; + port1.frequency = 0; + port1.loss = 0; + port1.DCloss = 0; + port1.delay = 0; + port1.velocityFactor = 0.66; + port2.enabled = false; + port2.frequency = 0; + port2.loss = 0; + port2.DCloss = 0; + port2.delay = 0; + port2.velocityFactor = 0.66; + + measuring = false; + kit = nullptr; +} + +void PortExtension::applyToMeasurement(Protocol::Datapoint &d) +{ + if(measuring) { + if(measurements.size() > 0) { + if(d.pointNum == 0) { + // sweep complete, evaluate measurement + // TODO + if(msgBox) { + msgBox->close(); + msgBox = nullptr; + } + } else { + measurements.push_back(d); + } + } else if(d.pointNum == 0) { + // first point of sweep, start measurement + measurements.push_back(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; + if(port1.frequency != 0) { + db_attennuation += port1.loss * sqrt(d.frequency / port1.frequency); + } + // 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; + } + if(port2.enabled) { + auto phase = -2 * M_PI * port2.delay * d.frequency; + auto db_attennuation = port2.DCloss; + if(port2.frequency != 0) { + db_attennuation += port2.loss * sqrt(d.frequency / port2.frequency); + } + // 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.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(); + } +} + +void PortExtension::edit() +{ + constexpr double c = 299792458; + + auto dialog = new QDialog(); + auto ui = new Ui::PortExtensionEditDialog(); + ui->setupUi(dialog); + + // set initial values + ui->P1Time->setUnit("s"); + ui->P1Time->setPrefixes("pnum "); + ui->P1Distance->setUnit("m"); + ui->P1Distance->setPrefixes("m "); + ui->P1DCloss->setUnit("db"); + ui->P1Loss->setUnit("db"); + ui->P1Frequency->setUnit("Hz"); + ui->P1Frequency->setPrefixes(" kMG"); + ui->P1Time->setValue(port1.delay); + ui->P1Velocity->setValue(port1.velocityFactor); + ui->P1Distance->setValue(port1.delay * port1.velocityFactor * c); + ui->P1DCloss->setValue(port1.DCloss); + ui->P1Loss->setValue(port1.loss); + ui->P1Frequency->setValue(port1.frequency); + if(!kit) { + ui->P1calkit->setEnabled(false); + } + + ui->P2Time->setUnit("s"); + ui->P2Time->setPrefixes("pnum "); + ui->P2Distance->setUnit("m"); + ui->P2Distance->setPrefixes("m "); + ui->P2DCloss->setUnit("db"); + ui->P2Loss->setUnit("db"); + ui->P2Frequency->setUnit("Hz"); + ui->P2Frequency->setPrefixes(" kMG"); + ui->P2Time->setValue(port2.delay); + ui->P2Velocity->setValue(port2.velocityFactor); + ui->P2Distance->setValue(port2.delay * port2.velocityFactor * c); + ui->P2DCloss->setValue(port2.DCloss); + ui->P2Loss->setValue(port2.loss); + ui->P2Frequency->setValue(port2.frequency); + if(!kit) { + ui->P2calkit->setEnabled(false); + } + + // connections to link delay and distance + connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c); + }); + connect(ui->P1Distance, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P1Time->setValueQuiet(newval / (ui->P1Velocity->value() * c)); + }); + connect(ui->P1Velocity, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P1Time->setValueQuiet(ui->P1Distance->value() / (newval * c)); + }); + connect(ui->P1short, &QPushButton::pressed, [=](){ + isOpen = false; + isPort1 = true; + isIdeal = ui->P1ideal->isChecked(); + startMeasurement(); + }); + connect(ui->P1open, &QPushButton::pressed, [=](){ + isOpen = true; + isPort1 = true; + isIdeal = ui->P1ideal->isChecked(); + startMeasurement(); + }); + + connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c); + }); + connect(ui->P2Distance, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P2Time->setValueQuiet(newval / (ui->P2Velocity->value() * c)); + }); + connect(ui->P2Velocity, &SIUnitEdit::valueChanged, [=](double newval) { + ui->P2Time->setValueQuiet(ui->P2Distance->value() / (newval * c)); + }); + connect(ui->P2short, &QPushButton::pressed, [=](){ + isOpen = false; + isPort1 = false; + isIdeal = ui->P2ideal->isChecked(); + startMeasurement(); + }); + connect(ui->P2open, &QPushButton::pressed, [=](){ + isOpen = true; + isPort1 = false; + isIdeal = ui->P2ideal->isChecked(); + startMeasurement(); + }); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){ + port1.delay = ui->P1Time->value(); + port1.velocityFactor = ui->P1Velocity->value(); + port1.DCloss = ui->P1DCloss->value(); + port1.loss = ui->P1Loss->value(); + port1.frequency = ui->P1Frequency->value(); + port2.delay = ui->P2Time->value(); + port2.velocityFactor = ui->P2Velocity->value(); + port2.DCloss = ui->P2DCloss->value(); + port2.loss = ui->P2Loss->value(); + port2.frequency = ui->P2Frequency->value(); + dialog->accept(); + }); + connect(ui->buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + dialog->show(); +} + +void PortExtension::startMeasurement() +{ + measurements.clear(); + msgBox = new QMessageBox(QMessageBox::Information, "Auto port extension", "Taking measurement...", QMessageBox::Cancel); + connect(msgBox, &QMessageBox::rejected, [=]() { + measuring = false; + measurements.clear(); + }); + msgBox->show(); + measuring = true; +} + +QToolBar *PortExtension::createToolbar() +{ + auto tb = new QToolBar("Port Extension"); + auto editButton = new QPushButton("Port Extension"); + auto p1enable = new QCheckBox("Port 1"); + auto p2enable = new QCheckBox("Port 2"); + connect(p1enable, &QCheckBox::clicked, [=]() { + port1.enabled = p1enable->isChecked(); + }); + connect(p2enable, &QCheckBox::clicked, [=]() { + port2.enabled = p2enable->isChecked(); + }); + connect(editButton, &QPushButton::pressed, this, &PortExtension::edit); + tb->addWidget(editButton); + tb->addWidget(p1enable); + tb->addWidget(p2enable); + return tb; +} + +void PortExtension::setCalkit(Calkit *kit) +{ + this->kit = kit; +} diff --git a/Software/PC_Application/VNA/portextension.h b/Software/PC_Application/VNA/portextension.h new file mode 100644 index 0000000..a7d145e --- /dev/null +++ b/Software/PC_Application/VNA/portextension.h @@ -0,0 +1,44 @@ +#ifndef PORTEXTENSION_H +#define PORTEXTENSION_H + +#include +#include "../VNA_embedded/Application/Communication/Protocol.hpp" +#include +#include "Calibration/calkit.h" +#include + +class PortExtension : public QObject +{ + Q_OBJECT +public: + PortExtension(); + void applyToMeasurement(Protocol::Datapoint& d); + QToolBar *createToolbar(); + void setCalkit(Calkit *kit); +public slots: + void edit(); + +private: + void startMeasurement(); + class Extension { + public: + bool enabled; + double delay; + double velocityFactor; + double DCloss; + double loss; + double frequency; + }; + Extension port1, port2; + + // status variables for automatic measurements + Calkit *kit; + bool measuring; + bool isPort1; + bool isOpen; + bool isIdeal; + std::vector measurements; + QMessageBox *msgBox; +}; + +#endif // PORTEXTENSION_H diff --git a/Software/PC_Application/VNA/portextensiondialog.h b/Software/PC_Application/VNA/portextensiondialog.h new file mode 100644 index 0000000..59fc420 --- /dev/null +++ b/Software/PC_Application/VNA/portextensiondialog.h @@ -0,0 +1,25 @@ +#ifndef PORTEXTENSIONDIALOG_H +#define PORTEXTENSIONDIALOG_H + +#include + +namespace Ui { +class PortExtensionDialog; +} + +class PortExtensionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PortExtensionDialog(QWidget *parent = nullptr); + ~PortExtensionDialog(); + +private slots: + void on_buttonBox_accepted(); + +private: + Ui::PortExtensionDialog *ui; +}; + +#endif // PORTEXTENSIONDIALOG_H diff --git a/Software/PC_Application/VNA/portextensioneditdialog.ui b/Software/PC_Application/VNA/portextensioneditdialog.ui new file mode 100644 index 0000000..f63dba1 --- /dev/null +++ b/Software/PC_Application/VNA/portextensioneditdialog.ui @@ -0,0 +1,334 @@ + + + PortExtensionEditDialog + + + + 0 + 0 + 318 + 476 + + + + Port Extension + + + true + + + + + + 0 + + + + Port 1 + + + + + + Delay + + + + + + Distance: + + + + + + + + + + Time: + + + + + + + + + + Velocity Factor: + + + + + + + + + + + + + Loss + + + + + + + + At DC: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + at + + + + + + + + + + + + + + + Determine automatically + + + + + + Assume ideal open/short + + + true + + + + + + + Use definition from calibration kit + + + + + + + + + Measure short + + + + + + + Measure open + + + + + + + + + + + + + Port 2 + + + + + + Delay + + + + + + Distance: + + + + + + + + + + Time: + + + + + + + + + + Velocity Factor: + + + + + + + + + + + + + Loss + + + + + + + + At DC: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + at + + + + + + + + + + + + + + + Determine automatically + + + + + + Assume ideal open/short + + + true + + + + + + + Use definition from calibration kit + + + + + + + + + Measure short + + + + + + + Measure open + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+
+ + +
diff --git a/Software/PC_Application/VNA/vna.cpp b/Software/PC_Application/VNA/vna.cpp index 0f896aa..d85d416 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -109,6 +109,7 @@ VNA::VNA(AppWindow *window) connect(calEditKit, &QAction::triggered, [=](){ cal.getCalibrationKit().edit(); }); + portExtension.setCalkit(&cal.getCalibrationKit()); // Tools menu auto toolsMenu = new QMenu("Tools"); @@ -310,6 +311,10 @@ VNA::VNA(AppWindow *window) window->addToolBar(tb_cal); toolbars.insert(tb_cal); + auto tb_portExtension = portExtension.createToolbar(); + window->addToolBar(tb_portExtension); + toolbars.insert(tb_portExtension); + markerModel = new TraceMarkerModel(traceModel); @@ -379,6 +384,7 @@ void VNA::initializeDevice() if(QFile::exists(filename)) { cal.openFromFile(filename); ApplyCalibration(cal.getType()); + portExtension.setCalkit(&cal.getCalibrationKit()); } removeDefaultCal->setEnabled(true); } else { @@ -418,6 +424,8 @@ void VNA::NewDatapoint(Protocol::Datapoint d) if(calValid) { cal.correctMeasurement(d); } + portExtension.applyToMeasurement(d); + traceModel.addVNAData(d); emit dataChanged(); if(d.pointNum == settings.points - 1) { diff --git a/Software/PC_Application/VNA/vna.h b/Software/PC_Application/VNA/vna.h index 48f6917..e92e376 100644 --- a/Software/PC_Application/VNA/vna.h +++ b/Software/PC_Application/VNA/vna.h @@ -8,6 +8,7 @@ #include "CustomWidgets/tilewidget.h" #include "Device/device.h" #include +#include "portextension.h" class VNA : public Mode { @@ -69,6 +70,8 @@ private: QMenu *defaultCalMenu; QAction *assignDefaultCal, *removeDefaultCal; + PortExtension portExtension; + // Status Labels QLabel *lAverages;