2025-08-10 15:13:24 +02:00
|
|
|
#include "calibrationviewdialog.h"
|
|
|
|
|
#include "ui_calibrationviewdialog.h"
|
|
|
|
|
|
|
|
|
|
#include <QGraphicsSimpleTextItem>
|
|
|
|
|
#include <QVector2D>
|
|
|
|
|
|
|
|
|
|
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<QPointF> vertices, QColor color, QString label = QString(), bool arrow = false) {
|
|
|
|
|
// draw lines
|
|
|
|
|
for(unsigned int i=1;i<vertices.size();i++) {
|
|
|
|
|
|
|
|
|
|
scene->addLine(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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:07:34 +02:00
|
|
|
// Fill the measurement correction table
|
|
|
|
|
ui->table->clear();
|
|
|
|
|
ui->table->setRowCount(ports*ports);
|
|
|
|
|
ui->table->setColumnCount(2);
|
|
|
|
|
ui->table->setHorizontalHeaderLabels({"Parameter", "Calibration Status"});
|
|
|
|
|
for(unsigned int i=1;i<=ports;i++) {
|
|
|
|
|
for(unsigned int j=1;j<=ports;j++) {
|
|
|
|
|
auto row = (i-1)*ports+j-1;
|
|
|
|
|
// add parameter
|
|
|
|
|
ui->table->setItem(row, 0, new QTableWidgetItem("S"+QString::number(j)+QString::number(i)));
|
|
|
|
|
// check the calibration status
|
|
|
|
|
QString status = "Uncalibrated";
|
|
|
|
|
if(i == j) {
|
|
|
|
|
// check reflection parameters
|
|
|
|
|
if(cal->hasSourceMatch(i) && cal->hasDirectivity(i) && cal->hasReflectionTracking(i)) {
|
|
|
|
|
// we are calibrated
|
|
|
|
|
status = "Calibrated";
|
|
|
|
|
// check if we have enhanced responses
|
|
|
|
|
QList<int> enhanced;
|
|
|
|
|
for(unsigned int k=1;k<=ports;k++) {
|
|
|
|
|
if(k==i) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(cal->hasReceiverMatch(i, k)) {
|
|
|
|
|
enhanced.append(k);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(enhanced.size() == 1) {
|
|
|
|
|
status += " with enhanced response from port "+QString::number(enhanced[0]);
|
|
|
|
|
} else if(enhanced.size() > 1) {
|
|
|
|
|
status += " with enhanced response from ports ";
|
|
|
|
|
for(unsigned int k=0;k<enhanced.size();k++) {
|
|
|
|
|
if(k == enhanced.size() - 1) {
|
|
|
|
|
status += " and "+QString::number(enhanced[k]);
|
|
|
|
|
} else if(k > 0) {
|
|
|
|
|
status += ", ";
|
|
|
|
|
}
|
|
|
|
|
status += QString::number(enhanced[k]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// check transmission calibration
|
|
|
|
|
if(cal->hasTransmissionTracking(i, j)) {
|
|
|
|
|
// we are calibrated
|
|
|
|
|
status = "Calibrated";
|
|
|
|
|
// check if we have isolation terms
|
|
|
|
|
if(cal->hasIsolation(i, j)) {
|
|
|
|
|
status += " with isolation measurement";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// add calibration status
|
|
|
|
|
ui->table->setItem(row, 1, new QTableWidgetItem(status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ui->table->resizeColumnsToContents();
|
2025-08-10 15:13:24 +02:00
|
|
|
}
|