wrapper work
This commit is contained in:
parent
f0a40417e4
commit
a530cea085
@ -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");
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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 \
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user