Additional de-embedding options: 2xthru and matching network
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
43
Software/PC_Application/Tools/parameters.cpp
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
187
Software/PC_Application/Tools/parameters.h
Normal 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
|
93
Software/PC_Application/VNA/Deembedding/deembedding.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
31
Software/PC_Application/VNA/Deembedding/deembedding.h
Normal 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
|
107
Software/PC_Application/VNA/Deembedding/deembeddingdialog.cpp
Normal 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 ¤t, 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();
|
||||||
|
}
|
49
Software/PC_Application/VNA/Deembedding/deembeddingdialog.h
Normal 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
|
154
Software/PC_Application/VNA/Deembedding/deembeddingdialog.ui
Normal 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>
|
@ -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 "";
|
||||||
|
}
|
||||||
|
}
|
31
Software/PC_Application/VNA/Deembedding/deembeddingoption.h
Normal 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
|
41
Software/PC_Application/VNA/Deembedding/form.ui
Normal 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>
|
549
Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp
Normal 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);
|
||||||
|
}
|
90
Software/PC_Application/VNA/Deembedding/matchingnetwork.h
Normal 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
|
547
Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui
Normal 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>
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
@ -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">
|
317
Software/PC_Application/VNA/Deembedding/twothru.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
39
Software/PC_Application/VNA/Deembedding/twothru.h
Normal 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
|
61
Software/PC_Application/VNA/Deembedding/twothrudialog.ui
Normal 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>
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
BIN
Software/PC_Application/icons/DUT.png
Normal file
After Width: | Height: | Size: 897 B |
37
Software/PC_Application/icons/DUT.svg
Normal 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 |
18
Software/PC_Application/icons/parallelC.svg
Normal 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 |
18
Software/PC_Application/icons/parallelL.svg
Normal 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 |
18
Software/PC_Application/icons/parallelR.svg
Normal 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 |
BIN
Software/PC_Application/icons/port1.png
Normal file
After Width: | Height: | Size: 995 B |
24
Software/PC_Application/icons/port1.svg
Normal 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 |
BIN
Software/PC_Application/icons/port2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
19
Software/PC_Application/icons/port2.svg
Normal 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 |
14
Software/PC_Application/icons/seriesC.svg
Normal 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 |
14
Software/PC_Application/icons/seriesL.svg
Normal 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 |
14
Software/PC_Application/icons/seriesR.svg
Normal 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 |
265
Software/PC_Application/test.setup
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|