Compare commits

...

4 commits

Author SHA1 Message Date
Jan Käberich 5d00d4786b new calibration type without receiver matching for lossy calibration standards
Some checks failed
Build / PC_Application_Ubuntu (push) Has been cancelled
Build / PC_Application_RPi5 (push) Has been cancelled
Build / PC_Application_Windows (push) Has been cancelled
Build / PC_Application_OSX (push) Has been cancelled
Build / PC_Application_OSX_13 (push) Has been cancelled
Build / Embedded_Firmware (push) Has been cancelled
HIL_Tests / Get_Repository (push) Has been cancelled
Unit_Tests / Tests (push) Has been cancelled
HIL_Tests / PC_Application_RPi5 (push) Has been cancelled
HIL_Tests / Embedded_Firmware (push) Has been cancelled
HIL_Tests / HIL (push) Has been cancelled
2025-09-22 16:58:49 +02:00
Jan Käberich 3e327e7e6b option to use already existing measurements for calibration 2025-09-22 16:01:38 +02:00
Jan Käberich b2fd49d800 increase resolution for referenced data in 0xE0 manual control dialog 2025-09-17 10:47:27 +02:00
Jan Käberich f327a4b4a0 allow firmware updates for version 0xE0 2025-09-17 10:46:44 +02:00
14 changed files with 187 additions and 13 deletions

View file

@ -6,6 +6,7 @@
#include "Util/util.h"
#include "LibreCAL/librecaldialog.h"
#include "preferences.h"
#include "Traces/sparamtraceselectordialog.h"
#include "Tools/Eigen/Dense"
@ -303,6 +304,7 @@ QString Calibration::TypeToString(Calibration::Type type)
case Type::None: return "None";
case Type::OSL: return "OSL";
case Type::SOLT: return "SOLT";
case Type::SOLTwithoutRxMatch: return "SOLTwithoutRxMatch";
case Type::ThroughNormalization: return "ThroughNormalization";
case Type::TRL: return "TRL";
case Type::Last: return "Invalid";
@ -408,7 +410,7 @@ void Calibration::correctTraces(std::map<QString, Trace *> traceSet)
}
}
void Calibration::edit()
void Calibration::edit(TraceModel *traceModel)
{
auto d = new QDialog();
d->setAttribute(Qt::WA_DeleteOnClose);
@ -510,6 +512,10 @@ void Calibration::edit()
ui->bDelete->setEnabled(ui->table->currentRow() >= 0);
ui->bMoveUp->setEnabled(ui->table->currentRow() >= 1);
ui->bMoveDown->setEnabled(ui->table->currentRow() >= 0 && ui->table->currentRow() < ui->table->rowCount() - 1);
auto selected = ui->table->selectionModel()->selectedRows();
ui->measure->setEnabled(selected.size() > 0);
ui->selectMeasurement->setEnabled(traceModel && selected.size() == 1);
ui->clearMeasurement->setEnabled(selected.size() > 0);
};
auto updateMeasurementTable = [=](){
@ -619,6 +625,35 @@ void Calibration::edit()
emit startMeasurements(m);
});
connect(ui->selectMeasurement, &QPushButton::clicked, [=](){
auto selected = ui->table->selectionModel()->selectedRows();
if(selected.size() != 1) {
InformationBox::ShowError("Unable to select measurement", "Exactly one measurement must be selected");
return;
}
// figure out which S parameters we need
auto meas = measurements[selected[0].row()];
auto ports = meas->getPorts();
if(ports.size() == 0) {
InformationBox::ShowError("Unable to select measurement", "Selecting measurements for this type of calibration measurement is not supported");
return;
}
auto selector = new SParamTraceSelectorDialog(*traceModel, ports);
connect(selector, &SParamTraceSelectorDialog::tracesSelected, d, [=](std::vector<DeviceDriver::VNAMeasurement> traceMeasurements){
clearMeasurements({meas});
for(const auto &tm : traceMeasurements) {
addMeasurements({meas}, tm);
}
updateMeasurementTable();
updateCalibrationList();
});
selector->show();
});
if(!traceModel) {
// can not select a measurement if no trace model is supplied
ui->selectMeasurement->setEnabled(false);
}
connect(this, &Calibration::measurementsUpdated, d, [=](){
updateMeasurementTable();
updateCalibrationList();
@ -665,7 +700,7 @@ void Calibration::edit()
});
});
QObject::connect(ui->table, &QTableWidget::currentCellChanged, updateTableEditButtons);
QObject::connect(ui->table, &QTableWidget::itemSelectionChanged, updateTableEditButtons);
auto addMenu = new QMenu();
for(auto t : CalibrationMeasurement::Base::availableTypes()) {
@ -809,6 +844,17 @@ Calibration::Point Calibration::computeSOLT(double f)
return point;
}
Calibration::Point Calibration::computeSOLTwithoutRxMatch(double f) {
// This is very similar to SOLT but it assumes that receiver matching at the VNA is perfect.
// It can be used if the through calibration standard is very lossy which would result in
// very noisy values for the receiver match
auto p = computeSOLT(f);
for(auto &l : p.L) {
fill(l.begin(), l.end(), 0.0);
}
return p;
}
Calibration::Point Calibration::computeThroughNormalization(double f)
{
Point point = createInitializedPoint(f);
@ -1736,6 +1782,7 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
case Type::None:
return true; // Always possible to reset the calibration
case Type::SOLT:
case Type::SOLTwithoutRxMatch:
// through measurements between all ports
for(unsigned int i=1;i<=type.usedPorts.size();i++) {
for(unsigned int j=i+1;j<=type.usedPorts.size();j++) {
@ -1829,6 +1876,7 @@ bool Calibration::compute(Calibration::CalType type)
switch(type.type) {
case Type::OSL: p = computeOSL(f); break;
case Type::SOLT: p = computeSOLT(f); break;
case Type::SOLTwithoutRxMatch: p = computeSOLTwithoutRxMatch(f); break;
case Type::ThroughNormalization: p = computeThroughNormalization(f); break;
case Type::TRL: p = computeTRL(f); break;
case Type::None:
@ -1858,6 +1906,7 @@ int Calibration::minimumPorts(Calibration::Type type)
switch(type) {
case Type::OSL: return 1;
case Type::SOLT: return 1;
case Type::SOLTwithoutRxMatch: return 2;
case Type::ThroughNormalization: return 2;
case Type::TRL: return 2;
case Type::None:

View file

@ -22,6 +22,7 @@ public:
None,
OSL,
SOLT,
SOLTwithoutRxMatch,
ThroughNormalization,
TRL,
Last,
@ -46,7 +47,7 @@ public:
void correctTraces(std::map<QString, Trace*> traceSet);
// Starts the calibration edit dialog, allowing the user to make/delete measurements
void edit();
void edit(TraceModel *traceModel = nullptr);
Calkit& getKit();
@ -163,6 +164,7 @@ private:
Point createInitializedPoint(double f);
Point computeOSL(double f);
Point computeSOLT(double f);
Point computeSOLTwithoutRxMatch(double f);
Point computeThroughNormalization(double f);
Point computeTRL(double f);

View file

@ -48,7 +48,7 @@
<item>
<widget class="QTableWidget" name="table">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
@ -148,6 +148,14 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="selectMeasurement">
<property name="text">
<string>Select
Measurement</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearMeasurement">
<property name="text">
@ -185,7 +193,7 @@ Kit</string>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -287,7 +295,7 @@ Kit</string>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>

View file

@ -61,6 +61,8 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
virtual std::vector<unsigned int> getPorts() = 0;
static bool canMeasureSimultaneously(std::set<Base *> measurements);
QDateTime getTimestamp() const;
@ -102,6 +104,8 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
virtual std::vector<unsigned int> getPorts() override {return {port};}
class Point {
public:
double frequency;
@ -222,6 +226,8 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
virtual std::vector<unsigned int> getPorts() override {return {port1, port2};}
class Point {
public:
double frequency;
@ -298,6 +304,8 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
virtual std::vector<unsigned int> getPorts() override {return {};}
class Point {
public:
double frequency;

View file

@ -794,6 +794,7 @@ QString LibreVNADriver::getFirmwareMagicString()
{
switch(hardwareVersion) {
case 0x01: return "VNA!";
case 0xE0: return "VNS1";
case 0xFE: return "VNP2";
case 0xFF: return "VNPT";
default: return "XXXX";

View file

@ -131,8 +131,8 @@ void ManualControlDialogVE0::NewStatus(Protocol::ManualStatus status)
auto port1db = Util::SparamTodB(port1referenced);
auto port2db = Util::SparamTodB(port2referenced);
ui->port1referenced->setText(QString::number(port1db, 'f', 1) + "db@" + QString::number(arg(port1referenced)*180/M_PI, 'f', 0) + "°");
ui->port2referenced->setText(QString::number(port2db, 'f', 1) + "db@" + QString::number(arg(port2referenced)*180/M_PI, 'f', 0) + "°");
ui->port1referenced->setText(QString::number(port1db, 'f', 2) + "db@" + QString::number(arg(port1referenced)*180/M_PI, 'f', 2) + "°");
ui->port2referenced->setText(QString::number(port2db, 'f', 2) + "db@" + QString::number(arg(port2referenced)*180/M_PI, 'f', 2) + "°");
}
void ManualControlDialogVE0::UpdateDevice()

View file

@ -116,6 +116,7 @@ HEADERS += \
Traces/eyediagramplot.h \
Traces/fftcomplex.h \
Traces/sparamtraceselector.h \
Traces/sparamtraceselectordialog.h \
Traces/trace.h \
Traces/traceaxis.h \
Traces/tracecsvexport.h \
@ -271,6 +272,7 @@ SOURCES += \
Traces/eyediagramplot.cpp \
Traces/fftcomplex.cpp \
Traces/sparamtraceselector.cpp \
Traces/sparamtraceselectordialog.cpp \
Traces/trace.cpp \
Traces/traceaxis.cpp \
Traces/tracecsvexport.cpp \
@ -389,6 +391,7 @@ FORMS += \
Traces/eyediagrameditdialog.ui \
Traces/smithchartdialog.ui \
Traces/polarchartdialog.ui \
Traces/sparamtraceselectordialog.ui \
Traces/tracecsvexport.ui \
Traces/traceeditdialog.ui \
Traces/traceimportdialog.ui \

View file

@ -13,7 +13,8 @@ SparamTraceSelector::SparamTraceSelector(const TraceModel &model, std::vector<un
: model(model),
empty_allowed(empty_allowed),
used_ports(used_ports),
editablePorts(editablePorts)
editablePorts(editablePorts),
valid(false)
{
createGUI();
setInitialChoices();
@ -140,6 +141,7 @@ void SparamTraceSelector::traceSelectionChanged(QComboBox *cb)
} else if(cb->currentIndex() == 0 && points > 0) {
if(!empty_allowed) {
valid = false;
emit selectionValid(false);
}
// Check if all trace selections are set for none
@ -161,7 +163,8 @@ void SparamTraceSelector::traceSelectionChanged(QComboBox *cb)
}
if(empty_allowed) {
// always valid as soon as at least one trace is selected
emit selectionValid(points > 0);
valid = points > 0;
emit selectionValid(valid);
} else {
// actually need to check
valid = true;

View file

@ -16,7 +16,7 @@ public:
SparamTraceSelector(const TraceModel &model, std::vector<unsigned int> used_ports, bool empty_allowed = false, unsigned int editablePorts = 0);
SparamTraceSelector(const TraceModel &model, std::set<unsigned int> used_ports, bool empty_allowed = false, unsigned int editablePorts = 0);
bool isValid();
bool isValid() {return valid;}
std::map<QString, Trace*> getTraces();
unsigned int getPoints() { return points;}

View file

@ -0,0 +1,36 @@
#include "sparamtraceselectordialog.h"
#include "ui_sparamtraceselectordialog.h"
#include "sparamtraceselector.h"
#include <QPushButton>
SParamTraceSelectorDialog::SParamTraceSelectorDialog(const TraceModel &model, std::vector<unsigned int> used_ports, bool empty_allowed)
: QDialog(nullptr)
, ui(new Ui::SParamTraceSelectorDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
auto selector = new SparamTraceSelector(model, used_ports, empty_allowed);
ui->verticalLayout->replaceWidget(ui->placeholder, selector);
auto okButton = ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok);
connect(selector, &SparamTraceSelector::selectionValid, okButton, &QPushButton::setEnabled);
okButton->setEnabled(selector->isValid());
connect(okButton, &QPushButton::clicked, [=](){
auto traces = selector->getTraces();
if(traces.size() == 0) {
// should not happen
reject();
}
emit tracesSelected(Trace::assembleDatapoints(traces));
accept();
});
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &SParamTraceSelectorDialog::reject);
}
SParamTraceSelectorDialog::~SParamTraceSelectorDialog()
{
delete ui;
}

View file

@ -0,0 +1,27 @@
#ifndef SPARAMTRACESELECTORDIALOG_H
#define SPARAMTRACESELECTORDIALOG_H
#include <QDialog>
#include "tracemodel.h"
namespace Ui {
class SParamTraceSelectorDialog;
}
class SParamTraceSelectorDialog : public QDialog
{
Q_OBJECT
public:
explicit SParamTraceSelectorDialog(const TraceModel &model, std::vector<unsigned int> used_ports, bool empty_allowed = false);
~SParamTraceSelectorDialog();
signals:
void tracesSelected(std::vector<DeviceDriver::VNAMeasurement> traceMeasurements);
private:
Ui::SParamTraceSelectorDialog *ui;
};
#endif // SPARAMTRACESELECTORDIALOG_H

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SParamTraceSelectorDialog</class>
<widget class="QDialog" name="SParamTraceSelectorDialog">
<property name="windowModality">
<enum>Qt::WindowModality::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>494</width>
<height>222</height>
</rect>
</property>
<property name="windowTitle">
<string>S-Paramter Trace Selector Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="placeholder" native="true"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -110,7 +110,7 @@ VNA::VNA(AppWindow *window, QString name)
auto calData = calMenu->addAction("Calibration Measurements");
connect(calData, &QAction::triggered, [=](){
cal.edit();
cal.edit(&traceModel);
});
auto calEditKit = calMenu->addAction("Edit Calibration Kit");
@ -1375,7 +1375,7 @@ void VNA::ApplyCalibration(Calibration::CalType type)
// Not all required traces available
InformationBox::ShowMessageBlocking("Missing calibration measurements", "Not all calibration measurements for this type of calibration have been taken. The calibration can be enabled after the missing measurements have been acquired.");
DisableCalibration();
cal.edit();
cal.edit(&traceModel);
} else {
// Not all required traces available
InformationBox::ShowMessageBlocking("Missing calibration measurements", "Not all calibration measurements for this type of calibration have been taken. Please switch to frequency sweep to take these measurements.");

View file

@ -110,6 +110,7 @@ SOURCES += \
../LibreVNA-GUI/Traces/eyediagramplot.cpp \
../LibreVNA-GUI/Traces/fftcomplex.cpp \
../LibreVNA-GUI/Traces/sparamtraceselector.cpp \
../LibreVNA-GUI/Traces/sparamtraceselectordialog.cpp \
../LibreVNA-GUI/Traces/trace.cpp \
../LibreVNA-GUI/Traces/traceaxis.cpp \
../LibreVNA-GUI/Traces/tracecsvexport.cpp \
@ -310,6 +311,7 @@ HEADERS += \
../LibreVNA-GUI/Traces/eyediagramplot.h \
../LibreVNA-GUI/Traces/fftcomplex.h \
../LibreVNA-GUI/Traces/sparamtraceselector.h \
../LibreVNA-GUI/Traces/sparamtraceselectordialog.h \
../LibreVNA-GUI/Traces/trace.h \
../LibreVNA-GUI/Traces/traceaxis.h \
../LibreVNA-GUI/Traces/tracecsvexport.h \
@ -425,6 +427,7 @@ FORMS += \
../LibreVNA-GUI/Traces/eyediagrameditdialog.ui \
../LibreVNA-GUI/Traces/polarchartdialog.ui \
../LibreVNA-GUI/Traces/smithchartdialog.ui \
../LibreVNA-GUI/Traces/sparamtraceselectordialog.ui \
../LibreVNA-GUI/Traces/tracecsvexport.ui \
../LibreVNA-GUI/Traces/traceeditdialog.ui \
../LibreVNA-GUI/Traces/traceimportdialog.ui \