From 68e8d29e0c67d60cf489d30a2b44e8b8c0d9fa6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Sun, 10 Aug 2025 15:13:24 +0200 Subject: [PATCH] Calibration error term model view --- .../LibreVNA-GUI/Calibration/calibration.cpp | 111 ++++++++ .../LibreVNA-GUI/Calibration/calibration.h | 8 + .../Calibration/calibrationmeasurement.cpp | 4 + .../Calibration/calibrationviewdialog.cpp | 259 ++++++++++++++++++ .../Calibration/calibrationviewdialog.h | 51 ++++ .../Calibration/calibrationviewdialog.ui | 103 +++++++ .../LibreVNA-GUI/LibreVNA-GUI.pro | 3 + .../PC_Application/LibreVNA-GUI/VNA/vna.cpp | 13 +- .../LibreVNA-Test/LibreVNA-Test.pro | 3 + 9 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.cpp create mode 100644 Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.h create mode 100644 Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.ui diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.cpp b/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.cpp index 24bb4d1..63e30c0 100644 --- a/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.cpp @@ -1278,6 +1278,117 @@ bool Calibration::validForDevice(QString serial) const } } +bool Calibration::hasDirectivity(unsigned int port) +{ + unsigned int index = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), port) - caltype.usedPorts.begin(); + if(points.size() == 0 || index >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(0.0, 0.0); + for(const auto &p : points) { + if(p.D[index] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + +bool Calibration::hasReflectionTracking(unsigned int port) +{ + unsigned int index = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), port) - caltype.usedPorts.begin(); + if(points.size() == 0 || index >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(1.0, 0.0); + for(const auto &p : points) { + if(p.R[index] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + +bool Calibration::hasSourceMatch(unsigned int port) +{ + unsigned int index = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), port) - caltype.usedPorts.begin(); + if(points.size() == 0 || index >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(0.0, 0.0); + for(const auto &p : points) { + if(p.S[index] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + +bool Calibration::hasReceiverMatch(unsigned int sourcePort, unsigned int receivePort) +{ + unsigned int indexSrc = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), sourcePort) - caltype.usedPorts.begin(); + unsigned int indexRcv = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), receivePort) - caltype.usedPorts.begin(); + if(points.size() == 0 || indexSrc >= caltype.usedPorts.size() || indexRcv >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(0.0, 0.0); + for(const auto &p : points) { + if(p.L[indexSrc][indexRcv] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + +bool Calibration::hasTransmissionTracking(unsigned int sourcePort, unsigned int receivePort) +{ + unsigned int indexSrc = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), sourcePort) - caltype.usedPorts.begin(); + unsigned int indexRcv = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), receivePort) - caltype.usedPorts.begin(); + if(points.size() == 0 || indexSrc >= caltype.usedPorts.size() || indexRcv >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(1.0, 0.0); + for(const auto &p : points) { + if(p.T[indexSrc][indexRcv] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + +bool Calibration::hasIsolation(unsigned int sourcePort, unsigned int receivePort) +{ + unsigned int indexSrc = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), sourcePort) - caltype.usedPorts.begin(); + unsigned int indexRcv = std::find(caltype.usedPorts.begin(), caltype.usedPorts.end(), receivePort) - caltype.usedPorts.begin(); + if(points.size() == 0 || indexSrc >= caltype.usedPorts.size() || indexRcv >= caltype.usedPorts.size()) { + // no calibration or it does not contain this port + return false; + } + auto def = std::complex(0.0, 0.0); + for(const auto &p : points) { + if(p.I[indexSrc][indexRcv] != def) { + // at least one point does not match the default value -> we have a valid calibration for this + return true; + } + } + // all points still at default value + return false; +} + bool Calibration::hasUnsavedChanges() const { return unsavedChanges; diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.h b/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.h index 73248f7..b5f6771 100644 --- a/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.h +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibration.h @@ -99,6 +99,14 @@ public: QString getValidDevice() const; bool validForDevice(QString serial) const; + // query whether error terms coefficients are available. Port count starts at 1 + bool hasDirectivity(unsigned int port); + bool hasReflectionTracking(unsigned int port); + bool hasSourceMatch(unsigned int port); + bool hasReceiverMatch(unsigned int sourcePort, unsigned int receivePort); + bool hasTransmissionTracking(unsigned int sourcePort, unsigned int receivePort); + bool hasIsolation(unsigned int sourcePort, unsigned int receivePort); + public slots: // Call once all datapoints of the current span have been added void measurementsComplete(); diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationmeasurement.cpp b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationmeasurement.cpp index bd4d15a..321d955 100644 --- a/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationmeasurement.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationmeasurement.cpp @@ -627,6 +627,10 @@ void CalibrationMeasurement::Isolation::addPoint(const DeviceDriver::VNAMeasurem QString name = meas.first; unsigned int rcv = name.mid(1, 1).toInt() - 1; unsigned int src = name.mid(2, 1).toInt() - 1; + if(rcv > 8 || src > 8) { + // skip + continue; + } if(rcv >= p.S.size()) { p.S.resize(rcv + 1); } diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.cpp b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.cpp new file mode 100644 index 0000000..fed8c53 --- /dev/null +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.cpp @@ -0,0 +1,259 @@ +#include "calibrationviewdialog.h" +#include "ui_calibrationviewdialog.h" + +#include +#include + +const QColor CalibrationViewDialog::colorNoCal = Qt::darkRed; +const QColor CalibrationViewDialog::colorHasCal = Qt::darkGreen; + +CalibrationViewDialog::CalibrationViewDialog(Calibration *cal, unsigned int ports, QWidget *parent) + : QDialog(parent) + , ui(new Ui::CalibrationViewDialog) + , cal(cal) + , ports(ports) +{ + setAttribute(Qt::WA_DeleteOnClose); + ui->setupUi(this); + ui->port->setMaximum(ports); + scene = new QGraphicsScene(); + populateScene(); + ui->view->setScene(scene); + + connect(ui->port, &QSpinBox::valueChanged, this, &CalibrationViewDialog::populateScene); +} + +CalibrationViewDialog::~CalibrationViewDialog() +{ + delete ui; +} + +void CalibrationViewDialog::populateScene() +{ + scene->clear(); + auto colorF = QApplication::palette().text().color(); + auto colorB = QApplication::palette().base().color(); + auto pen = QPen(colorF); + + auto drawDot = [this](float x, float y, float size, QPen pen = QPen(), QBrush brush = QBrush()) { + scene->addEllipse(x - size/2, y - size/2, size, size, pen, brush); + }; + + auto drawText = [this](float x, float y, QString s, QColor color, auto alignH = Qt::AlignCenter, auto alignV = Qt::AlignCenter, float rotation = 0.0f) { + auto text = scene->addText(s); + text->setRotation(rotation); + switch(alignH) { + default: + case Qt::AlignLeft: break; + case Qt::AlignCenter: + case Qt::AlignHCenter: x -= text->boundingRect().bottomRight().x()/2; break; + case Qt::AlignRight: x -= text->boundingRect().bottomRight().x(); break; + } + switch(alignV) { + default: + case Qt::AlignTop: break; + case Qt::AlignCenter: + case Qt::AlignVCenter: y -= text->boundingRect().bottomRight().y()/2; break; + case Qt::AlignBottom: y -= text->boundingRect().bottomRight().y(); break; + } + text->setPos(QPointF(x, y)); + text->setDefaultTextColor(color); + }; + + auto drawPath = [this, drawText](QList vertices, QColor color, QString label = QString(), bool arrow = false) { + // draw lines + for(unsigned int i=1;iaddLine(QLineF(vertices[i-1], vertices[i]), color); + if(i == vertices.size() / 2) { + // this is the middle segment, add label and arrow if required + auto midPoint = (vertices[i-1]+vertices[i])/2; + QVector2D direction = QVector2D(vertices[i] - vertices[i-1]); + direction.normalize(); + auto ortho = QVector2D(-direction.y(), direction.x()); + if(arrow) { + auto poly = QPolygonF({ + QPointF(midPoint + direction.toPointF()*arrowLength/2), + QPointF(midPoint - direction.toPointF()*arrowLength/2 + ortho.toPointF()*arrowWidth/2), + QPointF(midPoint - direction.toPointF()*arrowLength/2 - ortho.toPointF()*arrowWidth/2) + }); + scene->addPolygon(poly, color, color); + } + if(!label.isEmpty()) { + auto pos = midPoint; + if(label.startsWith("_")) { + label.remove(0, 1); + pos -= ortho.toPointF() * labelDistance; + } else { + pos += ortho.toPointF() * labelDistance; + } + auto alignH = abs(direction.x()) > abs(direction.y()) ? Qt::AlignCenter : Qt::AlignLeft; + auto alignV = abs(direction.y()) > abs(direction.x()) ? Qt::AlignCenter : Qt::AlignTop; + drawText(pos.x(), pos.y(), label, color, alignH, alignV); + } + } + } + }; + + auto DUTwidth = 2 * ports * pathSpacing; + auto DUTstartX = ports * pathSpacing + 2*boxSpacing; + + // set the overall scene size + scene->setSceneRect(0, 0, marginLeft + DUTstartX + DUTwidth + marginRight, marginTop + ports * portHeight + marginBottom); + + // create the DUT + // rectangle + scene->addRect(marginLeft + DUTstartX, marginTop, DUTwidth, ports * portHeight, pen); + drawText(marginLeft + DUTstartX + DUTwidth/2, marginTop, "DUT", colorF, Qt::AlignCenter, Qt::AlignTop); + // ports + for(unsigned int i=1;i<=ports;i++) { + // input marker + drawDot(marginLeft + DUTstartX, marginTop + i*portHeight - portHeight/2 + portForwardYOffset, portSize, colorF, colorB); + // output marker + drawDot(marginLeft + DUTstartX, marginTop + i*portHeight - portHeight/2 + portReverseYOffset, portSize, colorF, colorB); + } + // the reflection path + drawPath({ + QPointF(marginLeft + DUTstartX + portSize/2, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(marginLeft + DUTstartX + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(marginLeft + DUTstartX + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(marginLeft + DUTstartX + portSize/2, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, colorF, "_S"+QString::number(ui->port->value())+QString::number(ui->port->value()), true); + // the forward transmission paths + float xstart = marginLeft + DUTstartX + pathSpacing; + for(unsigned int i=1;i<=ports;i++) { + if((int) i == ui->port->value()) { + // skip, this is the reflection path + continue; + } + drawDot(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset, junctionSize, colorF, colorF); + drawPath({ + QPointF(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + QPointF(marginLeft + DUTstartX + portSize/2, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + }, colorF, QString((int) i > ui->port->value() ? "_" : "") + "S"+QString::number(i)+QString::number(ui->port->value()), true); + xstart += pathSpacing; + } + // the reverse transmission paths + bool first = true; + for(unsigned int i=1;i<=ports;i++) { + if((int) i == ui->port->value()) { + // skip, this is the reflection path + continue; + } + if(first) { + first = false; + drawDot(marginLeft + DUTstartX + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + drawPath({ + QPointF(marginLeft + DUTstartX + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, colorF, "", false); + } else { + drawDot(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + } + drawPath({ + QPointF(marginLeft + DUTstartX + portSize/2, marginTop + i*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + i*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, colorF, QString((int) i > ui->port->value() ? "" : "_") + "S"+QString::number(ui->port->value())+QString::number(i), true); + xstart += pathSpacing; + } + + // isolation, transmission and receiver match paths + xstart = marginLeft; + for(unsigned int i=1;i<=ports;i++) { + if((int) i == ui->port->value()) { + // skip, this is the reflection path + continue; + } + // isolation + drawDot(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset, junctionSize, colorF, colorF); + drawPath({ + QPointF(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + }, colorF); + drawPath({ + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + }, cal->hasIsolation(ui->port->value(), i) ? colorHasCal : colorNoCal, QString((int) i > ui->port->value() ? "_" : "") + "I"+QString::number(i)+QString::number(ui->port->value()), true); + drawPath({ + QPointF(xstart + pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + QPointF(marginLeft, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + }, colorF); + xstart += pathSpacing; + // transmission + drawDot(xstart, marginTop + i*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + drawPath({ + QPointF(marginLeft + DUTstartX - portSize / 2, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + QPointF(marginLeft + DUTstartX - pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + }, colorF); + drawPath({ + QPointF(marginLeft + DUTstartX - pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + }, cal->hasTransmissionTracking(ui->port->value(), i) ? colorHasCal : colorNoCal, "_T"+QString::number(i)+QString::number(ui->port->value()), true); + // Reveicer match + drawDot(marginLeft + DUTstartX - pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + drawPath({ + QPointF(marginLeft + DUTstartX - pathSpacing, marginTop + i*portHeight - portHeight/2 + portReverseYOffset), + QPointF(marginLeft + DUTstartX - pathSpacing, marginTop + i*portHeight - portHeight/2 + portForwardYOffset), + QPointF(marginLeft + DUTstartX - portSize/2, marginTop + i*portHeight - portHeight/2 + portForwardYOffset), + }, cal->hasReceiverMatch(ui->port->value(), i) ? colorHasCal : colorNoCal, "L"+QString::number(i)+QString::number(ui->port->value()), true); + } + + // reflection error box + drawDot(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset, junctionSize, colorF, colorF); + drawDot(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset, junctionSize, colorF, colorF); + drawDot(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + drawDot(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset, junctionSize, colorF, colorF); + drawDot(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset, junctionSize, colorF, colorF); + // unity paths + drawPath({ + QPointF(xstart, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(marginLeft + DUTstartX - portSize/2, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + }, colorF, "", true); + drawPath({ + QPointF(marginLeft + DUTstartX - portSize/2, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, colorF); + drawPath({ + QPointF(marginLeft + portSize/2, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, colorF); + + // directivity + drawPath({ + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, cal->hasDirectivity(ui->port->value()) ? colorHasCal : colorNoCal, "_D"+QString::number(ui->port->value()), true); + + // reflection tracking + drawPath({ + QPointF(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart + pathSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + }, cal->hasReflectionTracking(ui->port->value()) ? colorHasCal : colorNoCal, "_R"+QString::number(ui->port->value()), true); + + // source match + drawPath({ + QPointF(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portReverseYOffset), + QPointF(xstart + pathSpacing + boxSpacing, marginTop + ui->port->value()*portHeight - portHeight/2 + portForwardYOffset), + }, cal->hasSourceMatch(ui->port->value()) ? colorHasCal : colorNoCal, "S"+QString::number(ui->port->value()), true); + + // create the VNA ports + for(unsigned int i=1;i<=ports;i++) { + // stimulus port + if(i == (unsigned int) ui->port->value()) { + drawDot(marginLeft, marginTop + i*portHeight - portHeight/2 + portForwardYOffset, portSize, colorF, colorB); + drawText(marginLeft - portSize/2, marginTop + i*portHeight - portHeight/2 + portForwardYOffset, "a"+QString::number(i), colorF, Qt::AlignRight, Qt::AlignCenter); + } + // output marker + drawDot(marginLeft, marginTop + i*portHeight - portHeight/2 + portReverseYOffset, portSize, colorF, colorB); + drawText(marginLeft - portSize/2, marginTop + i*portHeight - portHeight/2 + portReverseYOffset, "b"+QString::number(i), colorF, Qt::AlignRight, Qt::AlignCenter); + } + + // create the ports of the VNA + +} diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.h b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.h new file mode 100644 index 0000000..1e4b734 --- /dev/null +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.h @@ -0,0 +1,51 @@ +#ifndef CALIBRATIONVIEWDIALOG_H +#define CALIBRATIONVIEWDIALOG_H + +#include + +#include "calibration.h" +#include + +namespace Ui { +class CalibrationViewDialog; +} + +class CalibrationViewDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CalibrationViewDialog(Calibration *cal, unsigned int ports, QWidget *parent = nullptr); + ~CalibrationViewDialog(); + +private slots: + void populateScene(); +private: + static constexpr int marginTop = 10; + static constexpr int marginBottom = 10; + static constexpr int marginLeft = 30; + static constexpr int marginRight = 10; + + static constexpr int portHeight = 170; + static constexpr int portForwardYOffset = -50; + static constexpr int portReverseYOffset = 50; + static constexpr int boxSpacing = portReverseYOffset - portForwardYOffset; + + static constexpr int portSize = 10; + static constexpr int arrowLength = 15; + static constexpr int arrowWidth = 10; + static constexpr int junctionSize = 6; + static constexpr int labelDistance = 6; + + static constexpr int pathSpacing = 40; + + static const QColor colorNoCal; + static const QColor colorHasCal; + + Ui::CalibrationViewDialog *ui; + Calibration *cal; + unsigned int ports; + QGraphicsScene *scene; +}; + +#endif // CALIBRATIONVIEWDIALOG_H diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.ui b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.ui new file mode 100644 index 0000000..de23638 --- /dev/null +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/calibrationviewdialog.ui @@ -0,0 +1,103 @@ + + + CalibrationViewDialog + + + + 0 + 0 + 818 + 623 + + + + Calibration Error Term Model + + + + + + + + View error term model when stimulus is at port + + + + + + + 1 + + + 8 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + <html><head/><body><p><span style='color: darkgreen;'>Green</span> error terms have been calculated from calibration measurements.</p><p><span style='color: darkred;'>Red</span> error terms are at their default values (either 1 or 0).</p></body></html> + + + + + + + QGraphicsView::DragMode::ScrollHandDrag + + + + + + + <html><head/><body><p>D: Directivity, R: Reflection tracking, S: Source match, L: Receiver match, T: Transmission tracking, I: Isolation</p></body></html> + + + true + + + + + + + QDialogButtonBox::StandardButton::Ok + + + + + + + + + buttonBox + accepted() + CalibrationViewDialog + accept() + + + 374 + 509 + + + 374 + 265 + + + + + diff --git a/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro index d067010..913de1a 100644 --- a/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro @@ -6,6 +6,7 @@ HEADERS += \ Calibration/LibreCAL/usbdevice.h \ Calibration/calibration.h \ Calibration/calibrationmeasurement.h \ + Calibration/calibrationviewdialog.h \ Calibration/calkit.h \ Calibration/calkitdialog.h \ Calibration/calstandard.h \ @@ -171,6 +172,7 @@ SOURCES += \ Calibration/LibreCAL/usbdevice.cpp \ Calibration/calibration.cpp \ Calibration/calibrationmeasurement.cpp \ + Calibration/calibrationviewdialog.cpp \ Calibration/calkit.cpp \ Calibration/calkitdialog.cpp \ Calibration/calstandard.cpp \ @@ -340,6 +342,7 @@ FORMS += \ Calibration/LibreCAL/factoryUpdateDialog.ui \ Calibration/LibreCAL/librecaldialog.ui \ Calibration/calibrationdialogui.ui \ + Calibration/calibrationviewdialog.ui \ Calibration/calkitdialog.ui \ Calibration/manualcalibrationdialog.ui \ CustomWidgets/csvimport.ui \ diff --git a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp index 1ed594e..75fb076 100644 --- a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp +++ b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp @@ -1,4 +1,4 @@ -#include "vna.h" +#include "vna.h" #include "unit.h" #include "CustomWidgets/toggleswitch.h" @@ -18,6 +18,7 @@ #include "CustomWidgets/informationbox.h" #include "Deembedding/manualdeembeddingdialog.h" #include "Calibration/manualcalibrationdialog.h" +#include "Calibration/calibrationviewdialog.h" #include "Calibration/LibreCAL/librecaldialog.h" #include "Util/util.h" #include "Tools/parameters.h" @@ -129,6 +130,16 @@ VNA::VNA(AppWindow *window, QString name) calMenu->addSeparator(); + auto calViewTerms = calMenu->addAction("View error term model"); + connect(calViewTerms, &QAction::triggered, [=](){ + auto dialog = new CalibrationViewDialog(&cal, DeviceDriver::getInfo(window->getDevice()).Limits.VNA.ports); + if(AppWindow::showGUI()) { + dialog->show(); + } + }); + + calMenu->addSeparator(); + auto calImportTerms = calMenu->addAction("Import error terms as traces"); calImportTerms->setEnabled(false); connect(calImportTerms, &QAction::triggered, [=](){ diff --git a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro index fe883f3..63820e5 100644 --- a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro +++ b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro @@ -12,6 +12,7 @@ SOURCES += \ ../LibreVNA-GUI/Calibration/LibreCAL/usbdevice.cpp \ ../LibreVNA-GUI/Calibration/calibration.cpp \ ../LibreVNA-GUI/Calibration/calibrationmeasurement.cpp \ + ../LibreVNA-GUI/Calibration/calibrationviewdialog.cpp \ ../LibreVNA-GUI/Calibration/calkit.cpp \ ../LibreVNA-GUI/Calibration/calkitdialog.cpp \ ../LibreVNA-GUI/Calibration/calstandard.cpp \ @@ -199,6 +200,7 @@ HEADERS += \ ../LibreVNA-GUI/Calibration/LibreCAL/usbdevice.h \ ../LibreVNA-GUI/Calibration/calibration.h \ ../LibreVNA-GUI/Calibration/calibrationmeasurement.h \ + ../LibreVNA-GUI/Calibration/calibrationviewdialog.h \ ../LibreVNA-GUI/Calibration/calkit.h \ ../LibreVNA-GUI/Calibration/calkitdialog.h \ ../LibreVNA-GUI/Calibration/calstandard.h \ @@ -376,6 +378,7 @@ FORMS += \ ../LibreVNA-GUI/Calibration/LibreCAL/factoryUpdateDialog.ui \ ../LibreVNA-GUI/Calibration/LibreCAL/librecaldialog.ui \ ../LibreVNA-GUI/Calibration/calibrationdialogui.ui \ + ../LibreVNA-GUI/Calibration/calibrationviewdialog.ui \ ../LibreVNA-GUI/Calibration/calkitdialog.ui \ ../LibreVNA-GUI/Calibration/manualcalibrationdialog.ui \ ../LibreVNA-GUI/CustomWidgets/csvimport.ui \