Additional de-embedding options: 2xthru and matching network

This commit is contained in:
Jan Käberich 2021-01-29 21:44:44 +01:00
parent 51806b936c
commit 09d5c53bc7
37 changed files with 2954 additions and 100 deletions

View File

@ -24,6 +24,7 @@ HEADERS += \
SpectrumAnalyzer/tracewidgetsa.h \ SpectrumAnalyzer/tracewidgetsa.h \
Tools/eseries.h \ Tools/eseries.h \
Tools/impedancematchdialog.h \ Tools/impedancematchdialog.h \
Tools/parameters.h \
Traces/Math/dft.h \ Traces/Math/dft.h \
Traces/Math/expression.h \ Traces/Math/expression.h \
Traces/Math/medianfilter.h \ Traces/Math/medianfilter.h \
@ -96,7 +97,12 @@ HEADERS += \
Traces/xyplotaxisdialog.h \ Traces/xyplotaxisdialog.h \
Util/qpointervariant.h \ Util/qpointervariant.h \
Util/util.h \ Util/util.h \
VNA/portextension.h \ VNA/Deembedding/deembedding.h \
VNA/Deembedding/deembeddingdialog.h \
VNA/Deembedding/deembeddingoption.h \
VNA/Deembedding/matchingnetwork.h \
VNA/Deembedding/portextension.h \
VNA/Deembedding/twothru.h \
VNA/tracewidgetvna.h \ VNA/tracewidgetvna.h \
VNA/vna.h \ VNA/vna.h \
appwindow.h \ appwindow.h \
@ -135,6 +141,7 @@ SOURCES += \
SpectrumAnalyzer/tracewidgetsa.cpp \ SpectrumAnalyzer/tracewidgetsa.cpp \
Tools/eseries.cpp \ Tools/eseries.cpp \
Tools/impedancematchdialog.cpp \ Tools/impedancematchdialog.cpp \
Tools/parameters.cpp \
Traces/Math/dft.cpp \ Traces/Math/dft.cpp \
Traces/Math/expression.cpp \ Traces/Math/expression.cpp \
Traces/Math/medianfilter.cpp \ Traces/Math/medianfilter.cpp \
@ -194,7 +201,12 @@ SOURCES += \
Traces/tracewidget.cpp \ Traces/tracewidget.cpp \
Traces/tracexyplot.cpp \ Traces/tracexyplot.cpp \
Traces/xyplotaxisdialog.cpp \ Traces/xyplotaxisdialog.cpp \
VNA/portextension.cpp \ VNA/Deembedding/deembedding.cpp \
VNA/Deembedding/deembeddingdialog.cpp \
VNA/Deembedding/deembeddingoption.cpp \
VNA/Deembedding/matchingnetwork.cpp \
VNA/Deembedding/portextension.cpp \
VNA/Deembedding/twothru.cpp \
VNA/tracewidgetvna.cpp \ VNA/tracewidgetvna.cpp \
VNA/vna.cpp \ VNA/vna.cpp \
appwindow.cpp \ appwindow.cpp \
@ -243,7 +255,11 @@ FORMS += \
Traces/tracetouchstoneexport.ui \ Traces/tracetouchstoneexport.ui \
Traces/tracewidget.ui \ Traces/tracewidget.ui \
Traces/xyplotaxisdialog.ui \ Traces/xyplotaxisdialog.ui \
VNA/portextensioneditdialog.ui \ VNA/Deembedding/deembeddingdialog.ui \
VNA/Deembedding/form.ui \
VNA/Deembedding/matchingnetworkdialog.ui \
VNA/Deembedding/portextensioneditdialog.ui \
VNA/Deembedding/twothrudialog.ui \
main.ui \ main.ui \
preferencesdialog.ui preferencesdialog.ui

View File

@ -5,6 +5,7 @@
#include <fstream> #include <fstream>
#include "unit.h" #include "unit.h"
#include <QDebug> #include <QDebug>
#include "Tools/parameters.h"
using namespace std; using namespace std;
@ -234,52 +235,6 @@ void Calibration::constructTransmissionNormalization()
} }
} }
template<typename T>
class Tparam {
public:
Tparam(){};
Tparam(T t11, T t12, T t21, T t22)
: t11(t11), t12(t12), t21(t21), t22(t22){};
void fromSparam(T S11, T S21, T S12, T S22) {
t11 = -(S11*S22 - S12*S21) / S21;
t12 = S11 / S21;
t21 = -S22 / S21;
t22 = 1.0 / S21;
}
void toSparam(T &S11, T &S21, T &S12, T &S22) {
S11 = t12 / t22;
S21 = T(1) / t22;
S12 = (t11*t22 - t12*t21) / t22;
S22 = -t21 / t22;
}
Tparam inverse() {
Tparam i;
T det = t11*t22 - t12*t21;
i.t11 = t22 / det;
i.t12 = -t12 / det;
i.t21 = -t21 / det;
i.t22 = t11 / det;
return i;
}
Tparam operator*(const Tparam &r) {
Tparam p;
p.t11 = t11*r.t11 + t12*r.t21;
p.t12 = t11*r.t12 + t12*r.t22;
p.t21 = t21*r.t11 + t22*r.t21;
p.t22 = t21*r.t12 + t22*r.t22;
return p;
}
Tparam operator*(const T &r) {
Tparam p;
p.t11 = t11 * r;
p.t12 = t12 * r;
p.t21 = t21 * r;
p.t22 = t22 * r;
return p;
}
T t11, t12, t21, t22;
};
template<typename T> void solveQuadratic(T a, T b, T c, T &result1, T &result2) template<typename T> void solveQuadratic(T a, T b, T c, T &result1, T &result2)
{ {
T root = sqrt(b * b - T(4) * a * c); T root = sqrt(b * b - T(4) * a * c);
@ -317,24 +272,24 @@ void Calibration::constructTRL()
// calculate TRL calibration // calculate TRL calibration
// variable names and formulas according to http://emlab.uiuc.edu/ece451/notes/new_TRL.pdf // variable names and formulas according to http://emlab.uiuc.edu/ece451/notes/new_TRL.pdf
// page 19 // page 19
auto R_T = Tparam<complex<double>>(); Sparam Sthrough(S11_through, S12_through, S21_through, S22_through);
auto R_D = Tparam<complex<double>>(); Sparam Sline(S11_line, S12_line, S21_line, S22_line);
R_T.fromSparam(S11_through, S21_through, S12_through, S22_through); auto R_T = Tparam(Sthrough);
R_D.fromSparam(S11_line, S21_line, S12_line, S22_line); auto R_D = Tparam(Sline);
auto T = R_D*R_T.inverse(); auto T = R_D*R_T.inverse();
complex<double> a_over_c, b; complex<double> a_over_c, b;
// page 21-22 // page 21-22
solveQuadratic(T.t21, T.t22 - T.t11, -T.t12, b, a_over_c); solveQuadratic(T.m21, T.m22 - T.m11, -T.m12, b, a_over_c);
// ensure correct root selection // ensure correct root selection
// page 23 // page 23
if(abs(b) >= abs(a_over_c)) { if(abs(b) >= abs(a_over_c)) {
swap(b, a_over_c); swap(b, a_over_c);
} }
// page 24 // page 24
auto g = R_T.t22; auto g = R_T.m22;
auto d = R_T.t11 / g; auto d = R_T.m11 / g;
auto e = R_T.t12 / g; auto e = R_T.m12 / g;
auto f = R_T.t21 / g; auto f = R_T.m21 / g;
// page 25 // page 25
auto r22_rho22 = g * (1.0 - e / a_over_c) / (1.0 - b / a_over_c); auto r22_rho22 = g * (1.0 - e / a_over_c) / (1.0 - b / a_over_c);
@ -360,11 +315,15 @@ void Calibration::constructTRL()
auto alpha = alpha_a / a; auto alpha = alpha_a / a;
auto beta = beta_over_alpha * alpha; auto beta = beta_over_alpha * alpha;
auto c = a / a_over_c; auto c = a / a_over_c;
auto Box_A = Tparam<complex<double>>(r22 * a, r22 * b, r22 * c, r22); auto Box_A = Tparam(r22 * a, r22 * b, r22 * c, r22);
auto Box_B = Tparam<complex<double>>(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22); auto Box_B = Tparam(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22);
complex<double> dummy1, dummy2; auto S_A = Sparam(Box_A);
Box_A.toSparam(p.fe00, dummy1, p.fe10e01, p.fe11); p.fe00 = S_A.m11;
Box_B.toSparam(p.fe22, p.fe10e32, dummy1, dummy2); p.fe10e01 = S_A.m12;
p.fe11 = S_A.m22;
auto S_B = Sparam(Box_B);
p.fe22 = S_B.m11;
p.fe10e32 = S_B.m21;
// no isolation measurement available // no isolation measurement available
p.fe30 = 0.0; p.fe30 = 0.0;
@ -376,10 +335,15 @@ void Calibration::constructTRL()
rho22 = 1.0/(alpha - beta * gamma); rho22 = 1.0/(alpha - beta * gamma);
r22 = r22_rho22 / rho22; r22 = r22_rho22 / rho22;
Box_A = Tparam<complex<double>>(r22 * a, r22 * b, r22 * c, r22); Box_A = Tparam(r22 * a, r22 * b, r22 * c, r22);
Box_B = Tparam<complex<double>>(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22); Box_B = Tparam(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22);
Box_A.toSparam(dummy1, dummy2, p.re23e01, p.re11); S_A = Sparam(Box_A);
Box_B.toSparam(p.re22, p.re23e32, dummy1, p.re33); p.re23e01 = S_A.m12;
p.re11 = S_A.m22;
S_B = Sparam(Box_B);
p.re22 = S_B.m11;
p.re23e32 = S_B.m21;
p.re33 = S_B.m22;
// no isolation measurement available // no isolation measurement available
p.re03 = 0.0; p.re03 = 0.0;

View File

@ -0,0 +1,43 @@
#include "parameters.h"
Sparam::Sparam(const Tparam &t) {
m11 = t.m12 / t.m22;
m21 = Type(1) / t.m22;
m12 = (t.m11*t.m22 - t.m12*t.m21) / t.m22;
m22 = -t.m21 / t.m22;
}
Sparam::Sparam(const ABCDparam &a, Type Z01, Type Z02) {
auto denom = a.m11*Z02+a.m12+a.m21*Z01*Z02+a.m22*Z01;
m11 = (a.m11*Z02+a.m12-a.m21*conj(Z01)*Z02-a.m22*conj(Z01)) / denom;
m12 = (2.0*(a.m11*a.m22-a.m12*a.m21)*sqrt(real(Z01)*real(Z02))) / denom;
m21 = (2.0*sqrt(real(Z01)*real(Z02))) / denom;
m22 = (-a.m11*conj(Z02)+a.m12-a.m21*Z01*conj(Z02)+a.m22*Z01) / denom;
}
Sparam::Sparam(const ABCDparam &a, Type Z0)
: Sparam(a, Z0, Z0)
{
}
ABCDparam::ABCDparam(const Sparam &s, Type Z01, Type Z02)
{
auto denom = 2.0*s.m21*sqrt(real(Z01)*real(Z02));
m11 = ((conj(Z01)+s.m11*Z01)*(1.0-s.m22)+s.m12*s.m21*Z01) / denom;
m12 = ((conj(Z01)+s.m11*Z01)*(conj(Z02)+s.m22*Z02)-s.m12*s.m21*Z01*Z02) / denom;
m21 = ((1.0-s.m11)*(1.0-s.m22)-s.m12*s.m21) / denom;
m22 = ((1.0-s.m11)*(conj(Z02)+s.m22*Z02)+s.m12*s.m21*Z02) / denom;
}
Tparam::Tparam(const Sparam &s)
{
m11 = -(s.m11*s.m22 - s.m12*s.m21) / s.m21;
m12 = s.m11 / s.m21;
m21 = -s.m22 / s.m21;
m22 = 1.0 / s.m21;
}
ABCDparam::ABCDparam(const Sparam &s, Type Z0)
: ABCDparam(s, Z0, Z0)
{
}

View File

@ -0,0 +1,187 @@
#ifndef TPARAM_H
#define TPARAM_H
#include <complex>
using Type = std::complex<double>;
class Parameters {
public:
Parameters(Type m11, Type m12, Type m21, Type m22)
: m11(m11), m12(m12), m21(m21), m22(m22){};
Parameters(){};
Type m11, m12, m21, m22;
};
// forward declaration of parameter classes
class Sparam;
class Tparam;
class ABCDparam;
class Sparam : public Parameters {
public:
using Parameters::Parameters;
Sparam(const Tparam &t);
Sparam(const ABCDparam &a, Type Z01, Type Z02);
Sparam(const ABCDparam &a, Type Z0);
Sparam operator+(const Sparam &r) {
Sparam p;
p.m11 = this->m11+r.m11;
p.m12 = this->m12+r.m12;
p.m21 = this->m21+r.m21;
p.m22 = this->m22+r.m22;
return p;
}
Sparam operator*(const Type &r) {
Sparam p(m11*r, m12*r, m21*r, m22*r);
return p;
}
};
class ABCDparam : public Parameters {
public:
using Parameters::Parameters;
ABCDparam(const Sparam &s, Type Z01, Type Z02);
ABCDparam(const Sparam &s, Type Z0);
ABCDparam operator*(const ABCDparam &r) {
ABCDparam p;
p.m11 = this->m11*r.m11 + this->m12*r.m21;
p.m12 = this->m11*r.m12 + this->m12*r.m22;
p.m21 = this->m21*r.m11 + this->m22*r.m21;
p.m22 = this->m21*r.m12 + this->m22*r.m22;
return p;
}
ABCDparam inverse() {
ABCDparam i;
Type det = m11*m22 - m12*m21;
i.m11 = m22 / det;
i.m12 = -m12 / det;
i.m21 = -m21 / det;
i.m22 = m11 / det;
return i;
}
ABCDparam operator*(const Type &r) {
ABCDparam p(m11*r, m12*r, m21*r, m22*r);
return p;
}
ABCDparam root() {
// calculate root of 2x2 matrix, according to https://en.wikipedia.org/wiki/Square_root_of_a_2_by_2_matrix (choose positive roots)
auto tau = m11 + m22;
auto sigma = m11*m22 - m12*m21;
auto s = sqrt(sigma);
auto t = sqrt(tau + 2.0*s);
ABCDparam r = *this;
r.m11 += s;
r.m22 += s;
r = r * (1.0/t);
return r;
}
};
class Tparam : public Parameters {
public:
using Parameters::Parameters;
Tparam(const Sparam &s);
Tparam operator*(const Tparam &r) {
Tparam p;
p.m11 = this->m11*r.m11 + this->m12*r.m21;
p.m12 = this->m11*r.m12 + this->m12*r.m22;
p.m21 = this->m21*r.m11 + this->m22*r.m21;
p.m22 = this->m21*r.m12 + this->m22*r.m22;
return p;
}
Tparam operator+(const Tparam &r) {
Tparam p;
p.m11 = this->m11+r.m11;
p.m12 = this->m12+r.m12;
p.m21 = this->m21+r.m21;
p.m22 = this->m22+r.m22;
return p;
}
Tparam inverse() {
Tparam i;
Type det = m11*m22 - m12*m21;
i.m11 = m22 / det;
i.m12 = -m12 / det;
i.m21 = -m21 / det;
i.m22 = m11 / det;
return i;
}
Tparam operator*(const Type &r) {
Tparam p(m11*r, m12*r, m21*r, m22*r);
return p;
}
Tparam root() {
// calculate root of 2x2 matrix, according to https://en.wikipedia.org/wiki/Square_root_of_a_2_by_2_matrix (choose positive roots)
auto tau = m11 + m22;
auto sigma = m11*m22 - m12*m21;
auto s = sqrt(sigma);
auto t = sqrt(tau + 2.0*s);
Tparam r = *this;
r.m11 += s;
r.m22 += s;
r = r * (1.0/t);
return r;
}
};
//template<typename T>
//class Tparam {
//public:
// Tparam(){};
// Tparam(T t11, T t12, T t21, T t22)
// : t11(t11), t12(t12), t21(t21), t22(t22){};
// void fromSparam(T S11, T S21, T S12, T S22) {
// t11 = -(S11*S22 - S12*S21) / S21;
// t12 = S11 / S21;
// t21 = -S22 / S21;
// t22 = 1.0 / S21;
// }
// void toSparam(T &S11, T &S21, T &S12, T &S22) {
// S11 = t12 / t22;
// S21 = T(1) / t22;
// S12 = (t11*t22 - t12*t21) / t22;
// S22 = -t21 / t22;
// }
// Tparam inverse() {
// Tparam i;
// T det = t11*t22 - t12*t21;
// i.t11 = t22 / det;
// i.t12 = -t12 / det;
// i.t21 = -t21 / det;
// i.t22 = t11 / det;
// return i;
// }
// Tparam root() {
// // calculate root of 2x2 matrix, according to https://en.wikipedia.org/wiki/Square_root_of_a_2_by_2_matrix (choose positive roots)
// auto tau = t11 + t22;
// auto sigma = t11*t22 - t12*t21;
// auto s = sqrt(sigma);
// auto t = sqrt(tau + 2.0*s);
// Tparam r = *this;
// r.t11 += s;
// r.t22 += s;
// r = r * (1.0/t);
// return r;
// }
// Tparam operator*(const Tparam &r) {
// Tparam p;
// p.t11 = t11*r.t11 + t12*r.t21;
// p.t12 = t11*r.t12 + t12*r.t22;
// p.t21 = t21*r.t11 + t22*r.t21;
// p.t22 = t21*r.t12 + t22*r.t22;
// return p;
// }
// Tparam operator*(const T &r) {
// Tparam p;
// p.t11 = t11 * r;
// p.t12 = t12 * r;
// p.t21 = t21 * r;
// p.t22 = t22 * r;
// return p;
// }
// T t11, t12, t21, t22;
//};
#endif // TPARAM_H

View File

@ -0,0 +1,93 @@
#include "deembedding.h"
#include "deembeddingdialog.h"
#include <QDebug>
using namespace std;
void Deembedding::configure()
{
auto d = new DeembeddingDialog(this);
d->show();
}
void Deembedding::Deembed(Protocol::Datapoint &d)
{
for(auto it = options.begin();it != options.end();it++) {
(*it)->transformDatapoint(d);
}
}
void Deembedding::removeOption(unsigned int index)
{
if(index < options.size()) {
delete options[index];
options.erase(options.begin() + index);
}
}
void Deembedding::addOption(DeembeddingOption *option)
{
options.push_back(option);
connect(option, &DeembeddingOption::deleted, [=](DeembeddingOption *o){
// find deleted option and remove from list
auto pos = find(options.begin(), options.end(), o);
if(pos != options.end()) {
options.erase(pos);
}
});
}
void Deembedding::swapOptions(unsigned int index)
{
if(index + 1 >= options.size()) {
return;
}
std::swap(options[index], options[index+1]);
}
nlohmann::json Deembedding::toJSON()
{
nlohmann::json list;
for(auto m : options) {
nlohmann::json jm;
jm["operation"] = DeembeddingOption::getName(m->getType()).toStdString();
jm["settings"] = m->toJSON();
list.push_back(jm);
}
return list;
}
void Deembedding::fromJSON(nlohmann::json j)
{
// clear all options
while(options.size() > 0) {
removeOption(0);
}
for(auto jm : j) {
QString operation = QString::fromStdString(jm.value("operation", ""));
if(operation.isEmpty()) {
qWarning() << "Skipping empty de-embedding operation";
continue;
}
// attempt to find the type of operation
DeembeddingOption::Type type = DeembeddingOption::Type::Last;
for(unsigned int i=0;i<(int) DeembeddingOption::Type::Last;i++) {
if(DeembeddingOption::getName((DeembeddingOption::Type) i) == operation) {
// found the correct operation
type = (DeembeddingOption::Type) i;
break;
}
}
if(type == DeembeddingOption::Type::Last) {
// unable to find this operation
qWarning() << "Unable to create de-embedding operation:" << operation;
continue;
}
qDebug() << "Creating math operation of type:" << operation;
auto op = DeembeddingOption::create(type);
if(jm.contains("settings")) {
op->fromJSON(jm["settings"]);
}
addOption(op);
}
}

View File

@ -0,0 +1,31 @@
#ifndef DEEMBEDDING_H
#define DEEMBEDDING_H
#include "deembeddingoption.h"
#include <vector>
#include <QObject>
#include "savable.h"
class Deembedding : public QObject, public Savable
{
Q_OBJECT
public:
Deembedding(){};
~Deembedding(){};
void Deembed(Protocol::Datapoint &d);
void removeOption(unsigned int index);
void addOption(DeembeddingOption* option);
void swapOptions(unsigned int index);
std::vector<DeembeddingOption*>& getOptions() {return options;};
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
public slots:
void configure();
private:
std::vector<DeembeddingOption*> options;
};
#endif // DEEMBEDDING_H

View File

@ -0,0 +1,107 @@
#include "deembeddingdialog.h"
#include "ui_deembeddingdialog.h"
#include "deembeddingoption.h"
#include <QMenu>
DeembeddingDialog::DeembeddingDialog(Deembedding *d, QWidget *parent) :
QDialog(parent),
ui(new Ui::DeembeddingDialog),
model(d)
{
ui->setupUi(this);
ui->view->setModel(&model);
auto addMenu = new QMenu();
for(unsigned int i=0;i<(unsigned int)DeembeddingOption::Type::Last;i++) {
auto type = (DeembeddingOption::Type) i;
auto action = new QAction(DeembeddingOption::getName(type));
connect(action, &QAction::triggered, [=](){
auto option = DeembeddingOption::create(type);
model.addOption(option);
});
addMenu->addAction(action);
}
ui->bAdd->setMenu(addMenu);
connect(ui->view->selectionModel(), &QItemSelectionModel::currentRowChanged, [=](const QModelIndex &current, const QModelIndex &previous){
Q_UNUSED(previous)
if(!current.isValid()) {
ui->bDelete->setEnabled(false);
ui->bMoveUp->setEnabled(false);
ui->bMoveDown->setEnabled(false);
ui->bEdit->setEnabled(false);
} else {
ui->bDelete->setEnabled(true);
ui->bMoveUp->setEnabled(current.row() > 0);
ui->bMoveDown->setEnabled(current.row() + 1 < model.rowCount());
ui->bEdit->setEnabled(true);
}
});
connect(ui->bDelete, &QPushButton::clicked, [=](){
model.deleteRow(ui->view->currentIndex().row());
});
connect(ui->bMoveUp, &QPushButton::clicked, [=](){
auto index = ui->view->currentIndex();
d->swapOptions(index.row() - 1);
ui->view->setCurrentIndex(index.sibling(index.row() - 1, 0));
});
connect(ui->bMoveDown, &QPushButton::clicked, [=](){
auto index = ui->view->currentIndex();
d->swapOptions(index.row());
ui->view->setCurrentIndex(index.sibling(index.row() + 1, 0));
});
connect(ui->view, &QListView::doubleClicked, [=](const QModelIndex &index) {
if(index.isValid()) {
d->getOptions()[index.row()]->edit();
}
});
connect(ui->bEdit, &QPushButton::clicked, [=](){
auto index = ui->view->currentIndex();
if(index.isValid()) {
d->getOptions()[index.row()]->edit();
}
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
}
DeembeddingDialog::~DeembeddingDialog()
{
delete ui;
}
OptionModel::OptionModel(Deembedding *d, QObject *parent)
: QAbstractListModel(parent),
d(d){}
int OptionModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return d->getOptions().size();
}
QVariant OptionModel::data(const QModelIndex &index, int role) const
{
if(index.isValid() && role == Qt::DisplayRole) {
auto type = d->getOptions()[index.row()]->getType();
return DeembeddingOption::getName(type);
} else {
return QVariant();
}
}
void OptionModel::addOption(DeembeddingOption *option)
{
beginInsertRows(QModelIndex(), d->getOptions().size(), d->getOptions().size());
d->addOption(option);
endInsertRows();
// open the editor for the newly added operation
option->edit();
}
void OptionModel::deleteRow(unsigned int row)
{
beginRemoveRows(QModelIndex(), row, row);
d->removeOption(row);
endRemoveRows();
}

View File

@ -0,0 +1,49 @@
#ifndef DEEMBEDDINGDIALOG_H
#define DEEMBEDDINGDIALOG_H
#include <QDialog>
#include "deembeddingoption.h"
#include "deembedding.h"
#include <QAbstractTableModel>
namespace Ui {
class DeembeddingDialog;
}
class OptionModel : public QAbstractListModel
{
Q_OBJECT
public:
OptionModel(Deembedding *d, QObject *parent = 0);
enum {
ColIndexStatus = 0,
ColIndexDescription = 1,
ColIndexDomain = 2,
ColIndexLast,
};
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
void addOption(DeembeddingOption *option);
void deleteRow(unsigned int row);
private:
Deembedding *d;
};
class DeembeddingDialog : public QDialog
{
Q_OBJECT
public:
explicit DeembeddingDialog(Deembedding* d, QWidget *parent = nullptr);
~DeembeddingDialog();
private:
Ui::DeembeddingDialog *ui;
OptionModel model;
};
#endif // DEEMBEDDINGDIALOG_H

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeembeddingDialog</class>
<widget class="QDialog" name="DeembeddingDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>386</width>
<height>324</height>
</rect>
</property>
<property name="windowTitle">
<string>De-embedding</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListView" name="view"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="bAdd">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Add</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-add" resource="../../icons.qrc">
<normaloff>:/icons/add.png</normaloff>:/icons/add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bDelete">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Delete</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-remove" resource="../../icons.qrc">
<normaloff>:/icons/remove.png</normaloff>:/icons/remove.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bMoveUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Move up</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-up">
<normaloff>../../Traces/Math</normaloff>../../Traces/Math</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bMoveDown">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Move down</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-down">
<normaloff>../../Traces/Math</normaloff>../../Traces/Math</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Edit</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="accessories-text-editor" resource="../../icons.qrc">
<normaloff>:/icons/edit.png</normaloff>:/icons/edit.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>18</width>
<height>186</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,33 @@
#include "deembeddingoption.h"
#include "portextension.h"
#include "twothru.h"
#include "matchingnetwork.h"
DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type)
{
switch(type) {
case Type::PortExtension:
return new PortExtension();
case Type::TwoThru:
return new TwoThru();
case Type::MatchingNetwork:
return new MatchingNetwork();
default:
return nullptr;
}
}
QString DeembeddingOption::getName(DeembeddingOption::Type type)
{
switch(type) {
case Type::PortExtension:
return "Port Extension";
case Type::TwoThru:
return "2xThru";
case Type::MatchingNetwork:
return "Matching Network";
default:
return "";
}
}

View File

@ -0,0 +1,31 @@
#ifndef DEEMBEDDINGOPTION_H
#define DEEMBEDDINGOPTION_H
#include <QWidget>
#include "savable.h"
#include "Device/device.h"
class DeembeddingOption : public QObject, public Savable
{
Q_OBJECT
public:
enum class Type {
PortExtension,
TwoThru,
MatchingNetwork,
// Add new deembedding options here, do not explicitly assign values and keep the Last entry at the last position
Last,
};
static DeembeddingOption *create(Type type);
static QString getName(Type type);
virtual void transformDatapoint(Protocol::Datapoint &p) = 0;
virtual void edit(){};
virtual Type getType() = 0;
signals:
// Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself
void deleted(DeembeddingOption *option);
};
#endif // DEEMBEDDING_H

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>339</width>
<height>238</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget#Form {image: url(:/icons/parallelC.svg);}
border: 1px solid red;</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>186</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,549 @@
#include "matchingnetwork.h"
#include "ui_matchingnetworkdialog.h"
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSpacerItem>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <algorithm>
#include <QDebug>
using namespace std;
MatchingNetwork::MatchingNetwork()
{
dropPending = false;
dragComponent = nullptr;
dropComponent = nullptr;
addNetwork = true;
}
void MatchingNetwork::transformDatapoint(Protocol::Datapoint &p)
{
auto S = Sparam(complex<double>(p.real_S11, p.imag_S11),
complex<double>(p.real_S12, p.imag_S12),
complex<double>(p.real_S21, p.imag_S21),
complex<double>(p.real_S22, p.imag_S22));
auto measurement = ABCDparam(S, 50.0);
if(matching.count(p.frequency) == 0) {
// this point is not calculated yet
MatchingPoint m;
// start with identiy matrix
m.p1 = ABCDparam(1.0,0.0,0.0,1.0);
for(auto c : p1Network) {
m.p1 = m.p1 * c->parameters(p.frequency);
}
// same for network at port 2
m.p2 = ABCDparam(1.0,0.0,0.0,1.0);
for(auto c : p2Network) {
m.p2 = m.p2 * c->parameters(p.frequency);
}
if(!addNetwork) {
// need to remove the effect of the networks, invert matrices
m.p1 = m.p1.inverse();
m.p2 = m.p2.inverse();
}
matching[p.frequency] = m;
}
// at this point the map contains the matching network effect
auto m = matching[p.frequency];
auto corrected = m.p1 * measurement * m.p2;
S = Sparam(corrected, 50.0);
p.real_S11 = real(S.m11);
p.imag_S11 = imag(S.m11);
p.real_S12 = real(S.m12);
p.imag_S12 = imag(S.m12);
p.real_S21 = real(S.m21);
p.imag_S21 = imag(S.m21);
p.real_S22 = real(S.m22);
p.imag_S22 = imag(S.m22);
}
void MatchingNetwork::edit()
{
auto dialog = new QDialog();
auto ui = new Ui::MatchingNetworkDialog();
ui->setupUi(dialog);
graph = new QWidget();
ui->scrollArea->setWidget(graph);
auto layout = new QHBoxLayout();
graph->setLayout(layout);
graph->setAcceptDrops(true);
graph->setObjectName("Graph");
graph->installEventFilter(this);
ui->lSeriesC->installEventFilter(this);
ui->lSeriesL->installEventFilter(this);
ui->lSeriesR->installEventFilter(this);
ui->lParallelC->installEventFilter(this);
ui->lParallelL->installEventFilter(this);
ui->lParallelR->installEventFilter(this);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
layout->addStretch(1);
auto p1 = new QWidget();
p1->setMinimumSize(portWidth, 150);
p1->setMaximumSize(portWidth, 150);
p1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
p1->setStyleSheet("image: url(:/icons/port1.svg);");
auto DUT = new QWidget();
DUT->setMinimumSize(DUTWidth, 150);
DUT->setMaximumSize(DUTWidth, 150);
DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
DUT->setStyleSheet("image: url(:/icons/DUT.svg);");
auto p2 = new QWidget();
p2->setMinimumSize(portWidth, 150);
p2->setMaximumSize(portWidth, 150);
p2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
p2->setStyleSheet("image: url(:/icons/port2.svg);");
layout->addWidget(p1);
for(auto w : p1Network) {
layout->addWidget(w);
connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
layout->addWidget(DUT);
for(auto w : p2Network) {
layout->addWidget(w);
connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
layout->addWidget(p2);
layout->addStretch(1);
dialog->show();
if(addNetwork) {
ui->bAddNetwork->setChecked(true);
} else {
ui->bRemoveNetwork->setChecked(true);
}
connect(ui->bAddNetwork, &QRadioButton::toggled, [=](bool add) {
addNetwork = add;
// network changed, need to recalculate matching
matching.clear();
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
}
nlohmann::json MatchingNetwork::toJSON()
{
nlohmann::json j;
for(int i=0;i<2;i++) {
auto network = i==0 ? p1Network : p2Network;
nlohmann::json jn;
for(auto c : network) {
nlohmann::json jc;
jc["component"] = c->getName().toStdString();
jc["params"] = c->toJSON();
jn.push_back(jc);
}
j.push_back(jn);
}
return j;
}
void MatchingNetwork::fromJSON(nlohmann::json j)
{
for(int i=0;i<2;i++) {
auto jn = j[i];
auto &network = i==0 ? p1Network : p2Network;
network.clear();
for(auto jc : jn) {
if(!jc.contains("component")) {
continue;
}
auto c = MatchingComponent::createFromName(QString::fromStdString(jc["component"]));
if(!c) {
continue;
}
c->fromJSON(jc["params"]);
network.push_back(c);
}
}
matching.clear();
}
MatchingComponent *MatchingNetwork::componentAtPosition(int pos)
{
pos -= graph->layout()->itemAt(0)->geometry().width();
pos -= portWidth;
if(pos > 0 && pos <= (int) p1Network.size() * componentWidth) {
// position is in port 1 network
return p1Network[pos / componentWidth];
} else if(pos > (int) p1Network.size() * componentWidth + DUTWidth) {
pos -= (int) p1Network.size() * componentWidth + DUTWidth;
if(pos <= (int) p2Network.size() * componentWidth) {
// position is in port 2 network
return p2Network[pos / componentWidth];
}
}
return nullptr;
}
unsigned int MatchingNetwork::findInsertPosition(int xcoord)
{
xcoord -= graph->layout()->itemAt(0)->geometry().width();
xcoord -= portWidth;
if(xcoord <= (int) p1Network.size() * componentWidth + DUTWidth/2) {
// added in port 1 network
int index = (xcoord + componentWidth / 2) / componentWidth;
if(index < 0) {
index = 0;
} else if(index > (int) p1Network.size()) {
index = p1Network.size();
}
// add 2 (first two widgets are always the stretch and port 1 widget)
return index + 2;
} else {
// added in port 2 network
xcoord -= (int) p1Network.size() * componentWidth + DUTWidth;
int index = (xcoord + componentWidth / 2) / componentWidth;
if(index < 0) {
index = 0;
} else if(index > (int) p2Network.size()) {
index = p2Network.size();
}
// add 3 (same two widgets as in port 1 + DUT) and the size of the port 1 network
return index + 3 + p1Network.size();
}
}
void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c)
{
auto index = findInsertPosition(pos);
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
l->insertWidget(index, c);
c->show();
// add component to correct matching network
index -= 2; // first two widgets are fixed
if(index <= p1Network.size()) {
addComponent(true, index, c);
} else {
index -= 1 + p1Network.size();
addComponent(false, index, c);
}
// network changed, need to recalculate matching
matching.clear();
connect(c, &MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
void MatchingNetwork::addComponent(bool port1, int index, MatchingComponent *c)
{
if(port1) {
p1Network.insert(p1Network.begin() + index, c);
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
p1Network.erase(remove(p1Network.begin(), p1Network.end(), c), p1Network.end());
});
} else {
// same procedure for port 2 network
p2Network.insert(p2Network.begin() + index, c);
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
p2Network.erase(remove(p2Network.begin(), p2Network.end(), c), p2Network.end());
});
}
}
void MatchingNetwork::createDragComponent(MatchingComponent *c)
{
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QByteArray encodedPointer;
QDataStream stream(&encodedPointer, QIODevice::WriteOnly);
stream << quintptr(c);
mimeData->setData("matchingComponent/pointer", encodedPointer);
drag->setMimeData(mimeData);
drag->exec(Qt::MoveAction);
}
void MatchingNetwork::updateInsertIndicator(int xcoord)
{
auto index = findInsertPosition(xcoord);
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
l->removeWidget(insertIndicator);
l->insertWidget(index, insertIndicator);
}
bool MatchingNetwork::eventFilter(QObject *object, QEvent *event)
{
if(object->objectName() == "Graph") {
if(event->type() == QEvent::MouseButtonPress) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
dragComponent = componentAtPosition(mouseEvent->pos().x());
if(dragComponent) {
dragStartPosition = mouseEvent->pos();
return true;
}
}
return false;
} else if(event->type() == QEvent::MouseMove) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
return false;
}
if (!dragComponent) {
return false;
}
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
< QApplication::startDragDistance()) {
return false;
}
// remove and hide component while it is being dragged
graph->layout()->removeWidget(dragComponent);
dragComponent->hide();
p1Network.erase(remove(p1Network.begin(), p1Network.end(), dragComponent), p1Network.end());
p2Network.erase(remove(p2Network.begin(), p2Network.end(), dragComponent), p2Network.end());
graph->update();
// network changed, need to recalculate matching
matching.clear();
createDragComponent(dragComponent);
return true;
} else if(event->type() == QEvent::DragEnter) {
auto dragEvent = static_cast<QDragEnterEvent*>(event);
if(dragEvent->mimeData()->hasFormat("matchingComponent/pointer")) {
dropPending = true;
auto data = dragEvent->mimeData()->data("matchingComponent/pointer");
QDataStream stream(&data, QIODevice::ReadOnly);
quintptr dropPtr;
stream >> dropPtr;
dropComponent = (MatchingComponent*) dropPtr;
dragEvent->acceptProposedAction();
insertIndicator = new QWidget();
insertIndicator->setMinimumSize(2, 150);
insertIndicator->setMaximumSize(2, 150);
insertIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
insertIndicator->setStyleSheet("background-color:red;");
updateInsertIndicator(dragEvent->pos().x());
return true;
}
} else if(event->type() == QEvent::DragMove) {
auto dragEvent = static_cast<QDragMoveEvent*>(event);
updateInsertIndicator(dragEvent->pos().x());
return true;
} else if(event->type() == QEvent::Drop) {
auto dragEvent = static_cast<QDropEvent*>(event);
delete insertIndicator;
addComponentAtPosition(dragEvent->pos().x(), dropComponent);
return true;
} else if(event->type() == QEvent::DragLeave) {
dropPending = false;
dropComponent = nullptr;
delete insertIndicator;
}
} else {
// clicked/dragged one of the components outside of the graph
if(event->type() == QEvent::MouseButtonPress) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
dragStartPosition = mouseEvent->pos();
if(object->objectName() == "lSeriesC") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesC);
} else if(object->objectName() == "lSeriesL") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesL);
} else if(object->objectName() == "lSeriesR") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesR);
} else if(object->objectName() == "lParallelC") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelC);
} else if(object->objectName() == "lParallelL") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelL);
} else if(object->objectName() == "lParallelR") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelR);
} else {
dragComponent = nullptr;
}
return true;
}
return false;
} else if(event->type() == QEvent::MouseMove) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
return false;
}
if (!dragComponent) {
return false;
}
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
< QApplication::startDragDistance()) {
return false;
}
createDragComponent(dragComponent);
return true;
}
}
return false;
}
MatchingComponent::MatchingComponent(Type type)
{
this->type = type;
setMinimumSize(150, 150);
setMaximumSize(150, 150);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
eValue = new SIUnitEdit();
eValue->setPrecision(4);
eValue->setPrefixes("fpnum k");
connect(eValue, &SIUnitEdit::valueChanged, this, &MatchingComponent::valueChanged);
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
switch(type) {
case Type::SeriesR:
case Type::SeriesL:
case Type::SeriesC: {
auto layout = new QVBoxLayout();
layout->addWidget(eValue);
setLayout(layout);
}
break;
case Type::ParallelR:
case Type::ParallelL:
case Type::ParallelC: {
auto layout = new QVBoxLayout();
layout->addWidget(eValue);
layout->addStretch(1);
layout->setContentsMargins(9, 5, 9, 9);
setLayout(layout);
}
break;
default:
break;
}
switch(type) {
case Type::SeriesR:
eValue->setUnit("Ω");
eValue->setValue(50);
setStyleSheet("image: url(:/icons/seriesR.svg);");
break;
case Type::SeriesL:
eValue->setUnit("H");
eValue->setValue(1e-9);
setStyleSheet("image: url(:/icons/seriesL.svg);");
break;
case Type::SeriesC:
eValue->setUnit("F");
eValue->setValue(1e-12);
setStyleSheet("image: url(:/icons/seriesC.svg);");
break;
case Type::ParallelR:
eValue->setUnit("Ω");
eValue->setValue(50);
setStyleSheet("image: url(:/icons/parallelR.svg);");
break;
case Type::ParallelL:
eValue->setUnit("H");
eValue->setValue(1e-9);
setStyleSheet("image: url(:/icons/parallelL.svg);");
break;
case Type::ParallelC:
eValue->setUnit("F");
eValue->setValue(1e-12);
setStyleSheet("image: url(:/icons/parallelC.svg);");
break;
default:
break;
}
}
ABCDparam MatchingComponent::parameters(double freq)
{
switch(type) {
case Type::SeriesR:
return ABCDparam(1.0, eValue->value(), 0.0, 1.0);
case Type::SeriesL:
return ABCDparam(1.0, complex<double>(0, freq * 2 * M_PI * eValue->value()), 0.0, 1.0);
case Type::SeriesC:
return ABCDparam(1.0, complex<double>(0, -1.0 / (freq * 2 * M_PI * eValue->value())), 0.0, 1.0);
case Type::ParallelR:
return ABCDparam(1.0, 0.0, 1.0/eValue->value(), 1.0);
case Type::ParallelL:
return ABCDparam(1.0, 0.0, 1.0/complex<double>(0, freq * 2 * M_PI * eValue->value()), 1.0);
case Type::ParallelC:
return ABCDparam(1.0, 0.0, 1.0/complex<double>(0, -1.0 / (freq * 2 * M_PI * eValue->value())), 1.0);
default:
return ABCDparam(1.0, 0.0, 0.0, 1.0);
}
}
void MatchingComponent::MatchingComponent::setValue(double v)
{
eValue->setValue(v);
}
MatchingComponent *MatchingComponent::createFromName(QString name)
{
for(unsigned int i=0;i<(int) Type::Last;i++) {
if(name == typeToName((Type) i)) {
return new MatchingComponent((Type) i);
}
}
// invalid name
return nullptr;
}
QString MatchingComponent::getName()
{
return typeToName(type);
}
nlohmann::json MatchingComponent::toJSON()
{
nlohmann::json j;
j["value"] = eValue->value();
return j;
}
void MatchingComponent::fromJSON(nlohmann::json j)
{
eValue->setValue(j.value("value", 1e-12));
}
QString MatchingComponent::typeToName(MatchingComponent::Type type)
{
switch(type) {
case Type::SeriesR: return "SeriesR";
case Type::SeriesL: return "SeriesL";
case Type::SeriesC: return "SeriesC";
case Type::ParallelR: return "ParallelR";
case Type::ParallelL: return "ParallelL";
case Type::ParallelC: return "ParallelC";
default: return "";
}
}
void MatchingComponent::MatchingComponent::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Delete) {
emit deleted(this);
delete this;
}
}
void MatchingComponent::MatchingComponent::focusInEvent(QFocusEvent *event)
{
Q_UNUSED(event);
oldStylesheet = styleSheet();
setStyleSheet(styleSheet().append("\nborder: 1px solid red;"));
}
void MatchingComponent::MatchingComponent::focusOutEvent(QFocusEvent *event)
{
Q_UNUSED(event);
setStyleSheet(oldStylesheet);
}

View File

@ -0,0 +1,90 @@
#ifndef MATCHINGNETWORK_H
#define MATCHINGNETWORK_H
#include <QWidget>
#include <CustomWidgets/siunitedit.h>
#include "deembeddingoption.h"
#include <vector>
#include "Tools/parameters.h"
#include "savable.h"
class MatchingComponent : public QFrame, public Savable
{
Q_OBJECT
public:
enum class Type {
SeriesR,
SeriesL,
SeriesC,
ParallelR,
ParallelL,
ParallelC,
// Add new matching components here, do not explicitly assign values and keep the Last entry at the last position
Last,
};
MatchingComponent(Type type);
ABCDparam parameters(double freq);
void setValue(double v);
static MatchingComponent* createFromName(QString name);
QString getName();
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
signals:
void valueChanged();
void deleted(MatchingComponent* m);
protected:
SIUnitEdit *eValue;
private:
static QString typeToName(Type type);
Type type;
void keyPressEvent(QKeyEvent *event) override;
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
QString oldStylesheet;
};
class MatchingNetwork : public DeembeddingOption
{
public:
MatchingNetwork();
// DeembeddingOption interface
public:
void transformDatapoint(Protocol::Datapoint &p) override;
void edit() override;
Type getType() override {return Type::MatchingNetwork;};
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
private:
static constexpr int componentWidth = 150;
static constexpr int DUTWidth = 150;
static constexpr int portWidth = 75;
MatchingComponent *componentAtPosition(int pos);
unsigned int findInsertPosition(int xcoord);
void addComponentAtPosition(int pos, MatchingComponent *c);
void addComponent(bool port1, int index, MatchingComponent *c);
void createDragComponent(MatchingComponent *c);
void updateInsertIndicator(int xcoord);
bool eventFilter(QObject *object, QEvent *event) override;
std::vector<MatchingComponent*> p1Network, p2Network;
QWidget *graph, *insertIndicator;
QPoint dragStartPosition;
MatchingComponent *dragComponent;
bool dropPending;
MatchingComponent *dropComponent;
class MatchingPoint {
public:
ABCDparam p1, p2;
};
std::map<double, MatchingPoint> matching;
bool addNetwork;
};
#endif // MATCHINGNETWORK_H

View File

@ -0,0 +1,547 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MatchingNetworkDialog</class>
<widget class="QWidget" name="MatchingNetworkDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>772</width>
<height>442</height>
</rect>
</property>
<property name="windowTitle">
<string>Matching Network</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">QWidget#Form {image: url(:/icons/tex/parallelL.svg);}
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="minimumSize">
<size>
<width>0</width>
<height>170</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>170</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>750</width>
<height>168</height>
</rect>
</property>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Operation</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="bAddNetwork">
<property name="text">
<string>Add effect of matching network</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Choose this option if you are directly connected to the DUT and would like to see the parameters with the specified matching network</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="bRemoveNetwork">
<property name="text">
<string>Remove effect of matching network</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Choose this option if the matching network is physically present but you would like to see the parameters of just the DUT</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Matching Components</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Drag/drop into signal path</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lSeriesC">
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/seriesC.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Series C</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lSeriesL">
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/seriesL.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Series L</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QFrame" name="frame_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lSeriesR">
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/seriesR.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Series R</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QFrame" name="frame_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lParallelC">
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/parallelC.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Parallel C</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QFrame" name="frame_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lParallelL">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/parallelL.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Parallel L</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="2">
<widget class="QFrame" name="frame_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>80</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lParallelR">
<property name="styleSheet">
<string notr="true">border-image: url(:/icons/parallelR.svg);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>Parallel R</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

View File

@ -7,7 +7,7 @@
using namespace std; using namespace std;
PortExtension::PortExtension() PortExtension::PortExtension()
: QObject() : DeembeddingOption()
{ {
port1.enabled = false; port1.enabled = false;
port1.frequency = 0; port1.frequency = 0;
@ -26,7 +26,7 @@ PortExtension::PortExtension()
kit = nullptr; kit = nullptr;
} }
void PortExtension::applyToMeasurement(Protocol::Datapoint &d) void PortExtension::transformDatapoint(Protocol::Datapoint &d)
{ {
if(measuring) { if(measuring) {
if(measurements.size() > 0) { if(measurements.size() > 0) {
@ -180,6 +180,7 @@ void PortExtension::edit()
ui->setupUi(dialog); ui->setupUi(dialog);
// set initial values // set initial values
ui->P1Enabled->setChecked(port1.enabled);
ui->P1Time->setUnit("s"); ui->P1Time->setUnit("s");
ui->P1Time->setPrefixes("pnum "); ui->P1Time->setPrefixes("pnum ");
ui->P1Distance->setUnit("m"); ui->P1Distance->setUnit("m");
@ -198,6 +199,7 @@ void PortExtension::edit()
ui->P1calkit->setEnabled(false); ui->P1calkit->setEnabled(false);
} }
ui->P2Enabled->setChecked(port2.enabled);
ui->P2Time->setUnit("s"); ui->P2Time->setUnit("s");
ui->P2Time->setPrefixes("pnum "); ui->P2Time->setPrefixes("pnum ");
ui->P2Distance->setUnit("m"); ui->P2Distance->setUnit("m");
@ -229,6 +231,9 @@ void PortExtension::edit()
port2.frequency = ui->P2Frequency->value(); port2.frequency = ui->P2Frequency->value();
}; };
connect(ui->P1Enabled, &QCheckBox::toggled, [=](bool enabled) {
port1.enabled = enabled;
});
// connections to link delay and distance // connections to link delay and distance
connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) { connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c); ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c);
@ -258,6 +263,9 @@ void PortExtension::edit()
startMeasurement(); startMeasurement();
}); });
connect(ui->P2Enabled, &QCheckBox::toggled, [=](bool enabled) {
port2.enabled = enabled;
});
connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) { connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c); ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c);
updateValuesFromUI(); updateValuesFromUI();
@ -303,26 +311,43 @@ void PortExtension::startMeasurement()
measuring = true; 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) void PortExtension::setCalkit(Calkit *kit)
{ {
this->kit = kit; this->kit = kit;
} }
nlohmann::json PortExtension::toJSON()
{
nlohmann::json j;
for(int i=0;i<2;i++) {
auto ext = i == 0 ? port1 : port2;
nlohmann::json je;
je["enabled"] = ext.enabled;
je["delay"] = ext.delay;
je["velocityFactor"] = ext.velocityFactor;
je["DCloss"] = ext.DCloss;
je["loss"] = ext.loss;
je["frequency"] = ext.frequency;
j.push_back(je);
}
return j;
}
void PortExtension::fromJSON(nlohmann::json j)
{
for(int i=0;i<2;i++) {
Extension ext;
nlohmann::json je = j[i];
ext.enabled = je.value("enabled", false);
ext.delay = je.value("delay", 0.0);
ext.velocityFactor = je.value("velocityFactor", 0.66);
ext.DCloss = je.value("DCloss", 0.0);
ext.loss = je.value("loss", 0.0);
ext.frequency = je.value("frequency", 6000000000);
if(i==0) {
port1 = ext;
} else {
port2 = ext;
}
}
}

View File

@ -6,21 +6,24 @@
#include <QToolBar> #include <QToolBar>
#include "Calibration/calkit.h" #include "Calibration/calkit.h"
#include <QMessageBox> #include <QMessageBox>
#include "deembeddingoption.h"
namespace Ui { namespace Ui {
class PortExtensionEditDialog; class PortExtensionEditDialog;
} }
class PortExtension : public QObject class PortExtension : public DeembeddingOption
{ {
Q_OBJECT Q_OBJECT
public: public:
PortExtension(); PortExtension();
void applyToMeasurement(Protocol::Datapoint& d); void transformDatapoint(Protocol::Datapoint& d) override;
QToolBar *createToolbar();
void setCalkit(Calkit *kit); void setCalkit(Calkit *kit);
Type getType() override {return Type::PortExtension;}
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
public slots: public slots:
void edit(); void edit() override;
private: private:
void startMeasurement(); void startMeasurement();

View File

@ -27,6 +27,13 @@
<string>Port 1</string> <string>Port 1</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_7"> <layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="P1Enabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
@ -170,6 +177,13 @@
<string>Port 2</string> <string>Port 2</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="P2Enabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_6"> <widget class="QGroupBox" name="groupBox_6">
<property name="title"> <property name="title">

View File

@ -0,0 +1,317 @@
#include "twothru.h"
#include "CustomWidgets/informationbox.h"
#include "ui_twothrudialog.h"
#include "Traces/fftcomplex.h"
using namespace std;
TwoThru::TwoThru()
{
measuring = false;
}
void TwoThru::transformDatapoint(Protocol::Datapoint &p)
{
auto S11 = complex<double>(p.real_S11, p.imag_S11);
auto S12 = complex<double>(p.real_S12, p.imag_S12);
auto S21 = complex<double>(p.real_S21, p.imag_S21);
auto S22 = complex<double>(p.real_S22, p.imag_S22);
Sparam S(S11, S12, S21, S22);
Tparam meas(S);
if(measuring) {
if(measurements.size() > 0 && p.pointNum == 0) {
// complete sweep measured, exit measurement mode
measuring = false;
// calculate error boxes, see https://www.freelists.org/post/si-list/IEEE-P370-Opensource-Deembedding-MATLAB-functions
// create vectors of S parameters
vector<complex<double>> S11, S12, S21, S22;
vector<double> f;
for(auto m : measurements) {
if(m.frequency == 0) {
// ignore possible DC point
continue;
}
S11.push_back(complex<double>(m.real_S11, m.imag_S11));
S12.push_back(complex<double>(m.real_S12, m.imag_S12));
S21.push_back(complex<double>(m.real_S21, m.imag_S21));
S22.push_back(complex<double>(m.real_S22, m.imag_S22));
f.push_back(m.frequency);
}
auto n = f.size();
auto makeSymmetric = [](const vector<complex<double>> &in) -> vector<complex<double>> {
auto abs_DC = 2.0 * abs(in[0]) - abs(in[1]);
auto phase_DC = 2.0 * arg(in[0]) - arg(in[1]);
auto DC = polar(abs_DC, phase_DC);
vector<complex<double>> ret;
ret.push_back(DC);
// add non-symmetric part
ret.insert(ret.end(), in.begin(), in.end());
// add flipped complex conjugate values
for(auto it = in.rbegin(); it != in.rend(); it++) {
ret.push_back(conj(*it));
}
return ret;
};
auto makeRealAndScale = [](vector<complex<double>> &in) {
for(unsigned int i=0;i<in.size();i++) {
in[i] = real(in[i]) / in.size();
}
};
// S parameter error boxes
vector<Sparam> data_side1, data_side2;
{
auto p112x = makeSymmetric(S11);
auto p212x = makeSymmetric(S21);
// transform into time domain and calculate step responses
auto t112x = p112x;
Fft::transform(t112x, true);
makeRealAndScale(t112x);
Fft::shift(t112x, false);
partial_sum(t112x.begin(), t112x.end(), t112x.begin());
auto t212x = p212x;
Fft::transform(t212x, true);
makeRealAndScale(t212x);
Fft::shift(t212x, false);
partial_sum(t212x.begin(), t212x.end(), t212x.begin());
// find the midpoint of the trace
auto mid = lower_bound(t212x.begin(), t212x.end(), 0.5, [](complex<double> p, double c) -> bool {
return real(p) < c;
}) - t212x.begin();
// mask step response
vector<complex<double>> t111xStep(2*n + 1, 0.0);
copy(t112x.begin() + n, t112x.begin() + mid, t111xStep.begin() + n);
Fft::shift(t111xStep, true);
// create impulse response from masked step response
adjacent_difference(t111xStep.begin(), t111xStep.end(), t111xStep.begin());
Fft::transform(t111xStep, false);
auto &p111x = t111xStep;
// calculate p221x and p211x
vector<complex<double>> p221x;
vector<complex<double>> p211x;
double k = 1.0;
complex<double> test, last_test;
for(unsigned int i=0;i<p112x.size();i++) {
p221x.push_back((p112x[i]-p111x[i])/p212x[i]);
test = sqrt(p212x[i]*(1.0-p221x[i]*p221x[i]));
if(i > 0) {
if(arg(test) - arg(last_test) > 0) {
k = -k;
}
}
last_test = test;
p211x.push_back(k*test);
}
// create S parameter errorbox
for(unsigned int i=1;i<=n;i++) {
data_side1.push_back(Sparam(p111x[i], p211x[i], p211x[i], p221x[i]));
}
}
// same thing for error box 2. Variable names get a bit confusing because they are viewed from port 2 (S22 is now called p112x, ...).
// All variable names follow https://gitlab.com/IEEE-SA/ElecChar/P370/-/blob/master/TG1/IEEEP3702xThru_Octave.m
{
auto p112x = makeSymmetric(S22);
auto p212x = makeSymmetric(S12);
// transform into time domain and calculate step responses
auto t112x = p112x;
Fft::transform(t112x, true);
makeRealAndScale(t112x);
Fft::shift(t112x, false);
partial_sum(t112x.begin(), t112x.end(), t112x.begin());
auto t212x = p212x;
Fft::transform(t212x, true);
makeRealAndScale(t212x);
Fft::shift(t212x, false);
partial_sum(t212x.begin(), t212x.end(), t212x.begin());
// find the midpoint of the trace
auto mid = lower_bound(t212x.begin(), t212x.end(), 0.5, [](complex<double> p, double c) -> bool {
return real(p) < c;
}) - t212x.begin();
// mask step response
vector<complex<double>> t111xStep(2*n + 1, 0.0);
copy(t112x.begin() + n, t112x.begin() + mid, t111xStep.begin() + n);
Fft::shift(t111xStep, true);
// create impulse response from masked step response
adjacent_difference(t111xStep.begin(), t111xStep.end(), t111xStep.begin());
Fft::transform(t111xStep, false);
auto &p111x = t111xStep;
// calculate p221x and p211x
vector<complex<double>> p221x;
vector<complex<double>> p211x;
double k = 1.0;
complex<double> test, last_test;
for(unsigned int i=0;i<p112x.size();i++) {
p221x.push_back((p112x[i]-p111x[i])/p212x[i]);
test = sqrt(p212x[i]*(1.0-p221x[i]*p221x[i]));
if(i > 0) {
if(arg(test) - arg(last_test) > 0) {
k = -k;
}
}
last_test = test;
p211x.push_back(k*test);
}
// create S parameter errorbox
for(unsigned int i=1;i<=n;i++) {
data_side2.push_back(Sparam(p111x[i], p211x[i], p211x[i], data_side1[i-1].m22));
data_side1[i-1].m22 = p221x[i];
}
}
// got the error boxes, convert to T parameters and invert
for(unsigned int i=0;i<n;i++) {
Point p;
p.freq = f[i];
p.inverseP1 = Tparam(data_side1[i]).inverse();
p.inverseP2 = Tparam(data_side2[i]).inverse();
points.push_back(p);
}
measurements.clear();
if(msgBox) {
msgBox->accept();
msgBox = nullptr;
}
updateLabel();
} else if(measurements.size() > 0 || p.pointNum == 0) {
measurements.push_back(p);
}
}
// correct measurement
if(points.size() > 0) {
if(p.frequency != 0 && (p.frequency < points.front().freq || p.frequency > points.back().freq)) {
// No exact match, measurement no longer valid
points.clear();
InformationBox::ShowMessage("Warning", "2xThru measurement cleared because it no longer matches the selected span");
return;
}
// find correct measurement point
auto point = lower_bound(points.begin(), points.end(), p.frequency, [](Point p, uint64_t freq) -> bool {
return p.freq < freq;
});
Tparam inv1, inv2;
if(point->freq == p.frequency) {
inv1 = point->inverseP1;
inv2 = point->inverseP2;
} else {
// need to interpolate
auto high = point;
point--;
auto low = point;
double alpha = (p.frequency - low->freq) / (high->freq - low->freq);
inv1 = low->inverseP1 * (1 - alpha) + high->inverseP1 * alpha;
inv2 = low->inverseP2 * (1 - alpha) + high->inverseP2 * alpha;
}
// perform correction
Tparam corrected = inv1*meas*inv2;
// transform back into S parameters
Sparam S(corrected);
p.real_S11 = real(S.m11);
p.imag_S11 = imag(S.m11);
p.real_S12 = real(S.m12);
p.imag_S12 = imag(S.m12);
p.real_S21 = real(S.m21);
p.imag_S21 = imag(S.m21);
p.real_S22 = real(S.m22);
p.imag_S22 = imag(S.m22);
}
}
void TwoThru::startMeasurement()
{
points.clear();
measurements.clear();
updateLabel();
msgBox = new QMessageBox(QMessageBox::Information, "2xThru", "Taking measurement...", QMessageBox::Cancel);
connect(msgBox, &QMessageBox::rejected, [=]() {
measuring = false;
points.clear();
measurements.clear();
updateLabel();
});
msgBox->show();
measuring = true;
}
void TwoThru::updateLabel()
{
if(points.size() > 0) {
ui->lInfo->setText("Got "+QString::number(points.size())+" points");
} else {
ui->lInfo->setText("No measurement, not deembedding");
}
}
void TwoThru::edit()
{
auto dialog = new QDialog();
ui = new Ui::TwoThruDialog();
ui->setupUi(dialog);
connect(ui->bMeasure, &QPushButton::clicked, this, &TwoThru::startMeasurement);
connect(ui->buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
updateLabel();
dialog->show();
}
nlohmann::json TwoThru::toJSON()
{
nlohmann::json j;
for(auto p : points) {
nlohmann::json jp;
jp["frequency"] = p.freq;
jp["p1_11_r"] = p.inverseP1.m11.real();
jp["p1_11_i"] = p.inverseP1.m11.imag();
jp["p1_12_r"] = p.inverseP1.m12.real();
jp["p1_12_i"] = p.inverseP1.m12.imag();
jp["p1_21_r"] = p.inverseP1.m21.real();
jp["p1_21_i"] = p.inverseP1.m21.imag();
jp["p1_22_r"] = p.inverseP1.m22.real();
jp["p1_22_i"] = p.inverseP1.m22.imag();
jp["p2_11_r"] = p.inverseP2.m11.real();
jp["p2_11_i"] = p.inverseP2.m11.imag();
jp["p2_12_r"] = p.inverseP2.m12.real();
jp["p2_12_i"] = p.inverseP2.m12.imag();
jp["p2_21_r"] = p.inverseP2.m21.real();
jp["p2_21_i"] = p.inverseP2.m21.imag();
jp["p2_22_r"] = p.inverseP2.m22.real();
jp["p2_22_i"] = p.inverseP2.m22.imag();
j.push_back(jp);
}
return j;
}
void TwoThru::fromJSON(nlohmann::json j)
{
points.clear();
for(auto jp : j) {
Point p;
p.freq = jp.value("frequency", 0.0);
p.inverseP1.m11 = complex<double>(jp.value("p1_11_r", 0.0), jp.value("p1_11_i", 0.0));
p.inverseP1.m12 = complex<double>(jp.value("p1_12_r", 0.0), jp.value("p1_12_i", 0.0));
p.inverseP1.m21 = complex<double>(jp.value("p1_21_r", 0.0), jp.value("p1_21_i", 0.0));
p.inverseP1.m22 = complex<double>(jp.value("p1_22_r", 0.0), jp.value("p1_22_i", 0.0));
p.inverseP2.m11 = complex<double>(jp.value("p2_11_r", 0.0), jp.value("p2_11_i", 0.0));
p.inverseP2.m12 = complex<double>(jp.value("p2_12_r", 0.0), jp.value("p2_12_i", 0.0));
p.inverseP2.m21 = complex<double>(jp.value("p2_21_r", 0.0), jp.value("p2_21_i", 0.0));
p.inverseP2.m22 = complex<double>(jp.value("p2_22_r", 0.0), jp.value("p2_22_i", 0.0));
points.push_back(p);
}
}

View File

@ -0,0 +1,39 @@
#ifndef TWOTHRU_H
#define TWOTHRU_H
#include "deembeddingoption.h"
#include "Tools/parameters.h"
#include <complex>
#include <QMessageBox>
namespace Ui {
class TwoThruDialog;
}
class TwoThru : public DeembeddingOption
{
public:
TwoThru();
virtual void transformDatapoint(Protocol::Datapoint &p) override;
virtual void edit() override;
virtual Type getType() override {return DeembeddingOption::Type::TwoThru;}
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
private slots:
void startMeasurement();
void updateLabel();
private:
using Point = struct {
double freq;
Tparam inverseP1, inverseP2;
};
std::vector<Protocol::Datapoint> measurements;
std::vector<Point> points;
bool measuring;
QMessageBox *msgBox;
Ui::TwoThruDialog *ui;
};
#endif // TWOTHRU_H

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TwoThruDialog</class>
<widget class="QDialog" name="TwoThruDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>233</width>
<height>103</height>
</rect>
</property>
<property name="windowTitle">
<string>2xThru</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lInfo">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bMeasure">
<property name="text">
<string>Measure</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -147,7 +147,7 @@ VNA::VNA(AppWindow *window)
import->show(); import->show();
}); });
portExtension.setCalkit(&cal.getCalibrationKit()); // portExtension.setCalkit(&cal.getCalibrationKit());
// Tools menu // Tools menu
auto toolsMenu = new QMenu("Tools", window); auto toolsMenu = new QMenu("Tools", window);
@ -155,6 +155,8 @@ VNA::VNA(AppWindow *window)
actions.insert(toolsMenu->menuAction()); actions.insert(toolsMenu->menuAction());
auto impedanceMatching = toolsMenu->addAction("Impedance Matching"); auto impedanceMatching = toolsMenu->addAction("Impedance Matching");
connect(impedanceMatching, &QAction::triggered, this, &VNA::StartImpedanceMatching); connect(impedanceMatching, &QAction::triggered, this, &VNA::StartImpedanceMatching);
auto confDeembed = toolsMenu->addAction("De-embedding");
connect(confDeembed, &QAction::triggered, &deembedding, &Deembedding::configure);
defaultCalMenu = new QMenu("Default Calibration", window); defaultCalMenu = new QMenu("Default Calibration", window);
assignDefaultCal = defaultCalMenu->addAction("Assign..."); assignDefaultCal = defaultCalMenu->addAction("Assign...");
@ -367,9 +369,9 @@ VNA::VNA(AppWindow *window)
window->addToolBar(tb_cal); window->addToolBar(tb_cal);
toolbars.insert(tb_cal); toolbars.insert(tb_cal);
auto tb_portExtension = portExtension.createToolbar(); // auto tb_portExtension = portExtension.createToolbar();
window->addToolBar(tb_portExtension); // window->addToolBar(tb_portExtension);
toolbars.insert(tb_portExtension); // toolbars.insert(tb_portExtension);
markerModel = new TraceMarkerModel(traceModel, this); markerModel = new TraceMarkerModel(traceModel, this);
@ -490,7 +492,7 @@ void VNA::initializeDevice()
if(QFile::exists(filename)) { if(QFile::exists(filename)) {
if(cal.openFromFile(filename)) { if(cal.openFromFile(filename)) {
ApplyCalibration(cal.getType()); ApplyCalibration(cal.getType());
portExtension.setCalkit(&cal.getCalibrationKit()); // portExtension.setCalkit(&cal.getCalibrationKit());
qDebug() << "Calibration successful from " << filename; qDebug() << "Calibration successful from " << filename;
} else { } else {
qDebug() << "Calibration not successfull from: " << filename; qDebug() << "Calibration not successfull from: " << filename;
@ -528,6 +530,7 @@ nlohmann::json VNA::toJSON()
j["traces"] = traceModel.toJSON(); j["traces"] = traceModel.toJSON();
j["tiles"] = central->toJSON(); j["tiles"] = central->toJSON();
j["markers"] = markerModel->toJSON(); j["markers"] = markerModel->toJSON();
j["de-embedding"] = deembedding.toJSON();
return j; return j;
} }
@ -542,6 +545,9 @@ void VNA::fromJSON(nlohmann::json j)
if(j.contains("markers")) { if(j.contains("markers")) {
markerModel->fromJSON(j["markers"]); markerModel->fromJSON(j["markers"]);
} }
if(j.contains("de-embedding")) {
deembedding.fromJSON(j["de-embedding"]);
}
} }
using namespace std; using namespace std;
@ -568,7 +574,8 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
if(calValid) { if(calValid) {
cal.correctMeasurement(d); cal.correctMeasurement(d);
} }
portExtension.applyToMeasurement(d);
deembedding.Deembed(d);
traceModel.addVNAData(d, settings); traceModel.addVNAData(d, settings);
emit dataChanged(); emit dataChanged();

View File

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

View File

@ -35,5 +35,17 @@
<file>icons/zoom-out.png</file> <file>icons/zoom-out.png</file>
<file>icons/math_disabled.svg</file> <file>icons/math_disabled.svg</file>
<file>icons/math_enabled.svg</file> <file>icons/math_enabled.svg</file>
<file>icons/parallelC.svg</file>
<file>icons/parallelL.svg</file>
<file>icons/parallelR.svg</file>
<file>icons/seriesC.svg</file>
<file>icons/seriesL.svg</file>
<file>icons/seriesR.svg</file>
<file>icons/DUT.png</file>
<file>icons/port1.png</file>
<file>icons/port2.png</file>
<file>icons/DUT.svg</file>
<file>icons/port1.svg</file>
<file>icons/port2.svg</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 0.34375 -6.8125 L 0.34375 -6.5 L 0.59375 -6.5 C 1.359375 -6.5 1.375 -6.390625 1.375 -6.03125 L 1.375 -0.78125 C 1.375 -0.421875 1.359375 -0.3125 0.59375 -0.3125 L 0.34375 -0.3125 L 0.34375 0 L 4 0 C 5.671875 0 7.046875 -1.46875 7.046875 -3.34375 C 7.046875 -5.25 5.703125 -6.8125 4 -6.8125 Z M 2.71875 -0.3125 C 2.25 -0.3125 2.234375 -0.375 2.234375 -0.703125 L 2.234375 -6.09375 C 2.234375 -6.4375 2.25 -6.5 2.71875 -6.5 L 3.71875 -6.5 C 4.34375 -6.5 5.03125 -6.28125 5.53125 -5.578125 C 5.96875 -4.984375 6.046875 -4.125 6.046875 -3.34375 C 6.046875 -2.25 5.859375 -1.640625 5.5 -1.15625 C 5.296875 -0.890625 4.734375 -0.3125 3.734375 -0.3125 Z M 2.71875 -0.3125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 5.796875 -2.296875 C 5.796875 -0.890625 4.828125 -0.09375 3.890625 -0.09375 C 3.421875 -0.09375 2.25 -0.34375 2.25 -2.234375 L 2.25 -6.03125 C 2.25 -6.390625 2.265625 -6.5 3.03125 -6.5 L 3.265625 -6.5 L 3.265625 -6.8125 C 2.921875 -6.78125 2.1875 -6.78125 1.796875 -6.78125 C 1.421875 -6.78125 0.671875 -6.78125 0.328125 -6.8125 L 0.328125 -6.5 L 0.5625 -6.5 C 1.328125 -6.5 1.359375 -6.390625 1.359375 -6.03125 L 1.359375 -2.265625 C 1.359375 -0.875 2.515625 0.21875 3.875 0.21875 C 5.015625 0.21875 5.90625 -0.703125 6.078125 -1.84375 C 6.109375 -2.046875 6.109375 -2.140625 6.109375 -2.53125 L 6.109375 -5.71875 C 6.109375 -6.046875 6.109375 -6.5 7.140625 -6.5 L 7.140625 -6.8125 C 6.78125 -6.796875 6.296875 -6.78125 5.96875 -6.78125 C 5.609375 -6.78125 5.140625 -6.796875 4.78125 -6.8125 L 4.78125 -6.5 C 5.796875 -6.5 5.796875 -6.03125 5.796875 -5.765625 Z M 5.796875 -2.296875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 6.640625 -6.75 L 0.546875 -6.75 L 0.359375 -4.5 L 0.609375 -4.5 C 0.75 -6.109375 0.890625 -6.4375 2.40625 -6.4375 C 2.578125 -6.4375 2.84375 -6.4375 2.9375 -6.421875 C 3.15625 -6.375 3.15625 -6.265625 3.15625 -6.046875 L 3.15625 -0.78125 C 3.15625 -0.453125 3.15625 -0.3125 2.109375 -0.3125 L 1.703125 -0.3125 L 1.703125 0 C 2.109375 -0.03125 3.125 -0.03125 3.59375 -0.03125 C 4.046875 -0.03125 5.078125 -0.03125 5.484375 0 L 5.484375 -0.3125 L 5.078125 -0.3125 C 4.03125 -0.3125 4.03125 -0.453125 4.03125 -0.78125 L 4.03125 -6.046875 C 4.03125 -6.234375 4.03125 -6.375 4.21875 -6.421875 C 4.328125 -6.4375 4.59375 -6.4375 4.78125 -6.4375 C 6.296875 -6.4375 6.4375 -6.109375 6.578125 -4.5 L 6.828125 -4.5 Z M 6.640625 -6.75 "/>
</symbol>
</g>
<clipPath id="clip1">
<path d="M 99 28 L 113.386719 28 L 113.386719 29 L 99 29 Z M 99 28 "/>
</clipPath>
</defs>
<g id="surface1">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14.171875 42.718031 L 99.214844 42.718031 L 99.214844 99.413344 L 14.171875 99.413344 Z M 14.171875 42.718031 " transform="matrix(1,0,0,-1,0,113.386)"/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="45.554" y="45.725"/>
<use xlink:href="#glyph0-2" x="53.16443" y="45.725"/>
<use xlink:href="#glyph0-3" x="60.63638" y="45.725"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 14.171875 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 99.214844 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 42.518812 L 56.695312 28.346937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 28.346937 L 56.695312 16.440687 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 50.742188 16.440687 L 62.644531 16.440687 M 52.726562 14.456312 L 60.660156 14.456312 M 54.214844 12.471937 L 59.175781 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 28.347656 85.04225 M 28.347656 85.04225 L 85.039062 85.04225 M 85.039062 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 58.28125 85.04225 C 58.28125 85.91725 57.570312 86.628187 56.695312 86.628187 C 55.816406 86.628187 55.105469 85.91725 55.105469 85.04225 C 55.105469 84.163344 55.816406 83.452406 56.695312 83.452406 C 57.570312 83.452406 58.28125 84.163344 58.28125 85.04225 Z M 58.28125 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 85.04225 L 56.695312 60.663344 M 56.695312 52.725844 L 56.695312 28.346937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 68.597656 60.663344 L 44.789062 60.663344 M 68.597656 52.725844 L 44.789062 52.725844 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 28.346937 L 56.695312 16.440687 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 50.742188 16.440687 L 62.644531 16.440687 M 52.726562 14.456312 L 60.660156 14.456312 M 54.214844 12.471937 L 59.175781 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 28.347656 85.04225 M 28.347656 85.04225 L 85.039062 85.04225 M 85.039062 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 58.28125 85.04225 C 58.28125 85.91725 57.570312 86.628187 56.695312 86.628187 C 55.816406 86.628187 55.105469 85.91725 55.105469 85.04225 C 55.105469 84.163344 55.816406 83.452406 56.695312 83.452406 C 57.570312 83.452406 58.28125 84.163344 58.28125 85.04225 Z M 58.28125 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 85.04225 L 56.695312 72.569594 M 56.695312 40.819594 L 56.695312 28.346937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.535156 72.968031 C 59.820312 72.968031 62.488281 71.143812 62.488281 68.897719 C 62.488281 66.651625 59.820312 64.831312 56.535156 64.831312 C 59.820312 64.831312 62.488281 63.007094 62.488281 60.761 C 62.488281 58.514906 59.820312 56.694594 56.535156 56.694594 C 59.820312 56.694594 62.488281 54.870375 62.488281 52.624281 C 62.488281 50.378187 59.820312 48.557875 56.535156 48.557875 C 59.820312 48.557875 62.488281 46.737562 62.488281 44.487562 C 62.488281 42.241469 59.820312 40.421156 56.535156 40.421156 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 28.346937 L 56.695312 16.440687 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 50.742188 16.440687 L 62.644531 16.440687 M 52.726562 14.456312 L 60.660156 14.456312 M 54.214844 12.471937 L 59.175781 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 28.347656 85.04225 M 28.347656 85.04225 L 85.039062 85.04225 M 85.039062 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 58.28125 85.04225 C 58.28125 85.91725 57.570312 86.628187 56.695312 86.628187 C 55.816406 86.628187 55.105469 85.91725 55.105469 85.04225 C 55.105469 84.163344 55.816406 83.452406 56.695312 83.452406 C 57.570312 83.452406 58.28125 84.163344 58.28125 85.04225 Z M 58.28125 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 85.04225 L 56.695312 72.569594 M 56.695312 40.819594 L 56.695312 28.346937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 72.968031 L 62.644531 69.889906 L 50.742188 64.530531 L 62.644531 59.175062 L 50.742188 53.815687 L 62.644531 48.456312 L 50.742188 43.100844 L 56.695312 40.421156 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 56.695312 28.346937 L 56.695312 16.440687 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 50.742188 16.440687 L 62.644531 16.440687 M 52.726562 14.456312 L 60.660156 14.456312 M 54.214844 12.471937 L 59.175781 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="56.693pt" height="113.386pt" viewBox="0 0 56.693 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 28 28 L 56.691406 28 L 56.691406 29 L 28 29 Z M 28 28 "/>
</clipPath>
<clipPath id="clip2">
<path d="M 16.441406 20.410156 L 32.316406 20.410156 L 32.316406 26.757812 L 16.441406 26.757812 Z M 16.441406 26.757812 L 22.792969 26.757812 L 22.792969 29.933594 L 16.441406 29.933594 Z M 16.441406 29.933594 L 32.316406 29.933594 L 32.316406 36.28125 L 16.441406 36.28125 Z M 16.441406 29.933594 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.347656 85.04225 L 56.695312 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<g clip-path="url(#clip2)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.347656 85.04225 C 28.347656 87.233656 26.570312 89.007094 24.378906 89.007094 C 22.1875 89.007094 20.410156 87.233656 20.410156 85.04225 C 20.410156 82.850844 22.1875 81.0735 24.378906 81.0735 C 26.570312 81.0735 28.347656 82.850844 28.347656 85.04225 Z M 28.347656 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25.964844 85.04225 C 25.964844 85.91725 25.253906 86.628187 24.378906 86.628187 C 23.503906 86.628187 22.792969 85.91725 22.792969 85.04225 C 22.792969 84.163344 23.503906 83.452406 24.378906 83.452406 C 25.253906 83.452406 25.964844 84.163344 25.964844 85.04225 Z M 25.964844 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25.964844 85.04225 L 28.347656 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 24.378906 81.0735 L 24.378906 24.378187 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 24.378906 24.378187 L 24.378906 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 18.425781 12.471937 L 30.332031 12.471937 M 20.410156 10.487562 L 28.347656 10.487562 M 21.898438 8.503187 L 26.859375 8.503187 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="56.693pt" height="113.386pt" viewBox="0 0 56.693 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 24.378906 20.410156 L 40.25 20.410156 L 40.25 26.757812 L 24.378906 26.757812 Z M 33.902344 26.757812 L 40.25 26.757812 L 40.25 29.933594 L 33.902344 29.933594 Z M 24.378906 29.933594 L 40.25 29.933594 L 40.25 36.28125 L 24.378906 36.28125 Z M 24.378906 29.933594 "/>
</clipPath>
</defs>
<g id="surface1">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.347656 85.04225 L 0 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.347656 85.04225 C 28.347656 87.233656 30.125 89.007094 32.316406 89.007094 C 34.507812 89.007094 36.28125 87.233656 36.28125 85.04225 C 36.28125 82.850844 34.507812 81.0735 32.316406 81.0735 C 30.125 81.0735 28.347656 82.850844 28.347656 85.04225 Z M 28.347656 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 30.726562 85.04225 C 30.726562 85.91725 31.4375 86.628187 32.316406 86.628187 C 33.191406 86.628187 33.902344 85.91725 33.902344 85.04225 C 33.902344 84.163344 33.191406 83.452406 32.316406 83.452406 C 31.4375 83.452406 30.726562 84.163344 30.726562 85.04225 Z M 30.726562 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 30.726562 85.04225 L 28.347656 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32.316406 81.0735 L 32.316406 24.378187 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32.316406 24.378187 L 32.316406 12.471937 " transform="matrix(1,0,0,-1,0,113.386)"/>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 26.363281 12.471937 L 38.265625 12.471937 M 28.347656 10.487562 L 36.28125 10.487562 M 29.835938 8.503187 L 34.796875 8.503187 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 0.398438 85.04225 M 0 85.04225 L 52.726562 85.04225 M 60.660156 85.04225 L 113.386719 85.04225 M 112.988281 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 52.726562 96.944594 L 52.726562 73.136 M 60.660156 96.944594 L 60.660156 73.136 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 0.398438 85.04225 M 0 85.04225 L 40.820312 85.04225 M 72.566406 85.04225 L 113.386719 85.04225 M 112.988281 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40.421875 84.882094 C 40.421875 88.16725 42.242188 90.835219 44.488281 90.835219 C 46.734375 90.835219 48.558594 88.16725 48.558594 84.882094 C 48.558594 88.16725 50.378906 90.835219 52.625 90.835219 C 54.871094 90.835219 56.695312 88.16725 56.695312 84.882094 C 56.695312 88.16725 58.515625 90.835219 60.761719 90.835219 C 63.007812 90.835219 64.828125 88.16725 64.828125 84.882094 C 64.828125 88.16725 66.652344 90.835219 68.898438 90.835219 C 71.144531 90.835219 72.964844 88.16725 72.964844 84.882094 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113.386pt" height="113.386pt" viewBox="0 0 113.386 113.386" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 28 L 113.386719 28 L 113.386719 29 L 0 29 Z M 0 28 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 85.04225 L 0.398438 85.04225 M 0 85.04225 L 40.820312 85.04225 M 72.566406 85.04225 L 113.386719 85.04225 M 112.988281 85.04225 L 113.386719 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
<path style="fill:none;stroke-width:0.797;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40.421875 85.04225 L 43.5 90.991469 L 48.855469 79.089125 L 54.214844 90.991469 L 59.570312 79.089125 L 64.929688 90.991469 L 70.289062 79.089125 L 72.964844 85.04225 " transform="matrix(1,0,0,-1,0,113.386)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,265 @@
{
"Generator": null,
"SpectrumAnalyzer": {
"markers": null,
"tiles": {
"plot": "XY-plot",
"plotsettings": {
"XAxis": {
"div": 200000.0,
"log": false,
"max": 405226753.0,
"min": 402073243.0,
"mode": "Use Span",
"type": "Frequency"
},
"YPrimary": {
"autorange": false,
"div": 10.0,
"log": false,
"max": 0.0,
"min": -120.0,
"traces": [
502445883,
2060438610
],
"type": "Magnitude"
},
"YSecondary": {
"autorange": true,
"div": 1.0,
"log": false,
"max": 0.0,
"min": 0.0,
"traces": null,
"type": "Unknown"
}
},
"split": false
},
"traces": [
{
"color": "#ffff00",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "Port1",
"parameter": 4,
"paused": false,
"reflection": false,
"type": "Live",
"visible": true
},
{
"color": "#0000ff",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "Port2",
"parameter": 5,
"paused": false,
"reflection": false,
"type": "Live",
"visible": true
}
]
},
"VNA": {
"de-embedding": [
{
"operation": "Matching Network",
"settings": [
[
{
"component": "SeriesC",
"params": {
"value": 1.2e-11
}
}
],
[
{
"component": "SeriesR",
"params": {
"value": 44.0
}
},
{
"component": "ParallelL",
"params": {
"value": 5.3000000000000005e-08
}
}
]
]
}
],
"markers": null,
"tiles": {
"orientation": "vertical",
"sizes": [
381,
381
],
"split": true,
"tile1": {
"orientation": "horizontal",
"sizes": [
791,
790
],
"split": true,
"tile1": {
"plot": "smithchart",
"plotsettings": {
"limit_to_span": true,
"traces": [
2459058830
]
},
"split": false
},
"tile2": {
"plot": "XY-plot",
"plotsettings": {
"XAxis": {
"div": 500000000.0,
"log": false,
"max": 6000000000.0,
"min": 0.0,
"mode": "Use Span",
"type": "Frequency"
},
"YPrimary": {
"autorange": false,
"div": 10.0,
"log": false,
"max": 20.0,
"min": -120.0,
"traces": [
2100767570
],
"type": "Magnitude"
},
"YSecondary": {
"autorange": false,
"div": 30.0,
"log": false,
"max": 180.0,
"min": -180.0,
"traces": [
2100767570
],
"type": "Phase"
}
},
"split": false
}
},
"tile2": {
"orientation": "horizontal",
"sizes": [
791,
790
],
"split": true,
"tile1": {
"plot": "XY-plot",
"plotsettings": {
"XAxis": {
"div": 500000000.0,
"log": false,
"max": 6000000000.0,
"min": 0.0,
"mode": "Use Span",
"type": "Frequency"
},
"YPrimary": {
"autorange": false,
"div": 10.0,
"log": false,
"max": 20.0,
"min": -120.0,
"traces": [
572044863
],
"type": "Magnitude"
},
"YSecondary": {
"autorange": false,
"div": 30.0,
"log": false,
"max": 180.0,
"min": -180.0,
"traces": [
572044863
],
"type": "Phase"
}
},
"split": false
},
"tile2": {
"plot": "smithchart",
"plotsettings": {
"limit_to_span": true,
"traces": [
783313651
]
},
"split": false
}
}
},
"traces": [
{
"color": "#ffff00",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "S11",
"parameter": 0,
"paused": false,
"reflection": true,
"type": "Live",
"visible": true
},
{
"color": "#0000ff",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "S12",
"parameter": 1,
"paused": false,
"reflection": false,
"type": "Live",
"visible": true
},
{
"color": "#00ff00",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "S21",
"parameter": 2,
"paused": false,
"reflection": false,
"type": "Live",
"visible": true
},
{
"color": "#ff0000",
"livetype": 0,
"math": null,
"math_enabled": false,
"name": "S22",
"parameter": 3,
"paused": false,
"reflection": true,
"type": "Live",
"visible": true
}
]
}
}