Port extension support

This commit is contained in:
Jan Käberich 2020-10-31 16:52:59 +01:00
parent d0640e0e42
commit 7f691bd37d
9 changed files with 653 additions and 3 deletions

View File

@ -33,6 +33,7 @@ HEADERS += \
Traces/tracewidget.h \
Traces/tracexyplot.h \
Traces/xyplotaxisdialog.h \
VNA/portextension.h \
VNA/vna.h \
appwindow.h \
averaging.h \
@ -78,6 +79,7 @@ SOURCES += \
Traces/tracewidget.cpp \
Traces/tracexyplot.cpp \
Traces/xyplotaxisdialog.cpp \
VNA/portextension.cpp \
VNA/vna.cpp \
appwindow.cpp \
averaging.cpp \
@ -111,6 +113,7 @@ FORMS += \
Traces/traceimportdialog.ui \
Traces/tracewidget.ui \
Traces/xyplotaxisdialog.ui \
VNA/portextensioneditdialog.ui \
main.ui \
preferencesdialog.ui

View File

@ -44,7 +44,7 @@ bool Calibration::calculationPossible(Calibration::Type type)
{
return SanityCheckSamples(Measurements(type, false));
}
#include <QDebug>
bool Calibration::constructErrorTerms(Calibration::Type type)
{
if(!calculationPossible(type)) {
@ -700,7 +700,7 @@ istream& operator >>(istream &in, Calibration &c)
}
for(auto t : Calibration::Types()) {
if(Calibration::TypeToString(t) == QString::fromStdString(line)) {
// try to apply this calibration type
// try to P2 this calibration type
if(c.calculationPossible(t)) {
c.constructErrorTerms(t);
} else {

View File

@ -239,7 +239,7 @@ double Calkit::minFreq(bool TRL)
return TRL_line_minfreq;
} else {
fillTouchstoneCache();
double min = std::numeric_limits<double>::min();
double min = 0;
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
// find the highest minimum frequency in all measurement files
for(auto ts : ts_list) {

View File

@ -0,0 +1,233 @@
#include "portextension.h"
#include "ui_portextensioneditdialog.h"
#include <QCheckBox>
#include <cmath>
using namespace std;
PortExtension::PortExtension()
: QObject()
{
port1.enabled = false;
port1.frequency = 0;
port1.loss = 0;
port1.DCloss = 0;
port1.delay = 0;
port1.velocityFactor = 0.66;
port2.enabled = false;
port2.frequency = 0;
port2.loss = 0;
port2.DCloss = 0;
port2.delay = 0;
port2.velocityFactor = 0.66;
measuring = false;
kit = nullptr;
}
void PortExtension::applyToMeasurement(Protocol::Datapoint &d)
{
if(measuring) {
if(measurements.size() > 0) {
if(d.pointNum == 0) {
// sweep complete, evaluate measurement
// TODO
if(msgBox) {
msgBox->close();
msgBox = nullptr;
}
} else {
measurements.push_back(d);
}
} else if(d.pointNum == 0) {
// first point of sweep, start measurement
measurements.push_back(d);
}
}
if(port1.enabled || port2.enabled) {
// Convert measurements to complex variables
auto S11 = complex<double>(d.real_S11, d.imag_S11);
auto S21 = complex<double>(d.real_S21, d.imag_S21);
auto S22 = complex<double>(d.real_S22, d.imag_S22);
auto S12 = complex<double>(d.real_S12, d.imag_S12);
if(port1.enabled) {
auto phase = -2 * M_PI * port1.delay * d.frequency;
auto db_attennuation = port1.DCloss;
if(port1.frequency != 0) {
db_attennuation += port1.loss * sqrt(d.frequency / port1.frequency);
}
// convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase);
S11 /= correction * correction;
S21 /= correction;
S12 /= correction;
}
if(port2.enabled) {
auto phase = -2 * M_PI * port2.delay * d.frequency;
auto db_attennuation = port2.DCloss;
if(port2.frequency != 0) {
db_attennuation += port2.loss * sqrt(d.frequency / port2.frequency);
}
// convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase);
S22 /= correction * correction;
S21 /= correction;
S12 /= correction;
}
d.real_S11 = S11.real();
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
}
}
void PortExtension::edit()
{
constexpr double c = 299792458;
auto dialog = new QDialog();
auto ui = new Ui::PortExtensionEditDialog();
ui->setupUi(dialog);
// set initial values
ui->P1Time->setUnit("s");
ui->P1Time->setPrefixes("pnum ");
ui->P1Distance->setUnit("m");
ui->P1Distance->setPrefixes("m ");
ui->P1DCloss->setUnit("db");
ui->P1Loss->setUnit("db");
ui->P1Frequency->setUnit("Hz");
ui->P1Frequency->setPrefixes(" kMG");
ui->P1Time->setValue(port1.delay);
ui->P1Velocity->setValue(port1.velocityFactor);
ui->P1Distance->setValue(port1.delay * port1.velocityFactor * c);
ui->P1DCloss->setValue(port1.DCloss);
ui->P1Loss->setValue(port1.loss);
ui->P1Frequency->setValue(port1.frequency);
if(!kit) {
ui->P1calkit->setEnabled(false);
}
ui->P2Time->setUnit("s");
ui->P2Time->setPrefixes("pnum ");
ui->P2Distance->setUnit("m");
ui->P2Distance->setPrefixes("m ");
ui->P2DCloss->setUnit("db");
ui->P2Loss->setUnit("db");
ui->P2Frequency->setUnit("Hz");
ui->P2Frequency->setPrefixes(" kMG");
ui->P2Time->setValue(port2.delay);
ui->P2Velocity->setValue(port2.velocityFactor);
ui->P2Distance->setValue(port2.delay * port2.velocityFactor * c);
ui->P2DCloss->setValue(port2.DCloss);
ui->P2Loss->setValue(port2.loss);
ui->P2Frequency->setValue(port2.frequency);
if(!kit) {
ui->P2calkit->setEnabled(false);
}
// connections to link delay and distance
connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c);
});
connect(ui->P1Distance, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Time->setValueQuiet(newval / (ui->P1Velocity->value() * c));
});
connect(ui->P1Velocity, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Time->setValueQuiet(ui->P1Distance->value() / (newval * c));
});
connect(ui->P1short, &QPushButton::pressed, [=](){
isOpen = false;
isPort1 = true;
isIdeal = ui->P1ideal->isChecked();
startMeasurement();
});
connect(ui->P1open, &QPushButton::pressed, [=](){
isOpen = true;
isPort1 = true;
isIdeal = ui->P1ideal->isChecked();
startMeasurement();
});
connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c);
});
connect(ui->P2Distance, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Time->setValueQuiet(newval / (ui->P2Velocity->value() * c));
});
connect(ui->P2Velocity, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Time->setValueQuiet(ui->P2Distance->value() / (newval * c));
});
connect(ui->P2short, &QPushButton::pressed, [=](){
isOpen = false;
isPort1 = false;
isIdeal = ui->P2ideal->isChecked();
startMeasurement();
});
connect(ui->P2open, &QPushButton::pressed, [=](){
isOpen = true;
isPort1 = false;
isIdeal = ui->P2ideal->isChecked();
startMeasurement();
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
port1.delay = ui->P1Time->value();
port1.velocityFactor = ui->P1Velocity->value();
port1.DCloss = ui->P1DCloss->value();
port1.loss = ui->P1Loss->value();
port1.frequency = ui->P1Frequency->value();
port2.delay = ui->P2Time->value();
port2.velocityFactor = ui->P2Velocity->value();
port2.DCloss = ui->P2DCloss->value();
port2.loss = ui->P2Loss->value();
port2.frequency = ui->P2Frequency->value();
dialog->accept();
});
connect(ui->buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
dialog->show();
}
void PortExtension::startMeasurement()
{
measurements.clear();
msgBox = new QMessageBox(QMessageBox::Information, "Auto port extension", "Taking measurement...", QMessageBox::Cancel);
connect(msgBox, &QMessageBox::rejected, [=]() {
measuring = false;
measurements.clear();
});
msgBox->show();
measuring = true;
}
QToolBar *PortExtension::createToolbar()
{
auto tb = new QToolBar("Port Extension");
auto editButton = new QPushButton("Port Extension");
auto p1enable = new QCheckBox("Port 1");
auto p2enable = new QCheckBox("Port 2");
connect(p1enable, &QCheckBox::clicked, [=]() {
port1.enabled = p1enable->isChecked();
});
connect(p2enable, &QCheckBox::clicked, [=]() {
port2.enabled = p2enable->isChecked();
});
connect(editButton, &QPushButton::pressed, this, &PortExtension::edit);
tb->addWidget(editButton);
tb->addWidget(p1enable);
tb->addWidget(p2enable);
return tb;
}
void PortExtension::setCalkit(Calkit *kit)
{
this->kit = kit;
}

View File

@ -0,0 +1,44 @@
#ifndef PORTEXTENSION_H
#define PORTEXTENSION_H
#include <QObject>
#include "../VNA_embedded/Application/Communication/Protocol.hpp"
#include <QToolBar>
#include "Calibration/calkit.h"
#include <QMessageBox>
class PortExtension : public QObject
{
Q_OBJECT
public:
PortExtension();
void applyToMeasurement(Protocol::Datapoint& d);
QToolBar *createToolbar();
void setCalkit(Calkit *kit);
public slots:
void edit();
private:
void startMeasurement();
class Extension {
public:
bool enabled;
double delay;
double velocityFactor;
double DCloss;
double loss;
double frequency;
};
Extension port1, port2;
// status variables for automatic measurements
Calkit *kit;
bool measuring;
bool isPort1;
bool isOpen;
bool isIdeal;
std::vector<Protocol::Datapoint> measurements;
QMessageBox *msgBox;
};
#endif // PORTEXTENSION_H

View File

@ -0,0 +1,25 @@
#ifndef PORTEXTENSIONDIALOG_H
#define PORTEXTENSIONDIALOG_H
#include <QDialog>
namespace Ui {
class PortExtensionDialog;
}
class PortExtensionDialog : public QDialog
{
Q_OBJECT
public:
explicit PortExtensionDialog(QWidget *parent = nullptr);
~PortExtensionDialog();
private slots:
void on_buttonBox_accepted();
private:
Ui::PortExtensionDialog *ui;
};
#endif // PORTEXTENSIONDIALOG_H

View File

@ -0,0 +1,334 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PortExtensionEditDialog</class>
<widget class="QDialog" name="PortExtensionEditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>476</height>
</rect>
</property>
<property name="windowTitle">
<string>Port Extension</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Port 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Delay</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="P1Distance"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="P1Time"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Velocity Factor:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SIUnitEdit" name="P1Velocity"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Loss</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>At DC:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P1DCloss"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="SIUnitEdit" name="P1Loss"/>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P1Frequency"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Determine automatically</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="P1ideal">
<property name="text">
<string>Assume ideal open/short</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="P1calkit">
<property name="text">
<string>Use definition from calibration kit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="P1short">
<property name="text">
<string>Measure short</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="P1open">
<property name="text">
<string>Measure open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Port 2</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Delay</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="P2Distance"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="P2Time"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Velocity Factor:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SIUnitEdit" name="P2Velocity"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Loss</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>At DC:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P2DCloss"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="SIUnitEdit" name="P2Loss"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P2Frequency"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Determine automatically</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QRadioButton" name="P2ideal">
<property name="text">
<string>Assume ideal open/short</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="P2calkit">
<property name="text">
<string>Use definition from calibration kit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="P2short">
<property name="text">
<string>Measure short</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="P2open">
<property name="text">
<string>Measure open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -109,6 +109,7 @@ VNA::VNA(AppWindow *window)
connect(calEditKit, &QAction::triggered, [=](){
cal.getCalibrationKit().edit();
});
portExtension.setCalkit(&cal.getCalibrationKit());
// Tools menu
auto toolsMenu = new QMenu("Tools");
@ -310,6 +311,10 @@ VNA::VNA(AppWindow *window)
window->addToolBar(tb_cal);
toolbars.insert(tb_cal);
auto tb_portExtension = portExtension.createToolbar();
window->addToolBar(tb_portExtension);
toolbars.insert(tb_portExtension);
markerModel = new TraceMarkerModel(traceModel);
@ -379,6 +384,7 @@ void VNA::initializeDevice()
if(QFile::exists(filename)) {
cal.openFromFile(filename);
ApplyCalibration(cal.getType());
portExtension.setCalkit(&cal.getCalibrationKit());
}
removeDefaultCal->setEnabled(true);
} else {
@ -418,6 +424,8 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
if(calValid) {
cal.correctMeasurement(d);
}
portExtension.applyToMeasurement(d);
traceModel.addVNAData(d);
emit dataChanged();
if(d.pointNum == settings.points - 1) {

View File

@ -8,6 +8,7 @@
#include "CustomWidgets/tilewidget.h"
#include "Device/device.h"
#include <functional>
#include "portextension.h"
class VNA : public Mode
{
@ -69,6 +70,8 @@ private:
QMenu *defaultCalMenu;
QAction *assignDefaultCal, *removeDefaultCal;
PortExtension portExtension;
// Status Labels
QLabel *lAverages;