wrapper work

This commit is contained in:
Jan Käberich 2022-08-04 20:12:15 +02:00
parent f0a40417e4
commit a530cea085
30 changed files with 385 additions and 588 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<VNAData>(); measurements[Measurement::Port1Open].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Port1Short].datapoints = vector<VNAData>(); measurements[Measurement::Port1Short].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Port1Load].datapoints = vector<VNAData>(); measurements[Measurement::Port1Load].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Port2Open].datapoints = vector<VNAData>(); measurements[Measurement::Port2Open].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Port2Short].datapoints = vector<VNAData>(); measurements[Measurement::Port2Short].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Port2Load].datapoints = vector<VNAData>(); measurements[Measurement::Port2Load].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Isolation].datapoints = vector<VNAData>(); measurements[Measurement::Isolation].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Through].datapoints = vector<VNAData>(); measurements[Measurement::Through].datapoints = vector<VirtualDevice::VNAMeasurement>();
measurements[Measurement::Line].datapoints = vector<VNAData>(); measurements[Measurement::Line].datapoints = vector<VirtualDevice::VNAMeasurement>();
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, VNAData &d) void Calibration::addMeasurement(Calibration::Measurement type, VirtualDevice::VNAMeasurement &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, VNAData &d) void Calibration::addMeasurements(std::set<Calibration::Measurement> types, VirtualDevice::VNAMeasurement &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 = measurements[Measurement::Port1Open].datapoints[i].S.m11; auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11; auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11; auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"];
auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22; auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22; auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22; auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"];
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 = measurements[Measurement::Isolation].datapoints[i].S.m21; S21_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S21"];
S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12; S12_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S12"];
} }
auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11; auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"];
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22; auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"];
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
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 = measurements[Measurement::Port1Open].datapoints[i].S.m11; auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11; auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11; auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"];
// 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 = measurements[Measurement::Port2Open].datapoints[i].S.m22; auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22; auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22; auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"];
// 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 = measurements[Measurement::Through].datapoints[i].S.m21; auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
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 = measurements[Measurement::Through].datapoints[i].S.m11; auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"];
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21; auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22; auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"];
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12; auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
auto S11_line = measurements[Measurement::Line].datapoints[i].S.m11; auto S11_line = measurements[Measurement::Line].datapoints[i].measurements["S11"];
auto S21_line = measurements[Measurement::Line].datapoints[i].S.m21; auto S21_line = measurements[Measurement::Line].datapoints[i].measurements["S21"];
auto S22_line = measurements[Measurement::Line].datapoints[i].S.m22; auto S22_line = measurements[Measurement::Line].datapoints[i].measurements["S22"];
auto S12_line = measurements[Measurement::Line].datapoints[i].S.m12; auto S12_line = measurements[Measurement::Line].datapoints[i].measurements["S12"];
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 = measurements[Measurement::Port1Short].datapoints[i].S.m11; S11_reflection = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22; S22_reflection = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
} else { } else {
// used open // used open
S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11; S11_reflection = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22; S22_reflection = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
} }
// 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(VNAData &d) void Calibration::correctMeasurement(VirtualDevice::VNAMeasurement &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 // Extract measurement S parameters
auto S11m = d.S.m11; auto S11m = d.measurements["S11"];
auto S21m = d.S.m21; auto S21m = d.measurements["S21"];
auto S22m = d.S.m22; auto S22m = d.measurements["S22"];
auto S12m = d.S.m12; auto S12m = d.measurements["S12"];
// find correct entry // find correct entry
auto p = getCalibrationPoint(d); auto p = getCalibrationPoint(d);
@ -459,7 +459,11 @@ void Calibration::correctMeasurement(VNAData &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.S = Sparam(S11, S12, S21, S22); auto S = Sparam(S11, S12, S21, S22);
d.measurements["S11"] = S.m11;
d.measurements["S12"] = S.m12;
d.measurements["S21"] = S.m21;
d.measurements["S22"] = S.m22;
} }
void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22) void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22)
@ -733,15 +737,7 @@ std::vector<Trace *> Calibration::getMeasurementTraces()
for(auto p : m.second.datapoints) { for(auto p : m.second.datapoints) {
Trace::Data d; Trace::Data d;
d.x = p.frequency; d.x = p.frequency;
if(prefix == "S11") { d.y = p.measurements[prefix];
d.y = p.S.m11;
} else if(prefix == "S12") {
d.y = p.S.m12;
} else if(prefix == "S21") {
d.y = p.S.m21;
} else {
d.y = p.S.m22;
}
t->addData(d, TraceMath::DataType::Frequency); t->addData(d, TraceMath::DataType::Frequency);
} }
traces.push_back(t); traces.push_back(t);
@ -802,21 +798,11 @@ bool Calibration::openFromFile(QString filename)
nlohmann::json j; nlohmann::json j;
file >> j; file >> j;
fromJSON(j); fromJSON(j);
} catch(exception &e) {
// json parsing failed, probably using a legacy file format
try {
file.clear();
file.seekg(0);
file >> *this;
InformationBox::ShowMessage("Loading calibration file", "The file \"" + filename + "\" is stored in a deprecated"
" calibration format. Future versions of this application might not support"
" 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;
} }
}
this->currentCalFile = filename; // if all ok, remember this this->currentCalFile = filename; // if all ok, remember this
return true; return true;
@ -909,14 +895,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.S.m11.real(); j_point["S11_real"] = p.measurements["S11"].real();
j_point["S11_imag"] = p.S.m11.imag(); j_point["S11_imag"] = p.measurements["S11"].imag();
j_point["S12_real"] = p.S.m12.real(); j_point["S12_real"] = p.measurements["S12"].real();
j_point["S12_imag"] = p.S.m12.imag(); j_point["S12_imag"] = p.measurements["S12"].imag();
j_point["S21_real"] = p.S.m21.real(); j_point["S21_real"] = p.measurements["S21"].real();
j_point["S21_imag"] = p.S.m21.imag(); j_point["S21_imag"] = p.measurements["S21"].imag();
j_point["S22_real"] = p.S.m22.real(); j_point["S22_real"] = p.measurements["S22"].real();
j_point["S22_imag"] = p.S.m22.imag(); j_point["S22_imag"] = p.measurements["S22"].imag();
j_points.push_back(j_point); j_points.push_back(j_point);
} }
j_measurement["points"] = j_points; j_measurement["points"] = j_points;
@ -957,13 +943,14 @@ 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"]) {
VNAData p; VirtualDevice::VNAMeasurement p;
p.pointNum = pointNum++; p.pointNum = pointNum++;
p.frequency = j_p.value("frequency", 0.0); p.frequency = j_p.value("frequency", 0.0);
p.S.m11 = complex<double>(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0)); p.Z0 = 50.0;
p.S.m12 = complex<double>(j_p.value("S12_real", 0.0), j_p.value("S12_imag", 0.0)); p.measurements["S11"] = complex<double>(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0));
p.S.m21 = complex<double>(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0)); p.measurements["S12"] = complex<double>(j_p.value("S12_real", 0.0), 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.measurements["S21"] = complex<double>(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0));
p.measurements["S22"] = complex<double>(j_p.value("S22_real", 0.0), j_p.value("S22_imag", 0.0));
measurements[m].datapoints.push_back(p); measurements[m].datapoints.push_back(p);
} }
} }
@ -986,56 +973,6 @@ QString Calibration::getCurrentCalibrationFile(){
return this->currentCalFile; return this->currentCalFile;
} }
istream& operator >>(istream &in, Calibration &c)
{
// old file format did not contain port standard gender, set default
c.port1Standard = Calibration::PortStandard::Male;
c.port2Standard = Calibration::PortStandard::Male;
c.throughZeroLength = false;
std::string line;
while(getline(in, line)) {
QString qLine = QString::fromStdString(line).simplified();
for(auto m : c.Measurements()) {
if(Calibration::MeasurementToString(m) == qLine) {
// this is the correct measurement
c.measurements[m].datapoints.clear();
uint timestamp;
in >> timestamp;
c.measurements[m].timestamp = QDateTime::fromSecsSinceEpoch(timestamp);
unsigned int points;
in >> points;
qDebug() << "Found measurement" << Calibration::MeasurementToString(m) << ", containing" << points << "points";
for(unsigned int i=0;i<points;i++) {
Protocol::Datapoint p;
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;
c.measurements[m].datapoints.push_back(VNAData(p));
if(in.eof() || in.bad() || in.fail()) {
c.clearMeasurement(m);
throw runtime_error("Failed to parse measurement \"" + line + "\", aborting calibration data import.");
}
}
break;
}
}
for(auto t : Calibration::Types()) {
if(Calibration::TypeToString(t) == qLine) {
// try to apply this calibration type
qDebug() << "Specified calibration in file is" << Calibration::TypeToString(t);
if(c.calculationPossible(t)) {
c.constructErrorTerms(t);
} else {
throw runtime_error("Incomplete calibration data, the requested \"" + line + "\"-Calibration could not be performed.");
}
break;
}
}
}
qDebug() << "Calibration file parsing complete";
return in;
}
bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement> &requiredMeasurements) bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement> &requiredMeasurements)
{ {
// sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty) // sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty)
@ -1068,7 +1005,7 @@ bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement>
return true; return true;
} }
Calibration::Point Calibration::getCalibrationPoint(VNAData &d) Calibration::Point Calibration::getCalibrationPoint(VirtualDevice::VNAMeasurement &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, VNAData &d); void addMeasurement(Measurement type, VirtualDevice::VNAMeasurement &d);
void addMeasurements(std::set<Measurement> types, VNAData &d); void addMeasurements(std::set<Measurement> types, VirtualDevice::VNAMeasurement &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(VNAData &d); void correctMeasurement(VirtualDevice::VNAMeasurement &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 {
@ -141,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(VNAData &d); Point getCalibrationPoint(VirtualDevice::VNAMeasurement &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).
@ -173,7 +173,7 @@ private:
class MeasurementData { class MeasurementData {
public: public:
QDateTime timestamp; QDateTime timestamp;
std::vector<VNAData> datapoints; std::vector<VirtualDevice::VNAMeasurement> datapoints;
}; };
Type type; Type type;

View File

@ -190,6 +190,7 @@ VirtualDevice::VirtualDevice(QString serial)
connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){ connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){
VNAMeasurement m; VNAMeasurement m;
m.pointNum = res.pointNum; m.pointNum = res.pointNum;
m.Z0 = 50.0;
if(zerospan) { if(zerospan) {
m.us = res.us; m.us = res.us;
} else { } else {
@ -486,3 +487,48 @@ VirtualDevice *VirtualDevice::getConnected()
{ {
return connected; return connected;
} }
Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2)
{
Sparam S;
S.m11 = measurements["S"+QString::number(port1)+QString::number(port1)];
S.m12 = measurements["S"+QString::number(port1)+QString::number(port2)];
S.m21 = measurements["S"+QString::number(port2)+QString::number(port1)];
S.m22 = measurements["S"+QString::number(port2)+QString::number(port2)];
return S;
}
void VirtualDevice::VNAMeasurement::fromSparam(Sparam S, int port1, int port2)
{
QString s11 = "S"+QString::number(port1)+QString::number(port1);
QString s12 = "S"+QString::number(port1)+QString::number(port2);
QString s21 = "S"+QString::number(port2)+QString::number(port1);
QString s22 = "S"+QString::number(port2)+QString::number(port2);
if(measurements.count(s11)) {
measurements[s11] = S.m11;
}
if(measurements.count(s12)) {
measurements[s12] = S.m12;
}
if(measurements.count(s21)) {
measurements[s21] = S.m21;
}
if(measurements.count(s22)) {
measurements[s22] = S.m22;
}
}
VirtualDevice::VNAMeasurement VirtualDevice::VNAMeasurement::interpolateTo(const VirtualDevice::VNAMeasurement &to, double a)
{
VNAMeasurement ret;
ret.frequency = frequency * (1.0 - a) + to.frequency * a;
ret.dBm = dBm * (1.0 - a) + to.dBm * a;
ret.Z0 = Z0 * (1.0 - a) + to.Z0 * a;
for(auto m : measurements) {
if(to.measurements.count(m.first) == 0) {
throw runtime_error("Nothing to interpolate to, expected measurement +\""+m.first.toStdString()+"\"");
}
ret.measurements[m.first] = measurements[m.first] * (1.0 - a) + to.measurements.at(m.first) * a;
}
return ret;
}

View File

@ -2,6 +2,7 @@
#define VIRTUALDEVICE_H #define VIRTUALDEVICE_H
#include "device.h" #include "device.h"
#include "Tools/parameters.h"
#include <set> #include <set>
#include <complex> #include <complex>
@ -66,6 +67,7 @@ public:
class VNAMeasurement { class VNAMeasurement {
public: public:
int pointNum; int pointNum;
double Z0;
union { union {
struct { struct {
// for non-zero span // for non-zero span
@ -78,6 +80,10 @@ public:
}; };
}; };
std::map<QString, std::complex<double>> measurements; std::map<QString, std::complex<double>> measurements;
Sparam toSparam(int port1, int port2);
void fromSparam(Sparam S, int port1, int port2);
VNAMeasurement interpolateTo(const VNAMeasurement &to, double a);
}; };
QStringList availableVNAMeasurements(); QStringList availableVNAMeasurements();

View File

@ -118,7 +118,6 @@ HEADERS += \
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 \

View File

@ -61,10 +61,10 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
// Create default traces // Create default traces
auto tPort1 = new Trace("Port1", Qt::yellow); auto tPort1 = new Trace("Port1", Qt::yellow);
tPort1->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port1); tPort1->fromLivedata(Trace::LivedataType::Overwrite, "PORT1");
traceModel.addTrace(tPort1); traceModel.addTrace(tPort1);
auto tPort2 = new Trace("Port2", Qt::blue); auto tPort2 = new Trace("Port2", Qt::blue);
tPort2->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port2); tPort2->fromLivedata(Trace::LivedataType::Overwrite, "PORT2");
traceModel.addTrace(tPort2); traceModel.addTrace(tPort2);
auto traceXY = new TraceXYPlot(traceModel); auto traceXY = new TraceXYPlot(traceModel);

View File

@ -12,7 +12,7 @@ protected slots:
virtual void importDialog() override; virtual void importDialog() override;
protected: protected:
virtual Trace::LiveParameter defaultParameter() override {return Trace::LiveParameter::Port1;}; virtual QString defaultParameter() override {return "PORT1";}
}; };
#endif // TRACEWIDGETSA_H #endif // TRACEWIDGETSA_H

View File

@ -184,7 +184,7 @@ std::vector<Marker::Format> Marker::applicableFormats()
case Type::Maximum: case Type::Maximum:
case Type::Minimum: case Type::Minimum:
case Type::PeakTable: case Type::PeakTable:
if(Trace::isSAParamater(parentTrace->liveParameter())) { if(Trace::isSAParameter(parentTrace->liveParameter())) {
ret.push_back(Format::dBm); ret.push_back(Format::dBm);
ret.push_back(Format::dBuV); ret.push_back(Format::dBuV);
} else { } else {
@ -217,7 +217,7 @@ std::vector<Marker::Format> Marker::applicableFormats()
case Type::Maximum: case Type::Maximum:
case Type::Minimum: case Type::Minimum:
case Type::PeakTable: case Type::PeakTable:
if(Trace::isSAParamater(parentTrace->liveParameter())) { if(Trace::isSAParameter(parentTrace->liveParameter())) {
ret.push_back(Format::dBm); ret.push_back(Format::dBm);
ret.push_back(Format::dBuV); ret.push_back(Format::dBuV);
} else { } else {
@ -871,20 +871,13 @@ std::set<Marker::Type> Marker::getSupportedTypes()
supported.insert(Type::Bandpass); supported.insert(Type::Bandpass);
} }
if(parentTrace->getSource() == Trace::Source::Live) { if(parentTrace->getSource() == Trace::Source::Live) {
switch(parentTrace->liveParameter()) { if(Trace::isVNAParameter(parentTrace->liveParameter())) {
case Trace::LiveParameter::S11:
case Trace::LiveParameter::S12:
case Trace::LiveParameter::S21:
case Trace::LiveParameter::S22:
// no special marker types for VNA yet // no special marker types for VNA yet
break; }
case Trace::LiveParameter::Port1: if(Trace::isSAParameter(parentTrace->liveParameter())) {
case Trace::LiveParameter::Port2:
// special SA marker types // special SA marker types
supported.insert(Type::TOI); supported.insert(Type::TOI);
supported.insert(Type::PhaseNoise); supported.insert(Type::PhaseNoise);
break;
default: break;
} }
} }
break; break;

View File

@ -16,7 +16,7 @@
using namespace std; using namespace std;
using namespace mup; using namespace mup;
Trace::Trace(QString name, QColor color, LiveParameter live) Trace::Trace(QString name, QColor color, QString live)
: model(nullptr), : model(nullptr),
_name(name), _name(name),
_color(color), _color(color),
@ -25,7 +25,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
hashSet(false), hashSet(false),
JSONskipHash(false), JSONskipHash(false),
_liveType(LivedataType::Overwrite), _liveType(LivedataType::Overwrite),
_liveParam(live), liveParam(live),
vFactor(0.66), vFactor(0.66),
reflection(true), reflection(true),
visible(true), visible(true),
@ -130,12 +130,12 @@ void Trace::addData(const Trace::Data& d, DataType domain, double reference_impe
emit outputSamplesChanged(index, index + 1); emit outputSamplesChanged(index, index + 1);
} }
void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettings &s, int index) void Trace::addData(const Trace::Data &d, const VirtualDevice::SASettings &s, int index)
{ {
settings.SA = s; settings.SA = s;
settings.valid = true; settings.valid = true;
auto domain = DataType::Frequency; auto domain = DataType::Frequency;
if (s.f_start == s.f_stop) { if (s.freqStart == s.freqStop) {
// in zerospan mode // in zerospan mode
domain = DataType::TimeZeroSpan; domain = DataType::TimeZeroSpan;
} }
@ -143,7 +143,7 @@ void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettin
} }
void Trace::setName(QString name) { void Trace::setName(QString name) {
_name = name; name = name;
emit nameChanged(); emit nameChanged();
} }
@ -259,7 +259,7 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter)
return lastTraceName; return lastTraceName;
} }
void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data) void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VirtualDevice::VNAMeasurement> &data)
{ {
S11.clear(); S11.clear();
S12.clear(); S12.clear();
@ -267,25 +267,26 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c
S22.clear(); S22.clear();
for(auto d : data) { for(auto d : data) {
Trace::Data td; Trace::Data td;
auto S = d.toSparam(1, 2);
td.x = d.frequency; td.x = d.frequency;
td.y = d.S.m11; td.y = S.m11;
S11.addData(td, DataType::Frequency); S11.addData(td, DataType::Frequency);
td.y = d.S.m12; td.y = S.m12;
S12.addData(td, DataType::Frequency); S12.addData(td, DataType::Frequency);
td.y = d.S.m21; td.y = S.m21;
S21.addData(td, DataType::Frequency); S21.addData(td, DataType::Frequency);
td.y = d.S.m22; td.y = S.m22;
S22.addData(td, DataType::Frequency); S22.addData(td, DataType::Frequency);
} }
} }
void Trace::fromLivedata(Trace::LivedataType type, LiveParameter param) void Trace::fromLivedata(Trace::LivedataType type, QString param)
{ {
clearMathSources(); clearMathSources();
source = Source::Live; source = Source::Live;
_liveType = type; _liveType = type;
_liveParam = param; liveParam = param;
if(param == LiveParameter::S11 || param == LiveParameter::S22) { if(param.length() == 3 && param[0] == 'S' && param[1].isDigit() && param[1] == param[2]) {
reflection = true; reflection = true;
} else { } else {
reflection = false; reflection = false;
@ -305,8 +306,8 @@ void Trace::fromMath()
} }
void Trace::setColor(QColor color) { void Trace::setColor(QColor color) {
if(_color != color) { if(color != color) {
_color = color; color = color;
emit colorChanged(this); emit colorChanged(this);
} }
} }
@ -637,6 +638,16 @@ const std::vector<Trace::MathInfo>& Trace::getMathOperations() const
return mathOps; return mathOps;
} }
bool Trace::isSAParameter(QString param)
{
return param.length() == 5 && param.startsWith("PORT") && param[4].isDigit();
}
bool Trace::isVNAParameter(QString param)
{
return param.length() == 3 && param[0] == 'S' && param[1].isDigit() && param[2].isDigit();
}
double Trace::velocityFactor() double Trace::velocityFactor()
{ {
return vFactor; return vFactor;
@ -678,7 +689,7 @@ nlohmann::json Trace::toJSON()
switch(source) { switch(source) {
case Source::Live: case Source::Live:
j["type"] = "Live"; j["type"] = "Live";
j["parameter"] = _liveParam; j["parameter"] = liveParam.toStdString();
j["livetype"] = _liveType; j["livetype"] = _liveType;
j["paused"] = paused; j["paused"] = paused;
break; break;
@ -737,7 +748,7 @@ void Trace::fromJSON(nlohmann::json j)
visible = j.value("visible", true); visible = j.value("visible", true);
auto type = QString::fromStdString(j.value("type", "Live")); auto type = QString::fromStdString(j.value("type", "Live"));
if(type == "Live") { if(type == "Live") {
_liveParam = j.value("parameter", LiveParameter::S11); liveParam = QString::fromStdString(j.value("parameter", "S11"));
_liveType = j.value("livetype", LivedataType::Overwrite); _liveType = j.value("livetype", LivedataType::Overwrite);
paused = j.value("paused", false); paused = j.value("paused", false);
} else if(type == "Touchstone" || type == "File") { } else if(type == "Touchstone" || type == "File") {
@ -862,9 +873,9 @@ std::vector<Trace *> Trace::createFromCSV(CSV &csv)
return traces; return traces;
} }
std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22) std::vector<VirtualDevice::VNAMeasurement> Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22)
{ {
vector<VNAData> ret; vector<VirtualDevice::VNAMeasurement> ret;
// Sanity check traces // Sanity check traces
unsigned int samples = S11.size(); unsigned int samples = S11.size();
@ -906,15 +917,11 @@ std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S1
// Checks passed, assemble datapoints // Checks passed, assemble datapoints
for(unsigned int i=0;i<samples;i++) { for(unsigned int i=0;i<samples;i++) {
Protocol::Datapoint d; VirtualDevice::VNAMeasurement d;
d.real_S11 = real(S11.sample(i).y); d.measurements["S11"] = S11.sample(i).y;
d.imag_S11 = imag(S11.sample(i).y); d.measurements["S12"] = S12.sample(i).y;
d.real_S12 = real(S12.sample(i).y); d.measurements["S21"] = S21.sample(i).y;
d.imag_S12 = imag(S12.sample(i).y); d.measurements["S22"] = S22.sample(i).y;
d.real_S21 = real(S21.sample(i).y);
d.imag_S21 = imag(S21.sample(i).y);
d.real_S22 = real(S22.sample(i).y);
d.imag_S22 = imag(S22.sample(i).y);
d.pointNum = i; d.pointNum = i;
d.frequency = freqs[i]; d.frequency = freqs[i];
ret.push_back(d); ret.push_back(d);
@ -922,70 +929,6 @@ std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S1
return ret; return ret;
} }
Trace::LiveParameter Trace::ParameterFromString(QString s)
{
s = s.toUpper();
if(s == "S11") {
return LiveParameter::S11;
} else if(s == "S12") {
return LiveParameter::S12;
} else if(s == "S21") {
return LiveParameter::S21;
} else if(s == "S22") {
return LiveParameter::S22;
} else if(s == "PORT1") {
return LiveParameter::Port1;
} else if(s == "PORT2") {
return LiveParameter::Port2;
} else {
return LiveParameter::Invalid;
}
}
QString Trace::ParameterToString(LiveParameter p)
{
switch(p) {
case Trace::LiveParameter::S11: return "S11";
case Trace::LiveParameter::S12: return "S12";
case Trace::LiveParameter::S21: return "S21";
case Trace::LiveParameter::S22: return "S22";
case Trace::LiveParameter::Port1: return "Port1";
case Trace::LiveParameter::Port2: return "Port2";
default: return "Invalid";
}
}
bool Trace::isVNAParameter(Trace::LiveParameter p)
{
switch(p) {
case Trace::LiveParameter::S11:
case Trace::LiveParameter::S12:
case Trace::LiveParameter::S21:
case Trace::LiveParameter::S22:
return true;
case Trace::LiveParameter::Port1:
case Trace::LiveParameter::Port2:
default:
return false;
}
}
bool Trace::isSAParamater(Trace::LiveParameter p)
{
switch(p) {
case Trace::LiveParameter::S11:
case Trace::LiveParameter::S12:
case Trace::LiveParameter::S21:
case Trace::LiveParameter::S22:
return false;
case Trace::LiveParameter::Port1:
case Trace::LiveParameter::Port2:
return true;
default:
return false;
}
}
Trace::LivedataType Trace::TypeFromString(QString s) Trace::LivedataType Trace::TypeFromString(QString s)
{ {
s = s.toUpper(); s = s.toUpper();
@ -1365,7 +1308,7 @@ unsigned int Trace::getFileParameter() const
double Trace::getNoise(double frequency) double Trace::getNoise(double frequency)
{ {
if(source != Trace::Source::Live || !settings.valid || (_liveParam != LiveParameter::Port1 && _liveParam != LiveParameter::Port2) || lastMath->getDataType() != DataType::Frequency) { if(source != Trace::Source::Live || !settings.valid || !liveParam.startsWith("PORT") || lastMath->getDataType() != DataType::Frequency) {
// data not suitable for noise calculation // data not suitable for noise calculation
return std::numeric_limits<double>::quiet_NaN(); return std::numeric_limits<double>::quiet_NaN();
} }

View File

@ -3,10 +3,9 @@
#include "touchstone.h" #include "touchstone.h"
#include "csv.h" #include "csv.h"
#include "Device/device.h" #include "Device/virtualdevice.h"
#include "Math/tracemath.h" #include "Math/tracemath.h"
#include "Tools/parameters.h" #include "Tools/parameters.h"
#include "VNA/vnadata.h"
#include <QObject> #include <QObject>
#include <complex> #include <complex>
@ -33,17 +32,7 @@ public:
Last, Last,
}; };
enum class LiveParameter { Trace(QString name = QString(), QColor color = Qt::darkYellow, QString live = "S11");
S11,
S12,
S21,
S22,
Port1,
Port2,
Invalid,
};
Trace(QString name = QString(), QColor color = Qt::darkYellow, LiveParameter live = LiveParameter::S11);
~Trace(); ~Trace();
enum class LivedataType { enum class LivedataType {
@ -55,13 +44,13 @@ public:
void clear(bool force = false); void clear(bool force = false);
void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1); void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1);
void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s, int index = -1); void addData(const Data& d, const VirtualDevice::SASettings &s, int index = -1);
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<VNAData> &data); static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VirtualDevice::VNAMeasurement> &data);
void fromLivedata(LivedataType type, LiveParameter param); void fromLivedata(LivedataType type, QString param);
void fromMath(); void fromMath();
QString name() { return _name; } QString name() { return _name; }
QColor color() { return _color; } QColor color() { return _color; }
@ -72,7 +61,7 @@ public:
bool isPaused(); bool isPaused();
Source getSource() {return source;} Source getSource() {return source;}
bool isReflection(); bool isReflection();
LiveParameter liveParameter() { return _liveParam; } QString liveParameter() { return liveParam; }
LivedataType liveType() { return _liveType; } LivedataType liveType() { return _liveType; }
TraceMath::DataType outputType() const { return lastMath->getDataType(); } TraceMath::DataType outputType() const { return lastMath->getDataType(); }
unsigned int size() const; unsigned int size() const;
@ -125,6 +114,9 @@ public:
}; };
const std::vector<MathInfo>& getMathOperations() const; const std::vector<MathInfo>& getMathOperations() const;
static bool isSAParameter(QString param);
static bool isVNAParameter(QString param);
double velocityFactor(); double velocityFactor();
double timeToDistance(double time); double timeToDistance(double time);
double distanceToTime(double distance); double distanceToTime(double distance);
@ -145,12 +137,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<VNAData> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22); static std::vector<VirtualDevice::VNAMeasurement> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22);
static LiveParameter ParameterFromString(QString s);
static QString ParameterToString(LiveParameter p);
static bool isVNAParameter(LiveParameter p);
static bool isSAParamater(LiveParameter p);
static LivedataType TypeFromString(QString s); static LivedataType TypeFromString(QString s);
static QString TypeToString(LivedataType t); static QString TypeToString(LivedataType t);
@ -247,7 +234,7 @@ private:
// Members for when source == Source::Live // Members for when source == Source::Live
LivedataType _liveType; LivedataType _liveType;
LiveParameter _liveParam; QString liveParam;
// Members for when source == Source::File // Members for when source == Source::File
QString filename; QString filename;
@ -273,7 +260,7 @@ private:
std::set<Marker*> markers; std::set<Marker*> markers;
struct { struct {
union { union {
Protocol::SpectrumAnalyzerSettings SA; VirtualDevice::SASettings SA;
}; };
bool valid; bool valid;
} settings; } settings;

View File

@ -124,25 +124,15 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
} }
VNAtrace = Trace::isVNAParameter(t.liveParameter()); VNAtrace = Trace::isVNAParameter(t.liveParameter());
if(VirtualDevice::getConnected()) {
if(VNAtrace) { if(VNAtrace) {
ui->CLiveParam->addItem("S11"); ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableVNAMeasurements());
ui->CLiveParam->addItem("S12");
ui->CLiveParam->addItem("S21");
ui->CLiveParam->addItem("S22");
} else { } else {
ui->CLiveParam->addItem("Port 1"); ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableSAMeasurements());
ui->CLiveParam->addItem("Port 2"); }
} }
switch(t.liveParameter()) { ui->CLiveParam->setCurrentText(t.liveParameter());
case Trace::LiveParameter::S11: ui->CLiveParam->setCurrentIndex(0); break;
case Trace::LiveParameter::S12: ui->CLiveParam->setCurrentIndex(1); break;
case Trace::LiveParameter::S21: ui->CLiveParam->setCurrentIndex(2); break;
case Trace::LiveParameter::S22: ui->CLiveParam->setCurrentIndex(3); break;
case Trace::LiveParameter::Port1: ui->CLiveParam->setCurrentIndex(0); break;
case Trace::LiveParameter::Port2: ui->CLiveParam->setCurrentIndex(1); break;
default: break;
}
connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateTouchstoneFileStatus); connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateTouchstoneFileStatus);
connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateTouchstoneFileStatus); connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateTouchstoneFileStatus);
@ -354,26 +344,12 @@ void TraceEditDialog::on_buttonBox_accepted()
} }
} else if(ui->bLive->isChecked()) { } else if(ui->bLive->isChecked()) {
Trace::LivedataType type = Trace::LivedataType::Overwrite; Trace::LivedataType type = Trace::LivedataType::Overwrite;
Trace::LiveParameter param = Trace::LiveParameter::S11;
switch(ui->CLiveType->currentIndex()) { switch(ui->CLiveType->currentIndex()) {
case 0: type = Trace::LivedataType::Overwrite; break; case 0: type = Trace::LivedataType::Overwrite; break;
case 1: type = Trace::LivedataType::MaxHold; break; case 1: type = Trace::LivedataType::MaxHold; break;
case 2: type = Trace::LivedataType::MinHold; break; case 2: type = Trace::LivedataType::MinHold; break;
} }
if(VNAtrace) { trace.fromLivedata(type, ui->CLiveParam->currentText());
switch(ui->CLiveParam->currentIndex()) {
case 0: param = Trace::LiveParameter::S11; break;
case 1: param = Trace::LiveParameter::S12; break;
case 2: param = Trace::LiveParameter::S21; break;
case 3: param = Trace::LiveParameter::S22; break;
}
} else {
switch(ui->CLiveParam->currentIndex()) {
case 0: param = Trace::LiveParameter::Port1; break;
case 1: param = Trace::LiveParameter::Port2; break;
}
}
trace.fromLivedata(type, param);
} else { } else {
// math operation trace // math operation trace
trace.fromMath(); trace.fromMath();

View File

@ -1,4 +1,4 @@
#include "tracemodel.h" #include "tracemodel.h"
#include <QIcon> #include <QIcon>
#include <QDebug> #include <QDebug>
@ -161,9 +161,7 @@ bool TraceModel::PortExcitationRequired(int port)
if(t->getSource() == Trace::Source::Live && !t->isPaused()) { if(t->getSource() == Trace::Source::Live && !t->isPaused()) {
// this trace needs measurements from VNA, check if port has to be excited for its measurement // this trace needs measurements from VNA, check if port has to be excited for its measurement
auto param = t->liveParameter(); auto param = t->liveParameter();
if(port == 1 && (param == Trace::LiveParameter::S11 || param == Trace::LiveParameter::S21)) { if(port == QString(param[2]).toInt()) {
return true;
} else if(port == 2 && (param == Trace::LiveParameter::S22 || param == Trace::LiveParameter::S12)) {
return true; return true;
} }
} }
@ -214,7 +212,7 @@ void TraceModel::clearLiveData()
} }
} }
void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype) void TraceModel::addVNAData(const VirtualDevice::VNAMeasurement& d, TraceMath::DataType datatype)
{ {
source = DataSource::VNA; source = DataSource::VNA;
for(auto t : traces) { for(auto t : traces) {
@ -226,31 +224,28 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
td.x = d.frequency; td.x = d.frequency;
break; break;
case TraceMath::DataType::Power: case TraceMath::DataType::Power:
td.x = (double) d.cdbm / 100.0; td.x = d.dBm;
break; break;
case TraceMath::DataType::TimeZeroSpan: case TraceMath::DataType::TimeZeroSpan:
td.x = d.time; td.x = d.us;
index = d.pointNum; index = d.pointNum;
break; break;
default: default:
// invalid type, can not add // invalid type, can not add
return; return;
} }
switch(t->liveParameter()) { if(d.measurements.count(t->liveParameter())) {
case Trace::LiveParameter::S11: td.y = d.S.m11; break; td.y = d.measurements.at(t->liveParameter());
case Trace::LiveParameter::S12: td.y = d.S.m12; break; } else {
case Trace::LiveParameter::S21: td.y = d.S.m21; break; // parameter not included in data, skip
case Trace::LiveParameter::S22: td.y = d.S.m22; break;
default:
// not a VNA trace, skip
continue; continue;
} }
t->addData(td, datatype, d.reference_impedance, index); t->addData(td, datatype, d.Z0, index);
} }
} }
} }
void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings) void TraceModel::addSAData(const VirtualDevice::SAMeasurement& d, const VirtualDevice::SASettings &settings)
{ {
source = DataSource::SA; source = DataSource::SA;
for(auto t : traces) { for(auto t : traces) {
@ -264,11 +259,10 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
} else { } else {
td.x = d.frequency; td.x = d.frequency;
} }
switch(t->liveParameter()) { if(d.measurements.count(t->liveParameter())) {
case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 0); break; td.y = d.measurements.at(t->liveParameter());
case Trace::LiveParameter::Port2: td.y = complex<double>(d.port2, 0); break; } else {
default: // parameter not included in data, skip
// not a SA trace, skip
continue; continue;
} }
t->addData(td, settings, index); t->addData(td, settings, index);

View File

@ -4,7 +4,6 @@
#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>
@ -65,8 +64,8 @@ signals:
public slots: public slots:
void clearLiveData(); void clearLiveData();
void addVNAData(const VNAData& d, TraceMath::DataType datatype); void addVNAData(const VirtualDevice::VNAMeasurement& d, TraceMath::DataType datatype);
void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings); void addSAData(const VirtualDevice::SAMeasurement &d, const VirtualDevice::SASettings &settings);
private: private:
DataSource source; DataSource source;

View File

@ -180,7 +180,7 @@ void TraceWidget::SetupSCPI()
}; };
auto createStringFromData = [](Trace *t, const Trace::Data &d) -> QString { auto createStringFromData = [](Trace *t, const Trace::Data &d) -> QString {
if(Trace::isSAParamater(t->liveParameter())) { if(Trace::isSAParameter(t->liveParameter())) {
if(std::isnan(d.x)) { if(std::isnan(d.x)) {
return "NaN"; return "NaN";
} }
@ -373,7 +373,7 @@ void TraceWidget::SetupSCPI()
if(!t || params.size() < 2) { if(!t || params.size() < 2) {
return "ERROR"; return "ERROR";
} }
auto newparam = Trace::ParameterFromString(params[1]); auto newparam = params[1];
if((Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam)) if((Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))
|| (Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))) { || (Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))) {
t->fromLivedata(t->liveType(), newparam); t->fromLivedata(t->liveType(), newparam);
@ -386,7 +386,7 @@ void TraceWidget::SetupSCPI()
if(!t) { if(!t) {
return "ERROR"; return "ERROR";
} }
return Trace::ParameterToString(t->liveParameter()); return t->liveParameter();
})); }));
add(new SCPICommand("TYPE", [=](QStringList params) -> QString { add(new SCPICommand("TYPE", [=](QStringList params) -> QString {
auto t = findTrace(params); auto t = findTrace(params);

View File

@ -31,7 +31,7 @@ protected:
void SetupSCPI(); void SetupSCPI();
void contextMenuEvent(QContextMenuEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
virtual Trace::LiveParameter defaultParameter() = 0; virtual QString defaultParameter() = 0;
QPoint dragStartPosition; QPoint dragStartPosition;
Trace *dragTrace; Trace *dragTrace;
Ui::TraceWidget *ui; Ui::TraceWidget *ui;

View File

@ -76,31 +76,26 @@ void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22)
auto S21 = t[2]; auto S21 = t[2];
auto S22 = t[3]; auto S22 = t[3];
for(unsigned int i=0;i<traceChooser->getPoints();i++) { for(unsigned int i=0;i<traceChooser->getPoints();i++) {
Protocol::Datapoint p; VirtualDevice::VNAMeasurement p;
p.pointNum = i; p.pointNum = i;
p.Z0 = 0;
p.dBm = 0;
Sparam S;
if(S11) { if(S11) {
auto sample = S11->sample(i); S.m11 = S11->sample(i).y;
p.imag_S11 = sample.y.imag(); p.frequency = S11->sample(i).x;
p.real_S11 = sample.y.real();
p.frequency = sample.x;
} }
if(S12) { if(S12) {
auto sample = S12->sample(i); S.m12 = S12->sample(i).y;
p.imag_S12 = sample.y.imag(); p.frequency = S11->sample(i).x;
p.real_S12 = sample.y.real();
p.frequency = sample.x;
} }
if(S21) { if(S21) {
auto sample = S21->sample(i); S.m21 = S21->sample(i).y;
p.imag_S21 = sample.y.imag(); p.frequency = S11->sample(i).x;
p.real_S21 = sample.y.real();
p.frequency = sample.x;
} }
if(S22) { if(S22) {
auto sample = S22->sample(i); S.m22 = S22->sample(i).y;
p.imag_S22 = sample.y.imag(); p.frequency = S11->sample(i).x;
p.real_S22 = sample.y.real();
p.frequency = sample.x;
} }
measurements.push_back(p); measurements.push_back(p);
} }
@ -120,7 +115,7 @@ Deembedding::Deembedding(TraceModel &tm)
} }
void Deembedding::Deembed(VNAData &d) void Deembedding::Deembed(VirtualDevice::VNAMeasurement &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

@ -17,15 +17,15 @@ class Deembedding : public QObject, public Savable
Q_OBJECT Q_OBJECT
public: public:
Deembedding(TraceModel &tm); Deembedding(TraceModel &tm);
~Deembedding(){}; ~Deembedding(){}
void Deembed(VNAData &d); void Deembed(VirtualDevice::VNAMeasurement &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);
void addOption(DeembeddingOption* option); void addOption(DeembeddingOption* option);
void swapOptions(unsigned int index); void swapOptions(unsigned int index);
std::vector<DeembeddingOption*>& getOptions() {return options;}; std::vector<DeembeddingOption*>& getOptions() {return options;}
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override; void fromJSON(nlohmann::json j) override;
public slots: public slots:
@ -42,7 +42,7 @@ private:
TraceModel &tm; TraceModel &tm;
bool measuring; bool measuring;
std::vector<VNAData> measurements; std::vector<VirtualDevice::VNAMeasurement> measurements;
QDialog *measurementDialog; QDialog *measurementDialog;
Ui_DeembeddingMeasurementDialog *measurementUI; Ui_DeembeddingMeasurementDialog *measurementUI;

View File

@ -23,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(VNAData &p) = 0; virtual void transformDatapoint(VirtualDevice::VNAMeasurement &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<VNAData> m){Q_UNUSED(m)}; virtual void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> 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

@ -15,10 +15,11 @@ ImpedanceRenormalization::ImpedanceRenormalization()
} }
void ImpedanceRenormalization::transformDatapoint(VNAData &p) void ImpedanceRenormalization::transformDatapoint(VirtualDevice::VNAMeasurement &p)
{ {
p.S = Sparam(ABCDparam(p.S, p.reference_impedance), impedance); //p.S = Sparam(ABCDparam(p.S, p.Z0), impedance);
p.reference_impedance = impedance; // TODO
p.Z0 = impedance;
} }
nlohmann::json ImpedanceRenormalization::toJSON() nlohmann::json ImpedanceRenormalization::toJSON()

View File

@ -13,7 +13,7 @@ class ImpedanceRenormalization : public DeembeddingOption
public: public:
ImpedanceRenormalization(); ImpedanceRenormalization();
void transformDatapoint(VNAData &p) override; void transformDatapoint(VirtualDevice::VNAMeasurement &p) override;
Type getType() override { return Type::ImpedanceRenormalization;} Type getType() override { return Type::ImpedanceRenormalization;}
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override; void fromJSON(nlohmann::json j) override;

View File

@ -26,10 +26,10 @@ MatchingNetwork::MatchingNetwork()
addNetwork = true; addNetwork = true;
} }
void MatchingNetwork::transformDatapoint(VNAData &p) void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p)
{ {
auto S = p.S; auto S = p.toSparam(1, 2);
auto measurement = ABCDparam(S, p.reference_impedance); auto measurement = ABCDparam(S, p.Z0);
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;
@ -53,7 +53,7 @@ void MatchingNetwork::transformDatapoint(VNAData &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;
p.S = Sparam(corrected, p.reference_impedance); p.fromSparam(Sparam(corrected, p.Z0), 1, 2);
} }
void MatchingNetwork::edit() void MatchingNetwork::edit()

View File

@ -64,7 +64,7 @@ public:
// DeembeddingOption interface // DeembeddingOption interface
public: public:
void transformDatapoint(VNAData &p) override; void transformDatapoint(VirtualDevice::VNAMeasurement &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;

View File

@ -29,7 +29,7 @@ PortExtension::PortExtension()
kit = nullptr; kit = nullptr;
} }
void PortExtension::transformDatapoint(VNAData &d) void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d)
{ {
if(port1.enabled || port2.enabled) { if(port1.enabled || port2.enabled) {
if(port1.enabled) { if(port1.enabled) {
@ -41,9 +41,9 @@ void PortExtension::transformDatapoint(VNAData &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);
d.S.m11 /= correction * correction; d.measurements["S11"] /= correction * correction;
d.S.m21 /= correction; d.measurements["S21"] /= correction;
d.S.m12 /= correction; d.measurements["S12"] /= 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;
@ -54,9 +54,9 @@ void PortExtension::transformDatapoint(VNAData &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);
d.S.m22 /= correction * correction; d.measurements["S22"] /= correction * correction;
d.S.m21 /= correction; d.measurements["S21"] /= correction;
d.S.m12 /= correction; d.measurements["S12"] /= correction;
} }
} }
} }
@ -194,7 +194,7 @@ void PortExtension::edit()
} }
} }
void PortExtension::measurementCompleted(std::vector<VNAData> m) void PortExtension::measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m)
{ {
if(m.size() > 0) { if(m.size() > 0) {
double last_phase = 0.0; double last_phase = 0.0;
@ -205,9 +205,9 @@ void PortExtension::measurementCompleted(std::vector<VNAData> m)
// grab correct measurement // grab correct measurement
complex<double> reflection; complex<double> reflection;
if(isPort1) { if(isPort1) {
reflection = p.S.m11; reflection = p.measurements["S11"];
} else { } else {
reflection = p.S.m22; reflection = p.measurements["S22"];
} }
// 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(VNAData& d) override; void transformDatapoint(VirtualDevice::VNAMeasurement& 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<VNAData> m) override; void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m) override;
private: private:
void startMeasurement(); void startMeasurement();

View File

@ -15,11 +15,11 @@ TwoThru::TwoThru()
Z0 = 50.0; Z0 = 50.0;
} }
void TwoThru::transformDatapoint(VNAData &p) void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p)
{ {
// correct measurement // correct measurement
if(points.size() > 0) { if(points.size() > 0) {
Tparam meas(p.S); Tparam meas(p.toSparam(1,2));
Tparam inv1, inv2; Tparam inv1, inv2;
if(p.frequency < points.front().freq) { if(p.frequency < points.front().freq) {
@ -49,7 +49,7 @@ void TwoThru::transformDatapoint(VNAData &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
p.S = Sparam(corrected); p.fromSparam(Sparam(corrected), 1, 2);
} }
} }
@ -99,7 +99,7 @@ void TwoThru::updateGUI()
} }
} }
void TwoThru::measurementCompleted(std::vector<VNAData> m) void TwoThru::measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m)
{ {
if (measuring2xthru) { if (measuring2xthru) {
measurements2xthru = m; measurements2xthru = m;
@ -210,7 +210,7 @@ void TwoThru::fromJSON(nlohmann::json j)
} }
} }
std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> data_2xthru) std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> 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
@ -229,10 +229,10 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
// ignore possible DC point // ignore possible DC point
continue; continue;
} }
S11.push_back(m.S.m11); S11.push_back(m.measurements["S11"]);
S12.push_back(m.S.m12); S12.push_back(m.measurements["S12"]);
S21.push_back(m.S.m21); S21.push_back(m.measurements["S21"]);
S22.push_back(m.S.m22); S22.push_back(m.measurements["S22"]);
f.push_back(m.frequency); f.push_back(m.frequency);
} }
auto n = f.size(); auto n = f.size();
@ -390,7 +390,7 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
return ret; return ret;
} }
std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> data_2xthru, std::vector<VNAData> data_fix_dut_fix, double z0) std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru, std::vector<VirtualDevice::VNAMeasurement> data_fix_dut_fix, double z0)
{ {
vector<Point> ret; vector<Point> ret;
@ -414,13 +414,13 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
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(d.S); p.push_back(d.toSparam(1, 2));
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(d.S); data_fix_dut_fix_Sparam.push_back(d.toSparam(1, 2));
} }
// grabbing S21 // grabbing S21
@ -663,9 +663,9 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
return ret; return ret;
} }
std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData> input) std::vector<VirtualDevice::VNAMeasurement> TwoThru::interpolateEvenFrequencySteps(std::vector<VirtualDevice::VNAMeasurement> input)
{ {
vector<VNAData> ret; vector<VirtualDevice::VNAMeasurement> 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;
@ -687,8 +687,8 @@ std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData>
// needs to interpolate // needs to interpolate
double freq = freqStep; double freq = freqStep;
while(freq <= input.back().frequency) { while(freq <= input.back().frequency) {
VNAData interp; VirtualDevice::VNAMeasurement interp;
auto it = lower_bound(input.begin(), input.end(), freq, [](const VNAData &lhs, const double f) -> bool { auto it = lower_bound(input.begin(), input.end(), freq, [](const VirtualDevice::VNAMeasurement &lhs, const double f) -> bool {
return lhs.frequency < f; return lhs.frequency < f;
}); });
if(it->frequency == freq) { if(it->frequency == freq) {
@ -699,12 +699,7 @@ std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData>
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.S.m11 = low.S.m11 * (1.0 - alpha) + high.S.m11 * alpha; interp = low.interpolateTo(high, alpha);
interp.S.m12 = low.S.m12 * (1.0 - alpha) + high.S.m12 * alpha;
interp.S.m21 = low.S.m21 * (1.0 - alpha) + high.S.m21 * alpha;
interp.S.m22 = low.S.m22 * (1.0 - alpha) + high.S.m22 * alpha;
interp.cdbm = low.cdbm * (1.0 - alpha) + high.cdbm * alpha;
interp.reference_impedance = low.reference_impedance * (1.0 - alpha) + high.reference_impedance * alpha;
} }
interp.pointNum = it->pointNum; interp.pointNum = it->pointNum;
interp.frequency = freq; interp.frequency = freq;

View File

@ -16,7 +16,7 @@ class TwoThru : public DeembeddingOption
public: public:
TwoThru(); TwoThru();
virtual void transformDatapoint(VNAData& p) override; virtual void transformDatapoint(VirtualDevice::VNAMeasurement& 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<VNAData> m) override; void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m) override;
private: private:
using Point = struct { using Point = struct {
double freq; double freq;
Tparam inverseP1, inverseP2; Tparam inverseP1, inverseP2;
}; };
static std::vector<VNAData> interpolateEvenFrequencySteps(std::vector<VNAData> input); static std::vector<VirtualDevice::VNAMeasurement> interpolateEvenFrequencySteps(std::vector<VirtualDevice::VNAMeasurement> input);
static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru); static std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru);
static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru, std::vector<VNAData> data_fix_dut_fix, double z0); static std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru, std::vector<VirtualDevice::VNAMeasurement> data_fix_dut_fix, double z0);
std::vector<VNAData> measurements2xthru; std::vector<VirtualDevice::VNAMeasurement> measurements2xthru;
std::vector<VNAData> measurementsDUT; std::vector<VirtualDevice::VNAMeasurement> measurementsDUT;
double Z0; double Z0;
std::vector<Point> points; std::vector<Point> points;
bool measuring2xthru; bool measuring2xthru;

View File

@ -10,11 +10,11 @@ class TraceWidgetVNA : public TraceWidget
public: public:
TraceWidgetVNA(TraceModel &model, Calibration &cal, Deembedding &deembed, QWidget *parent = nullptr); TraceWidgetVNA(TraceModel &model, Calibration &cal, Deembedding &deembed, QWidget *parent = nullptr);
protected slots: protected slots:
virtual void exportDialog() override {}; virtual void exportDialog() override {}
virtual void importDialog() override; virtual void importDialog() override;
protected: protected:
virtual Trace::LiveParameter defaultParameter() override {return Trace::LiveParameter::S11;}; virtual QString defaultParameter() override {return "S11";}
// These can optionally be applied when importing an s2p file // These can optionally be applied when importing an s2p file
Calibration &cal; Calibration &cal;
Deembedding &deembed; Deembedding &deembed;

View File

@ -1,31 +0,0 @@
#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;
time = (double) d.us / 1000000.0;
cdbm = d.cdbm;
pointNum = d.pointNum;
reference_impedance = 50.0;
}
double frequency;
double time;
int cdbm;
Sparam S;
unsigned int pointNum;
double reference_impedance;
};
#endif // VNADATA_H

View File

@ -12,7 +12,7 @@ void Averaging::reset(unsigned int points)
{ {
avg.clear(); avg.clear();
for(unsigned int i = 0;i<points;i++) { for(unsigned int i = 0;i<points;i++) {
avg.push_back(deque<array<complex<double>, 4>>()); avg.push_back(deque<vector<complex<double>>>());
} }
} }
@ -22,162 +22,41 @@ void Averaging::setAverages(unsigned int a)
reset(avg.size()); reset(avg.size());
} }
VNAData Averaging::process(VNAData d) VirtualDevice::VNAMeasurement Averaging::process(VirtualDevice::VNAMeasurement d)
{ {
auto S11 = d.S.m11; if(d.measurements.size() != numMeasurements) {
auto S12 = d.S.m12; numMeasurements = d.measurements.size();
auto S21 = d.S.m21; reset(avg.size());
auto S22 = d.S.m22;
if (d.pointNum == avg.size()) {
// add moving average entry
deque<array<complex<double>, 4>> deque;
avg.push_back(deque);
} }
if (d.pointNum < avg.size()) { vector<complex<double>> data;
// can compute average for(auto m : d.measurements) {
// get correct queue data.push_back(m.second);
auto deque = &avg[d.pointNum];
// add newest sample to queue
array<complex<double>, 4> sample = {S11, S12, S21, S22};
deque->push_back(sample);
if(deque->size() > averages) {
deque->pop_front();
} }
process(d.pointNum, data);
switch(mode) { int i=0;
case Mode::Mean: { for(auto &m : d.measurements) {
// calculate average m.second = data[i++];
complex<double> sum[4];
for(auto s : *deque) {
sum[0] += s[0];
sum[1] += s[1];
sum[2] += s[2];
sum[3] += s[3];
} }
S11 = sum[0] / (double) (deque->size());
S12 = sum[1] / (double) (deque->size());
S21 = sum[2] / (double) (deque->size());
S22 = sum[3] / (double) (deque->size());
}
break;
case Mode::Median: {
auto size = deque->size();
// create sorted arrays
std::vector<complex<double>> S11sorted, S12sorted, S21sorted, S22sorted;
S11sorted.reserve(size);
S12sorted.reserve(size);
S21sorted.reserve(size);
S22sorted.reserve(size);
auto comp = [=](const complex<double>&a, const complex<double>&b){
return abs(a) < abs(b);
};
for(auto d : *deque) {
S11sorted.insert(upper_bound(S11sorted.begin(), S11sorted.end(), d[0], comp), d[0]);
S12sorted.insert(upper_bound(S12sorted.begin(), S12sorted.end(), d[1], comp), d[1]);
S21sorted.insert(upper_bound(S21sorted.begin(), S21sorted.end(), d[2], comp), d[2]);
S22sorted.insert(upper_bound(S22sorted.begin(), S22sorted.end(), d[3], comp), d[3]);
}
if(size & 0x01) {
// odd number of samples
S11 = S11sorted[size / 2];
S12 = S12sorted[size / 2];
S21 = S21sorted[size / 2];
S22 = S22sorted[size / 2];
} else {
// even number, use average of middle samples
S11 = (S11sorted[size / 2 - 1] + S11sorted[size / 2]) / 2.0;
S12 = (S12sorted[size / 2 - 1] + S12sorted[size / 2]) / 2.0;
S21 = (S21sorted[size / 2 - 1] + S21sorted[size / 2]) / 2.0;
S22 = (S22sorted[size / 2 - 1] + S22sorted[size / 2]) / 2.0;
}
}
break;
}
}
d.S = Sparam(S11, S12, S21, S22);
return d; return d;
} }
VirtualDevice::SAMeasurement Averaging::process(VirtualDevice::SAMeasurement d) VirtualDevice::SAMeasurement Averaging::process(VirtualDevice::SAMeasurement d)
{ {
if(d.measurements.size() != numMeasurements) { if(d.measurements.size() != numMeasurements) {
numMeasurements = d.measurements.size();
reset(avg.size()); reset(avg.size());
} }
if (d.pointNum == avg.size()) { vector<complex<double>> data;
// add moving average entry
deque<vector<complex<double>>> deque;
avg.push_back(deque);
}
if (d.pointNum < avg.size()) {
// can compute average
// get correct queue
auto deque = &avg[d.pointNum];
// add newest sample to queue
vector<complex<double>> sample;
for(auto m : d.measurements) { for(auto m : d.measurements) {
sample.push_back(m.second); data.push_back(m.second);
} }
deque->push_back(sample); process(d.pointNum, data);
if(deque->size() > averages) { int i=0;
deque->pop_front();
}
deque<double> averagedResults;
switch(mode) {
case Mode::Mean: {
// calculate average
complex<double> sum[numMeasurements];
for(auto s : *deque) {
for(int i=0;i<numMeasurements;i++) {
sum[i] += s[i];
}
}
for(auto s : sum) {
averagedResults.push_back(abs(s / (double) (deque->size())));
}
}
break;
case Mode::Median: {
auto size = deque->size();
// create sorted vectors
array<vector<double>, numMeasurements> vectors;
for(auto &v : vectors) {
v.reserve(size);
}
for(auto d : *deque) {
for(auto &v : vectors) {
v.insert(upper_bound(v.begin(), v.end(), abs(d[0])), abs(d[0]));
}
}
if(size & 0x01) {
// odd number of samples
for(auto v : vectors) {
averagedResults.push_back(v[size / 2]);
}
} else {
// even number, use average of middle samples
for(auto v : vectors) {
averagedResults.push_back((v[size / 2 - 1] + v[size / 2]) / 2);
}
}
}
break;
}
for(auto &m : d.measurements) { for(auto &m : d.measurements) {
m.second = averagedResults.pop_front(); m.second = data[i++].real();
} }
}
return d; return d;
} }
@ -208,3 +87,80 @@ void Averaging::setMode(const Mode &value)
{ {
mode = value; mode = value;
} }
void Averaging::process(int pointNum, std::vector<std::complex<double>> &data)
{
if(data.size() != numMeasurements) {
numMeasurements = data.size();
reset(avg.size());
}
if (pointNum == avg.size()) {
// add moving average entry
deque<vector<complex<double>>> deque;
avg.push_back(deque);
}
if (pointNum < avg.size()) {
// can compute average
// get correct queue
auto deque = &avg[pointNum];
// add newest sample to queue
deque->push_back(data);
// remove oldest sample if required number of averages reached
if(deque->size() > averages) {
deque->pop_front();
}
std::deque<complex<double>> averagedResults = {};
switch(mode) {
case Mode::Mean: {
// calculate average
complex<double> sum[numMeasurements];
for(auto s : *deque) {
for(int i=0;i<numMeasurements;i++) {
sum[i] += s[i];
}
}
for(auto s : sum) {
averagedResults.push_back(abs(s / (double) (deque->size())));
}
}
break;
case Mode::Median: {
auto size = deque->size();
// create sorted vectors
vector<vector<complex<double>>> vectors(numMeasurements);
auto comp = [=](const complex<double>&a, const complex<double>&b){
return abs(a) < abs(b);
};
for(auto d : *deque) {
int i=0;
for(auto &v : vectors) {
v.insert(upper_bound(v.begin(), v.end(), d[i], comp), d[i]);
i++;
}
}
if(size & 0x01) {
// odd number of samples
for(auto v : vectors) {
averagedResults.push_back(v[size / 2]);
}
} else {
// even number, use average of middle samples
for(auto v : vectors) {
averagedResults.push_back((v[size / 2 - 1] + v[size / 2]) / 2.0);
}
}
}
break;
}
for(auto &m : data) {
m = averagedResults.front();
averagedResults.pop_front();
}
}
}

View File

@ -1,8 +1,7 @@
#ifndef AVERAGING_H #ifndef AVERAGING_H
#define AVERAGING_H #define AVERAGING_H
#include "Device/virtualdevice.h".h" #include "Device/virtualdevice.h"
#include "VNA/vnadata.h"
#include <array> #include <array>
#include <deque> #include <deque>
@ -19,7 +18,7 @@ public:
Averaging(); Averaging();
void reset(unsigned int points); void reset(unsigned int points);
void setAverages(unsigned int a); void setAverages(unsigned int a);
VNAData process(VNAData d); VirtualDevice::VNAMeasurement process(VirtualDevice::VNAMeasurement d);
VirtualDevice::SAMeasurement process(VirtualDevice::SAMeasurement d); VirtualDevice::SAMeasurement process(VirtualDevice::SAMeasurement 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
@ -31,6 +30,8 @@ public:
void setMode(const Mode &value); void setMode(const Mode &value);
private: private:
void process(int pointNum, std::vector<std::complex<double> > &data);
std::vector<std::deque<std::vector<std::complex<double>>>> avg; std::vector<std::deque<std::vector<std::complex<double>>>> avg;
int maxPoints; int maxPoints;
int numMeasurements; int numMeasurements;