Merge branch 'master' of github.com:jankae/LibreVNA

This commit is contained in:
Jan Käberich 2022-03-28 22:07:20 +02:00
commit ea6fdac2a4
49 changed files with 637 additions and 348 deletions

View File

@ -15,15 +15,15 @@ using namespace std;
Calibration::Calibration() Calibration::Calibration()
{ {
// Create vectors for measurements // Create vectors for measurements
measurements[Measurement::Port1Open].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port1Open].datapoints = vector<VNAData>();
measurements[Measurement::Port1Short].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port1Short].datapoints = vector<VNAData>();
measurements[Measurement::Port1Load].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port1Load].datapoints = vector<VNAData>();
measurements[Measurement::Port2Open].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port2Open].datapoints = vector<VNAData>();
measurements[Measurement::Port2Short].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port2Short].datapoints = vector<VNAData>();
measurements[Measurement::Port2Load].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Port2Load].datapoints = vector<VNAData>();
measurements[Measurement::Isolation].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Isolation].datapoints = vector<VNAData>();
measurements[Measurement::Through].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Through].datapoints = vector<VNAData>();
measurements[Measurement::Line].datapoints = vector<Protocol::Datapoint>(); measurements[Measurement::Line].datapoints = vector<VNAData>();
type = Type::None; type = Type::None;
port1Standard = port2Standard = PortStandard::Male; port1Standard = port2Standard = PortStandard::Male;
@ -84,13 +84,13 @@ void Calibration::clearMeasurement(Calibration::Measurement type)
qDebug() << "Deleted" << MeasurementToString(type) << "measurement"; qDebug() << "Deleted" << MeasurementToString(type) << "measurement";
} }
void Calibration::addMeasurement(Calibration::Measurement type, Protocol::Datapoint &d) void Calibration::addMeasurement(Calibration::Measurement type, VNAData &d)
{ {
measurements[type].datapoints.push_back(d); measurements[type].datapoints.push_back(d);
measurements[type].timestamp = QDateTime::currentDateTime(); measurements[type].timestamp = QDateTime::currentDateTime();
} }
void Calibration::addMeasurements(std::set<Calibration::Measurement> types, Protocol::Datapoint &d) void Calibration::addMeasurements(std::set<Calibration::Measurement> types, VNAData &d)
{ {
for(auto t : types) { for(auto t : types) {
addMeasurement(t, d); addMeasurement(t, d);
@ -176,22 +176,22 @@ void Calibration::construct12TermPoints()
Point p; Point p;
p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency; p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency;
// extract required complex reflection/transmission factors from datapoints // extract required complex reflection/transmission factors from datapoints
auto S11_open = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11;
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11;
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11); auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11;
auto S22_open = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22;
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22;
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22); auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22;
auto S21_isolation = complex<double>(0,0); auto S21_isolation = complex<double>(0,0);
auto S12_isolation = complex<double>(0,0); auto S12_isolation = complex<double>(0,0);
if(isolation_measured) { if(isolation_measured) {
S21_isolation = complex<double>(measurements[Measurement::Isolation].datapoints[i].real_S21, measurements[Measurement::Isolation].datapoints[i].imag_S21); S21_isolation = measurements[Measurement::Isolation].datapoints[i].S.m21;
S12_isolation = complex<double>(measurements[Measurement::Isolation].datapoints[i].real_S12, measurements[Measurement::Isolation].datapoints[i].imag_S12); S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12;
} }
auto S11_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11); auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11;
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21); auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22); auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22;
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12); auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male);
// Forward calibration // Forward calibration
@ -232,9 +232,9 @@ void Calibration::constructPort1SOL()
Point p; Point p;
p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency; p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency;
// extract required complex reflection/transmission factors from datapoints // extract required complex reflection/transmission factors from datapoints
auto S11_open = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11;
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11;
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11); auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11;
// OSL port1 // OSL port1
auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male);
// See page 13 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf // See page 13 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
@ -262,9 +262,9 @@ void Calibration::constructPort2SOL()
Point p; Point p;
p.frequency = measurements[Measurement::Port2Open].datapoints[i].frequency; p.frequency = measurements[Measurement::Port2Open].datapoints[i].frequency;
// extract required complex reflection/transmission factors from datapoints // extract required complex reflection/transmission factors from datapoints
auto S22_open = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22;
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22;
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22); auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22;
// OSL port2 // OSL port2
auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male); auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male);
// See page 19 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf // See page 19 of https://www.rfmentor.com/sites/default/files/NA_Error_Models_and_Cal_Methods.pdf
@ -292,8 +292,8 @@ void Calibration::constructTransmissionNormalization()
Point p; Point p;
p.frequency = measurements[Measurement::Through].datapoints[i].frequency; p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
// extract required complex reflection/transmission factors from datapoints // 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 S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12); auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
auto actual = kit.toSOLT(p.frequency); auto actual = kit.toSOLT(p.frequency);
p.fe10e32 = S21_through / actual.ThroughS21; p.fe10e32 = S21_through / actual.ThroughS21;
p.re23e01 = S12_through / actual.ThroughS12; p.re23e01 = S12_through / actual.ThroughS12;
@ -329,24 +329,24 @@ void Calibration::constructTRL()
p.frequency = measurements[Measurement::Through].datapoints[i].frequency; p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
// grab raw measurements // grab raw measurements
auto S11_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11); auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11;
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21); auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22); auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22;
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12); auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
auto S11_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S11, measurements[Measurement::Line].datapoints[i].imag_S11); auto S11_line = measurements[Measurement::Line].datapoints[i].S.m11;
auto S21_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S21, measurements[Measurement::Line].datapoints[i].imag_S21); auto S21_line = measurements[Measurement::Line].datapoints[i].S.m21;
auto S22_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S22, measurements[Measurement::Line].datapoints[i].imag_S22); auto S22_line = measurements[Measurement::Line].datapoints[i].S.m22;
auto S12_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S12, measurements[Measurement::Line].datapoints[i].imag_S12); auto S12_line = measurements[Measurement::Line].datapoints[i].S.m12;
auto trl = kit.toTRL(p.frequency); auto trl = kit.toTRL(p.frequency);
complex<double> S11_reflection, S22_reflection; complex<double> S11_reflection, S22_reflection;
if(trl.reflectionIsNegative) { if(trl.reflectionIsNegative) {
// used short // used short
S11_reflection = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11); S11_reflection = measurements[Measurement::Port1Short].datapoints[i].S.m11;
S22_reflection = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22); S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22;
} else { } else {
// used open // used open
S11_reflection = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11); S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11;
S22_reflection = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22); S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22;
} }
// 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
@ -432,17 +432,17 @@ void Calibration::constructTRL()
} }
} }
void Calibration::correctMeasurement(Protocol::Datapoint &d) void Calibration::correctMeasurement(VNAData &d)
{ {
if(type == Type::None) { if(type == Type::None) {
// No calibration data, do nothing // No calibration data, do nothing
return; return;
} }
// Convert measurements to complex variables // Convert measurements to complex variables
auto S11m = complex<double>(d.real_S11, d.imag_S11); auto S11m = d.S.m11;
auto S21m = complex<double>(d.real_S21, d.imag_S21); auto S21m = d.S.m21;
auto S22m = complex<double>(d.real_S22, d.imag_S22); auto S22m = d.S.m22;
auto S12m = complex<double>(d.real_S12, d.imag_S12); auto S12m = d.S.m12;
// find correct entry // find correct entry
auto p = getCalibrationPoint(d); auto p = getCalibrationPoint(d);
@ -459,14 +459,7 @@ void Calibration::correctMeasurement(Protocol::Datapoint &d)
- 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;
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.S = Sparam(S11, S12, S21, S22);
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
} }
void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22) void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22)
@ -741,13 +734,13 @@ std::vector<Trace *> Calibration::getMeasurementTraces()
Trace::Data d; Trace::Data d;
d.x = p.frequency; d.x = p.frequency;
if(prefix == "S11") { if(prefix == "S11") {
d.y = complex<double>(p.real_S11, p.imag_S11); d.y = p.S.m11;
} else if(prefix == "S12") { } else if(prefix == "S12") {
d.y = complex<double>(p.real_S12, p.imag_S12); d.y = p.S.m12;
} else if(prefix == "S21") { } else if(prefix == "S21") {
d.y = complex<double>(p.real_S21, p.imag_S21); d.y = p.S.m21;
} else { } else {
d.y = complex<double>(p.real_S22, p.imag_S22); d.y = p.S.m22;
} }
t->addData(d, TraceMath::DataType::Frequency); t->addData(d, TraceMath::DataType::Frequency);
} }
@ -790,7 +783,7 @@ bool Calibration::openFromFile(QString filename)
qDebug() << "Associated calibration kit expected in" << calkit_file; qDebug() << "Associated calibration kit expected in" << calkit_file;
try { try {
kit = Calkit::fromFile(calkit_file); kit = Calkit::fromFile(calkit_file);
} catch (runtime_error e) { } catch (runtime_error &e) {
InformationBox::ShowError("Missing calibration kit", "The calibration kit file associated with the selected calibration could not be parsed. The calibration might not be accurate. (" + QString(e.what()) + ")"); InformationBox::ShowError("Missing calibration kit", "The calibration kit file associated with the selected calibration could not be parsed. The calibration might not be accurate. (" + QString(e.what()) + ")");
qWarning() << "Parsing of calibration kit failed while opening calibration file: " << e.what(); qWarning() << "Parsing of calibration kit failed while opening calibration file: " << e.what();
} }
@ -809,7 +802,7 @@ bool Calibration::openFromFile(QString filename)
nlohmann::json j; nlohmann::json j;
file >> j; file >> j;
fromJSON(j); fromJSON(j);
} catch(exception e) { } catch(exception &e) {
// json parsing failed, probably using a legacy file format // json parsing failed, probably using a legacy file format
try { try {
file.clear(); file.clear();
@ -818,7 +811,7 @@ bool Calibration::openFromFile(QString filename)
InformationBox::ShowMessage("Loading calibration file", "The file \"" + filename + "\" is stored in a deprecated" InformationBox::ShowMessage("Loading calibration file", "The file \"" + filename + "\" is stored in a deprecated"
" calibration format. Future versions of this application might not support" " calibration format. Future versions of this application might not support"
" it anymore. Please save the calibration to update to the new format"); " it anymore. Please save the calibration to update to the new format");
} catch(exception e) { } catch(exception &e) {
InformationBox::ShowError("File parsing error", e.what()); InformationBox::ShowError("File parsing error", e.what());
qWarning() << "Calibration file parsing failed: " << e.what(); qWarning() << "Calibration file parsing failed: " << e.what();
return false; return false;
@ -916,14 +909,14 @@ nlohmann::json Calibration::toJSON()
for(auto p : m.second.datapoints) { for(auto p : m.second.datapoints) {
nlohmann::json j_point; nlohmann::json j_point;
j_point["frequency"] = p.frequency; j_point["frequency"] = p.frequency;
j_point["S11_real"] = p.real_S11; j_point["S11_real"] = p.S.m11.real();
j_point["S11_imag"] = p.imag_S11; j_point["S11_imag"] = p.S.m11.imag();
j_point["S12_real"] = p.real_S12; j_point["S12_real"] = p.S.m12.real();
j_point["S12_imag"] = p.imag_S12; j_point["S12_imag"] = p.S.m12.imag();
j_point["S21_real"] = p.real_S21; j_point["S21_real"] = p.S.m21.real();
j_point["S21_imag"] = p.imag_S21; j_point["S21_imag"] = p.S.m21.imag();
j_point["S22_real"] = p.real_S22; j_point["S22_real"] = p.S.m22.real();
j_point["S22_imag"] = p.imag_S22; j_point["S22_imag"] = p.S.m22.imag();
j_points.push_back(j_point); j_points.push_back(j_point);
} }
j_measurement["points"] = j_points; j_measurement["points"] = j_points;
@ -964,17 +957,13 @@ void Calibration::fromJSON(nlohmann::json j)
} }
int pointNum = 0; int pointNum = 0;
for(auto j_p : j_m["points"]) { for(auto j_p : j_m["points"]) {
Protocol::Datapoint p; VNAData p;
p.pointNum = pointNum++; p.pointNum = pointNum++;
p.frequency = j_p.value("frequency", 0.0); p.frequency = j_p.value("frequency", 0.0);
p.real_S11 = j_p.value("S11_real", 0.0); p.S.m11 = complex<double>(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0));
p.imag_S11 = j_p.value("S11_imag", 0.0); p.S.m12 = complex<double>(j_p.value("S12_real", 0.0), j_p.value("S12_imag", 0.0));
p.real_S12 = j_p.value("S12_real", 0.0); p.S.m21 = complex<double>(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0));
p.imag_S12 = j_p.value("S12_imag", 0.0); p.S.m22 = complex<double>(j_p.value("S22_real", 0.0), j_p.value("S22_imag", 0.0));
p.real_S21 = j_p.value("S21_real", 0.0);
p.imag_S21 = j_p.value("S21_imag", 0.0);
p.real_S22 = j_p.value("S22_real", 0.0);
p.imag_S22 = j_p.value("S22_imag", 0.0);
measurements[m].datapoints.push_back(p); measurements[m].datapoints.push_back(p);
} }
} }
@ -997,24 +986,6 @@ QString Calibration::getCurrentCalibrationFile(){
return this->currentCalFile; return this->currentCalFile;
} }
ostream& operator<<(ostream &os, const Calibration &c)
{
for(auto m : c.measurements) {
if(m.second.datapoints.size() > 0) {
os << c.MeasurementToString(m.first).toStdString() << endl;
os << m.second.timestamp.toSecsSinceEpoch() << endl;
os << m.second.datapoints.size() << endl;
for(auto p : m.second.datapoints) {
os << p.pointNum << " " << p.frequency << " ";
os << p.imag_S11 << " " << p.real_S11 << " " << p.imag_S21 << " " << p.real_S21 << " " << p.imag_S12 << " " << p.real_S12 << " " << p.imag_S22 << " " << p.real_S22;
os << endl;
}
}
}
os << Calibration::TypeToString(c.getType()).toStdString() << endl;
return os;
}
istream& operator >>(istream &in, Calibration &c) istream& operator >>(istream &in, Calibration &c)
{ {
// old file format did not contain port standard gender, set default // old file format did not contain port standard gender, set default
@ -1039,7 +1010,7 @@ istream& operator >>(istream &in, Calibration &c)
Protocol::Datapoint p; Protocol::Datapoint p;
in >> p.pointNum >> p.frequency; in >> p.pointNum >> p.frequency;
in >> p.imag_S11 >> p.real_S11 >> p.imag_S21 >> p.real_S21 >> p.imag_S12 >> p.real_S12 >> p.imag_S22 >> p.real_S22; in >> p.imag_S11 >> p.real_S11 >> p.imag_S21 >> p.real_S21 >> p.imag_S12 >> p.real_S12 >> p.imag_S22 >> p.real_S22;
c.measurements[m].datapoints.push_back(p); c.measurements[m].datapoints.push_back(VNAData(p));
if(in.eof() || in.bad() || in.fail()) { if(in.eof() || in.bad() || in.fail()) {
c.clearMeasurement(m); c.clearMeasurement(m);
throw runtime_error("Failed to parse measurement \"" + line + "\", aborting calibration data import."); throw runtime_error("Failed to parse measurement \"" + line + "\", aborting calibration data import.");
@ -1097,7 +1068,7 @@ bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement>
return true; return true;
} }
Calibration::Point Calibration::getCalibrationPoint(Protocol::Datapoint &d) Calibration::Point Calibration::getCalibrationPoint(VNAData &d)
{ {
if(!points.size()) { if(!points.size()) {
throw runtime_error("No calibration points available"); throw runtime_error("No calibration points available");

View File

@ -45,8 +45,8 @@ public:
void clearMeasurements(); void clearMeasurements();
void clearMeasurements(std::set<Measurement> types); void clearMeasurements(std::set<Measurement> types);
void clearMeasurement(Measurement type); void clearMeasurement(Measurement type);
void addMeasurement(Measurement type, Protocol::Datapoint &d); void addMeasurement(Measurement type, VNAData &d);
void addMeasurements(std::set<Measurement> types, Protocol::Datapoint &d); void addMeasurements(std::set<Measurement> types, VNAData &d);
enum class Type { enum class Type {
Port1SOL, Port1SOL,
@ -63,7 +63,7 @@ public:
bool constructErrorTerms(Type type); bool constructErrorTerms(Type type);
void resetErrorTerms(); void resetErrorTerms();
void correctMeasurement(Protocol::Datapoint &d); void correctMeasurement(VNAData &d);
void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22); void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
enum class InterpolationType { enum class InterpolationType {
@ -93,7 +93,6 @@ public:
const std::vector<Measurement> Measurements(Type type = Type::None, bool optional_included = true); 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::istream& operator >> (std::istream &in, Calibration& c); friend std::istream& operator >> (std::istream &in, Calibration& c);
int nPoints() { int nPoints() {
return points.size(); return points.size();
@ -142,7 +141,7 @@ private:
// Reverse error terms // Reverse error terms
std::complex<double> re33, re11, re23e32, re23e01, re22, re03, rex; std::complex<double> re33, re11, re23e32, re23e01, re22, re03, rex;
}; };
Point getCalibrationPoint(Protocol::Datapoint &d); Point getCalibrationPoint(VNAData &d);
/* /*
* Constructs directivity, match and tracking correction factors from measurements of three distinct impedances * Constructs directivity, match and tracking correction factors from measurements of three distinct impedances
* Normally, an open, short and load are used (with ideal reflection coefficients of 1, -1 and 0 respectively). * Normally, an open, short and load are used (with ideal reflection coefficients of 1, -1 and 0 respectively).
@ -174,7 +173,7 @@ private:
class MeasurementData { class MeasurementData {
public: public:
QDateTime timestamp; QDateTime timestamp;
std::vector<Protocol::Datapoint> datapoints; std::vector<VNAData> datapoints;
}; };
Type type; Type type;

View File

@ -13,6 +13,7 @@ class Calkit
friend class CalkitDialog; friend class CalkitDialog;
public: public:
Calkit(); Calkit();
Calkit(const Calkit&) = default;
Calkit& operator=(const Calkit& other) Calkit& operator=(const Calkit& other)
{ {
this->manufacturer = other.manufacturer; this->manufacturer = other.manufacturer;

View File

@ -195,7 +195,7 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
if(filename.length() > 0) { if(filename.length() > 0) {
try { try {
ownKit = Calkit::fromFile(filename); ownKit = Calkit::fromFile(filename);
} catch (runtime_error e) { } catch (runtime_error &e) {
InformationBox::ShowError("Error", "The calibration kit file could not be parsed (" + QString(e.what()) + ")"); InformationBox::ShowError("Error", "The calibration kit file could not be parsed (" + QString(e.what()) + ")");
qWarning() << "Parsing of calibration kit failed while opening calibration file: " << e.what(); qWarning() << "Parsing of calibration kit failed while opening calibration file: " << e.what();
} }

View File

@ -113,12 +113,11 @@ QVariant JSONModel::data(const QModelIndex &index, int role) const
case 0: case 0:
return info.name; return info.name;
case 1: case 1:
if(item->is_object() || item->is_array()) { if(!item->is_object() && !item->is_array()) {
return QVariant();
} else {
return info.data; return info.data;
} }
} }
return QVariant();
case Qt::CheckStateRole: { case Qt::CheckStateRole: {
if(index.column() == 0) { if(index.column() == 0) {
return info.enabled ? Qt::Checked : Qt::Unchecked; return info.enabled ? Qt::Checked : Qt::Unchecked;

View File

@ -110,12 +110,14 @@ HEADERS += \
VNA/Deembedding/deembedding.h \ VNA/Deembedding/deembedding.h \
VNA/Deembedding/deembeddingdialog.h \ VNA/Deembedding/deembeddingdialog.h \
VNA/Deembedding/deembeddingoption.h \ VNA/Deembedding/deembeddingoption.h \
VNA/Deembedding/impedancerenormalization.h \
VNA/Deembedding/manualdeembeddingdialog.h \ VNA/Deembedding/manualdeembeddingdialog.h \
VNA/Deembedding/matchingnetwork.h \ VNA/Deembedding/matchingnetwork.h \
VNA/Deembedding/portextension.h \ VNA/Deembedding/portextension.h \
VNA/Deembedding/twothru.h \ VNA/Deembedding/twothru.h \
VNA/tracewidgetvna.h \ VNA/tracewidgetvna.h \
VNA/vna.h \ VNA/vna.h \
VNA/vnadata.h \
about.h \ about.h \
appwindow.h \ appwindow.h \
averaging.h \ averaging.h \
@ -228,6 +230,7 @@ SOURCES += \
VNA/Deembedding/deembedding.cpp \ VNA/Deembedding/deembedding.cpp \
VNA/Deembedding/deembeddingdialog.cpp \ VNA/Deembedding/deembeddingdialog.cpp \
VNA/Deembedding/deembeddingoption.cpp \ VNA/Deembedding/deembeddingoption.cpp \
VNA/Deembedding/impedancerenormalization.cpp \
VNA/Deembedding/manualdeembeddingdialog.cpp \ VNA/Deembedding/manualdeembeddingdialog.cpp \
VNA/Deembedding/matchingnetwork.cpp \ VNA/Deembedding/matchingnetwork.cpp \
VNA/Deembedding/portextension.cpp \ VNA/Deembedding/portextension.cpp \
@ -293,6 +296,7 @@ FORMS += \
Traces/waterfallaxisdialog.ui \ Traces/waterfallaxisdialog.ui \
Traces/xyplotaxisdialog.ui \ Traces/xyplotaxisdialog.ui \
VNA/Deembedding/deembeddingdialog.ui \ VNA/Deembedding/deembeddingdialog.ui \
VNA/Deembedding/impedancenormalizationdialog.ui \
VNA/Deembedding/manualdeembeddingdialog.ui \ VNA/Deembedding/manualdeembeddingdialog.ui \
VNA/Deembedding/matchingnetworkdialog.ui \ VNA/Deembedding/matchingnetworkdialog.ui \
VNA/Deembedding/measurementdialog.ui \ VNA/Deembedding/measurementdialog.ui \

View File

@ -44,7 +44,7 @@ void TraceWidgetSA::importDialog()
if(AppWindow::showGUI()) { if(AppWindow::showGUI()) {
i->show(); i->show();
} }
} catch(const std::exception e) { } catch(const std::exception &e) {
InformationBox::ShowError("Failed to import file", QString("Attempt to import file ended with error: \"") + e.what()+"\""); InformationBox::ShowError("Failed to import file", QString("Attempt to import file ended with error: \"") + e.what()+"\"");
} }
} }

View File

@ -13,7 +13,7 @@ ImpedanceMatchDialog::ImpedanceMatchDialog(MarkerModel &model, Marker *marker, Q
{ {
ui->setupUi(this); ui->setupUi(this);
Z0 = Preferences::getInstance().Acquisition.refImp; Z0 = 50.0;
// set SI units and prefixes // set SI units and prefixes
ui->zReal->setUnit("Ohm"); ui->zReal->setUnit("Ohm");
@ -70,10 +70,13 @@ void ImpedanceMatchDialog::on_cSource_currentIndexChanged(int index)
auto m = qvariant_cast<Marker*>(ui->cSource->itemData(index)); auto m = qvariant_cast<Marker*>(ui->cSource->itemData(index));
ui->rbSeries->setChecked(true); ui->rbSeries->setChecked(true);
auto data = m->getData(); auto data = m->getData();
Z0 = m->getTrace()->getReferenceImpedance();
auto reflection = Z0 * (1.0 + data) / (1.0 - data); auto reflection = Z0 * (1.0 + data) / (1.0 - data);
ui->zReal->setValue(reflection.real()); ui->zReal->setValue(reflection.real());
ui->zImag->setValue(reflection.imag()); ui->zImag->setValue(reflection.imag());
ui->zFreq->setValue(m->getPosition()); ui->zFreq->setValue(m->getPosition());
} else {
Z0 = 50.0;
} }
} }
@ -267,7 +270,7 @@ void ImpedanceMatchDialog::calculateMatch()
ui->Image->setPixmap(QPixmap(":/icons/pCsC_small.png")); ui->Image->setPixmap(QPixmap(":/icons/pCsC_small.png"));
} }
} }
} catch (exception e){ } catch (exception &e){
// something went wrong, probably caused by (intermediate) invalid input, such as f=0Hz // something went wrong, probably caused by (intermediate) invalid input, such as f=0Hz
ui->lValue->setValue(nan("")); ui->lValue->setValue(nan(""));
ui->cValue->setValue(nan("")); ui->cValue->setValue(nan(""));

View File

@ -282,7 +282,7 @@ QString Marker::readableData(Format f)
return Unit::ToString(data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag(), "", " ", 5)+"j"; return Unit::ToString(data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag(), "", " ", 5)+"j";
case Format::Impedance: { case Format::Impedance: {
auto step = parentTrace->sample(parentTrace->index(position), true).y.real(); auto step = parentTrace->sample(parentTrace->index(position), true).y.real();
auto impedance = Util::SparamToImpedance(step).real(); auto impedance = Util::SparamToImpedance(step, trace()->getReferenceImpedance()).real();
return Unit::ToString(impedance, "Ω", "m kM", 3); return Unit::ToString(impedance, "Ω", "m kM", 3);
} }
break; break;
@ -301,8 +301,8 @@ QString Marker::readableData(Format f)
case Format::Impedance: { case Format::Impedance: {
auto step = parentTrace->sample(parentTrace->index(position), true).y.real(); auto step = parentTrace->sample(parentTrace->index(position), true).y.real();
auto stepDelta = delta->parentTrace->sample(delta->parentTrace->index(delta->position), true).y.real(); auto stepDelta = delta->parentTrace->sample(delta->parentTrace->index(delta->position), true).y.real();
auto impedance = Util::SparamToImpedance(step).real(); auto impedance = Util::SparamToImpedance(step, trace()->getReferenceImpedance()).real();
auto impedanceDelta = Util::SparamToImpedance(stepDelta).real(); auto impedanceDelta = Util::SparamToImpedance(stepDelta, trace()->getReferenceImpedance()).real();
return "Δ:"+Unit::ToString(impedance - impedanceDelta, "Ω", "m kM", 3); return "Δ:"+Unit::ToString(impedance - impedanceDelta, "Ω", "m kM", 3);
} }
break; break;
@ -340,13 +340,13 @@ QString Marker::readableData(Format f)
} }
case Format::RealImag: return "Δ:"+Unit::ToString(data.real() - delta->data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag() - delta->data.imag(), "", " ", 5)+"j"; case Format::RealImag: return "Δ:"+Unit::ToString(data.real() - delta->data.real(), "", " ", 5) + "+"+Unit::ToString(data.imag() - delta->data.imag(), "", " ", 5)+"j";
case Format::Impedance: { case Format::Impedance: {
auto impedance = Util::SparamToImpedance(data); auto impedance = Util::SparamToImpedance(data, trace()->getReferenceImpedance());
auto delta_impedance = Util::SparamToImpedance(delta->data); auto delta_impedance = Util::SparamToImpedance(delta->data, trace()->getReferenceImpedance());
return "Δ:"+Unit::ToString(impedance.real() - delta_impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag() - delta_impedance.imag(), "Ω", "m k", 5)+"j"; return "Δ:"+Unit::ToString(impedance.real() - delta_impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag() - delta_impedance.imag(), "Ω", "m k", 5)+"j";
} }
case Format::SeriesR: return "Δ:"+Unit::ToString(Util::SparamToResistance(data) - Util::SparamToResistance(delta->data), "Ω", "m kM", 4); case Format::SeriesR: return "Δ:"+Unit::ToString(Util::SparamToResistance(data, trace()->getReferenceImpedance()) - Util::SparamToResistance(delta->data, trace()->getReferenceImpedance()), "Ω", "m kM", 4);
case Format::Capacitance: return "Δ:"+Unit::ToString(Util::SparamToCapacitance(data, position) - Util::SparamToCapacitance(delta->data, delta->position), "F", "pnum ", 4); case Format::Capacitance: return "Δ:"+Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()) - Util::SparamToCapacitance(delta->data, delta->position, trace()->getReferenceImpedance()), "F", "pnum ", 4);
case Format::Inductance: return "Δ:"+Unit::ToString(Util::SparamToInductance(data, position) - Util::SparamToInductance(delta->data, delta->position), "H", "pnum ", 4); case Format::Inductance: return "Δ:"+Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()) - Util::SparamToInductance(delta->data, delta->position, trace()->getReferenceImpedance()), "H", "pnum ", 4);
case Format::QualityFactor: return "ΔQ:" + Unit::ToString(Util::SparamToQualityFactor(data) - Util::SparamToQualityFactor(delta->data), "", " ", 3); case Format::QualityFactor: return "ΔQ:" + Unit::ToString(Util::SparamToQualityFactor(data) - Util::SparamToQualityFactor(delta->data), "", " ", 3);
case Format::Noise: return "Δ:"+Unit::ToString(parentTrace->getNoise(position) - delta->parentTrace->getNoise(delta->position), "dbm/Hz", " ", 3); case Format::Noise: return "Δ:"+Unit::ToString(parentTrace->getNoise(position) - delta->parentTrace->getNoise(delta->position), "dbm/Hz", " ", 3);
default: return "Invalid"; default: return "Invalid";
@ -368,9 +368,9 @@ QString Marker::readableData(Format f)
return "VSWR: NaN"; return "VSWR: NaN";
} }
break; break;
case Format::SeriesR: return Unit::ToString(Util::SparamToResistance(data), "Ω", "m kM", 4); case Format::SeriesR: return Unit::ToString(Util::SparamToResistance(data, trace()->getReferenceImpedance()), "Ω", "m kM", 4);
case Format::Capacitance: return Unit::ToString(Util::SparamToCapacitance(data, position), "F", "pnum ", 4); case Format::Capacitance: return Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()), "F", "pnum ", 4);
case Format::Inductance: return Unit::ToString(Util::SparamToInductance(data, position), "H", "pnum ", 4); case Format::Inductance: return Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()), "H", "pnum ", 4);
case Format::QualityFactor: return "Q:" + Unit::ToString(Util::SparamToQualityFactor(data), "", " ", 3); case Format::QualityFactor: return "Q:" + Unit::ToString(Util::SparamToQualityFactor(data), "", " ", 3);
case Format::Noise: return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3); case Format::Noise: return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3);
case Format::TOI: { case Format::TOI: {
@ -409,7 +409,7 @@ QString Marker::readableData(Format f)
} }
break; break;
case Format::Impedance: { case Format::Impedance: {
auto impedance = Util::SparamToImpedance(data); auto impedance = Util::SparamToImpedance(data, trace()->getReferenceImpedance());
return Unit::ToString(impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag(), "Ω", "m k", 5)+"j"; return Unit::ToString(impedance.real(), "Ω", "m k", 5) + "+"+Unit::ToString(impedance.imag(), "Ω", "m k", 5)+"j";
} }
case Format::CenterBandwidth: case Format::CenterBandwidth:

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>856</width> <width>881</width>
<height>259</height> <height>334</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -16,11 +16,11 @@
<property name="modal"> <property name="modal">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1"> <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="groupBox_2">
<property name="title"> <property name="title">
@ -72,6 +72,25 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Reference Impedance</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="1">
<widget class="SIUnitEdit" name="impedance"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Impedance:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">

View File

@ -19,6 +19,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
_liveParam(live), _liveParam(live),
vFactor(0.66), vFactor(0.66),
reflection(true), reflection(true),
reference_impedance(50.0),
visible(true), visible(true),
paused(false), paused(false),
createdFromFile(false), createdFromFile(false),
@ -61,7 +62,7 @@ void Trace::clear() {
emit outputSamplesChanged(0, 0); emit outputSamplesChanged(0, 0);
} }
void Trace::addData(const Trace::Data& d, DataType domain) { void Trace::addData(const Trace::Data& d, DataType domain, double reference_impedance) {
if(this->domain != domain) { if(this->domain != domain) {
clear(); clear();
this->domain = domain; this->domain = domain;
@ -100,6 +101,10 @@ void Trace::addData(const Trace::Data& d, DataType domain) {
// insert at this position // insert at this position
data.insert(lower, d); data.insert(lower, d);
} }
if(this->reference_impedance != reference_impedance) {
this->reference_impedance = reference_impedance;
emit typeChanged(this);
}
success(); success();
emit outputSamplesChanged(index, index + 1); emit outputSamplesChanged(index, index + 1);
} }
@ -154,6 +159,7 @@ void Trace::fillFromTouchstone(Touchstone &t, unsigned int parameter)
reflection = false; reflection = false;
} }
createdFromFile = true; createdFromFile = true;
reference_impedance = t.getReferenceImpedance();
emit typeChanged(this); emit typeChanged(this);
emit outputSamplesChanged(0, data.size()); emit outputSamplesChanged(0, data.size());
} }
@ -233,7 +239,7 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter)
return traceName; return traceName;
} }
void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<Protocol::Datapoint> &data) void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data)
{ {
S11.clear(); S11.clear();
S12.clear(); S12.clear();
@ -242,13 +248,13 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c
for(auto d : data) { for(auto d : data) {
Trace::Data td; Trace::Data td;
td.x = d.frequency; td.x = d.frequency;
td.y = complex<double>(d.real_S11, d.imag_S11); td.y = d.S.m11;
S11.addData(td, DataType::Frequency); S11.addData(td, DataType::Frequency);
td.y = complex<double>(d.real_S12, d.imag_S12); td.y = d.S.m12;
S12.addData(td, DataType::Frequency); S12.addData(td, DataType::Frequency);
td.y = complex<double>(d.real_S21, d.imag_S21); td.y = d.S.m21;
S21.addData(td, DataType::Frequency); S21.addData(td, DataType::Frequency);
td.y = complex<double>(d.real_S22, d.imag_S22); td.y = d.S.m22;
S22.addData(td, DataType::Frequency); S22.addData(td, DataType::Frequency);
} }
} }
@ -287,6 +293,11 @@ void Trace::removeMarker(Marker *m)
emit markerRemoved(m); emit markerRemoved(m);
} }
double Trace::getReferenceImpedance() const
{
return reference_impedance;
}
const std::vector<Trace::MathInfo>& Trace::getMathOperations() const const std::vector<Trace::MathInfo>& Trace::getMathOperations() const
{ {
return mathOps; return mathOps;
@ -474,12 +485,13 @@ std::vector<Trace *> Trace::createFromCSV(CSV &csv)
return traces; return traces;
} }
std::vector<Protocol::Datapoint> Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22) std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22)
{ {
vector<Protocol::Datapoint> ret; vector<VNAData> ret;
// Sanity check traces // Sanity check traces
unsigned int samples = S11.size(); unsigned int samples = S11.size();
auto impedance = S11.getReferenceImpedance();
vector<const Trace*> traces; vector<const Trace*> traces;
traces.push_back(&S11); traces.push_back(&S11);
traces.push_back(&S12); traces.push_back(&S12);
@ -491,6 +503,10 @@ std::vector<Protocol::Datapoint> Trace::assembleDatapoints(const Trace &S11, con
qWarning() << "Selected traces do not have the same size"; qWarning() << "Selected traces do not have the same size";
return ret; return ret;
} }
if(t->getReferenceImpedance() != impedance) {
qWarning() << "Selected traces do not have the same reference impedance";
return ret;
}
if(t->outputType() != Trace::DataType::Frequency) { if(t->outputType() != Trace::DataType::Frequency) {
qWarning() << "Selected trace not in frequency domain"; qWarning() << "Selected trace not in frequency domain";
return ret; return ret;

View File

@ -5,6 +5,9 @@
#include "csv.h" #include "csv.h"
#include "Device/device.h" #include "Device/device.h"
#include "Math/tracemath.h" #include "Math/tracemath.h"
#include "Tools/parameters.h"
#include "tracemodel.h"
#include "VNA/vnadata.h"
#include <QObject> #include <QObject>
#include <complex> #include <complex>
@ -41,15 +44,14 @@ public:
Invalid, Invalid,
}; };
void clear(); void clear();
void addData(const Data& d, DataType domain); void addData(const Data& d, DataType domain, double reference_impedance = 50.0);
void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s); void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s);
void setName(QString name); void setName(QString name);
void setVelocityFactor(double v); void setVelocityFactor(double v);
void fillFromTouchstone(Touchstone &t, unsigned int parameter); void fillFromTouchstone(Touchstone &t, unsigned int parameter);
QString fillFromCSV(CSV &csv, unsigned int parameter); // returns the suggested trace name (not yet set in member data) QString fillFromCSV(CSV &csv, unsigned int parameter); // returns the suggested trace name (not yet set in member data)
static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<Protocol::Datapoint> &data); static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data);
void fromLivedata(LivedataType type, LiveParameter param); void fromLivedata(LivedataType type, LiveParameter param);
QString name() { return _name; }; QString name() { return _name; };
QColor color() { return _color; }; QColor color() { return _color; };
@ -134,7 +136,7 @@ public:
// Assembles datapoints as received from the VNA from four S parameter traces. Requires that all traces are in the frequency domain, // Assembles datapoints as received from the VNA from four S parameter traces. Requires that all traces are in the frequency domain,
// have the same number of samples and their samples must be at the same frequencies across all traces // have the same number of samples and their samples must be at the same frequencies across all traces
static std::vector<Protocol::Datapoint> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22); static std::vector<VNAData> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22);
static LiveParameter ParameterFromString(QString s); static LiveParameter ParameterFromString(QString s);
static QString ParameterToString(LiveParameter p); static QString ParameterToString(LiveParameter p);
@ -144,6 +146,8 @@ public:
static LivedataType TypeFromString(QString s); static LivedataType TypeFromString(QString s);
static QString TypeToString(LivedataType t); static QString TypeToString(LivedataType t);
double getReferenceImpedance() const;
public slots: public slots:
void setVisible(bool visible); void setVisible(bool visible);
void setColor(QColor color); void setColor(QColor color);
@ -174,6 +178,7 @@ private:
bool paused; bool paused;
bool createdFromFile; bool createdFromFile;
bool calibration; bool calibration;
double reference_impedance;
DataType domain; DataType domain;
QString filename; QString filename;
unsigned int fileParameter; unsigned int fileParameter;

View File

@ -81,6 +81,11 @@ static void createLogarithmicTicks(vector<double>& ticks, double start, double s
} while(div <= stop); } while(div <= stop);
} }
YAxis::YAxis()
{
type = Type::Magnitude;
}
double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample) double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample)
{ {
switch(type) { switch(type) {
@ -104,11 +109,11 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample
case YAxis::Type::Imaginary: case YAxis::Type::Imaginary:
return data.y.imag(); return data.y.imag();
case YAxis::Type::SeriesR: case YAxis::Type::SeriesR:
return Util::SparamToResistance(data.y); return Util::SparamToResistance(data.y, t->getReferenceImpedance());
case YAxis::Type::Reactance: case YAxis::Type::Reactance:
return Util::SparamToImpedance(data.y).imag(); return Util::SparamToImpedance(data.y, t->getReferenceImpedance()).imag();
case YAxis::Type::Capacitance: case YAxis::Type::Capacitance:
return Util::SparamToCapacitance(data.y, data.x); return Util::SparamToCapacitance(data.y, data.x, t->getReferenceImpedance());
case YAxis::Type::Inductance: case YAxis::Type::Inductance:
return Util::SparamToInductance(data.y, data.x); return Util::SparamToInductance(data.y, data.x);
case YAxis::Type::QualityFactor: case YAxis::Type::QualityFactor:
@ -159,7 +164,7 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample
} }
double step = t->sample(sample, true).y.real(); double step = t->sample(sample, true).y.real();
if(abs(step) < 1.0) { if(abs(step) < 1.0) {
return Util::SparamToImpedance(step).real(); return Util::SparamToImpedance(step, t->getReferenceImpedance()).real();
} }
} }
break; break;
@ -246,7 +251,7 @@ QString YAxis::Unit(Type type, TraceModel::DataSource source)
case Type::Reactance: return "Ω"; case Type::Reactance: return "Ω";
case Type::Capacitance: return "F"; case Type::Capacitance: return "F";
case Type::Inductance: return "H"; case Type::Inductance: return "H";
case Type::Last: return ""; default: return "";
} }
} else if(source == TraceModel::DataSource::SA) { } else if(source == TraceModel::DataSource::SA) {
switch(type) { switch(type) {
@ -280,7 +285,7 @@ QString YAxis::Prefixes(Type type, TraceModel::DataSource source)
case Type::Reactance: return "m kM"; case Type::Reactance: return "m kM";
case Type::Capacitance: return "pnum "; case Type::Capacitance: return "pnum ";
case Type::Inductance: return "pnum "; case Type::Inductance: return "pnum ";
case Type::Last: return " "; default: return " ";
} }
} else if(source == TraceModel::DataSource::SA) { } else if(source == TraceModel::DataSource::SA) {
switch(type) { switch(type) {
@ -358,8 +363,14 @@ bool Axis::getLog() const
return log; return log;
} }
XAxis::XAxis()
{
type = Type::Frequency;
}
double XAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample) double XAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample)
{ {
Q_UNUSED(sample)
switch(type) { switch(type) {
case Type::Distance: case Type::Distance:
if(!t) { if(!t) {
@ -430,6 +441,16 @@ XAxis::Type XAxis::getType() const
return type; return type;
} }
Axis::Axis()
{
log = false;
autorange = true;
rangeMin = -1.0;
rangeMax = 1.0;
rangeDiv = 1.0;
ticks.clear();
}
double Axis::transform(double value, double to_low, double to_high) double Axis::transform(double value, double to_low, double to_high)
{ {
return Util::Scale(value, rangeMin, rangeMax, to_low, to_high, log); return Util::Scale(value, rangeMin, rangeMax, to_low, to_high, log);

View File

@ -8,6 +8,7 @@
class Axis { class Axis {
public: public:
Axis();
virtual double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) = 0; virtual double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) = 0;
double transform(double value, double to_low, double to_high); double transform(double value, double to_low, double to_high);
double inverseTransform(double value, double to_low, double to_high); double inverseTransform(double value, double to_low, double to_high);
@ -55,6 +56,7 @@ public:
Impedance, Impedance,
Last, Last,
}; };
YAxis();
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override; double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
void set(Type type, bool log, bool autorange, double min, double max, double div); void set(Type type, bool log, bool autorange, double min, double max, double div);
static QString TypeToName(Type type); static QString TypeToName(Type type);
@ -80,6 +82,7 @@ public:
Power, Power,
Last, Last,
}; };
XAxis();
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override; double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
void set(Type type, bool log, bool autorange, double min, double max, double div); void set(Type type, bool log, bool autorange, double min, double max, double div);
static QString TypeToName(Type type); static QString TypeToName(Type type);

View File

@ -22,6 +22,9 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
ui->name->setText(t.name()); ui->name->setText(t.name());
ui->color->setColor(trace.color()); ui->color->setColor(trace.color());
ui->vFactor->setValue(t.velocityFactor()); ui->vFactor->setValue(t.velocityFactor());
ui->impedance->setUnit("Ω");
ui->impedance->setPrecision(3);
ui->impedance->setValue(t.getReferenceImpedance());
connect(ui->bLive, &QPushButton::clicked, [=](bool live) { connect(ui->bLive, &QPushButton::clicked, [=](bool live) {
if(live) { if(live) {

View File

@ -9,8 +9,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1038</width> <width>931</width>
<height>365</height> <height>392</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -21,7 +21,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="0,1"> <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="0,1">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
@ -112,6 +112,24 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Reference impedance:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="impedance">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QStackedWidget" name="stack"> <widget class="QStackedWidget" name="stack">
<property name="currentIndex"> <property name="currentIndex">

View File

@ -207,7 +207,7 @@ void TraceModel::clearLiveData()
} }
} }
void TraceModel::addVNAData(const Protocol::Datapoint &d, TraceMath::DataType datatype) void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
{ {
source = DataSource::VNA; source = DataSource::VNA;
for(auto t : traces) { for(auto t : traces) {
@ -225,15 +225,15 @@ void TraceModel::addVNAData(const Protocol::Datapoint &d, TraceMath::DataType da
return; return;
} }
switch(t->liveParameter()) { switch(t->liveParameter()) {
case Trace::LiveParameter::S11: td.y = complex<double>(d.real_S11, d.imag_S11); break; case Trace::LiveParameter::S11: td.y = d.S.m11; break;
case Trace::LiveParameter::S12: td.y = complex<double>(d.real_S12, d.imag_S12); break; case Trace::LiveParameter::S12: td.y = d.S.m12; break;
case Trace::LiveParameter::S21: td.y = complex<double>(d.real_S21, d.imag_S21); break; case Trace::LiveParameter::S21: td.y = d.S.m21; break;
case Trace::LiveParameter::S22: td.y = complex<double>(d.real_S22, d.imag_S22); break; case Trace::LiveParameter::S22: td.y = d.S.m22; break;
default: default:
// not a VNA trace, skip // not a VNA trace, skip
continue; continue;
} }
t->addData(td, datatype); t->addData(td, datatype, d.reference_impedance);
} }
} }
} }

View File

@ -4,6 +4,7 @@
#include "Device/device.h" #include "Device/device.h"
#include "savable.h" #include "savable.h"
#include "trace.h" #include "trace.h"
#include "VNA/vnadata.h"
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <vector> #include <vector>
@ -64,7 +65,7 @@ signals:
public slots: public slots:
void clearLiveData(); void clearLiveData();
void addVNAData(const Protocol::Datapoint& d, TraceMath::DataType datatype); void addVNAData(const VNAData& d, TraceMath::DataType datatype);
void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings); void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings);
private: private:

View File

@ -460,6 +460,12 @@ void TracePlot::checkIfStillSupported(Trace *t)
if(!configureForTrace(t)) { if(!configureForTrace(t)) {
enableTrace(t, false); enableTrace(t, false);
} }
// remove non-supported traces after graph has been adjusted
for(auto t : activeTraces()) {
if(!supported(t)) {
enableTrace(t, false);
}
}
break; break;
} }

View File

@ -7,6 +7,7 @@
#include "QFileDialog" #include "QFileDialog"
#include "Util/util.h" #include "Util/util.h"
#include "appwindow.h" #include "appwindow.h"
#include "CustomWidgets/informationbox.h"
#include <QPainter> #include <QPainter>
#include <array> #include <array>
@ -20,7 +21,9 @@ TraceSmithChart::TraceSmithChart(TraceModel &model, QWidget *parent)
: TracePlot(model, parent) : TracePlot(model, parent)
{ {
limitToSpan = true; limitToSpan = true;
limitToEdge = true;
edgeReflection = 1.0; edgeReflection = 1.0;
Z0 = 50.0;
initializeTraceInfo(); initializeTraceInfo();
} }
@ -30,6 +33,7 @@ nlohmann::json TraceSmithChart::toJSON()
j["limit_to_span"] = limitToSpan; j["limit_to_span"] = limitToSpan;
j["limit_to_edge"] = limitToEdge; j["limit_to_edge"] = limitToEdge;
j["edge_reflection"] = edgeReflection; j["edge_reflection"] = edgeReflection;
j["Z0"] = Z0;
nlohmann::json jtraces; nlohmann::json jtraces;
for(auto t : traces) { for(auto t : traces) {
if(t.second) { if(t.second) {
@ -50,6 +54,7 @@ void TraceSmithChart::fromJSON(nlohmann::json j)
limitToSpan = j.value("limit_to_span", true); limitToSpan = j.value("limit_to_span", true);
limitToEdge = j.value("limit_to_edge", false); limitToEdge = j.value("limit_to_edge", false);
edgeReflection = j.value("edge_reflection", 1.0); edgeReflection = j.value("edge_reflection", 1.0);
Z0 = j.value("Z0", 50.0);
for(unsigned int hash : j["traces"]) { for(unsigned int hash : j["traces"]) {
// attempt to find the traces with this hash // attempt to find the traces with this hash
bool found = false; bool found = false;
@ -106,6 +111,10 @@ void TraceSmithChart::axisSetupDialog()
ui->zoomReflection->setValue(edgeReflection); ui->zoomReflection->setValue(edgeReflection);
ui->zoomFactor->setValue(1.0/edgeReflection); ui->zoomFactor->setValue(1.0/edgeReflection);
ui->impedance->setUnit("Ω");
ui->impedance->setPrecision(3);
ui->impedance->setValue(Z0);
auto model = new SmithChartContantLineModel(*this); auto model = new SmithChartContantLineModel(*this);
ui->lineTable->setModel(model); ui->lineTable->setModel(model);
ui->lineTable->setItemDelegateForColumn(SmithChartContantLineModel::ColIndexType, new SmithChartTypeDelegate); ui->lineTable->setItemDelegateForColumn(SmithChartContantLineModel::ColIndexType, new SmithChartTypeDelegate);
@ -124,6 +133,15 @@ void TraceSmithChart::axisSetupDialog()
edgeReflection = ui->zoomReflection->value(); edgeReflection = ui->zoomReflection->value();
ui->zoomFactor->setValueQuiet(1.0 / edgeReflection); ui->zoomFactor->setValueQuiet(1.0 / edgeReflection);
}); });
connect(ui->impedance, &SIUnitEdit::valueChanged, [=](){
Z0 = ui->impedance->value();
for(auto t : traces) {
if(t.second) {
checkIfStillSupported(t.first);
}
}
ui->impedance->setValueQuiet(Z0);
});
connect(ui->lineTable, &QTableView::clicked, [=](const QModelIndex &index){ connect(ui->lineTable, &QTableView::clicked, [=](const QModelIndex &index){
if(index.column() == SmithChartContantLineModel::ColIndexColor) { if(index.column() == SmithChartContantLineModel::ColIndexColor) {
auto line = &constantLines[index.row()]; auto line = &constantLines[index.row()];
@ -181,8 +199,7 @@ QPoint TraceSmithChart::dataToPixel(Trace::Data d)
if(d.x < sweep_fmin || d.x > sweep_fmax) { if(d.x < sweep_fmin || d.x > sweep_fmax) {
return QPoint(); return QPoint();
} }
return dataToPixel(d.y); return dataToPixel(d.y);}
}
std::complex<double> TraceSmithChart::pixelToData(QPoint p) std::complex<double> TraceSmithChart::pixelToData(QPoint p)
{ {
@ -264,6 +281,20 @@ bool TraceSmithChart::markerVisible(double x)
} }
} }
bool TraceSmithChart::configureForTrace(Trace *t)
{
if(dropSupported(t)) {
Z0 = t->getReferenceImpedance();
for(auto t : traces) {
if(t.second && t.first->getReferenceImpedance() != Z0) {
enableTrace(t.first, false);
}
}
return true;
}
return false;
}
void TraceSmithChart::draw(QPainter &p) { void TraceSmithChart::draw(QPainter &p) {
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
@ -305,7 +336,7 @@ void TraceSmithChart::draw(QPainter &p) {
p.drawLine(dataToPixel(complex<double>(edgeReflection,0)),dataToPixel(complex<double>(-edgeReflection,0))); p.drawLine(dataToPixel(complex<double>(edgeReflection,0)),dataToPixel(complex<double>(-edgeReflection,0)));
constexpr std::array<double, 5> impedanceLines = {10, 25, 50, 100, 250}; constexpr std::array<double, 5> impedanceLines = {10, 25, 50, 100, 250};
for(auto z : impedanceLines) { for(auto z : impedanceLines) {
z /= Preferences::getInstance().Acquisition.refImp; z /= Z0;
auto radius = 1.0/z; auto radius = 1.0/z;
drawArc(SmithChartArc(QPointF(1.0, radius), radius, 0, 2*M_PI)); drawArc(SmithChartArc(QPointF(1.0, radius), radius, 0, 2*M_PI));
drawArc(SmithChartArc(QPointF(1.0, -radius), radius, 0, 2*M_PI)); drawArc(SmithChartArc(QPointF(1.0, -radius), radius, 0, 2*M_PI));
@ -316,7 +347,7 @@ void TraceSmithChart::draw(QPainter &p) {
pen = QPen(line.getColor(), pref.Graphs.lineWidth); pen = QPen(line.getColor(), pref.Graphs.lineWidth);
pen.setCosmetic(true); pen.setCosmetic(true);
p.setPen(pen); p.setPen(pen);
for(auto arc : line.getArcs()) { for(auto arc : line.getArcs(Z0)) {
drawArc(arc); drawArc(arc);
} }
} }
@ -396,11 +427,40 @@ void TraceSmithChart::draw(QPainter &p) {
} }
} }
void TraceSmithChart::traceDropped(Trace *t, QPoint position)
{
if(!supported(t) && dropSupported(t)) {
// needs to switch to a different domain for the graph
if(!InformationBox::AskQuestion("Reference impedance change", "You dropped a trace that is not supported with the currently selected reference impedance."
" Do you want to remove all traces and change the graph to the correct reference imppedance?", true, "ReferenceImpedanceChangeRequest")) {
// user declined to change domain, to not add change impedance
return;
}
// attempt to configure for this trace
configureForTrace(t);
}
TracePlot::traceDropped(t, position);
}
bool TraceSmithChart::dropSupported(Trace *t)
{
if(!t->isReflection()) {
return false;
}
switch(t->outputType()) {
case Trace::DataType::Frequency:
case Trace::DataType::Power:
return true;
default:
return false;
}
}
QString TraceSmithChart::mouseText(QPoint pos) QString TraceSmithChart::mouseText(QPoint pos)
{ {
auto data = pixelToData(pos); auto data = pixelToData(pos);
if(abs(data) <= edgeReflection) { if(abs(data) <= edgeReflection) {
data = Preferences::getInstance().Acquisition.refImp * (1.0 + data) / (1.0 - data); data = Z0 * (1.0 + data) / (1.0 - data);
auto ret = Unit::ToString(data.real(), "", " ", 3); auto ret = Unit::ToString(data.real(), "", " ", 3);
if(data.imag() >= 0) { if(data.imag() >= 0) {
ret += "+"; ret += "+";
@ -477,16 +537,10 @@ void TraceSmithChart::updateContextMenu()
bool TraceSmithChart::supported(Trace *t) bool TraceSmithChart::supported(Trace *t)
{ {
if(!t->isReflection()) { if(t->getReferenceImpedance() != Z0) {
return false;
}
switch(t->outputType()) {
case Trace::DataType::Frequency:
case Trace::DataType::Power:
return true;
default:
return false; return false;
} }
return dropSupported(t);
} }
SmithChartArc::SmithChartArc(QPointF center, double radius, double startAngle, double spanAngle) SmithChartArc::SmithChartArc(QPointF center, double radius, double startAngle, double spanAngle)
@ -570,9 +624,8 @@ SmithChartConstantLine::SmithChartConstantLine()
color = Qt::darkRed; color = Qt::darkRed;
} }
std::vector<SmithChartArc> SmithChartConstantLine::getArcs() std::vector<SmithChartArc> SmithChartConstantLine::getArcs(double Z0)
{ {
double Z0 = Preferences::getInstance().Acquisition.refImp;
std::vector<SmithChartArc> arcs; std::vector<SmithChartArc> arcs;
switch(type) { switch(type) {
case Type::VSWR: case Type::VSWR:

View File

@ -33,7 +33,7 @@ public:
}; };
SmithChartConstantLine(); SmithChartConstantLine();
std::vector<SmithChartArc> getArcs(); std::vector<SmithChartArc> getArcs(double Z0);
QColor getColor() const; QColor getColor() const;
void setColor(const QColor &value); void setColor(const QColor &value);
@ -126,13 +126,17 @@ protected:
virtual bool markerVisible(double x); virtual bool markerVisible(double x);
//void paintEvent(QPaintEvent *event) override; //void paintEvent(QPaintEvent *event) override;
virtual bool configureForTrace(Trace *t);
virtual void updateContextMenu() override; virtual void updateContextMenu() override;
bool supported(Trace *t) override; bool supported(Trace *t) override;
virtual void draw(QPainter& painter) override; virtual void draw(QPainter& painter) override;
virtual void traceDropped(Trace *t, QPoint position) override;
virtual bool dropSupported(Trace *t) override;
QString mouseText(QPoint pos) override; QString mouseText(QPoint pos) override;
bool limitToSpan; bool limitToSpan;
bool limitToEdge; bool limitToEdge;
double edgeReflection; // magnitude of reflection coefficient at the edge of the smith chart (zoom factor) double edgeReflection; // magnitude of reflection coefficient at the edge of the smith chart (zoom factor)
double Z0;
QTransform transform; QTransform transform;
std::vector<SmithChartConstantLine> constantLines; std::vector<SmithChartConstantLine> constantLines;
}; };

View File

@ -68,6 +68,7 @@ void TraceTouchstoneExport::on_buttonBox_accepted()
if(filename.length() > 0) { if(filename.length() > 0) {
auto ports = ui->sbPorts->value(); auto ports = ui->sbPorts->value();
auto t = Touchstone(ports); auto t = Touchstone(ports);
t.setReferenceImpedance(referenceImpedance);
// add trace points to touchstone // add trace points to touchstone
for(unsigned int s=0;s<points;s++) { for(unsigned int s=0;s<points;s++) {
Touchstone::Datapoint tData; Touchstone::Datapoint tData;
@ -165,6 +166,7 @@ void TraceTouchstoneExport::selectionChanged(QComboBox *w)
// the first trace has been selected, extract frequency info // the first trace has been selected, extract frequency info
Trace *t = qvariant_cast<Trace*>(w->itemData(w->currentIndex())); Trace *t = qvariant_cast<Trace*>(w->itemData(w->currentIndex()));
points = t->size(); points = t->size();
referenceImpedance = t->getReferenceImpedance();
ui->points->setText(QString::number(points)); ui->points->setText(QString::number(points));
if(points > 0) { if(points > 0) {
lowerFreq = t->minX(); lowerFreq = t->minX();
@ -179,7 +181,7 @@ void TraceTouchstoneExport::selectionChanged(QComboBox *w)
for(auto c : v1) { for(auto c : v1) {
for(int i=1;i<c->count();i++) { for(int i=1;i<c->count();i++) {
Trace *t = qvariant_cast<Trace*>(c->itemData(i)); Trace *t = qvariant_cast<Trace*>(c->itemData(i));
if(t->size() != points || (points > 0 && (t->minX() != lowerFreq || t->maxX() != upperFreq))) { if(t->getReferenceImpedance() != referenceImpedance || t->size() != points || (points > 0 && (t->minX() != lowerFreq || t->maxX() != upperFreq))) {
// this trace is not available anymore // this trace is not available anymore
c->removeItem(i); c->removeItem(i);
// decrement to check the next index in the next loop iteration // decrement to check the next index in the next loop iteration

View File

@ -34,6 +34,7 @@ private:
unsigned int ports; unsigned int ports;
unsigned int points; unsigned int points;
double lowerFreq, upperFreq; double lowerFreq, upperFreq;
double referenceImpedance;
bool freqsSet; bool freqsSet;
}; };

View File

@ -21,6 +21,11 @@ TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent)
keepDataBeyondPlotSize(false), keepDataBeyondPlotSize(false),
maxDataSweeps(500) maxDataSweeps(500)
{ {
plotAreaTop = 0;
plotAreaLeft = 0;
plotAreaWidth = 0;
plotAreaBottom = 0;
xAxis.set(XAxis::Type::Frequency, false, true, 0, 6000000000, 500000000); xAxis.set(XAxis::Type::Frequency, false, true, 0, 6000000000, 500000000);
yAxis.set(YAxis::Type::Magnitude, false, true, -1, 1, 1); yAxis.set(YAxis::Type::Magnitude, false, true, -1, 1, 1);
initializeTraceInfo(); initializeTraceInfo();
@ -478,7 +483,7 @@ double TraceWaterfall::nearestTracePoint(Trace *t, QPoint pixel, double *distanc
QString TraceWaterfall::mouseText(QPoint pos) QString TraceWaterfall::mouseText(QPoint pos)
{ {
QString ret; QString ret;
if(QRect(plotAreaLeft, 0, plotAreaWidth + 1, plotAreaBottom).contains(pos)) { if(QRect(plotAreaLeft, plotAreaTop, plotAreaWidth + 1, plotAreaBottom).contains(pos)) {
double x = xAxis.inverseTransform(pos.x(), plotAreaLeft, plotAreaLeft + plotAreaWidth); double x = xAxis.inverseTransform(pos.x(), plotAreaLeft, plotAreaLeft + plotAreaWidth);
int significantDigits = floor(log10(abs(xAxis.getRangeMax()))) - floor(log10((abs(xAxis.getRangeMax() - xAxis.getRangeMin())) / 1000.0)) + 1; int significantDigits = floor(log10(abs(xAxis.getRangeMax()))) - floor(log10((abs(xAxis.getRangeMax() - xAxis.getRangeMin())) / 1000.0)) + 1;
ret += Unit::ToString(x, xAxis.Unit(), "fpnum kMG", significantDigits) + "\n"; ret += Unit::ToString(x, xAxis.Unit(), "fpnum kMG", significantDigits) + "\n";

View File

@ -62,13 +62,13 @@ double Util::distanceToLine(QPointF point, QPointF l1, QPointF l2, QPointF *clos
return orthVect.length(); return orthVect.length();
} }
std::complex<double> Util::SparamToImpedance(std::complex<double> d) { std::complex<double> Util::SparamToImpedance(std::complex<double> d, std::complex<double> Z0) {
return Preferences::getInstance().Acquisition.refImp * (1.0 + d) / (1.0 - d); return Z0 * (1.0 + d) / (1.0 - d);
} }
double Util::dBmTodBuV(double dBm) double Util::dBmTodBuV(double dBm)
{ {
double uVpower = 0.000001*0.000001/Preferences::getInstance().Acquisition.refImp; double uVpower = 0.000001*0.000001/50.0;
double dBdiff = 10*log10(uVpower*1000); double dBdiff = 10*log10(uVpower*1000);
return dBm - dBdiff; return dBm - dBdiff;
} }

View File

@ -45,16 +45,16 @@ namespace Util {
static inline double SparamToVSWR(std::complex<double> d) { static inline double SparamToVSWR(std::complex<double> d) {
return SparamToVSWR(abs(d)); return SparamToVSWR(abs(d));
} }
std::complex<double> SparamToImpedance(std::complex<double> d); std::complex<double> SparamToImpedance(std::complex<double> d, std::complex<double> Z0 = 50.0);
// all these conversions assume series connection of real and imag part // all these conversions assume series connection of real and imag part
static inline double SparamToResistance(std::complex<double> d) { static inline double SparamToResistance(std::complex<double> d, std::complex<double> Z0 = 50.0) {
return SparamToImpedance(d).real(); return SparamToImpedance(d, Z0).real();
} }
static inline double SparamToCapacitance(std::complex<double> d, double freq) { static inline double SparamToCapacitance(std::complex<double> d, double freq, std::complex<double> Z0 = 50.0) {
return -1.0 / (SparamToImpedance(d).imag() * 2.0 * M_PI * freq); return -1.0 / (SparamToImpedance(d, Z0).imag() * 2.0 * M_PI * freq);
} }
static inline double SparamToInductance(std::complex<double> d, double freq) { static inline double SparamToInductance(std::complex<double> d, double freq, std::complex<double> Z0 = 50.0) {
return SparamToImpedance(d).imag() / (2.0 * M_PI * freq); return SparamToImpedance(d, Z0).imag() / (2.0 * M_PI * freq);
} }
static inline double SparamToQualityFactor(std::complex<double> d) { static inline double SparamToQualityFactor(std::complex<double> d) {
return abs(d.imag()) / d.real(); return abs(d.imag()) / d.real();

View File

@ -120,7 +120,7 @@ Deembedding::Deembedding(TraceModel &tm)
} }
void Deembedding::Deembed(Protocol::Datapoint &d) void Deembedding::Deembed(VNAData &d)
{ {
// figure out the point in one sweep based on the incomig pointNums // figure out the point in one sweep based on the incomig pointNums
static unsigned lastPointNum; static unsigned lastPointNum;

View File

@ -19,7 +19,7 @@ public:
Deembedding(TraceModel &tm); Deembedding(TraceModel &tm);
~Deembedding(){}; ~Deembedding(){};
void Deembed(Protocol::Datapoint &d); void Deembed(VNAData &d);
void Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22); void Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
void removeOption(unsigned int index); void removeOption(unsigned int index);
@ -42,7 +42,7 @@ private:
TraceModel &tm; TraceModel &tm;
bool measuring; bool measuring;
std::vector<Protocol::Datapoint> measurements; std::vector<VNAData> measurements;
QDialog *measurementDialog; QDialog *measurementDialog;
Ui_DeembeddingMeasurementDialog *measurementUI; Ui_DeembeddingMeasurementDialog *measurementUI;

View File

@ -3,6 +3,7 @@
#include "portextension.h" #include "portextension.h"
#include "twothru.h" #include "twothru.h"
#include "matchingnetwork.h" #include "matchingnetwork.h"
#include "impedancerenormalization.h"
DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type) DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type)
{ {
@ -13,6 +14,8 @@ DeembeddingOption *DeembeddingOption::create(DeembeddingOption::Type type)
return new TwoThru(); return new TwoThru();
case Type::MatchingNetwork: case Type::MatchingNetwork:
return new MatchingNetwork(); return new MatchingNetwork();
case Type::ImpedanceRenormalization:
return new ImpedanceRenormalization();
default: default:
return nullptr; return nullptr;
} }
@ -27,6 +30,8 @@ QString DeembeddingOption::getName(DeembeddingOption::Type type)
return "2xThru"; return "2xThru";
case Type::MatchingNetwork: case Type::MatchingNetwork:
return "Matching Network"; return "Matching Network";
case Type::ImpedanceRenormalization:
return "Impedance Renormalization";
default: default:
return ""; return "";
} }

View File

@ -3,6 +3,7 @@
#include "savable.h" #include "savable.h"
#include "Device/device.h" #include "Device/device.h"
#include "Traces/tracemodel.h"
#include <QWidget> #include <QWidget>
@ -14,6 +15,7 @@ public:
PortExtension, PortExtension,
TwoThru, TwoThru,
MatchingNetwork, MatchingNetwork,
ImpedanceRenormalization,
// Add new deembedding options here, do not explicitly assign values and keep the Last entry at the last position // Add new deembedding options here, do not explicitly assign values and keep the Last entry at the last position
Last, Last,
}; };
@ -21,12 +23,12 @@ public:
static DeembeddingOption *create(Type type); static DeembeddingOption *create(Type type);
static QString getName(Type type); static QString getName(Type type);
virtual void transformDatapoint(Protocol::Datapoint &p) = 0; virtual void transformDatapoint(VNAData &p) = 0;
virtual void edit(){}; virtual void edit(){};
virtual Type getType() = 0; virtual Type getType() = 0;
public slots: public slots:
virtual void measurementCompleted(std::vector<Protocol::Datapoint> m){Q_UNUSED(m)}; virtual void measurementCompleted(std::vector<VNAData> m){Q_UNUSED(m)};
signals: signals:
// Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself // Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself
void deleted(DeembeddingOption *option); void deleted(DeembeddingOption *option);

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImpedanceRenormalizationDialog</class>
<widget class="QDialog" name="ImpedanceRenormalizationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>241</width>
<height>76</height>
</rect>
</property>
<property name="windowTitle">
<string>S parameter renormalization</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Normalize to:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="impedance"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ImpedanceRenormalizationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ImpedanceRenormalizationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,57 @@
#include "impedancerenormalization.h"
#include "ui_impedancenormalizationdialog.h"
#include "Tools/parameters.h"
#include "appwindow.h"
#include <complex>
using namespace std;
ImpedanceRenormalization::ImpedanceRenormalization()
: DeembeddingOption(),
impedance(50.0)
{
}
void ImpedanceRenormalization::transformDatapoint(VNAData &p)
{
p.S = Sparam(ABCDparam(p.S, p.reference_impedance), impedance);
p.reference_impedance = impedance;
}
nlohmann::json ImpedanceRenormalization::toJSON()
{
nlohmann::json j;
j["impedance"] = impedance;
return j;
}
void ImpedanceRenormalization::fromJSON(nlohmann::json j)
{
impedance = j.value("impedance", impedance);
}
void ImpedanceRenormalization::edit()
{
auto dialog = new QDialog();
ui = new Ui::ImpedanceRenormalizationDialog();
ui->setupUi(dialog);
connect(dialog, &QDialog::finished, [=](){
delete ui;
});
// set initial values
ui->impedance->setUnit("Ω");
ui->impedance->setPrecision(3);
ui->impedance->setValue(impedance);
connect(ui->impedance, &SIUnitEdit::valueChanged, [&](double newval){
impedance = newval;
});
if(AppWindow::showGUI()) {
dialog->show();
}
}

View File

@ -0,0 +1,29 @@
#ifndef IMPEDANCERENORMALIZATION_H
#define IMPEDANCERENORMALIZATION_H
#include "deembeddingoption.h"
namespace Ui {
class ImpedanceRenormalizationDialog;
}
class ImpedanceRenormalization : public DeembeddingOption
{
Q_OBJECT
public:
ImpedanceRenormalization();
void transformDatapoint(VNAData &p) override;
Type getType() override { return Type::ImpedanceRenormalization;}
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
public slots:
virtual void edit() override;
private:
double impedance;
Ui::ImpedanceRenormalizationDialog *ui;
};
#endif // IMPEDANCERENORMALIZATION_H

View File

@ -26,13 +26,10 @@ MatchingNetwork::MatchingNetwork()
addNetwork = true; addNetwork = true;
} }
void MatchingNetwork::transformDatapoint(Protocol::Datapoint &p) void MatchingNetwork::transformDatapoint(VNAData &p)
{ {
auto S = Sparam(complex<double>(p.real_S11, p.imag_S11), auto S = p.S;
complex<double>(p.real_S12, p.imag_S12), auto measurement = ABCDparam(S, p.reference_impedance);
complex<double>(p.real_S21, p.imag_S21),
complex<double>(p.real_S22, p.imag_S22));
auto measurement = ABCDparam(S, Preferences::getInstance().Acquisition.refImp);
if(matching.count(p.frequency) == 0) { if(matching.count(p.frequency) == 0) {
// this point is not calculated yet // this point is not calculated yet
MatchingPoint m; MatchingPoint m;
@ -56,15 +53,7 @@ void MatchingNetwork::transformDatapoint(Protocol::Datapoint &p)
// at this point the map contains the matching network effect // at this point the map contains the matching network effect
auto m = matching[p.frequency]; auto m = matching[p.frequency];
auto corrected = m.p1 * measurement * m.p2; auto corrected = m.p1 * measurement * m.p2;
S = Sparam(corrected, Preferences::getInstance().Acquisition.refImp); p.S = Sparam(corrected, p.reference_impedance);
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() void MatchingNetwork::edit()
@ -541,7 +530,7 @@ ABCDparam MatchingComponent::parameters(double freq)
} else { } else {
auto d = touchstone->interpolate(freq); auto d = touchstone->interpolate(freq);
auto S = Sparam(d.S[0], d.S[1], d.S[2], d.S[3]); auto S = Sparam(d.S[0], d.S[1], d.S[2], d.S[3]);
return ABCDparam(S, Preferences::getInstance().Acquisition.refImp); return ABCDparam(S, 50.0);
} }
default: default:
return ABCDparam(1.0, 0.0, 0.0, 1.0); return ABCDparam(1.0, 0.0, 0.0, 1.0);

View File

@ -64,9 +64,9 @@ public:
// DeembeddingOption interface // DeembeddingOption interface
public: public:
void transformDatapoint(Protocol::Datapoint &p) override; void transformDatapoint(VNAData &p) override;
void edit() override; void edit() override;
Type getType() override {return Type::MatchingNetwork;}; Type getType() override {return Type::MatchingNetwork;}
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override; void fromJSON(nlohmann::json j) override;
private: private:

View File

@ -29,15 +29,9 @@ PortExtension::PortExtension()
kit = nullptr; kit = nullptr;
} }
void PortExtension::transformDatapoint(Protocol::Datapoint &d) void PortExtension::transformDatapoint(VNAData &d)
{ {
if(port1.enabled || port2.enabled) { if(port1.enabled || port2.enabled) {
// Convert measurements to complex variables
auto S11 = complex<double>(d.real_S11, d.imag_S11);
auto S21 = complex<double>(d.real_S21, d.imag_S21);
auto S22 = complex<double>(d.real_S22, d.imag_S22);
auto S12 = complex<double>(d.real_S12, d.imag_S12);
if(port1.enabled) { if(port1.enabled) {
auto phase = -2 * M_PI * port1.delay * d.frequency; auto phase = -2 * M_PI * port1.delay * d.frequency;
auto db_attennuation = port1.DCloss; auto db_attennuation = port1.DCloss;
@ -47,9 +41,9 @@ void PortExtension::transformDatapoint(Protocol::Datapoint &d)
// convert from db to factor // convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0); auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase); auto correction = polar<double>(att, phase);
S11 /= correction * correction; d.S.m11 /= correction * correction;
S21 /= correction; d.S.m21 /= correction;
S12 /= correction; d.S.m12 /= correction;
} }
if(port2.enabled) { if(port2.enabled) {
auto phase = -2 * M_PI * port2.delay * d.frequency; auto phase = -2 * M_PI * port2.delay * d.frequency;
@ -60,18 +54,10 @@ void PortExtension::transformDatapoint(Protocol::Datapoint &d)
// convert from db to factor // convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0); auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase); auto correction = polar<double>(att, phase);
S22 /= correction * correction; d.S.m22 /= correction * correction;
S21 /= correction; d.S.m21 /= correction;
S12 /= correction; d.S.m12 /= correction;
} }
d.real_S11 = S11.real();
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
} }
} }
@ -208,7 +194,7 @@ void PortExtension::edit()
} }
} }
void PortExtension::measurementCompleted(std::vector<Protocol::Datapoint> m) void PortExtension::measurementCompleted(std::vector<VNAData> m)
{ {
if(m.size() > 0) { if(m.size() > 0) {
double last_phase = 0.0; double last_phase = 0.0;
@ -219,9 +205,9 @@ void PortExtension::measurementCompleted(std::vector<Protocol::Datapoint> m)
// grab correct measurement // grab correct measurement
complex<double> reflection; complex<double> reflection;
if(isPort1) { if(isPort1) {
reflection = complex<double>(p.real_S11, p.imag_S11); reflection = p.S.m11;
} else { } else {
reflection = complex<double>(p.real_S22, p.imag_S22); reflection = p.S.m22;
} }
// remove calkit if specified // remove calkit if specified
if(!isIdeal) { if(!isIdeal) {

View File

@ -18,14 +18,14 @@ class PortExtension : public DeembeddingOption
Q_OBJECT Q_OBJECT
public: public:
PortExtension(); PortExtension();
void transformDatapoint(Protocol::Datapoint& d) override; void transformDatapoint(VNAData& d) override;
void setCalkit(Calkit *kit); void setCalkit(Calkit *kit);
Type getType() override {return Type::PortExtension;} Type getType() override {return Type::PortExtension;}
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override; void fromJSON(nlohmann::json j) override;
public slots: public slots:
void edit() override; void edit() override;
void measurementCompleted(std::vector<Protocol::Datapoint> m) override; void measurementCompleted(std::vector<VNAData> m) override;
private: private:
void startMeasurement(); void startMeasurement();

View File

@ -12,19 +12,14 @@ using namespace std;
TwoThru::TwoThru() TwoThru::TwoThru()
{ {
Z0 = Preferences::getInstance().Acquisition.refImp; Z0 = 50.0;
} }
void TwoThru::transformDatapoint(Protocol::Datapoint &p) void TwoThru::transformDatapoint(VNAData &p)
{ {
// correct measurement // correct measurement
if(points.size() > 0) { if(points.size() > 0) {
auto S11 = complex<double>(p.real_S11, p.imag_S11); Tparam meas(p.S);
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);
Tparam inv1, inv2; Tparam inv1, inv2;
if(p.frequency < points.front().freq) { if(p.frequency < points.front().freq) {
@ -54,15 +49,7 @@ void TwoThru::transformDatapoint(Protocol::Datapoint &p)
// perform correction // perform correction
Tparam corrected = inv1*meas*inv2; Tparam corrected = inv1*meas*inv2;
// transform back into S parameters // transform back into S parameters
S = Sparam(corrected); p.S = Sparam(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);
} }
} }
@ -112,7 +99,7 @@ void TwoThru::updateGUI()
} }
} }
void TwoThru::measurementCompleted(std::vector<Protocol::Datapoint> m) void TwoThru::measurementCompleted(std::vector<VNAData> m)
{ {
if (measuring2xthru) { if (measuring2xthru) {
measurements2xthru = m; measurements2xthru = m;
@ -223,7 +210,7 @@ void TwoThru::fromJSON(nlohmann::json j)
} }
} }
std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::Datapoint> data_2xthru) std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> data_2xthru)
{ {
// calculate error boxes, see https://www.freelists.org/post/si-list/IEEE-P370-Opensource-Deembedding-MATLAB-functions // calculate error boxes, see https://www.freelists.org/post/si-list/IEEE-P370-Opensource-Deembedding-MATLAB-functions
// create vectors of S parameters // create vectors of S parameters
@ -242,10 +229,10 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::D
// ignore possible DC point // ignore possible DC point
continue; continue;
} }
S11.push_back(complex<double>(m.real_S11, m.imag_S11)); S11.push_back(m.S.m11);
S12.push_back(complex<double>(m.real_S12, m.imag_S12)); S12.push_back(m.S.m12);
S21.push_back(complex<double>(m.real_S21, m.imag_S21)); S21.push_back(m.S.m21);
S22.push_back(complex<double>(m.real_S22, m.imag_S22)); S22.push_back(m.S.m22);
f.push_back(m.frequency); f.push_back(m.frequency);
} }
auto n = f.size(); auto n = f.size();
@ -403,7 +390,7 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::D
return ret; return ret;
} }
std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::Datapoint> data_2xthru, std::vector<Protocol::Datapoint> data_fix_dut_fix, double z0) std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> data_2xthru, std::vector<VNAData> data_fix_dut_fix, double z0)
{ {
vector<Point> ret; vector<Point> ret;
@ -427,19 +414,13 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::D
vector<Sparam> p; vector<Sparam> p;
vector<double> f; vector<double> f;
for(auto d : data_2xthru) { for(auto d : data_2xthru) {
p.push_back(Sparam(complex<double>(d.real_S11, d.imag_S11), p.push_back(d.S);
complex<double>(d.real_S12, d.imag_S12),
complex<double>(d.real_S21, d.imag_S21),
complex<double>(d.real_S22, d.imag_S22)));
f.push_back(d.frequency); f.push_back(d.frequency);
} }
auto data_2xthru_Sparam = p; auto data_2xthru_Sparam = p;
vector<Sparam> data_fix_dut_fix_Sparam; vector<Sparam> data_fix_dut_fix_Sparam;
for(auto d : data_fix_dut_fix) { for(auto d : data_fix_dut_fix) {
data_fix_dut_fix_Sparam.push_back(Sparam(complex<double>(d.real_S11, d.imag_S11), data_fix_dut_fix_Sparam.push_back(d.S);
complex<double>(d.real_S12, d.imag_S12),
complex<double>(d.real_S21, d.imag_S21),
complex<double>(d.real_S22, d.imag_S22)));
} }
// grabbing S21 // grabbing S21
@ -682,9 +663,9 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<Protocol::D
return ret; return ret;
} }
std::vector<Protocol::Datapoint> TwoThru::interpolateEvenFrequencySteps(std::vector<Protocol::Datapoint> input) std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData> input)
{ {
vector<Protocol::Datapoint> ret; vector<VNAData> ret;
if(input.size() > 1) { if(input.size() > 1) {
int size = input.size(); int size = input.size();
double freqStep = 0.0; double freqStep = 0.0;
@ -706,8 +687,8 @@ std::vector<Protocol::Datapoint> TwoThru::interpolateEvenFrequencySteps(std::vec
// needs to interpolate // needs to interpolate
double freq = freqStep; double freq = freqStep;
while(freq <= input.back().frequency) { while(freq <= input.back().frequency) {
Protocol::Datapoint interp; VNAData interp;
auto it = lower_bound(input.begin(), input.end(), freq, [](const Protocol::Datapoint &lhs, const double f) -> bool { auto it = lower_bound(input.begin(), input.end(), freq, [](const VNAData &lhs, const double f) -> bool {
return lhs.frequency < f; return lhs.frequency < f;
}); });
if(it->frequency == freq) { if(it->frequency == freq) {
@ -718,15 +699,14 @@ std::vector<Protocol::Datapoint> TwoThru::interpolateEvenFrequencySteps(std::vec
it--; it--;
auto low = *it; auto low = *it;
double alpha = (freq - low.frequency) / (high.frequency - low.frequency); double alpha = (freq - low.frequency) / (high.frequency - low.frequency);
interp.real_S11 = low.real_S11 * (1.0 - alpha) + high.real_S11 * alpha; interp.S.m11 = low.S.m11 * (1.0 - alpha) + high.S.m11 * alpha;
interp.imag_S11 = low.imag_S11 * (1.0 - alpha) + high.imag_S11 * alpha; interp.S.m12 = low.S.m12 * (1.0 - alpha) + high.S.m12 * alpha;
interp.real_S12 = low.real_S12 * (1.0 - alpha) + high.real_S12 * alpha; interp.S.m21 = low.S.m21 * (1.0 - alpha) + high.S.m21 * alpha;
interp.imag_S12 = low.imag_S12 * (1.0 - alpha) + high.imag_S12 * alpha; interp.S.m22 = low.S.m22 * (1.0 - alpha) + high.S.m22 * alpha;
interp.real_S21 = low.real_S21 * (1.0 - alpha) + high.real_S21 * alpha; interp.cdbm = low.cdbm * (1.0 - alpha) + high.cdbm * alpha;
interp.imag_S21 = low.imag_S21 * (1.0 - alpha) + high.imag_S21 * alpha; interp.reference_impedance = low.reference_impedance * (1.0 - alpha) + high.reference_impedance * alpha;
interp.real_S22 = low.real_S22 * (1.0 - alpha) + high.real_S22 * alpha;
interp.imag_S22 = low.imag_S22 * (1.0 - alpha) + high.imag_S22 * alpha;
} }
interp.pointNum = it->pointNum;
interp.frequency = freq; interp.frequency = freq;
ret.push_back(interp); ret.push_back(interp);
freq += freqStep; freq += freqStep;

View File

@ -16,7 +16,7 @@ class TwoThru : public DeembeddingOption
public: public:
TwoThru(); TwoThru();
virtual void transformDatapoint(Protocol::Datapoint &p) override; virtual void transformDatapoint(VNAData& p) override;
virtual void edit() override; virtual void edit() override;
virtual Type getType() override {return DeembeddingOption::Type::TwoThru;} virtual Type getType() override {return DeembeddingOption::Type::TwoThru;}
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
@ -25,19 +25,19 @@ public:
private slots: private slots:
void startMeasurement(); void startMeasurement();
void updateGUI(); void updateGUI();
void measurementCompleted(std::vector<Protocol::Datapoint> m) override; void measurementCompleted(std::vector<VNAData> m) override;
private: private:
using Point = struct { using Point = struct {
double freq; double freq;
Tparam inverseP1, inverseP2; Tparam inverseP1, inverseP2;
}; };
static std::vector<Protocol::Datapoint> interpolateEvenFrequencySteps(std::vector<Protocol::Datapoint> input); static std::vector<VNAData> interpolateEvenFrequencySteps(std::vector<VNAData> input);
static std::vector<Point> calculateErrorBoxes(std::vector<Protocol::Datapoint> data_2xthru); static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru);
static std::vector<Point> calculateErrorBoxes(std::vector<Protocol::Datapoint> data_2xthru, std::vector<Protocol::Datapoint> data_fix_dut_fix, double z0); static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru, std::vector<VNAData> data_fix_dut_fix, double z0);
std::vector<Protocol::Datapoint> measurements2xthru; std::vector<VNAData> measurements2xthru;
std::vector<Protocol::Datapoint> measurementsDUT; std::vector<VNAData> measurementsDUT;
double Z0; double Z0;
std::vector<Point> points; std::vector<Point> points;
bool measuring2xthru; bool measuring2xthru;

View File

@ -21,6 +21,7 @@
#include "Deembedding/manualdeembeddingdialog.h" #include "Deembedding/manualdeembeddingdialog.h"
#include "Calibration/manualcalibrationdialog.h" #include "Calibration/manualcalibrationdialog.h"
#include "Util/util.h" #include "Util/util.h"
#include "Tools/parameters.h"
#include <QGridLayout> #include <QGridLayout>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -757,7 +758,7 @@ void VNA::fromJSON(nlohmann::json j)
EnableDeembedding(false); EnableDeembedding(false);
} }
// sweep configuration has to go last sog graphs can catch events from changed sweep // sweep configuration has to go last so graphs can catch events from changed sweep
if(j.contains("sweep")) { if(j.contains("sweep")) {
auto sweep = j["sweep"]; auto sweep = j["sweep"];
// restore sweep settings, keep current value as default in case of missing entry // restore sweep settings, keep current value as default in case of missing entry
@ -812,28 +813,30 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
return; return;
} }
d = average.process(d); auto vd = VNAData(d);
vd = average.process(vd);
if(calMeasuring) { if(calMeasuring) {
if(average.currentSweep() == averages) { if(average.currentSweep() == averages) {
// this is the last averaging sweep, use values for calibration // this is the last averaging sweep, use values for calibration
if(!calWaitFirst || d.pointNum == 0) { if(!calWaitFirst || vd.pointNum == 0) {
calWaitFirst = false; calWaitFirst = false;
cal.addMeasurements(calMeasurements, d); cal.addMeasurements(calMeasurements, vd);
if(d.pointNum == settings.npoints - 1) { if(vd.pointNum == settings.npoints - 1) {
calMeasuring = false; calMeasuring = false;
emit CalibrationMeasurementsComplete(calMeasurements); emit CalibrationMeasurementsComplete(calMeasurements);
} }
} }
} }
int percentage = (((average.currentSweep() - 1) * 100) + (d.pointNum + 1) * 100 / settings.npoints) / averages; int percentage = (((average.currentSweep() - 1) * 100) + (vd.pointNum + 1) * 100 / settings.npoints) / averages;
calDialog.setValue(percentage); calDialog.setValue(percentage);
} }
if(calValid) { if(calValid) {
cal.correctMeasurement(d); cal.correctMeasurement(vd);
} }
if(deembedding_active) { if(deembedding_active) {
deembedding.Deembed(d); deembedding.Deembed(vd);
} }
TraceMath::DataType type; TraceMath::DataType type;
@ -847,17 +850,17 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
break; break;
} }
traceModel.addVNAData(d, type); traceModel.addVNAData(vd, type);
emit dataChanged(); emit dataChanged();
if(d.pointNum == settings.npoints - 1) { if(vd.pointNum == settings.npoints - 1) {
UpdateAverageCount(); UpdateAverageCount();
markerModel->updateMarkers(); markerModel->updateMarkers();
} }
static unsigned int lastPoint = 0; static unsigned int lastPoint = 0;
if(d.pointNum > 0 && d.pointNum != lastPoint + 1) { if(vd.pointNum > 0 && vd.pointNum != lastPoint + 1) {
qWarning() << "Got point" << d.pointNum << "but last received point was" << lastPoint << "("<<(d.pointNum-lastPoint-1)<<"missed points)"; qWarning() << "Got point" << vd.pointNum << "but last received point was" << lastPoint << "("<<(vd.pointNum-lastPoint-1)<<"missed points)";
} }
lastPoint = d.pointNum; lastPoint = vd.pointNum;
if (needsSegmentUpdate) { if (needsSegmentUpdate) {
changingSettings = true; changingSettings = true;
@ -882,7 +885,7 @@ void VNA::SettingsChanged(bool resetTraces, std::function<void (Device::Transmis
} }
changingSettings = true; changingSettings = true;
// assemble VNA protocol settings // assemble VNA protocol settings
Protocol::SweepSettings s; Protocol::SweepSettings s = {};
s.suppressPeaks = Preferences::getInstance().Acquisition.suppressPeaks ? 1 : 0; s.suppressPeaks = Preferences::getInstance().Acquisition.suppressPeaks ? 1 : 0;
if(Preferences::getInstance().Acquisition.alwaysExciteBothPorts) { if(Preferences::getInstance().Acquisition.alwaysExciteBothPorts) {
s.excitePort1 = 1; s.excitePort1 = 1;
@ -1102,7 +1105,7 @@ void VNA::SetPowerSweepFrequency(double freq)
void VNA::SetPoints(unsigned int points) void VNA::SetPoints(unsigned int points)
{ {
auto maxPoints = Preferences::getInstance().Acquisition.allowSegmentedSweep ? UINT16_MAX : Device::Info().limits_maxPoints; unsigned int maxPoints = Preferences::getInstance().Acquisition.allowSegmentedSweep ? UINT16_MAX : Device::Info().limits_maxPoints;
if(points > maxPoints) { if(points > maxPoints) {
points = maxPoints; points = maxPoints;
} else if (points < 2) { } else if (points < 2) {
@ -1176,7 +1179,7 @@ void VNA::ApplyCalibration(Calibration::Type type)
} else { } else {
DisableCalibration(true); DisableCalibration(true);
} }
} catch (runtime_error e) { } catch (runtime_error &e) {
InformationBox::ShowError("Calibration failure", e.what()); InformationBox::ShowError("Calibration failure", e.what());
DisableCalibration(true); DisableCalibration(true);
} }
@ -1196,8 +1199,7 @@ void VNA::ApplyCalibration(Calibration::Type type)
void VNA::StartCalibrationMeasurements(std::set<Calibration::Measurement> m) void VNA::StartCalibrationMeasurements(std::set<Calibration::Measurement> m)
{ {
auto device = window->getDevice(); if(!window->getDevice()) {
if(!device) {
return; return;
} }
// Stop sweep // Stop sweep

View File

@ -42,6 +42,12 @@ public:
class Settings { class Settings {
public: public:
Settings()
: sweepType(SweepType::Frequency)
, Freq({.start=1000000, .stop=6000000000, .excitation_power=-10, .logSweep=false})
, Power({.start=-40, .stop=-10, .frequency=1000000000})
, npoints(501), bandwidth(1000), excitingPort1(true), excitingPort2(true)
, segments(1), activeSegment(0){}
SweepType sweepType; SweepType sweepType;
struct { struct {
double start; double start;

View File

@ -0,0 +1,29 @@
#ifndef VNADATA_H
#define VNADATA_H
#include "Tools/parameters.h"
#include <complex>
class VNAData {
public:
VNAData() = default;
VNAData(const Protocol::Datapoint &d) {
S = Sparam(std::complex<double>(d.real_S11, d.imag_S11),
std::complex<double>(d.real_S12, d.imag_S12),
std::complex<double>(d.real_S21, d.imag_S21),
std::complex<double>(d.real_S22, d.imag_S22));
frequency = d.frequency;
cdbm = d.cdbm;
pointNum = d.pointNum;
reference_impedance = 50.0;
}
double frequency;
int cdbm;
Sparam S;
unsigned int pointNum;
double reference_impedance;
};
#endif // VNADATA_H

View File

@ -22,12 +22,12 @@ void Averaging::setAverages(unsigned int a)
reset(avg.size()); reset(avg.size());
} }
Protocol::Datapoint Averaging::process(Protocol::Datapoint d) VNAData Averaging::process(VNAData d)
{ {
auto S11 = complex<double>(d.real_S11, d.imag_S11); auto S11 = d.S.m11;
auto S12 = complex<double>(d.real_S12, d.imag_S12); auto S12 = d.S.m12;
auto S21 = complex<double>(d.real_S21, d.imag_S21); auto S21 = d.S.m21;
auto S22 = complex<double>(d.real_S22, d.imag_S22); auto S22 = d.S.m22;
if (d.pointNum == avg.size()) { if (d.pointNum == avg.size()) {
// add moving average entry // add moving average entry
@ -99,14 +99,7 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
} }
} }
d.real_S11 = S11.real(); d.S = Sparam(S11, S12, S21, S22);
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
return d; return d;
} }

View File

@ -2,6 +2,7 @@
#define AVERAGING_H #define AVERAGING_H
#include "Device/device.h" #include "Device/device.h"
#include "VNA/vnadata.h"
#include <array> #include <array>
#include <deque> #include <deque>
@ -18,7 +19,7 @@ public:
Averaging(); Averaging();
void reset(unsigned int points); void reset(unsigned int points);
void setAverages(unsigned int a); void setAverages(unsigned int a);
Protocol::Datapoint process(Protocol::Datapoint d); VNAData process(VNAData d);
Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult d); Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult d);
// Returns the number of averaged sweeps. Value is incremented whenever the last point of the sweep is added. // Returns the number of averaged sweeps. Value is incremented whenever the last point of the sweep is added.
// Returned values are in range 0 to averages // Returned values are in range 0 to averages

View File

@ -88,9 +88,6 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
ui->StartupSARBW->setPrefixes(" k"); ui->StartupSARBW->setPrefixes(" k");
// Acquisition page // Acquisition page
ui->AcquisitionReferenceImpedance->setUnit("Ω");
ui->AcquisitionReferenceImpedance->setPrefixes(" ");
ui->AcquisitionReferenceImpedance->setPrecision(3);
ui->AcquisitionDFTlimitRBW->setUnit("Hz"); ui->AcquisitionDFTlimitRBW->setUnit("Hz");
ui->AcquisitionDFTlimitRBW->setPrefixes(" k"); ui->AcquisitionDFTlimitRBW->setPrefixes(" k");
connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) { connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) {
@ -237,7 +234,6 @@ void PreferencesDialog::setInitialGUIState()
ui->AcquisitionAdjustPowerLevel->setChecked(p->Acquisition.adjustPowerLevel); ui->AcquisitionAdjustPowerLevel->setChecked(p->Acquisition.adjustPowerLevel);
ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing); ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing);
ui->AcquisitionAllowSegmentedSweep->setChecked(p->Acquisition.allowSegmentedSweep); ui->AcquisitionAllowSegmentedSweep->setChecked(p->Acquisition.allowSegmentedSweep);
ui->AcquisitionReferenceImpedance->setValue(p->Acquisition.refImp);
ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode); ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode);
ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT); ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT);
ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0); ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0);
@ -298,7 +294,6 @@ void PreferencesDialog::updateFromGUI()
p->Acquisition.adjustPowerLevel = ui->AcquisitionAdjustPowerLevel->isChecked(); p->Acquisition.adjustPowerLevel = ui->AcquisitionAdjustPowerLevel->isChecked();
p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked(); p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked();
p->Acquisition.allowSegmentedSweep = ui->AcquisitionAllowSegmentedSweep->isChecked(); p->Acquisition.allowSegmentedSweep = ui->AcquisitionAllowSegmentedSweep->isChecked();
p->Acquisition.refImp = ui->AcquisitionReferenceImpedance->value();
p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked(); p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked();
p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value(); p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value();
p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1; p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1;

View File

@ -73,7 +73,6 @@ public:
bool useDFTinSAmode; bool useDFTinSAmode;
double RBWLimitForDFT; double RBWLimitForDFT;
bool useMedianAveraging; bool useMedianAveraging;
double refImp; // reference impedance
// advanced, hardware specific settings // advanced, hardware specific settings
double IF1; double IF1;
@ -153,7 +152,6 @@ private:
{&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true}, {&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true},
{&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0}, {&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0},
{&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false}, {&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false},
{&Acquisition.refImp, "Acquisition.referenceImpedance", 50.0},
{&Acquisition.IF1, "Acquisition.IF1", 62000000}, {&Acquisition.IF1, "Acquisition.IF1", 62000000},
{&Acquisition.ADCprescaler, "Acquisition.ADCprescaler", 128}, {&Acquisition.ADCprescaler, "Acquisition.ADCprescaler", 128},
{&Acquisition.DFTPhaseInc, "Acquisition.DFTPhaseInc", 1280}, {&Acquisition.DFTPhaseInc, "Acquisition.DFTPhaseInc", 1280},

View File

@ -745,24 +745,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QFormLayout" name="formLayout_11">
<item row="0" column="0">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Reference impedance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="AcquisitionReferenceImpedance">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Frequency of the first IF&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -16,6 +16,7 @@ using namespace std;
Touchstone::Touchstone(unsigned int ports) Touchstone::Touchstone(unsigned int ports)
{ {
this->m_ports = ports; this->m_ports = ports;
referenceImpedance = 50.0;
m_datapoints.clear(); m_datapoints.clear();
} }
@ -74,8 +75,8 @@ stringstream Touchstone::toString(Touchstone::Scale unit, Touchstone::Format for
case Format::RealImaginary: s << "RI "; break; case Format::RealImaginary: s << "RI "; break;
case Format::MagnitudeAngle: s << "MA "; break; case Format::MagnitudeAngle: s << "MA "; break;
} }
// reference impedance is always 50 ohm // reference impedance
s << "R 50\n"; s << "R " << referenceImpedance << "\n";
auto printParameter = [format](ostream &out, complex<double> &c) { auto printParameter = [format](ostream &out, complex<double> &c) {
switch (format) { switch (format) {
@ -192,10 +193,8 @@ Touchstone Touchstone::fromFile(string filename)
for(;iss>>s;) { for(;iss>>s;) {
if(last_R) { if(last_R) {
last_R = false; last_R = false;
// check reference impedance // read reference impedance
if (stoi(s, nullptr, 10) != 50) { ret.referenceImpedance = stod(s, nullptr);
throw runtime_error("Invalid reference impedance, only 50Ohm is supported");
}
break; break;
} }
if (!s.compare("HZ")) { if (!s.compare("HZ")) {
@ -438,3 +437,13 @@ void Touchstone::fromJSON(nlohmann::json j)
m_datapoints.push_back(d); m_datapoints.push_back(d);
} }
} }
double Touchstone::getReferenceImpedance() const
{
return referenceImpedance;
}
void Touchstone::setReferenceImpedance(double value)
{
referenceImpedance = value;
}

View File

@ -51,8 +51,12 @@ public:
virtual nlohmann::json toJSON(); virtual nlohmann::json toJSON();
virtual void fromJSON(nlohmann::json j); virtual void fromJSON(nlohmann::json j);
double getReferenceImpedance() const;
void setReferenceImpedance(double value);
private: private:
unsigned int m_ports; unsigned int m_ports;
double referenceImpedance;
std::vector<Datapoint> m_datapoints; std::vector<Datapoint> m_datapoints;
QString filename; QString filename;
}; };