Through normalization and TRL calibration added
This commit is contained in:
parent
c6d9796a11
commit
49917c4b19
@ -42,31 +42,7 @@ void Calibration::addMeasurement(Calibration::Measurement type, Protocol::Datapo
|
|||||||
|
|
||||||
bool Calibration::calculationPossible(Calibration::Type type)
|
bool Calibration::calculationPossible(Calibration::Type type)
|
||||||
{
|
{
|
||||||
std::vector<Measurement> requiredMeasurements;
|
return SanityCheckSamples(Measurements(type, false));
|
||||||
switch(type) {
|
|
||||||
case Type::Port1SOL:
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
|
||||||
break;
|
|
||||||
case Type::Port2SOL:
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
|
||||||
break;
|
|
||||||
case Type::FullSOLT:
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
|
||||||
requiredMeasurements.push_back(Measurement::Through);
|
|
||||||
break;
|
|
||||||
case Type::None:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return SanityCheckSamples(requiredMeasurements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Calibration::constructErrorTerms(Calibration::Type type)
|
bool Calibration::constructErrorTerms(Calibration::Type type)
|
||||||
@ -74,23 +50,19 @@ bool Calibration::constructErrorTerms(Calibration::Type type)
|
|||||||
if(!calculationPossible(type)) {
|
if(!calculationPossible(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(minFreq < kit.minFreq() || maxFreq > kit.maxFreq()) {
|
bool isTRL = type == Type::TRL;
|
||||||
|
if(minFreq < kit.minFreq(isTRL) || maxFreq > kit.maxFreq(isTRL)) {
|
||||||
// Calkit does not support complete calibration range
|
// Calkit does not support complete calibration range
|
||||||
QMessageBox::critical(nullptr, "Unable to perform calibration", "The calibration kit does not support the complete span. Please choose a different calibration kit or a narrower span.");
|
QMessageBox::critical(nullptr, "Unable to perform calibration", "The calibration kit does not support the complete span. Please choose a different calibration kit or a narrower span.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Port1SOL:
|
case Type::Port1SOL: constructPort1SOL(); break;
|
||||||
constructPort1SOL();
|
case Type::Port2SOL: constructPort2SOL(); break;
|
||||||
break;
|
case Type::FullSOLT: construct12TermPoints(); break;
|
||||||
case Type::Port2SOL:
|
case Type::TransmissionNormalization: constructTransmissionNormalization(); break;
|
||||||
constructPort2SOL();
|
case Type::TRL: constructTRL(); break;
|
||||||
break;
|
case Type::None: break;
|
||||||
case Type::FullSOLT:
|
|
||||||
construct12TermPoints();
|
|
||||||
break;
|
|
||||||
case Type::None:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
this->type = type;
|
this->type = type;
|
||||||
return true;
|
return true;
|
||||||
@ -104,17 +76,7 @@ void Calibration::resetErrorTerms()
|
|||||||
|
|
||||||
void Calibration::construct12TermPoints()
|
void Calibration::construct12TermPoints()
|
||||||
{
|
{
|
||||||
std::vector<Measurement> requiredMeasurements;
|
std::vector<Measurement> requiredMeasurements = Measurements(Type::FullSOLT);
|
||||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
|
||||||
requiredMeasurements.push_back(Measurement::Through);
|
|
||||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
|
||||||
throw runtime_error("Missing/wrong calibration measurement");
|
|
||||||
}
|
|
||||||
requiredMeasurements.push_back(Measurement::Isolation);
|
requiredMeasurements.push_back(Measurement::Isolation);
|
||||||
bool isolation_measured = SanityCheckSamples(requiredMeasurements);
|
bool isolation_measured = SanityCheckSamples(requiredMeasurements);
|
||||||
|
|
||||||
@ -141,11 +103,11 @@ void Calibration::construct12TermPoints()
|
|||||||
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22);
|
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22);
|
||||||
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
|
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
|
||||||
|
|
||||||
auto actual = kit.toReflection(p.frequency);
|
auto actual = kit.toSOLT(p.frequency);
|
||||||
// Forward calibration
|
// Forward calibration
|
||||||
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
||||||
p.fe30 = S21_isolation;
|
p.fe30 = S21_isolation;
|
||||||
// See page 17 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
// See page 18 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
|
||||||
// Formulas for S11M and S21M solved for e22 and e10e32
|
// Formulas for S11M and S21M solved for e22 and e10e32
|
||||||
auto deltaS = actual.ThroughS11*actual.ThroughS22 - actual.ThroughS21 * actual.ThroughS12;
|
auto deltaS = actual.ThroughS11*actual.ThroughS22 - actual.ThroughS21 * actual.ThroughS12;
|
||||||
p.fe22 = ((S11_through - p.fe00)*(1.0 - p.fe11 * actual.ThroughS11)-actual.ThroughS11*p.fe10e01)
|
p.fe22 = ((S11_through - p.fe00)*(1.0 - p.fe11 * actual.ThroughS11)-actual.ThroughS11*p.fe10e01)
|
||||||
@ -163,15 +125,6 @@ void Calibration::construct12TermPoints()
|
|||||||
|
|
||||||
void Calibration::constructPort1SOL()
|
void Calibration::constructPort1SOL()
|
||||||
{
|
{
|
||||||
std::vector<Measurement> requiredMeasurements;
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
|
||||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
|
||||||
throw runtime_error("Missing/wrong calibration measurement");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here the calibration measurements are all okay
|
|
||||||
points.clear();
|
points.clear();
|
||||||
for(unsigned int i = 0;i<measurements[Measurement::Port1Open].datapoints.size();i++) {
|
for(unsigned int i = 0;i<measurements[Measurement::Port1Open].datapoints.size();i++) {
|
||||||
Point p;
|
Point p;
|
||||||
@ -181,8 +134,8 @@ void Calibration::constructPort1SOL()
|
|||||||
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
|
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
|
||||||
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11);
|
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11);
|
||||||
// OSL port1
|
// OSL port1
|
||||||
auto actual = kit.toReflection(p.frequency);
|
auto actual = kit.toSOLT(p.frequency);
|
||||||
// See page 19 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
// See page 13 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
|
||||||
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
||||||
// All other calibration coefficients to ideal values
|
// All other calibration coefficients to ideal values
|
||||||
p.fe30 = 0.0;
|
p.fe30 = 0.0;
|
||||||
@ -200,15 +153,6 @@ void Calibration::constructPort1SOL()
|
|||||||
|
|
||||||
void Calibration::constructPort2SOL()
|
void Calibration::constructPort2SOL()
|
||||||
{
|
{
|
||||||
std::vector<Measurement> requiredMeasurements;
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
|
||||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
|
||||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
|
||||||
throw runtime_error("Missing/wrong calibration measurement");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here the calibration measurements are all okay
|
|
||||||
points.clear();
|
points.clear();
|
||||||
for(unsigned int i = 0;i<measurements[Measurement::Port2Open].datapoints.size();i++) {
|
for(unsigned int i = 0;i<measurements[Measurement::Port2Open].datapoints.size();i++) {
|
||||||
Point p;
|
Point p;
|
||||||
@ -218,8 +162,8 @@ void Calibration::constructPort2SOL()
|
|||||||
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
|
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
|
||||||
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22);
|
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22);
|
||||||
// OSL port2
|
// OSL port2
|
||||||
auto actual = kit.toReflection(p.frequency);
|
auto actual = kit.toSOLT(p.frequency);
|
||||||
// See page 19 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
// See page 19 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
|
||||||
computeSOL(S22_short, S22_open, S22_load, p.re33, p.re22, p.re23e32, actual.Open, actual.Short, actual.Load);
|
computeSOL(S22_short, S22_open, S22_load, p.re33, p.re22, p.re23e32, actual.Open, actual.Short, actual.Load);
|
||||||
// All other calibration coefficients to ideal values
|
// All other calibration coefficients to ideal values
|
||||||
p.fe30 = 0.0;
|
p.fe30 = 0.0;
|
||||||
@ -235,6 +179,187 @@ void Calibration::constructPort2SOL()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Calibration::constructTransmissionNormalization()
|
||||||
|
{
|
||||||
|
points.clear();
|
||||||
|
for(unsigned int i = 0;i<measurements[Measurement::Through].datapoints.size();i++) {
|
||||||
|
Point p;
|
||||||
|
p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
|
||||||
|
// extract required complex reflection/transmission factors from datapoints
|
||||||
|
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21);
|
||||||
|
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
|
||||||
|
auto actual = kit.toSOLT(p.frequency);
|
||||||
|
p.fe10e32 = S21_through / actual.ThroughS21;
|
||||||
|
p.re23e01 = S12_through / actual.ThroughS12;
|
||||||
|
// All other calibration coefficients to ideal values
|
||||||
|
p.fe30 = 0.0;
|
||||||
|
p.fe22 = 0.0;
|
||||||
|
p.fe00 = 0.0;
|
||||||
|
p.fe11 = 0.0;
|
||||||
|
p.fe10e01 = 1.0;
|
||||||
|
p.re03 = 0.0;
|
||||||
|
p.re11 = 0.0;
|
||||||
|
p.re33 = 0.0;
|
||||||
|
p.re22 = 0.0;
|
||||||
|
p.re23e32 = 1.0;
|
||||||
|
points.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
T root = sqrt(b * b - T(4) * a * c);
|
||||||
|
result1 = (-b + root) / (T(2) * a);
|
||||||
|
result2 = (-b - root) / (T(2) * a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Calibration::constructTRL()
|
||||||
|
{
|
||||||
|
points.clear();
|
||||||
|
for(unsigned int i = 0;i<measurements[Measurement::Through].datapoints.size();i++) {
|
||||||
|
Point p;
|
||||||
|
p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
|
||||||
|
|
||||||
|
// grab raw measurements
|
||||||
|
auto S11_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11);
|
||||||
|
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21);
|
||||||
|
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22);
|
||||||
|
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
|
||||||
|
auto S11_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S11, measurements[Measurement::Line].datapoints[i].imag_S11);
|
||||||
|
auto S21_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S21, measurements[Measurement::Line].datapoints[i].imag_S21);
|
||||||
|
auto S22_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S22, measurements[Measurement::Line].datapoints[i].imag_S22);
|
||||||
|
auto S12_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S12, measurements[Measurement::Line].datapoints[i].imag_S12);
|
||||||
|
auto trl = kit.toTRL(p.frequency);
|
||||||
|
complex<double> S11_reflection, S22_reflection;
|
||||||
|
if(trl.reflectionIsNegative) {
|
||||||
|
// used short
|
||||||
|
S11_reflection = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
|
||||||
|
S22_reflection = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
|
||||||
|
} else {
|
||||||
|
// used open
|
||||||
|
S11_reflection = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11);
|
||||||
|
S22_reflection = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22);
|
||||||
|
}
|
||||||
|
// calculate TRL calibration
|
||||||
|
// variable names and formulas according to http://emlab.uiuc.edu/ece451/notes/new_TRL.pdf
|
||||||
|
// page 19
|
||||||
|
auto R_T = Tparam<complex<double>>();
|
||||||
|
auto R_D = Tparam<complex<double>>();
|
||||||
|
R_T.fromSparam(S11_through, S21_through, S12_through, S22_through);
|
||||||
|
R_D.fromSparam(S11_line, S21_line, S12_line, S22_line);
|
||||||
|
auto T = R_D*R_T.inverse();
|
||||||
|
complex<double> a_over_c, b;
|
||||||
|
// page 21-22
|
||||||
|
solveQuadratic(T.t21, T.t22 - T.t11, -T.t12, b, a_over_c);
|
||||||
|
// ensure correct root selection
|
||||||
|
// page 23
|
||||||
|
if(abs(b) >= abs(a_over_c)) {
|
||||||
|
swap(b, a_over_c);
|
||||||
|
}
|
||||||
|
// page 24
|
||||||
|
auto g = R_T.t22;
|
||||||
|
auto d = R_T.t11 / g;
|
||||||
|
auto e = R_T.t12 / g;
|
||||||
|
auto f = R_T.t21 / g;
|
||||||
|
|
||||||
|
// page 25
|
||||||
|
auto r22_rho22 = g * (1.0 - e / a_over_c) / (1.0 - b / a_over_c);
|
||||||
|
auto gamma = (f - d / a_over_c) / (1.0 - e / a_over_c);
|
||||||
|
auto beta_over_alpha = (e - b) / (d - b * f);
|
||||||
|
// page 26
|
||||||
|
auto alpha_a = (d - b * f) / (1.0 - e / a_over_c);
|
||||||
|
auto w1 = S11_reflection;
|
||||||
|
auto w2 = S22_reflection;
|
||||||
|
// page 28
|
||||||
|
auto a = sqrt((w1 - b) / (w2 + gamma) * (1.0 + w2 * beta_over_alpha) / (1.0 - w1 / a_over_c) * alpha_a);
|
||||||
|
// page 29, check sign of a
|
||||||
|
auto reflection = (w1 - b) / (a * (1.0 - w1 / a_over_c));
|
||||||
|
if((reflection.real() > 0 && trl.reflectionIsNegative) || (reflection.real() < 0 && !trl.reflectionIsNegative)) {
|
||||||
|
// wrong sign for a
|
||||||
|
a = -a;
|
||||||
|
}
|
||||||
|
// Revert back from error boxes with T parameters to S paramaters,
|
||||||
|
// page 17 + formulas for calculating S parameters from T parameters.
|
||||||
|
// Forward coefficients, normalize for S21 = 1.0 -> r22 = 1.0
|
||||||
|
auto r22 = complex<double>(1.0);
|
||||||
|
auto rho22 = r22_rho22 / r22;
|
||||||
|
auto alpha = alpha_a / a;
|
||||||
|
auto beta = beta_over_alpha * alpha;
|
||||||
|
auto c = a / a_over_c;
|
||||||
|
auto Box_A = Tparam<complex<double>>(r22 * a, r22 * b, r22 * c, r22);
|
||||||
|
auto Box_B = Tparam<complex<double>>(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22);
|
||||||
|
// e00 is S11_A, S11 = T12/T22 = r22*a/r22
|
||||||
|
complex<double> dummy1, dummy2;
|
||||||
|
Box_A.toSparam(p.fe00, dummy1, p.fe10e01, p.fe11);
|
||||||
|
Box_B.toSparam(p.fe22, p.fe10e32, dummy1, dummy2);
|
||||||
|
// no isolation measurement available
|
||||||
|
p.fe30 = 0.0;
|
||||||
|
|
||||||
|
// Reverse coefficients, normalize for S12 = 1.0
|
||||||
|
// => det(T)/T22 = 1.0
|
||||||
|
// => (rho22*alpa*rho22 - rho22*beta*rho*gamma)/rho22 = 1.0
|
||||||
|
// => rho22*alpha - rho22*beta*gamma = 1.0
|
||||||
|
// => rho22 = 1.0/(alpha - beta * gamma)
|
||||||
|
rho22 = 1.0/(alpha - beta * gamma);
|
||||||
|
r22 = r22_rho22 / rho22;
|
||||||
|
|
||||||
|
Box_A = Tparam<complex<double>>(r22 * a, r22 * b, r22 * c, r22);
|
||||||
|
Box_B = Tparam<complex<double>>(rho22 * alpha, rho22 * beta, rho22 * gamma, rho22);
|
||||||
|
Box_A.toSparam(dummy1, dummy2, p.re23e01, p.re11);
|
||||||
|
Box_B.toSparam(p.re22, p.re23e32, dummy1, p.re33);
|
||||||
|
// no isolation measurement available
|
||||||
|
p.re03 = 0.0;
|
||||||
|
|
||||||
|
points.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Calibration::correctMeasurement(Protocol::Datapoint &d)
|
void Calibration::correctMeasurement(Protocol::Datapoint &d)
|
||||||
{
|
{
|
||||||
if(type == Type::None) {
|
if(type == Type::None) {
|
||||||
@ -250,15 +375,17 @@ void Calibration::correctMeasurement(Protocol::Datapoint &d)
|
|||||||
// find correct entry
|
// find correct entry
|
||||||
auto p = getCalibrationPoint(d);
|
auto p = getCalibrationPoint(d);
|
||||||
|
|
||||||
// equations from page 20 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
complex<double> S11, S12, S21, S22;
|
||||||
|
|
||||||
|
// equations from page 19 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
|
||||||
auto denom = (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11) * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
auto denom = (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11) * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
||||||
- (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01 * p.fe22 * p.re11;
|
- (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01 * p.fe22 * p.re11;
|
||||||
auto S11 = ((S11m - p.fe00) / p.fe10e01 * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
S11 = ((S11m - p.fe00) / p.fe10e01 * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
||||||
- p.fe22 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
- p.fe22 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
||||||
auto S21 = ((S21m - p.fe30) / p.fe10e32 * (1.0 + (S22m - p.re33) / p.re23e32 * (p.re22 - p.fe22))) / denom;
|
S21 = ((S21m - p.fe30) / p.fe10e32 * (1.0 + (S22m - p.re33) / p.re23e32 * (p.re22 - p.fe22))) / denom;
|
||||||
auto S22 = ((S22m - p.re33) / p.re23e32 * (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11)
|
S22 = ((S22m - p.re33) / p.re23e32 * (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11)
|
||||||
- p.re11 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
- p.re11 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
||||||
auto S12 = ((S12m - p.re03) / p.re23e01 * (1.0 + (S11m - p.fe00) / p.fe10e01 * (p.fe11 - p.re11))) / denom;
|
S12 = ((S12m - p.re03) / p.re23e01 * (1.0 + (S11m - p.fe00) / p.fe10e01 * (p.fe11 - p.re11))) / denom;
|
||||||
|
|
||||||
d.real_S11 = S11.real();
|
d.real_S11 = S11.real();
|
||||||
d.imag_S11 = S11.imag();
|
d.imag_S11 = S11.imag();
|
||||||
@ -319,6 +446,8 @@ QString Calibration::MeasurementToString(Calibration::Measurement m)
|
|||||||
return "Through";
|
return "Through";
|
||||||
case Measurement::Isolation:
|
case Measurement::Isolation:
|
||||||
return "Isolation";
|
return "Isolation";
|
||||||
|
case Measurement::Line:
|
||||||
|
return "Line";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@ -330,22 +459,32 @@ QString Calibration::TypeToString(Calibration::Type t)
|
|||||||
case Type::Port1SOL: return "Port 1"; break;
|
case Type::Port1SOL: return "Port 1"; break;
|
||||||
case Type::Port2SOL: return "Port 2"; break;
|
case Type::Port2SOL: return "Port 2"; break;
|
||||||
case Type::FullSOLT: return "SOLT"; break;
|
case Type::FullSOLT: return "SOLT"; break;
|
||||||
|
case Type::TransmissionNormalization: return "Normalize"; break;
|
||||||
|
case Type::TRL: return "TRL"; break;
|
||||||
default: return "None"; break;
|
default: return "None"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Calibration::Type> Calibration::Types()
|
const std::vector<Calibration::Type> Calibration::Types()
|
||||||
{
|
{
|
||||||
const std::vector<Calibration::Type> ret = {Type::Port1SOL, Type::Port2SOL, Type::FullSOLT};
|
const std::vector<Calibration::Type> ret = {Type::Port1SOL, Type::Port2SOL, Type::FullSOLT, Type::TransmissionNormalization, Type::TRL};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Calibration::Measurement> Calibration::Measurements(Calibration::Type type)
|
const std::vector<Calibration::Measurement> Calibration::Measurements(Calibration::Type type, bool optional_included)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::FullSOLT:
|
|
||||||
case Type::None:
|
case Type::None:
|
||||||
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load, Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load, Measurement::Through, Measurement::Isolation};
|
// all possible measurements
|
||||||
|
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load,
|
||||||
|
Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load,
|
||||||
|
Measurement::Through, Measurement::Isolation, Measurement::Line};
|
||||||
|
case Type::FullSOLT:
|
||||||
|
if(optional_included) {
|
||||||
|
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load, Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load, Measurement::Through, Measurement::Isolation};
|
||||||
|
} else {
|
||||||
|
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load, Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load, Measurement::Through};
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Type::Port1SOL:
|
case Type::Port1SOL:
|
||||||
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load};
|
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load};
|
||||||
@ -353,6 +492,16 @@ const std::vector<Calibration::Measurement> Calibration::Measurements(Calibratio
|
|||||||
case Type::Port2SOL:
|
case Type::Port2SOL:
|
||||||
return {Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load};
|
return {Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load};
|
||||||
break;
|
break;
|
||||||
|
case Type::TransmissionNormalization:
|
||||||
|
return {Measurement::Through};
|
||||||
|
break;
|
||||||
|
case Type::TRL:
|
||||||
|
if(kit.isTRLReflectionShort()) {
|
||||||
|
return {Measurement::Through, Measurement::Port1Short, Measurement::Port2Short, Measurement::Line};
|
||||||
|
} else {
|
||||||
|
return {Measurement::Through, Measurement::Port1Open, Measurement::Port2Open, Measurement::Line};
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
break;
|
break;
|
||||||
@ -394,6 +543,11 @@ Calibration::MeasurementInfo Calibration::getMeasurementInfo(Calibration::Measur
|
|||||||
case Measurement::Isolation:
|
case Measurement::Isolation:
|
||||||
info.name = "Isolation";
|
info.name = "Isolation";
|
||||||
info.prerequisites = "Both ports terminated into 50 ohm";
|
info.prerequisites = "Both ports terminated into 50 ohm";
|
||||||
|
break;
|
||||||
|
case Measurement::Line:
|
||||||
|
info.name = "Line";
|
||||||
|
info.prerequisites = "Port 1 connected to port 2 via line standard";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
info.points = measurements[m].datapoints.size();
|
info.points = measurements[m].datapoints.size();
|
||||||
if(info.points > 0) {
|
if(info.points > 0) {
|
||||||
@ -524,7 +678,7 @@ istream& operator >>(istream &in, Calibration &c)
|
|||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
while(getline(in, line)) {
|
while(getline(in, line)) {
|
||||||
for(auto m : Calibration::Measurements()) {
|
for(auto m : c.Measurements()) {
|
||||||
if(Calibration::MeasurementToString(m) == QString::fromStdString(line)) {
|
if(Calibration::MeasurementToString(m) == QString::fromStdString(line)) {
|
||||||
// this is the correct measurement
|
// this is the correct measurement
|
||||||
c.clearMeasurement(m);
|
c.clearMeasurement(m);
|
||||||
@ -561,7 +715,7 @@ istream& operator >>(istream &in, Calibration &c)
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Calibration::SanityCheckSamples(std::vector<Calibration::Measurement> &requiredMeasurements)
|
bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement> &requiredMeasurements)
|
||||||
{
|
{
|
||||||
// sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty)
|
// sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty)
|
||||||
vector<uint64_t> freqs;
|
vector<uint64_t> freqs;
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
Port2Load,
|
Port2Load,
|
||||||
Isolation,
|
Isolation,
|
||||||
Through,
|
Through,
|
||||||
|
Line,
|
||||||
};
|
};
|
||||||
void clearMeasurements();
|
void clearMeasurements();
|
||||||
void clearMeasurement(Measurement type);
|
void clearMeasurement(Measurement type);
|
||||||
@ -35,6 +36,8 @@ public:
|
|||||||
Port1SOL,
|
Port1SOL,
|
||||||
Port2SOL,
|
Port2SOL,
|
||||||
FullSOLT,
|
FullSOLT,
|
||||||
|
TransmissionNormalization,
|
||||||
|
TRL,
|
||||||
None,
|
None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +70,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const std::vector<Type> Types();
|
static const std::vector<Type> Types();
|
||||||
static const std::vector<Measurement> Measurements(Type type = Type::None);
|
const std::vector<Measurement> Measurements(Type type = Type::None, bool optional_included = true);
|
||||||
MeasurementInfo getMeasurementInfo(Measurement m);
|
MeasurementInfo getMeasurementInfo(Measurement m);
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Calibration& c);
|
friend std::ostream& operator<<(std::ostream& os, const Calibration& c);
|
||||||
@ -89,7 +92,9 @@ private:
|
|||||||
void construct12TermPoints();
|
void construct12TermPoints();
|
||||||
void constructPort1SOL();
|
void constructPort1SOL();
|
||||||
void constructPort2SOL();
|
void constructPort2SOL();
|
||||||
bool SanityCheckSamples(std::vector<Measurement> &requiredMeasurements);
|
void constructTransmissionNormalization();
|
||||||
|
void constructTRL();
|
||||||
|
bool SanityCheckSamples(const std::vector<Measurement> &requiredMeasurements);
|
||||||
class Point
|
class Point
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -64,7 +64,9 @@ void CalibrationTraceDialog::on_bOpen_clicked()
|
|||||||
{
|
{
|
||||||
cal->openFromFile();
|
cal->openFromFile();
|
||||||
UpdateApplyButton();
|
UpdateApplyButton();
|
||||||
emit applyCalibration(cal->getType());
|
if(cal->getType() != Calibration::Type::None) {
|
||||||
|
emit applyCalibration(cal->getType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalibrationTraceDialog::on_bSave_clicked()
|
void CalibrationTraceDialog::on_bSave_clicked()
|
||||||
|
@ -51,6 +51,12 @@ Calkit::Calkit()
|
|||||||
load_Sparam = 0;
|
load_Sparam = 0;
|
||||||
through_Sparam1 = 0;
|
through_Sparam1 = 0;
|
||||||
through_Sparam2 = 1;
|
through_Sparam2 = 1;
|
||||||
|
|
||||||
|
TRL_through_Z0 = 50.0;
|
||||||
|
TRL_reflection_short = true;
|
||||||
|
TRL_line_delay = 74;
|
||||||
|
TRL_line_maxfreq = 6000000000;
|
||||||
|
TRL_line_minfreq = 751000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Calkit::toFile(std::string filename)
|
void Calkit::toFile(std::string filename)
|
||||||
@ -75,6 +81,11 @@ void Calkit::toFile(std::string filename)
|
|||||||
if(through_measurements) {
|
if(through_measurements) {
|
||||||
file << through_file << "\n" << through_Sparam1 << "\n" << through_Sparam2 << "\n";
|
file << through_file << "\n" << through_Sparam1 << "\n" << through_Sparam2 << "\n";
|
||||||
}
|
}
|
||||||
|
file << TRL_through_Z0 << "\n";
|
||||||
|
file << TRL_reflection_short << "\n";
|
||||||
|
file << TRL_line_delay << "\n";
|
||||||
|
file << TRL_line_minfreq << "\n";
|
||||||
|
file << TRL_line_maxfreq << "\n";
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +136,11 @@ Calkit Calkit::fromFile(std::string filename)
|
|||||||
file >> c.through_Sparam1;
|
file >> c.through_Sparam1;
|
||||||
file >> c.through_Sparam2;
|
file >> c.through_Sparam2;
|
||||||
}
|
}
|
||||||
|
file >> c.TRL_through_Z0;
|
||||||
|
file >> c.TRL_reflection_short;
|
||||||
|
file >> c.TRL_line_delay;
|
||||||
|
file >> c.TRL_line_minfreq;
|
||||||
|
file >> c.TRL_line_maxfreq;
|
||||||
file.close();
|
file.close();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -135,10 +151,10 @@ void Calkit::edit()
|
|||||||
dialog->show();
|
dialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
Calkit::Reflection Calkit::toReflection(double frequency)
|
Calkit::SOLT Calkit::toSOLT(double frequency)
|
||||||
{
|
{
|
||||||
fillTouchstoneCache();
|
fillTouchstoneCache();
|
||||||
Reflection ref;
|
SOLT ref;
|
||||||
if(load_measurements) {
|
if(load_measurements) {
|
||||||
ref.Load = ts_load->interpolate(frequency).S[0];
|
ref.Load = ts_load->interpolate(frequency).S[0];
|
||||||
} else {
|
} else {
|
||||||
@ -204,40 +220,66 @@ Calkit::Reflection Calkit::toReflection(double frequency)
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Calkit::minFreq()
|
Calkit::TRL Calkit::toTRL(double)
|
||||||
{
|
{
|
||||||
fillTouchstoneCache();
|
TRL trl;
|
||||||
double min = std::numeric_limits<double>::min();
|
// reflection coefficent sign depends on whether an open or short is used
|
||||||
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
trl.reflectionIsNegative = TRL_reflection_short;
|
||||||
// find the highest minimum frequency in all measurement files
|
// assume ideal through for now
|
||||||
for(auto ts : ts_list) {
|
trl.ThroughS11 = 0.0;
|
||||||
if(!ts) {
|
trl.ThroughS12 = 1.0;
|
||||||
// this calibration standard is defined by coefficients, no minimum frequency
|
trl.ThroughS21 = 1.0;
|
||||||
continue;
|
trl.ThroughS22 = 0.0;
|
||||||
}
|
return trl;
|
||||||
if(ts->minFreq() > min) {
|
|
||||||
min = ts->minFreq();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double Calkit::maxFreq()
|
double Calkit::minFreq(bool TRL)
|
||||||
{
|
{
|
||||||
fillTouchstoneCache();
|
if(TRL) {
|
||||||
double max = std::numeric_limits<double>::max();
|
return TRL_line_minfreq;
|
||||||
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
} else {
|
||||||
// find the highest minimum frequency in all measurement files
|
fillTouchstoneCache();
|
||||||
for(auto ts : ts_list) {
|
double min = std::numeric_limits<double>::min();
|
||||||
if(!ts) {
|
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
||||||
// this calibration standard is defined by coefficients, no minimum frequency
|
// find the highest minimum frequency in all measurement files
|
||||||
continue;
|
for(auto ts : ts_list) {
|
||||||
}
|
if(!ts) {
|
||||||
if(ts->maxFreq() < max) {
|
// this calibration standard is defined by coefficients, no minimum frequency
|
||||||
max = ts->maxFreq();
|
continue;
|
||||||
|
}
|
||||||
|
if(ts->minFreq() > min) {
|
||||||
|
min = ts->minFreq();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return min;
|
||||||
}
|
}
|
||||||
return max;
|
}
|
||||||
|
|
||||||
|
double Calkit::maxFreq(bool TRL)
|
||||||
|
{
|
||||||
|
if(TRL) {
|
||||||
|
return TRL_line_maxfreq;
|
||||||
|
} else {
|
||||||
|
fillTouchstoneCache();
|
||||||
|
double max = std::numeric_limits<double>::max();
|
||||||
|
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
||||||
|
// find the highest minimum frequency in all measurement files
|
||||||
|
for(auto ts : ts_list) {
|
||||||
|
if(!ts) {
|
||||||
|
// this calibration standard is defined by coefficients, no minimum frequency
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(ts->maxFreq() < max) {
|
||||||
|
max = ts->maxFreq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Calkit::isTRLReflectionShort() const
|
||||||
|
{
|
||||||
|
return TRL_reflection_short;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Calkit::clearTouchstoneCache()
|
void Calkit::clearTouchstoneCache()
|
||||||
|
@ -11,7 +11,7 @@ class Calkit
|
|||||||
public:
|
public:
|
||||||
Calkit();
|
Calkit();
|
||||||
|
|
||||||
class Reflection {
|
class SOLT {
|
||||||
public:
|
public:
|
||||||
std::complex<double> Open;
|
std::complex<double> Open;
|
||||||
std::complex<double> Short;
|
std::complex<double> Short;
|
||||||
@ -19,13 +19,23 @@ public:
|
|||||||
std::complex<double> ThroughS11, ThroughS12, ThroughS21, ThroughS22;
|
std::complex<double> ThroughS11, ThroughS12, ThroughS21, ThroughS22;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TRL {
|
||||||
|
public:
|
||||||
|
bool reflectionIsNegative;
|
||||||
|
std::complex<double> ThroughS11, ThroughS12, ThroughS21, ThroughS22;
|
||||||
|
};
|
||||||
|
|
||||||
void toFile(std::string filename);
|
void toFile(std::string filename);
|
||||||
static Calkit fromFile(std::string filename);
|
static Calkit fromFile(std::string filename);
|
||||||
void edit();
|
void edit();
|
||||||
Reflection toReflection(double frequency);
|
SOLT toSOLT(double frequency);
|
||||||
double minFreq();
|
TRL toTRL(double frequency);
|
||||||
double maxFreq();
|
double minFreq(bool TRL = false);
|
||||||
|
double maxFreq(bool TRL = false);
|
||||||
|
bool isTRLReflectionShort() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// SOLT standard definitions
|
||||||
double open_Z0, open_delay, open_loss, open_C0, open_C1, open_C2, open_C3;
|
double open_Z0, open_delay, open_loss, open_C0, open_C1, open_C2, open_C3;
|
||||||
double short_Z0, short_delay, short_loss, short_L0, short_L1, short_L2, short_L3;
|
double short_Z0, short_delay, short_loss, short_L0, short_L1, short_L2, short_L3;
|
||||||
double load_Z0;
|
double load_Z0;
|
||||||
@ -37,6 +47,13 @@ private:
|
|||||||
bool load_measurements;
|
bool load_measurements;
|
||||||
bool through_measurements;
|
bool through_measurements;
|
||||||
|
|
||||||
|
// TRL standard definitions
|
||||||
|
double TRL_through_Z0;
|
||||||
|
bool TRL_reflection_short;
|
||||||
|
double TRL_line_delay;
|
||||||
|
double TRL_line_minfreq;
|
||||||
|
double TRL_line_maxfreq;
|
||||||
|
|
||||||
std::string open_file, short_file, load_file, through_file;
|
std::string open_file, short_file, load_file, through_file;
|
||||||
int open_Sparam, short_Sparam, load_Sparam, through_Sparam1, through_Sparam2;
|
int open_Sparam, short_Sparam, load_Sparam, through_Sparam1, through_Sparam2;
|
||||||
|
|
||||||
|
@ -38,10 +38,30 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
|
|||||||
ui->load_touchstone->setPorts(1);
|
ui->load_touchstone->setPorts(1);
|
||||||
ui->through_touchstone->setPorts(2);
|
ui->through_touchstone->setPorts(2);
|
||||||
|
|
||||||
|
ui->TRL_line_max->setUnit("Hz");
|
||||||
|
ui->TRL_line_max->setPrecision(4);
|
||||||
|
ui->TRL_line_max->setPrefixes(" kMG");
|
||||||
|
ui->TRL_line_min->setUnit("Hz");
|
||||||
|
ui->TRL_line_min->setPrecision(4);
|
||||||
|
ui->TRL_line_min->setPrefixes(" kMG");
|
||||||
|
|
||||||
editKit.clearTouchstoneCache();
|
editKit.clearTouchstoneCache();
|
||||||
ownKit = editKit;
|
ownKit = editKit;
|
||||||
updateEntries();
|
updateEntries();
|
||||||
|
|
||||||
|
connect(ui->TRL_line_min, &SIUnitEdit::valueChanged, [=](double newval){
|
||||||
|
ownKit.TRL_line_minfreq = newval;
|
||||||
|
updateEntries();
|
||||||
|
});
|
||||||
|
connect(ui->TRL_line_max, &SIUnitEdit::valueChanged, [=](double newval){
|
||||||
|
ownKit.TRL_line_maxfreq = newval;
|
||||||
|
updateEntries();
|
||||||
|
});
|
||||||
|
connect(ui->TRL_line_delay, &QLineEdit::editingFinished, [=](){
|
||||||
|
ownKit.TRL_line_delay = ui->TRL_line_delay->text().toDouble();
|
||||||
|
updateEntries();
|
||||||
|
});
|
||||||
|
|
||||||
auto UpdateStatus = [=]() {
|
auto UpdateStatus = [=]() {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if(ui->open_measurement->isChecked() && !ui->open_touchstone->getStatus()) {
|
if(ui->open_measurement->isChecked() && !ui->open_touchstone->getStatus()) {
|
||||||
@ -110,7 +130,6 @@ CalkitDialog::~CalkitDialog()
|
|||||||
|
|
||||||
void CalkitDialog::parseEntries()
|
void CalkitDialog::parseEntries()
|
||||||
{
|
{
|
||||||
|
|
||||||
// type
|
// type
|
||||||
ownKit.open_measurements = ui->open_measurement->isChecked();
|
ownKit.open_measurements = ui->open_measurement->isChecked();
|
||||||
ownKit.short_measurements = ui->short_measurement->isChecked();
|
ownKit.short_measurements = ui->short_measurement->isChecked();
|
||||||
@ -151,6 +170,13 @@ void CalkitDialog::parseEntries()
|
|||||||
ownKit.load_Sparam = ui->load_touchstone->getPorts()[0];
|
ownKit.load_Sparam = ui->load_touchstone->getPorts()[0];
|
||||||
ownKit.through_Sparam1 = ui->through_touchstone->getPorts()[0];
|
ownKit.through_Sparam1 = ui->through_touchstone->getPorts()[0];
|
||||||
ownKit.through_Sparam2 = ui->through_touchstone->getPorts()[1];
|
ownKit.through_Sparam2 = ui->through_touchstone->getPorts()[1];
|
||||||
|
|
||||||
|
// TRL
|
||||||
|
ownKit.TRL_through_Z0 = ui->TRL_through_Z0->text().toDouble();
|
||||||
|
ownKit.TRL_reflection_short = ui->TRL_R_short->isChecked();
|
||||||
|
ownKit.TRL_line_delay = ui->TRL_line_delay->text().toDouble();
|
||||||
|
ownKit.TRL_line_minfreq = ui->TRL_line_min->value();
|
||||||
|
ownKit.TRL_line_maxfreq = ui->TRL_line_max->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalkitDialog::updateEntries()
|
void CalkitDialog::updateEntries()
|
||||||
@ -216,4 +242,25 @@ void CalkitDialog::updateEntries()
|
|||||||
} else {
|
} else {
|
||||||
ui->through_coefficients->click();
|
ui->through_coefficients->click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TRL
|
||||||
|
ui->TRL_through_Z0->setText(QString::number(ownKit.TRL_through_Z0));
|
||||||
|
if(ownKit.TRL_reflection_short) {
|
||||||
|
ui->TRL_R_short->setChecked(true);
|
||||||
|
} else {
|
||||||
|
ui->TRL_R_open->setChecked(true);
|
||||||
|
}
|
||||||
|
ui->TRL_line_delay->setText(QString::number(ownKit.TRL_line_delay));
|
||||||
|
ui->TRL_line_min->setValueQuiet(ownKit.TRL_line_minfreq);
|
||||||
|
ui->TRL_line_max->setValueQuiet(ownKit.TRL_line_maxfreq);
|
||||||
|
// Check if line length is appropriate for frequencies
|
||||||
|
auto minDelay = 20.0/(ownKit.TRL_line_minfreq * 360.0) * 1e12;
|
||||||
|
auto maxDelay = 160.0/(ownKit.TRL_line_maxfreq * 360.0) * 1e12;
|
||||||
|
if(ownKit.TRL_line_delay < minDelay) {
|
||||||
|
ui->TRL_line_warning->setText("Line too short, minimum required delay is "+QString::number(minDelay, 'g', 3) + "ps");
|
||||||
|
} else if(ownKit.TRL_line_delay > maxDelay) {
|
||||||
|
ui->TRL_line_warning->setText("Line too long, maximum allowed delay is "+QString::number(maxDelay, 'g', 3) + "ps");
|
||||||
|
} else {
|
||||||
|
ui->TRL_line_warning->clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -53,7 +53,6 @@ QVariant MeasurementModel::data(const QModelIndex &index, int role) const
|
|||||||
case ColIndexDescription: return 500; break;
|
case ColIndexDescription: return 500; break;
|
||||||
case ColIndexData: return 300; break;
|
case ColIndexData: return 300; break;
|
||||||
case ColIndexDate: return 300; break;
|
case ColIndexDate: return 300; break;
|
||||||
case ColIndexStatusSymbol: return 150; break;
|
|
||||||
default: return QVariant(); break;
|
default: return QVariant(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +68,6 @@ QVariant MeasurementModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
case ColIndexDescription: return "Prerequisites"; break;
|
case ColIndexDescription: return "Prerequisites"; break;
|
||||||
case ColIndexData: return "Statistics"; break;
|
case ColIndexData: return "Statistics"; break;
|
||||||
case ColIndexDate: return "Timestamp"; break;
|
case ColIndexDate: return "Timestamp"; break;
|
||||||
case ColIndexStatusSymbol: return "Status"; break;
|
|
||||||
default: return QVariant(); break;
|
default: return QVariant(); break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,7 +26,6 @@ private:
|
|||||||
ColIndexDescription,
|
ColIndexDescription,
|
||||||
ColIndexData,
|
ColIndexData,
|
||||||
ColIndexDate,
|
ColIndexDate,
|
||||||
ColIndexStatusSymbol,
|
|
||||||
ColIndexLast
|
ColIndexLast
|
||||||
};
|
};
|
||||||
Calibration *cal;
|
Calibration *cal;
|
||||||
|
@ -702,10 +702,11 @@ void VNA::ApplyCalibration(Calibration::Type type)
|
|||||||
{
|
{
|
||||||
if(cal.calculationPossible(type)) {
|
if(cal.calculationPossible(type)) {
|
||||||
try {
|
try {
|
||||||
cal.constructErrorTerms(type);
|
if(cal.constructErrorTerms(type)) {
|
||||||
calValid = true;
|
calValid = true;
|
||||||
average.reset();
|
average.reset();
|
||||||
emit CalibrationApplied(type);
|
emit CalibrationApplied(type);
|
||||||
|
}
|
||||||
} catch (runtime_error e) {
|
} catch (runtime_error e) {
|
||||||
QMessageBox::critical(this, "Calibration failure", e.what());
|
QMessageBox::critical(this, "Calibration failure", e.what());
|
||||||
DisableCalibration(true);
|
DisableCalibration(true);
|
||||||
|
Loading…
Reference in New Issue
Block a user