mirror of
https://github.com/jankae/LibreVNA.git
synced 2025-12-06 07:12:10 +01:00
Compare commits
3 commits
1b3c1c4b3b
...
10ba138104
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10ba138104 | ||
|
|
2f018e3867 | ||
|
|
68e8d29e0c |
|
|
@ -301,6 +301,7 @@ QString Calibration::TypeToString(Calibration::Type type)
|
|||
{
|
||||
switch(type) {
|
||||
case Type::None: return "None";
|
||||
case Type::OSL: return "OSL";
|
||||
case Type::SOLT: return "SOLT";
|
||||
case Type::ThroughNormalization: return "ThroughNormalization";
|
||||
case Type::TRL: return "TRL";
|
||||
|
|
@ -708,19 +709,19 @@ Calibration::Point Calibration::createInitializedPoint(double f) {
|
|||
point.frequency = f;
|
||||
// resize vectors
|
||||
point.D.resize(caltype.usedPorts.size(), 0.0);
|
||||
point.R.resize(caltype.usedPorts.size(), 0.0);
|
||||
point.R.resize(caltype.usedPorts.size(), 1.0);
|
||||
point.S.resize(caltype.usedPorts.size(), 0.0);
|
||||
|
||||
point.L.resize(caltype.usedPorts.size());
|
||||
point.T.resize(caltype.usedPorts.size());
|
||||
point.I.resize(caltype.usedPorts.size());
|
||||
fill(point.L.begin(), point.L.end(), vector<complex<double>>(caltype.usedPorts.size(), 0.0));
|
||||
fill(point.T.begin(), point.T.end(), vector<complex<double>>(caltype.usedPorts.size(), 0.0));
|
||||
fill(point.T.begin(), point.T.end(), vector<complex<double>>(caltype.usedPorts.size(), 1.0));
|
||||
fill(point.I.begin(), point.I.end(), vector<complex<double>>(caltype.usedPorts.size(), 0.0));
|
||||
return point;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::computeSOLT(double f)
|
||||
Calibration::Point Calibration::computeOSL(double f)
|
||||
{
|
||||
Point point = createInitializedPoint(f);
|
||||
|
||||
|
|
@ -762,6 +763,13 @@ Calibration::Point Calibration::computeSOLT(double f)
|
|||
auto delta = (l_c * l_m * (o_m - s_m) + o_c * o_m * (s_m - l_m) + s_c * s_m * (l_m - o_m)) / denom;
|
||||
point.R[i] = point.D[i] * point.S[i] - delta;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::computeSOLT(double f)
|
||||
{
|
||||
Point point = computeOSL(f);
|
||||
|
||||
// calculate forward match and transmission
|
||||
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
|
||||
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
|
||||
|
|
@ -1278,6 +1286,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<double>(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<double>(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<double>(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<double>(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<double>(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<double>(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;
|
||||
|
|
@ -1617,6 +1736,14 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
|
|||
case Type::None:
|
||||
return true; // Always possible to reset the calibration
|
||||
case Type::SOLT:
|
||||
// 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++) {
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Through, .port1 = i, .port2 = j});
|
||||
}
|
||||
}
|
||||
[[fallthrough]];
|
||||
case Type::OSL:
|
||||
// SOL measurements for every port
|
||||
for(auto p : type.usedPorts) {
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Short, .port1 = p, .port2 = 0});
|
||||
|
|
@ -1629,12 +1756,6 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
|
|||
required.push_back({.type = CalibrationMeasurement::Base::Type::Load, .port1 = p, .port2 = 0});
|
||||
}
|
||||
}
|
||||
// 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++) {
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Through, .port1 = i, .port2 = j});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::ThroughNormalization:
|
||||
// through measurements between all ports
|
||||
|
|
@ -1706,6 +1827,7 @@ bool Calibration::compute(Calibration::CalType type)
|
|||
}
|
||||
Point p;
|
||||
switch(type.type) {
|
||||
case Type::OSL: p = computeOSL(f); break;
|
||||
case Type::SOLT: p = computeSOLT(f); break;
|
||||
case Type::ThroughNormalization: p = computeThroughNormalization(f); break;
|
||||
case Type::TRL: p = computeTRL(f); break;
|
||||
|
|
@ -1734,6 +1856,7 @@ void Calibration::reset()
|
|||
int Calibration::minimumPorts(Calibration::Type type)
|
||||
{
|
||||
switch(type) {
|
||||
case Type::OSL: return 1;
|
||||
case Type::SOLT: return 1;
|
||||
case Type::ThroughNormalization: return 2;
|
||||
case Type::TRL: return 2;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public:
|
|||
|
||||
enum class Type {
|
||||
None,
|
||||
OSL,
|
||||
SOLT,
|
||||
ThroughNormalization,
|
||||
TRL,
|
||||
|
|
@ -99,6 +100,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();
|
||||
|
|
@ -152,6 +161,7 @@ private:
|
|||
std::vector<Point> points;
|
||||
|
||||
Point createInitializedPoint(double f);
|
||||
Point computeOSL(double f);
|
||||
Point computeSOLT(double f);
|
||||
Point computeThroughNormalization(double f);
|
||||
Point computeTRL(double f);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
// create the ports of the VNA
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef CALIBRATIONVIEWDIALOG_H
|
||||
#define CALIBRATIONVIEWDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "calibration.h"
|
||||
#include <QGraphicsScene>
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CalibrationViewDialog</class>
|
||||
<widget class="QDialog" name="CalibrationViewDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>818</width>
|
||||
<height>623</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calibration Error Term Model</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>View error term model when stimulus is at port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="port">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><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></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="view">
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::DragMode::ScrollHandDrag</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>D: Directivity, R: Reflection tracking, S: Source match, L: Receiver match, T: Transmission tracking, I: Isolation</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CalibrationViewDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>374</x>
|
||||
<y>509</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>374</x>
|
||||
<y>265</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -7,7 +7,7 @@ ManualCalibrationDialog::ManualCalibrationDialog(const TraceModel &model, Calibr
|
|||
ui(new Ui::ManualCalibrationDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto traceSelector = new SparamTraceSelector(model, cal->getCaltype().usedPorts);
|
||||
auto traceSelector = new SparamTraceSelector(model, cal->getCaltype().usedPorts, true);
|
||||
ui->verticalLayout->insertWidget(1, traceSelector, 1.0);
|
||||
ui->buttonBox->setEnabled(false);
|
||||
connect(traceSelector, &SparamTraceSelector::selectionValid, ui->buttonBox, &QDialogButtonBox::setEnabled);
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -318,6 +318,10 @@ void Trace::fillFromDatapoints(std::map<QString, Trace *> traceSet, const std::v
|
|||
{
|
||||
// remove all previous points
|
||||
for(auto m : traceSet) {
|
||||
if(!m.second) {
|
||||
// no trace, skip
|
||||
continue;
|
||||
}
|
||||
if(!deembedded) {
|
||||
m.second->clear();
|
||||
} else {
|
||||
|
|
@ -332,6 +336,10 @@ void Trace::fillFromDatapoints(std::map<QString, Trace *> traceSet, const std::v
|
|||
td.y = m.second;
|
||||
QString measurement = m.first;
|
||||
if(traceSet.count(measurement)) {
|
||||
if(!traceSet[measurement]) {
|
||||
// no trace, skip
|
||||
continue;
|
||||
}
|
||||
if(!deembedded) {
|
||||
traceSet[measurement]->addData(td, DataType::Frequency);
|
||||
} else {
|
||||
|
|
@ -1065,16 +1073,24 @@ std::vector<DeviceDriver::VNAMeasurement> Trace::assembleDatapoints(std::map<QSt
|
|||
vector<DeviceDriver::VNAMeasurement> ret;
|
||||
|
||||
// Sanity check traces
|
||||
unsigned int samples = traceSet.begin()->second->size();
|
||||
auto impedance = traceSet.begin()->second->getReferenceImpedance();
|
||||
unsigned int samples = 0;
|
||||
auto impedance = 0;
|
||||
vector<double> freqs;
|
||||
for(auto m : traceSet) {
|
||||
const Trace *t = m.second;
|
||||
if(t->size() != samples) {
|
||||
if(!t) {
|
||||
// trace not valid, skip
|
||||
continue;
|
||||
}
|
||||
if(samples == 0) {
|
||||
samples = t->size();
|
||||
} else if(t->size() != samples) {
|
||||
qWarning() << "Selected traces do not have the same size";
|
||||
return ret;
|
||||
}
|
||||
if(t->getReferenceImpedance() != impedance) {
|
||||
if(impedance == 0) {
|
||||
impedance = t->getReferenceImpedance();
|
||||
} else if(t->getReferenceImpedance() != impedance) {
|
||||
qWarning() << "Selected traces do not have the same reference impedance";
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1098,13 +1114,22 @@ std::vector<DeviceDriver::VNAMeasurement> Trace::assembleDatapoints(std::map<QSt
|
|||
}
|
||||
}
|
||||
|
||||
if(samples == 0 || freqs.size() == 0) {
|
||||
qWarning() << "Empty trace set";
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Checks passed, assemble datapoints
|
||||
for(unsigned int i=0;i<samples;i++) {
|
||||
DeviceDriver::VNAMeasurement d;
|
||||
for(auto m : traceSet) {
|
||||
QString measurement = m.first;
|
||||
const Trace *t = m.second;
|
||||
d.measurements[measurement] = t->sample(i).y;
|
||||
if(t) {
|
||||
d.measurements[measurement] = t->sample(i).y;
|
||||
} else {
|
||||
d.measurements[measurement] = 0.0;
|
||||
}
|
||||
}
|
||||
d.pointNum = i;
|
||||
d.frequency = freqs[i];
|
||||
|
|
|
|||
|
|
@ -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, [=](){
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
Loading…
Reference in a new issue