diff --git a/Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp b/Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp index 25492df..5bfbe66 100644 --- a/Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp +++ b/Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp @@ -218,14 +218,203 @@ void LibreCALDialog::updateDeviceStatus() } void LibreCALDialog::startCalibration() +{ + disableUI(); + + ui->progressCal->setValue(0); + ui->lCalibrationStatus->setText("Creating calibration kit from coefficients..."); + ui->lCalibrationStatus->setStyleSheet("QLabel { color : black; }"); + auto& kit = cal->getKit(); + kit.clearStandards(); + kit.manufacturer = "LibreCAL ("+coeffSet.name+")"; + kit.serialnumber = device->serial(); + kit.description = "Automatically created from LibreCAL module"; + std::vector openStandards; + std::vector shortStandards; + std::vector loadStandards; + std::vector throughStandards; + for(int i=1;i<=device->getNumPorts();i++) { + if(coeffSet.opens[i-1]->t.points() > 0) { + auto o = new CalStandard::Open(); + o->setName("Port "+QString::number(i)); + o->setMeasurement(coeffSet.opens[i-1]->t); + openStandards.push_back(o); + kit.standards.push_back(o); + } + if(coeffSet.shorts[i-1]->t.points() > 0) { + auto o = new CalStandard::Short(); + o->setName("Port "+QString::number(i)); + o->setMeasurement(coeffSet.shorts[i-1]->t); + shortStandards.push_back(o); + kit.standards.push_back(o); + } + if(coeffSet.loads[i-1]->t.points() > 0) { + auto o = new CalStandard::Load(); + o->setName("Port "+QString::number(i)); + o->setMeasurement(coeffSet.loads[i-1]->t); + loadStandards.push_back(o); + kit.standards.push_back(o); + } + for(int j=i+1;j<=device->getNumPorts();j++) { + auto c = coeffSet.getThrough(i,j); + if(!c) { + continue; + } + if(c->t.points() > 0) { + auto o = new CalStandard::Through(); + o->setName("Port "+QString::number(i)+" to "+QString::number(j)); + o->setMeasurement(c->t); + throughStandards.push_back(o); + kit.standards.push_back(o); + } + } + } + ui->lCalibrationStatus->setText("Creating calibration measurements..."); + cal->reset(); + auto vnaPorts = VirtualDevice::getInfo(VirtualDevice::getConnected()).ports; + set openMeasurements; + set shortMeasurements; + set loadMeasurements; + vector throughMeasurements; + for(int p=0;psetPort(p+1); + open->setStandard(openStandards[portAssignment[p]-1]); + openMeasurements.insert(open); + cal->measurements.push_back(open); + + auto _short = new CalibrationMeasurement::Short(cal); + _short->setPort(p+1); + _short->setStandard(shortStandards[portAssignment[p]-1]); + shortMeasurements.insert(_short); + cal->measurements.push_back(_short); + + auto load = new CalibrationMeasurement::Load(cal); + load->setPort(p+1); + load->setStandard(loadStandards[portAssignment[p]-1]); + loadMeasurements.insert(load); + cal->measurements.push_back(load); + for(int p2=p+1;p2setPort1(p+1); + through->setPort2(p2+1); + // find correct through standard + int libreCALp1 = portAssignment[p]; + int libreCALp2 = portAssignment[p2]; + QString forwardName = "Port "+QString::number(libreCALp1)+" to "+QString::number(libreCALp2); + QString reverseName = "Port "+QString::number(libreCALp2)+" to "+QString::number(libreCALp1); + for(auto ts : throughStandards) { + if(ts->getName() == forwardName) { + through->setStandard(ts); + through->setReverseStandard(false); + } else if(ts->getName() == reverseName) { + through->setStandard(ts); + through->setReverseStandard(true); + } + } + throughMeasurements.push_back(through); + cal->measurements.push_back(through); + } + } + + ui->lCalibrationStatus->setText("Taking calibration measurements..."); + + measurementsTaken = 0; + + auto setTerminationOnAllUsedPorts = [=](CalDevice::Standard s) { + for(auto p : portAssignment) { + if(p > 0) { + device->setStandard(p, s); + } + } + }; + + auto startNextCalibrationStep = [=]() { + // indicate calibration percentage + auto totalMeasurements = 3 + throughMeasurements.size(); + ui->progressCal->setValue(measurementsTaken * 100 / totalMeasurements); + switch(measurementsTaken) { + case 0: + setTerminationOnAllUsedPorts(CalDevice::Standard::Open); + emit cal->startMeasurements(openMeasurements); + break; + case 1: + setTerminationOnAllUsedPorts(CalDevice::Standard::Short); + emit cal->startMeasurements(shortMeasurements); + break; + case 2: + setTerminationOnAllUsedPorts(CalDevice::Standard::Load); + emit cal->startMeasurements(loadMeasurements); + break; + default: { + // into through measurements now + int throughIndex = measurementsTaken - 3; + if(throughIndex >= throughMeasurements.size()) { + // this was the last measurement + // Try to apply the calibration + Calibration::CalType type; + type.type = Calibration::Type::SOLT; + for(int i=0;i 0) { + // this VNA port was used in the calibration + type.usedPorts.push_back(i+1); + } + } + auto res = cal->compute(type); + if(res) { + ui->progressCal->setValue(100); + ui->lCalibrationStatus->setText("Calibration activated."); + } else { + ui->progressCal->setValue(0); + ui->lCalibrationStatus->setText("Failed to activate calibration."); + ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }"); + } + // severe connection to this function + disconnect(cal, &Calibration::measurementsUpdated, this, nullptr); + enableUI(); + break; + } + setTerminationOnAllUsedPorts(CalDevice::Standard::None); + auto m = throughMeasurements[throughIndex]; + device->setStandard(m->getPort1(), CalDevice::Standard::Through); + device->setStandard(m->getPort2(), CalDevice::Standard::Through); + emit cal->startMeasurements({m}); + } + break; + } + measurementsTaken++; + }; + + connect(cal, &Calibration::measurementsUpdated, this, startNextCalibrationStep); + + startNextCalibrationStep(); +} + +void LibreCALDialog::disableUI() { ui->cbDevice->setEnabled(false); ui->cbCoefficients->setEnabled(false); ui->start->setEnabled(false); + for(auto cb : portAssignmentComboBoxes) { + cb->setEnabled(false); + } +} - ui->lCalibrationStatus->setText("Creating calibration kit from coefficients..."); - auto& kit = cal->getKit(); - kit = Calkit::fromLibreCAL(device, coeffSet); +void LibreCALDialog::enableUI() +{ + ui->cbDevice->setEnabled(true); + ui->cbCoefficients->setEnabled(true); + ui->start->setEnabled(true); + for(auto cb : portAssignmentComboBoxes) { + cb->setEnabled(true); + } } void LibreCALDialog::createPortAssignmentUI() @@ -233,6 +422,7 @@ void LibreCALDialog::createPortAssignmentUI() auto layout = static_cast(ui->assignmentBox->layout()); // Clear any possible previous elements portAssignment.clear(); + portAssignmentComboBoxes.clear(); while(layout->rowCount() > 1) { layout->removeRow(1); } @@ -255,7 +445,13 @@ void LibreCALDialog::createPortAssignmentUI() emit portAssignmentChanged(); }); // try to set the default - comboBox->setCurrentIndex(p); + if(comboBox->count() > p) { + comboBox->setCurrentIndex(p); + } else { + // port not available, set to unused + comboBox->setCurrentIndex(0); + } layout->addRow(label, comboBox); + portAssignmentComboBoxes.push_back(comboBox); } } diff --git a/Software/PC_Application/Calibration/LibreCAL/librecaldialog.h b/Software/PC_Application/Calibration/LibreCAL/librecaldialog.h index 15c2f0b..997061c 100644 --- a/Software/PC_Application/Calibration/LibreCAL/librecaldialog.h +++ b/Software/PC_Application/Calibration/LibreCAL/librecaldialog.h @@ -6,6 +6,7 @@ #include #include +#include namespace Ui { class LibreCALDialog; @@ -27,6 +28,8 @@ private slots: void updateDeviceStatus(); void startCalibration(); private: + void disableUI(); + void enableUI(); void createPortAssignmentUI(); Ui::LibreCALDialog *ui; Calibration *cal; @@ -35,6 +38,9 @@ private: QTimer updateTimer; bool busy; std::vector portAssignment; + std::vector portAssignmentComboBoxes; + + int measurementsTaken; }; #endif // LIBRECALDIALOG_H diff --git a/Software/PC_Application/Calibration/calibration.cpp b/Software/PC_Application/Calibration/calibration.cpp index 0689568..221fba9 100644 --- a/Software/PC_Application/Calibration/calibration.cpp +++ b/Software/PC_Application/Calibration/calibration.cpp @@ -209,22 +209,25 @@ void Calibration::edit() updateCalButtons(); }); - connect(ui->activate, &QPushButton::clicked, [=](){ - auto cal = availableCals[ui->calibrationList->currentRow()]; - if(compute(cal)) { - updateCalibrationList(); - updateCalStatistics(); - updateCalButtons(); - } - }); - - connect(ui->deactivate, &QPushButton::clicked, [=](){ - deactivate(); + connect(this, &Calibration::activated, d, [=](){ updateCalibrationList(); updateCalStatistics(); updateCalButtons(); }); + connect(this, &Calibration::deactivated, d, [=](){ + updateCalibrationList(); + updateCalStatistics(); + updateCalButtons(); + }); + + connect(ui->activate, &QPushButton::clicked, [=](){ + auto cal = availableCals[ui->calibrationList->currentRow()]; + compute(cal); + }); + + connect(ui->deactivate, &QPushButton::clicked, this, &Calibration::deactivate); + ui->table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); auto updateTableEditButtons = [=](){ @@ -263,6 +266,9 @@ void Calibration::edit() if(measurements.size() > 0) { if(!InformationBox::AskQuestion("Create default entries?", "Do you want to remove all existing entries and create default calibration measurements instead?", true)) { // user aborted + ui->createDefault->blockSignals(true); + ui->createDefault->setCurrentIndex(0); + ui->createDefault->blockSignals(false); return; } measurements.clear(); @@ -345,6 +351,10 @@ void Calibration::edit() d->show(); }); + connect(ui->editCalkit, &QPushButton::clicked, [=](){ + kit.edit(); + }); + QObject::connect(ui->table, &QTableWidget::currentCellChanged, updateTableEditButtons); auto addMenu = new QMenu(); diff --git a/Software/PC_Application/Calibration/calibration.h b/Software/PC_Application/Calibration/calibration.h index 34f89e7..b7abd10 100644 --- a/Software/PC_Application/Calibration/calibration.h +++ b/Software/PC_Application/Calibration/calibration.h @@ -9,6 +9,8 @@ class Calibration : public QObject, public Savable { Q_OBJECT + + friend class LibreCALDialog; public: Calibration(); @@ -20,7 +22,7 @@ public: class CalType { public: Type type; - std::vector usedPorts; + std::vector usedPorts; // port count starts at 1 QString getReadableDescription(); QString getShortString(); diff --git a/Software/PC_Application/Calibration/calibrationdialogui.ui b/Software/PC_Application/Calibration/calibrationdialogui.ui index 3e6a04c..00cc5ba 100644 --- a/Software/PC_Application/Calibration/calibrationdialogui.ui +++ b/Software/PC_Application/Calibration/calibrationdialogui.ui @@ -167,6 +167,21 @@ Calibration + + + + + 0 + 0 + + + + Edit +Calibration +Kit + + + diff --git a/Software/PC_Application/Calibration/calibrationmeasurement.cpp b/Software/PC_Application/Calibration/calibrationmeasurement.cpp index 17bed2c..65a1a23 100644 --- a/Software/PC_Application/Calibration/calibrationmeasurement.cpp +++ b/Software/PC_Application/Calibration/calibrationmeasurement.cpp @@ -6,6 +6,7 @@ #include #include #include +#include using namespace std; @@ -366,6 +367,8 @@ QWidget *CalibrationMeasurement::TwoPort::createSettingsWidget() auto cbPort1 = new QComboBox(); auto label2 = new QLabel(" to "); auto cbPort2 = new QComboBox(); + auto cbReverse = new QCheckBox("Reversed"); + cbReverse->setToolTip("Enable this option if the calibration standard is defined with the port order swapped"); auto dev = VirtualDevice::getConnected(); if(dev) { for(int i=1;i<=dev->getInfo().ports;i++) { @@ -389,12 +392,16 @@ QWidget *CalibrationMeasurement::TwoPort::createSettingsWidget() cbPort2->addItem(QString::number(port2)); cbPort2->setCurrentText(QString::number(port2)); } + cbReverse->setChecked(reverseStandard); connect(cbPort1, qOverload(&QComboBox::currentIndexChanged), [=](){ setPort1(cbPort1->currentText().toInt()); }); connect(cbPort2, qOverload(&QComboBox::currentIndexChanged), [=](){ setPort2(cbPort2->currentText().toInt()); }); + connect(cbReverse, &QCheckBox::toggled, [=](){ + setReverseStandard(cbReverse->isChecked()); + }); connect(this, &TwoPort::port1Changed, cbPort1, [=](){ auto string = QString::number(port1); if(cbPort1->findText(string) < 0) { @@ -411,6 +418,9 @@ QWidget *CalibrationMeasurement::TwoPort::createSettingsWidget() } cbPort2->setCurrentText(string); }); + connect(this, &TwoPort::reverseStandardChanged, cbReverse, [=](){ + cbReverse->setChecked(reverseStandard); + }); auto ret = new QWidget(); auto layout = new QHBoxLayout; layout->setContentsMargins(0,0,0,0); @@ -418,6 +428,7 @@ QWidget *CalibrationMeasurement::TwoPort::createSettingsWidget() layout->addWidget(cbPort1); layout->addWidget(label2); layout->addWidget(cbPort2); + layout->addWidget(cbReverse); layout->setStretch(1, 1); layout->setStretch(3, 1); ret->setLayout(layout); @@ -429,6 +440,7 @@ nlohmann::json CalibrationMeasurement::TwoPort::toJSON() auto j = Base::toJSON(); j["port1"] = port1; j["port2"] = port2; + j["reverseStandard"] = reverseStandard; nlohmann::json jpoints; for(auto &p : points) { nlohmann::json jpoint; @@ -446,6 +458,7 @@ void CalibrationMeasurement::TwoPort::fromJSON(nlohmann::json j) Base::fromJSON(j); port1 = j.value("port1", 0); port2 = j.value("port2", 0); + reverseStandard = j.value("reverseStandard", false); if(j.contains("points")) { for(auto jpoint : j["points"]) { Point p; @@ -479,7 +492,12 @@ Sparam CalibrationMeasurement::TwoPort::getMeasured(double frequency) Sparam CalibrationMeasurement::TwoPort::getActual(double frequency) { - return static_cast(standard)->toSparam(frequency); + auto param = static_cast(standard)->toSparam(frequency); + if(reverseStandard) { + swap(param.m11, param.m22); + swap(param.m12, param.m21); + } + return param; } int CalibrationMeasurement::TwoPort::getPort2() const @@ -503,6 +521,14 @@ void CalibrationMeasurement::TwoPort::setPort2(int p) } } +void CalibrationMeasurement::TwoPort::setReverseStandard(bool reverse) +{ + if(reverseStandard != reverse) { + reverseStandard = reverse; + emit reverseStandardChanged(reverse); + } +} + int CalibrationMeasurement::TwoPort::getPort1() const { return port1; diff --git a/Software/PC_Application/Calibration/calibrationmeasurement.h b/Software/PC_Application/Calibration/calibrationmeasurement.h index a488ff5..93055b0 100644 --- a/Software/PC_Application/Calibration/calibrationmeasurement.h +++ b/Software/PC_Application/Calibration/calibrationmeasurement.h @@ -141,7 +141,8 @@ public: TwoPort(Calibration *cal) : Base(cal), port1(0), - port2(0){} + port2(0), + reverseStandard(false){} virtual double minFreq() override; virtual double maxFreq() override; @@ -164,12 +165,15 @@ public: public slots: void setPort1(int p); void setPort2(int p); + void setReverseStandard(bool reverse); protected: signals: void port1Changed(int p); void port2Changed(int p); + void reverseStandardChanged(bool r); protected: int port1, port2; + bool reverseStandard; // Set to true if standard is defined with ports swapped class Point { public: double frequency; diff --git a/Software/PC_Application/Calibration/calkit.cpp b/Software/PC_Application/Calibration/calkit.cpp index a536dc6..07c8748 100644 --- a/Software/PC_Application/Calibration/calkit.cpp +++ b/Software/PC_Application/Calibration/calkit.cpp @@ -328,47 +328,6 @@ Calkit Calkit::fromFile(QString filename) return c; } -Calkit Calkit::fromLibreCAL(CalDevice *device, CalDevice::CoefficientSet s) -{ - Calkit ret; - ret.manufacturer = "LibreCAL ("+s.name+")"; - ret.serialnumber = device->serial(); - ret.description = "Automatically created from LibreCAL module"; - for(int i=1;i<=device->getNumPorts();i++) { - if(s.opens[i-1]->t.points() > 0) { - auto o = new CalStandard::Open(); - o->setName("Port "+QString::number(i)+" Open"); - o->setMeasurement(s.opens[i-1]->t); - ret.standards.push_back(o); - } - if(s.shorts[i-1]->t.points() > 0) { - auto o = new CalStandard::Short(); - o->setName("Port "+QString::number(i)+" Short"); - o->setMeasurement(s.shorts[i-1]->t); - ret.standards.push_back(o); - } - if(s.loads[i-1]->t.points() > 0) { - auto o = new CalStandard::Load(); - o->setName("Port "+QString::number(i)+" Load"); - o->setMeasurement(s.loads[i-1]->t); - ret.standards.push_back(o); - } - for(int j=i+1;j<=device->getNumPorts();j++) { - auto c = s.getThrough(i,j); - if(!c) { - continue; - } - if(c->t.points() > 0) { - auto o = new CalStandard::Through(); - o->setName("Port "+QString::number(i)+" to "+QString::number(j)+" Through"); - o->setMeasurement(c->t); - ret.standards.push_back(o); - } - } - } - return ret; -} - void Calkit::edit(std::function updateCal) { auto dialog = new CalkitDialog(*this); diff --git a/Software/PC_Application/Calibration/calkit.h b/Software/PC_Application/Calibration/calkit.h index 59db070..41becb7 100644 --- a/Software/PC_Application/Calibration/calkit.h +++ b/Software/PC_Application/Calibration/calkit.h @@ -15,6 +15,7 @@ class Calkit : public Savable { friend class CalkitDialog; + friend class LibreCALDialog; public: Calkit(); Calkit(const Calkit&) = default; @@ -43,7 +44,6 @@ public: void toFile(QString filename); static Calkit fromFile(QString filename); - static Calkit fromLibreCAL(CalDevice *device, CalDevice::CoefficientSet s); void edit(std::function updateCal = nullptr); std::vector getStandards() const; diff --git a/Software/PC_Application/VNA/vna.cpp b/Software/PC_Application/VNA/vna.cpp index 456f420..189eb7d 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -19,6 +19,7 @@ #include "CustomWidgets/informationbox.h" #include "Deembedding/manualdeembeddingdialog.h" #include "Calibration/manualcalibrationdialog.h" +#include "Calibration/LibreCAL/librecaldialog.h" #include "Util/util.h" #include "Tools/parameters.h" @@ -111,6 +112,12 @@ VNA::VNA(AppWindow *window, QString name) // }); }); + auto calElectronic = calMenu->addAction("Electronic Calibration"); + connect(calElectronic, &QAction::triggered, [=](){ + auto d = new LibreCALDialog(&cal); + d->show(); + }); + calMenu->addSeparator(); auto calImportTerms = calMenu->addAction("Import error terms as traces");