wrapper work
This commit is contained in:
parent
f0a40417e4
commit
a530cea085
@ -15,15 +15,15 @@ using namespace std;
|
||||
Calibration::Calibration()
|
||||
{
|
||||
// Create vectors for measurements
|
||||
measurements[Measurement::Port1Open].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port1Short].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port1Load].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port2Open].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port2Short].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port2Load].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Isolation].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Through].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Line].datapoints = vector<VNAData>();
|
||||
measurements[Measurement::Port1Open].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Port1Short].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Port1Load].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Port2Open].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Port2Short].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Port2Load].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Isolation].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Through].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
measurements[Measurement::Line].datapoints = vector<VirtualDevice::VNAMeasurement>();
|
||||
|
||||
type = Type::None;
|
||||
port1Standard = port2Standard = PortStandard::Male;
|
||||
@ -84,13 +84,13 @@ void Calibration::clearMeasurement(Calibration::Measurement type)
|
||||
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].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) {
|
||||
addMeasurement(t, d);
|
||||
@ -176,22 +176,22 @@ void Calibration::construct12TermPoints()
|
||||
Point p;
|
||||
p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency;
|
||||
// extract required complex reflection/transmission factors from datapoints
|
||||
auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11;
|
||||
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11;
|
||||
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11;
|
||||
auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22;
|
||||
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22;
|
||||
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22;
|
||||
auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
|
||||
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
|
||||
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"];
|
||||
auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
|
||||
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
|
||||
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"];
|
||||
auto S21_isolation = complex<double>(0,0);
|
||||
auto S12_isolation = complex<double>(0,0);
|
||||
if(isolation_measured) {
|
||||
S21_isolation = measurements[Measurement::Isolation].datapoints[i].S.m21;
|
||||
S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12;
|
||||
S21_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S21"];
|
||||
S12_isolation = measurements[Measurement::Isolation].datapoints[i].measurements["S12"];
|
||||
}
|
||||
auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11;
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
|
||||
auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22;
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
|
||||
auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"];
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
|
||||
auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"];
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
|
||||
|
||||
auto actual = kit.toSOLT(p.frequency, port1Standard == PortStandard::Male);
|
||||
// Forward calibration
|
||||
@ -232,9 +232,9 @@ void Calibration::constructPort1SOL()
|
||||
Point p;
|
||||
p.frequency = measurements[Measurement::Port1Open].datapoints[i].frequency;
|
||||
// extract required complex reflection/transmission factors from datapoints
|
||||
auto S11_open = measurements[Measurement::Port1Open].datapoints[i].S.m11;
|
||||
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].S.m11;
|
||||
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].S.m11;
|
||||
auto S11_open = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
|
||||
auto S11_short = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
|
||||
auto S11_load = measurements[Measurement::Port1Load].datapoints[i].measurements["S11"];
|
||||
// OSL port1
|
||||
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
|
||||
@ -262,9 +262,9 @@ void Calibration::constructPort2SOL()
|
||||
Point p;
|
||||
p.frequency = measurements[Measurement::Port2Open].datapoints[i].frequency;
|
||||
// extract required complex reflection/transmission factors from datapoints
|
||||
auto S22_open = measurements[Measurement::Port2Open].datapoints[i].S.m22;
|
||||
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].S.m22;
|
||||
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].S.m22;
|
||||
auto S22_open = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
|
||||
auto S22_short = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
|
||||
auto S22_load = measurements[Measurement::Port2Load].datapoints[i].measurements["S22"];
|
||||
// OSL port2
|
||||
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
|
||||
@ -292,8 +292,8 @@ void Calibration::constructTransmissionNormalization()
|
||||
Point p;
|
||||
p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
|
||||
// extract required complex reflection/transmission factors from datapoints
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
|
||||
auto actual = kit.toSOLT(p.frequency);
|
||||
p.fe10e32 = S21_through / actual.ThroughS21;
|
||||
p.re23e01 = S12_through / actual.ThroughS12;
|
||||
@ -329,24 +329,24 @@ void Calibration::constructTRL()
|
||||
p.frequency = measurements[Measurement::Through].datapoints[i].frequency;
|
||||
|
||||
// grab raw measurements
|
||||
auto S11_through = measurements[Measurement::Through].datapoints[i].S.m11;
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
|
||||
auto S22_through = measurements[Measurement::Through].datapoints[i].S.m22;
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
|
||||
auto S11_line = measurements[Measurement::Line].datapoints[i].S.m11;
|
||||
auto S21_line = measurements[Measurement::Line].datapoints[i].S.m21;
|
||||
auto S22_line = measurements[Measurement::Line].datapoints[i].S.m22;
|
||||
auto S12_line = measurements[Measurement::Line].datapoints[i].S.m12;
|
||||
auto S11_through = measurements[Measurement::Through].datapoints[i].measurements["S11"];
|
||||
auto S21_through = measurements[Measurement::Through].datapoints[i].measurements["S21"];
|
||||
auto S22_through = measurements[Measurement::Through].datapoints[i].measurements["S22"];
|
||||
auto S12_through = measurements[Measurement::Through].datapoints[i].measurements["S12"];
|
||||
auto S11_line = measurements[Measurement::Line].datapoints[i].measurements["S11"];
|
||||
auto S21_line = measurements[Measurement::Line].datapoints[i].measurements["S21"];
|
||||
auto S22_line = measurements[Measurement::Line].datapoints[i].measurements["S22"];
|
||||
auto S12_line = measurements[Measurement::Line].datapoints[i].measurements["S12"];
|
||||
auto trl = kit.toTRL(p.frequency);
|
||||
complex<double> S11_reflection, S22_reflection;
|
||||
if(trl.reflectionIsNegative) {
|
||||
// used short
|
||||
S11_reflection = measurements[Measurement::Port1Short].datapoints[i].S.m11;
|
||||
S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22;
|
||||
S11_reflection = measurements[Measurement::Port1Short].datapoints[i].measurements["S11"];
|
||||
S22_reflection = measurements[Measurement::Port2Short].datapoints[i].measurements["S22"];
|
||||
} else {
|
||||
// used open
|
||||
S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11;
|
||||
S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22;
|
||||
S11_reflection = measurements[Measurement::Port1Open].datapoints[i].measurements["S11"];
|
||||
S22_reflection = measurements[Measurement::Port2Open].datapoints[i].measurements["S22"];
|
||||
}
|
||||
// calculate TRL calibration
|
||||
// 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) {
|
||||
// No calibration data, do nothing
|
||||
return;
|
||||
}
|
||||
// Convert measurements to complex variables
|
||||
auto S11m = d.S.m11;
|
||||
auto S21m = d.S.m21;
|
||||
auto S22m = d.S.m22;
|
||||
auto S12m = d.S.m12;
|
||||
// Extract measurement S parameters
|
||||
auto S11m = d.measurements["S11"];
|
||||
auto S21m = d.measurements["S21"];
|
||||
auto S22m = d.measurements["S22"];
|
||||
auto S12m = d.measurements["S12"];
|
||||
|
||||
// find correct entry
|
||||
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;
|
||||
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)
|
||||
@ -733,15 +737,7 @@ std::vector<Trace *> Calibration::getMeasurementTraces()
|
||||
for(auto p : m.second.datapoints) {
|
||||
Trace::Data d;
|
||||
d.x = p.frequency;
|
||||
if(prefix == "S11") {
|
||||
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;
|
||||
}
|
||||
d.y = p.measurements[prefix];
|
||||
t->addData(d, TraceMath::DataType::Frequency);
|
||||
}
|
||||
traces.push_back(t);
|
||||
@ -803,19 +799,9 @@ bool Calibration::openFromFile(QString filename)
|
||||
file >> 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) {
|
||||
InformationBox::ShowError("File parsing error", e.what());
|
||||
qWarning() << "Calibration file parsing failed: " << e.what();
|
||||
return false;
|
||||
}
|
||||
InformationBox::ShowError("File parsing error", e.what());
|
||||
qWarning() << "Calibration file parsing failed: " << e.what();
|
||||
return false;
|
||||
}
|
||||
this->currentCalFile = filename; // if all ok, remember this
|
||||
|
||||
@ -909,14 +895,14 @@ nlohmann::json Calibration::toJSON()
|
||||
for(auto p : m.second.datapoints) {
|
||||
nlohmann::json j_point;
|
||||
j_point["frequency"] = p.frequency;
|
||||
j_point["S11_real"] = p.S.m11.real();
|
||||
j_point["S11_imag"] = p.S.m11.imag();
|
||||
j_point["S12_real"] = p.S.m12.real();
|
||||
j_point["S12_imag"] = p.S.m12.imag();
|
||||
j_point["S21_real"] = p.S.m21.real();
|
||||
j_point["S21_imag"] = p.S.m21.imag();
|
||||
j_point["S22_real"] = p.S.m22.real();
|
||||
j_point["S22_imag"] = p.S.m22.imag();
|
||||
j_point["S11_real"] = p.measurements["S11"].real();
|
||||
j_point["S11_imag"] = p.measurements["S11"].imag();
|
||||
j_point["S12_real"] = p.measurements["S12"].real();
|
||||
j_point["S12_imag"] = p.measurements["S12"].imag();
|
||||
j_point["S21_real"] = p.measurements["S21"].real();
|
||||
j_point["S21_imag"] = p.measurements["S21"].imag();
|
||||
j_point["S22_real"] = p.measurements["S22"].real();
|
||||
j_point["S22_imag"] = p.measurements["S22"].imag();
|
||||
j_points.push_back(j_point);
|
||||
}
|
||||
j_measurement["points"] = j_points;
|
||||
@ -957,13 +943,14 @@ void Calibration::fromJSON(nlohmann::json j)
|
||||
}
|
||||
int pointNum = 0;
|
||||
for(auto j_p : j_m["points"]) {
|
||||
VNAData p;
|
||||
VirtualDevice::VNAMeasurement p;
|
||||
p.pointNum = pointNum++;
|
||||
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.S.m12 = complex<double>(j_p.value("S12_real", 0.0), j_p.value("S12_imag", 0.0));
|
||||
p.S.m21 = complex<double>(j_p.value("S21_real", 0.0), j_p.value("S21_imag", 0.0));
|
||||
p.S.m22 = complex<double>(j_p.value("S22_real", 0.0), j_p.value("S22_imag", 0.0));
|
||||
p.Z0 = 50.0;
|
||||
p.measurements["S11"] = complex<double>(j_p.value("S11_real", 0.0), j_p.value("S11_imag", 0.0));
|
||||
p.measurements["S12"] = complex<double>(j_p.value("S12_real", 0.0), j_p.value("S12_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);
|
||||
}
|
||||
}
|
||||
@ -986,56 +973,6 @@ QString Calibration::getCurrentCalibrationFile(){
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::getCalibrationPoint(VNAData &d)
|
||||
Calibration::Point Calibration::getCalibrationPoint(VirtualDevice::VNAMeasurement &d)
|
||||
{
|
||||
if(!points.size()) {
|
||||
throw runtime_error("No calibration points available");
|
||||
|
@ -45,8 +45,8 @@ public:
|
||||
void clearMeasurements();
|
||||
void clearMeasurements(std::set<Measurement> types);
|
||||
void clearMeasurement(Measurement type);
|
||||
void addMeasurement(Measurement type, VNAData &d);
|
||||
void addMeasurements(std::set<Measurement> types, VNAData &d);
|
||||
void addMeasurement(Measurement type, VirtualDevice::VNAMeasurement &d);
|
||||
void addMeasurements(std::set<Measurement> types, VirtualDevice::VNAMeasurement &d);
|
||||
|
||||
enum class Type {
|
||||
Port1SOL,
|
||||
@ -63,7 +63,7 @@ public:
|
||||
bool constructErrorTerms(Type type);
|
||||
void resetErrorTerms();
|
||||
|
||||
void correctMeasurement(VNAData &d);
|
||||
void correctMeasurement(VirtualDevice::VNAMeasurement &d);
|
||||
void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
|
||||
|
||||
enum class InterpolationType {
|
||||
@ -141,7 +141,7 @@ private:
|
||||
// Reverse error terms
|
||||
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
|
||||
* 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 {
|
||||
public:
|
||||
QDateTime timestamp;
|
||||
std::vector<VNAData> datapoints;
|
||||
std::vector<VirtualDevice::VNAMeasurement> datapoints;
|
||||
};
|
||||
Type type;
|
||||
|
||||
|
@ -190,6 +190,7 @@ VirtualDevice::VirtualDevice(QString serial)
|
||||
connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){
|
||||
VNAMeasurement m;
|
||||
m.pointNum = res.pointNum;
|
||||
m.Z0 = 50.0;
|
||||
if(zerospan) {
|
||||
m.us = res.us;
|
||||
} else {
|
||||
@ -486,3 +487,48 @@ VirtualDevice *VirtualDevice::getConnected()
|
||||
{
|
||||
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
|
||||
|
||||
#include "device.h"
|
||||
#include "Tools/parameters.h"
|
||||
|
||||
#include <set>
|
||||
#include <complex>
|
||||
@ -66,6 +67,7 @@ public:
|
||||
class VNAMeasurement {
|
||||
public:
|
||||
int pointNum;
|
||||
double Z0;
|
||||
union {
|
||||
struct {
|
||||
// for non-zero span
|
||||
@ -78,6 +80,10 @@ public:
|
||||
};
|
||||
};
|
||||
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();
|
||||
|
@ -118,7 +118,6 @@ HEADERS += \
|
||||
VNA/Deembedding/twothru.h \
|
||||
VNA/tracewidgetvna.h \
|
||||
VNA/vna.h \
|
||||
VNA/vnadata.h \
|
||||
about.h \
|
||||
appwindow.h \
|
||||
averaging.h \
|
||||
|
@ -61,10 +61,10 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
|
||||
|
||||
// Create default traces
|
||||
auto tPort1 = new Trace("Port1", Qt::yellow);
|
||||
tPort1->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port1);
|
||||
tPort1->fromLivedata(Trace::LivedataType::Overwrite, "PORT1");
|
||||
traceModel.addTrace(tPort1);
|
||||
auto tPort2 = new Trace("Port2", Qt::blue);
|
||||
tPort2->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port2);
|
||||
tPort2->fromLivedata(Trace::LivedataType::Overwrite, "PORT2");
|
||||
traceModel.addTrace(tPort2);
|
||||
|
||||
auto traceXY = new TraceXYPlot(traceModel);
|
||||
|
@ -12,7 +12,7 @@ protected slots:
|
||||
virtual void importDialog() override;
|
||||
|
||||
protected:
|
||||
virtual Trace::LiveParameter defaultParameter() override {return Trace::LiveParameter::Port1;};
|
||||
virtual QString defaultParameter() override {return "PORT1";}
|
||||
};
|
||||
|
||||
#endif // TRACEWIDGETSA_H
|
||||
|
@ -184,7 +184,7 @@ std::vector<Marker::Format> Marker::applicableFormats()
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::PeakTable:
|
||||
if(Trace::isSAParamater(parentTrace->liveParameter())) {
|
||||
if(Trace::isSAParameter(parentTrace->liveParameter())) {
|
||||
ret.push_back(Format::dBm);
|
||||
ret.push_back(Format::dBuV);
|
||||
} else {
|
||||
@ -217,7 +217,7 @@ std::vector<Marker::Format> Marker::applicableFormats()
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::PeakTable:
|
||||
if(Trace::isSAParamater(parentTrace->liveParameter())) {
|
||||
if(Trace::isSAParameter(parentTrace->liveParameter())) {
|
||||
ret.push_back(Format::dBm);
|
||||
ret.push_back(Format::dBuV);
|
||||
} else {
|
||||
@ -871,20 +871,13 @@ std::set<Marker::Type> Marker::getSupportedTypes()
|
||||
supported.insert(Type::Bandpass);
|
||||
}
|
||||
if(parentTrace->getSource() == Trace::Source::Live) {
|
||||
switch(parentTrace->liveParameter()) {
|
||||
case Trace::LiveParameter::S11:
|
||||
case Trace::LiveParameter::S12:
|
||||
case Trace::LiveParameter::S21:
|
||||
case Trace::LiveParameter::S22:
|
||||
if(Trace::isVNAParameter(parentTrace->liveParameter())) {
|
||||
// no special marker types for VNA yet
|
||||
break;
|
||||
case Trace::LiveParameter::Port1:
|
||||
case Trace::LiveParameter::Port2:
|
||||
}
|
||||
if(Trace::isSAParameter(parentTrace->liveParameter())) {
|
||||
// special SA marker types
|
||||
supported.insert(Type::TOI);
|
||||
supported.insert(Type::PhaseNoise);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -16,7 +16,7 @@
|
||||
using namespace std;
|
||||
using namespace mup;
|
||||
|
||||
Trace::Trace(QString name, QColor color, LiveParameter live)
|
||||
Trace::Trace(QString name, QColor color, QString live)
|
||||
: model(nullptr),
|
||||
_name(name),
|
||||
_color(color),
|
||||
@ -25,7 +25,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
|
||||
hashSet(false),
|
||||
JSONskipHash(false),
|
||||
_liveType(LivedataType::Overwrite),
|
||||
_liveParam(live),
|
||||
liveParam(live),
|
||||
vFactor(0.66),
|
||||
reflection(true),
|
||||
visible(true),
|
||||
@ -130,12 +130,12 @@ void Trace::addData(const Trace::Data& d, DataType domain, double reference_impe
|
||||
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.valid = true;
|
||||
auto domain = DataType::Frequency;
|
||||
if (s.f_start == s.f_stop) {
|
||||
if (s.freqStart == s.freqStop) {
|
||||
// in zerospan mode
|
||||
domain = DataType::TimeZeroSpan;
|
||||
}
|
||||
@ -143,7 +143,7 @@ void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettin
|
||||
}
|
||||
|
||||
void Trace::setName(QString name) {
|
||||
_name = name;
|
||||
name = name;
|
||||
emit nameChanged();
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter)
|
||||
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();
|
||||
S12.clear();
|
||||
@ -267,25 +267,26 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c
|
||||
S22.clear();
|
||||
for(auto d : data) {
|
||||
Trace::Data td;
|
||||
auto S = d.toSparam(1, 2);
|
||||
td.x = d.frequency;
|
||||
td.y = d.S.m11;
|
||||
td.y = S.m11;
|
||||
S11.addData(td, DataType::Frequency);
|
||||
td.y = d.S.m12;
|
||||
td.y = S.m12;
|
||||
S12.addData(td, DataType::Frequency);
|
||||
td.y = d.S.m21;
|
||||
td.y = S.m21;
|
||||
S21.addData(td, DataType::Frequency);
|
||||
td.y = d.S.m22;
|
||||
td.y = S.m22;
|
||||
S22.addData(td, DataType::Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
void Trace::fromLivedata(Trace::LivedataType type, LiveParameter param)
|
||||
void Trace::fromLivedata(Trace::LivedataType type, QString param)
|
||||
{
|
||||
clearMathSources();
|
||||
source = Source::Live;
|
||||
_liveType = type;
|
||||
_liveParam = param;
|
||||
if(param == LiveParameter::S11 || param == LiveParameter::S22) {
|
||||
liveParam = param;
|
||||
if(param.length() == 3 && param[0] == 'S' && param[1].isDigit() && param[1] == param[2]) {
|
||||
reflection = true;
|
||||
} else {
|
||||
reflection = false;
|
||||
@ -305,8 +306,8 @@ void Trace::fromMath()
|
||||
}
|
||||
|
||||
void Trace::setColor(QColor color) {
|
||||
if(_color != color) {
|
||||
_color = color;
|
||||
if(color != color) {
|
||||
color = color;
|
||||
emit colorChanged(this);
|
||||
}
|
||||
}
|
||||
@ -637,6 +638,16 @@ const std::vector<Trace::MathInfo>& Trace::getMathOperations() const
|
||||
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()
|
||||
{
|
||||
return vFactor;
|
||||
@ -678,7 +689,7 @@ nlohmann::json Trace::toJSON()
|
||||
switch(source) {
|
||||
case Source::Live:
|
||||
j["type"] = "Live";
|
||||
j["parameter"] = _liveParam;
|
||||
j["parameter"] = liveParam.toStdString();
|
||||
j["livetype"] = _liveType;
|
||||
j["paused"] = paused;
|
||||
break;
|
||||
@ -737,7 +748,7 @@ void Trace::fromJSON(nlohmann::json j)
|
||||
visible = j.value("visible", true);
|
||||
auto type = QString::fromStdString(j.value("type", "Live"));
|
||||
if(type == "Live") {
|
||||
_liveParam = j.value("parameter", LiveParameter::S11);
|
||||
liveParam = QString::fromStdString(j.value("parameter", "S11"));
|
||||
_liveType = j.value("livetype", LivedataType::Overwrite);
|
||||
paused = j.value("paused", false);
|
||||
} else if(type == "Touchstone" || type == "File") {
|
||||
@ -862,9 +873,9 @@ std::vector<Trace *> Trace::createFromCSV(CSV &csv)
|
||||
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
|
||||
unsigned int samples = S11.size();
|
||||
@ -906,15 +917,11 @@ std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S1
|
||||
|
||||
// Checks passed, assemble datapoints
|
||||
for(unsigned int i=0;i<samples;i++) {
|
||||
Protocol::Datapoint d;
|
||||
d.real_S11 = real(S11.sample(i).y);
|
||||
d.imag_S11 = imag(S11.sample(i).y);
|
||||
d.real_S12 = real(S12.sample(i).y);
|
||||
d.imag_S12 = imag(S12.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);
|
||||
VirtualDevice::VNAMeasurement d;
|
||||
d.measurements["S11"] = S11.sample(i).y;
|
||||
d.measurements["S12"] = S12.sample(i).y;
|
||||
d.measurements["S21"] = S21.sample(i).y;
|
||||
d.measurements["S22"] = S22.sample(i).y;
|
||||
d.pointNum = i;
|
||||
d.frequency = freqs[i];
|
||||
ret.push_back(d);
|
||||
@ -922,70 +929,6 @@ std::vector<VNAData> Trace::assembleDatapoints(const Trace &S11, const Trace &S1
|
||||
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)
|
||||
{
|
||||
s = s.toUpper();
|
||||
@ -1365,7 +1308,7 @@ unsigned int Trace::getFileParameter() const
|
||||
|
||||
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
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
@ -3,10 +3,9 @@
|
||||
|
||||
#include "touchstone.h"
|
||||
#include "csv.h"
|
||||
#include "Device/device.h"
|
||||
#include "Device/virtualdevice.h"
|
||||
#include "Math/tracemath.h"
|
||||
#include "Tools/parameters.h"
|
||||
#include "VNA/vnadata.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <complex>
|
||||
@ -33,17 +32,7 @@ public:
|
||||
Last,
|
||||
};
|
||||
|
||||
enum class LiveParameter {
|
||||
S11,
|
||||
S12,
|
||||
S21,
|
||||
S22,
|
||||
Port1,
|
||||
Port2,
|
||||
Invalid,
|
||||
};
|
||||
|
||||
Trace(QString name = QString(), QColor color = Qt::darkYellow, LiveParameter live = LiveParameter::S11);
|
||||
Trace(QString name = QString(), QColor color = Qt::darkYellow, QString live = "S11");
|
||||
~Trace();
|
||||
|
||||
enum class LivedataType {
|
||||
@ -55,13 +44,13 @@ public:
|
||||
|
||||
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, const Protocol::SpectrumAnalyzerSettings& s, int index = -1);
|
||||
void addData(const Data& d, const VirtualDevice::SASettings &s, int index = -1);
|
||||
void setName(QString name);
|
||||
void setVelocityFactor(double v);
|
||||
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)
|
||||
static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data);
|
||||
void fromLivedata(LivedataType type, LiveParameter param);
|
||||
static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VirtualDevice::VNAMeasurement> &data);
|
||||
void fromLivedata(LivedataType type, QString param);
|
||||
void fromMath();
|
||||
QString name() { return _name; }
|
||||
QColor color() { return _color; }
|
||||
@ -72,7 +61,7 @@ public:
|
||||
bool isPaused();
|
||||
Source getSource() {return source;}
|
||||
bool isReflection();
|
||||
LiveParameter liveParameter() { return _liveParam; }
|
||||
QString liveParameter() { return liveParam; }
|
||||
LivedataType liveType() { return _liveType; }
|
||||
TraceMath::DataType outputType() const { return lastMath->getDataType(); }
|
||||
unsigned int size() const;
|
||||
@ -125,6 +114,9 @@ public:
|
||||
};
|
||||
const std::vector<MathInfo>& getMathOperations() const;
|
||||
|
||||
static bool isSAParameter(QString param);
|
||||
static bool isVNAParameter(QString param);
|
||||
|
||||
double velocityFactor();
|
||||
double timeToDistance(double time);
|
||||
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,
|
||||
// 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 LiveParameter ParameterFromString(QString s);
|
||||
static QString ParameterToString(LiveParameter p);
|
||||
static bool isVNAParameter(LiveParameter p);
|
||||
static bool isSAParamater(LiveParameter p);
|
||||
static std::vector<VirtualDevice::VNAMeasurement> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22);
|
||||
|
||||
static LivedataType TypeFromString(QString s);
|
||||
static QString TypeToString(LivedataType t);
|
||||
@ -247,7 +234,7 @@ private:
|
||||
|
||||
// Members for when source == Source::Live
|
||||
LivedataType _liveType;
|
||||
LiveParameter _liveParam;
|
||||
QString liveParam;
|
||||
|
||||
// Members for when source == Source::File
|
||||
QString filename;
|
||||
@ -273,7 +260,7 @@ private:
|
||||
std::set<Marker*> markers;
|
||||
struct {
|
||||
union {
|
||||
Protocol::SpectrumAnalyzerSettings SA;
|
||||
VirtualDevice::SASettings SA;
|
||||
};
|
||||
bool valid;
|
||||
} settings;
|
||||
|
@ -124,25 +124,15 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
|
||||
}
|
||||
|
||||
VNAtrace = Trace::isVNAParameter(t.liveParameter());
|
||||
if(VNAtrace) {
|
||||
ui->CLiveParam->addItem("S11");
|
||||
ui->CLiveParam->addItem("S12");
|
||||
ui->CLiveParam->addItem("S21");
|
||||
ui->CLiveParam->addItem("S22");
|
||||
} else {
|
||||
ui->CLiveParam->addItem("Port 1");
|
||||
ui->CLiveParam->addItem("Port 2");
|
||||
if(VirtualDevice::getConnected()) {
|
||||
if(VNAtrace) {
|
||||
ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableVNAMeasurements());
|
||||
} else {
|
||||
ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableSAMeasurements());
|
||||
}
|
||||
}
|
||||
|
||||
switch(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;
|
||||
}
|
||||
ui->CLiveParam->setCurrentText(t.liveParameter());
|
||||
|
||||
connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateTouchstoneFileStatus);
|
||||
connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateTouchstoneFileStatus);
|
||||
@ -354,26 +344,12 @@ void TraceEditDialog::on_buttonBox_accepted()
|
||||
}
|
||||
} else if(ui->bLive->isChecked()) {
|
||||
Trace::LivedataType type = Trace::LivedataType::Overwrite;
|
||||
Trace::LiveParameter param = Trace::LiveParameter::S11;
|
||||
switch(ui->CLiveType->currentIndex()) {
|
||||
case 0: type = Trace::LivedataType::Overwrite; break;
|
||||
case 1: type = Trace::LivedataType::MaxHold; break;
|
||||
case 2: type = Trace::LivedataType::MinHold; break;
|
||||
}
|
||||
if(VNAtrace) {
|
||||
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);
|
||||
trace.fromLivedata(type, ui->CLiveParam->currentText());
|
||||
} else {
|
||||
// math operation trace
|
||||
trace.fromMath();
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "tracemodel.h"
|
||||
#include "tracemodel.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QDebug>
|
||||
@ -161,9 +161,7 @@ bool TraceModel::PortExcitationRequired(int port)
|
||||
if(t->getSource() == Trace::Source::Live && !t->isPaused()) {
|
||||
// this trace needs measurements from VNA, check if port has to be excited for its measurement
|
||||
auto param = t->liveParameter();
|
||||
if(port == 1 && (param == Trace::LiveParameter::S11 || param == Trace::LiveParameter::S21)) {
|
||||
return true;
|
||||
} else if(port == 2 && (param == Trace::LiveParameter::S22 || param == Trace::LiveParameter::S12)) {
|
||||
if(port == QString(param[2]).toInt()) {
|
||||
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;
|
||||
for(auto t : traces) {
|
||||
@ -226,31 +224,28 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
|
||||
td.x = d.frequency;
|
||||
break;
|
||||
case TraceMath::DataType::Power:
|
||||
td.x = (double) d.cdbm / 100.0;
|
||||
td.x = d.dBm;
|
||||
break;
|
||||
case TraceMath::DataType::TimeZeroSpan:
|
||||
td.x = d.time;
|
||||
td.x = d.us;
|
||||
index = d.pointNum;
|
||||
break;
|
||||
default:
|
||||
// invalid type, can not add
|
||||
return;
|
||||
}
|
||||
switch(t->liveParameter()) {
|
||||
case Trace::LiveParameter::S11: td.y = d.S.m11; break;
|
||||
case Trace::LiveParameter::S12: td.y = d.S.m12; break;
|
||||
case Trace::LiveParameter::S21: td.y = d.S.m21; break;
|
||||
case Trace::LiveParameter::S22: td.y = d.S.m22; break;
|
||||
default:
|
||||
// not a VNA trace, skip
|
||||
if(d.measurements.count(t->liveParameter())) {
|
||||
td.y = d.measurements.at(t->liveParameter());
|
||||
} else {
|
||||
// parameter not included in data, skip
|
||||
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;
|
||||
for(auto t : traces) {
|
||||
@ -264,11 +259,10 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
|
||||
} else {
|
||||
td.x = d.frequency;
|
||||
}
|
||||
switch(t->liveParameter()) {
|
||||
case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 0); break;
|
||||
case Trace::LiveParameter::Port2: td.y = complex<double>(d.port2, 0); break;
|
||||
default:
|
||||
// not a SA trace, skip
|
||||
if(d.measurements.count(t->liveParameter())) {
|
||||
td.y = d.measurements.at(t->liveParameter());
|
||||
} else {
|
||||
// parameter not included in data, skip
|
||||
continue;
|
||||
}
|
||||
t->addData(td, settings, index);
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "Device/device.h"
|
||||
#include "savable.h"
|
||||
#include "trace.h"
|
||||
#include "VNA/vnadata.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <vector>
|
||||
@ -65,8 +64,8 @@ signals:
|
||||
|
||||
public slots:
|
||||
void clearLiveData();
|
||||
void addVNAData(const VNAData& d, TraceMath::DataType datatype);
|
||||
void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings);
|
||||
void addVNAData(const VirtualDevice::VNAMeasurement& d, TraceMath::DataType datatype);
|
||||
void addSAData(const VirtualDevice::SAMeasurement &d, const VirtualDevice::SASettings &settings);
|
||||
|
||||
private:
|
||||
DataSource source;
|
||||
|
@ -180,7 +180,7 @@ void TraceWidget::SetupSCPI()
|
||||
};
|
||||
|
||||
auto createStringFromData = [](Trace *t, const Trace::Data &d) -> QString {
|
||||
if(Trace::isSAParamater(t->liveParameter())) {
|
||||
if(Trace::isSAParameter(t->liveParameter())) {
|
||||
if(std::isnan(d.x)) {
|
||||
return "NaN";
|
||||
}
|
||||
@ -373,7 +373,7 @@ void TraceWidget::SetupSCPI()
|
||||
if(!t || params.size() < 2) {
|
||||
return "ERROR";
|
||||
}
|
||||
auto newparam = Trace::ParameterFromString(params[1]);
|
||||
auto newparam = params[1];
|
||||
if((Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))
|
||||
|| (Trace::isVNAParameter(t->liveParameter()) && Trace::isVNAParameter(newparam))) {
|
||||
t->fromLivedata(t->liveType(), newparam);
|
||||
@ -386,7 +386,7 @@ void TraceWidget::SetupSCPI()
|
||||
if(!t) {
|
||||
return "ERROR";
|
||||
}
|
||||
return Trace::ParameterToString(t->liveParameter());
|
||||
return t->liveParameter();
|
||||
}));
|
||||
add(new SCPICommand("TYPE", [=](QStringList params) -> QString {
|
||||
auto t = findTrace(params);
|
||||
|
@ -31,7 +31,7 @@ protected:
|
||||
void SetupSCPI();
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
virtual Trace::LiveParameter defaultParameter() = 0;
|
||||
virtual QString defaultParameter() = 0;
|
||||
QPoint dragStartPosition;
|
||||
Trace *dragTrace;
|
||||
Ui::TraceWidget *ui;
|
||||
|
@ -76,31 +76,26 @@ void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22)
|
||||
auto S21 = t[2];
|
||||
auto S22 = t[3];
|
||||
for(unsigned int i=0;i<traceChooser->getPoints();i++) {
|
||||
Protocol::Datapoint p;
|
||||
VirtualDevice::VNAMeasurement p;
|
||||
p.pointNum = i;
|
||||
p.Z0 = 0;
|
||||
p.dBm = 0;
|
||||
Sparam S;
|
||||
if(S11) {
|
||||
auto sample = S11->sample(i);
|
||||
p.imag_S11 = sample.y.imag();
|
||||
p.real_S11 = sample.y.real();
|
||||
p.frequency = sample.x;
|
||||
S.m11 = S11->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S12) {
|
||||
auto sample = S12->sample(i);
|
||||
p.imag_S12 = sample.y.imag();
|
||||
p.real_S12 = sample.y.real();
|
||||
p.frequency = sample.x;
|
||||
S.m12 = S12->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S21) {
|
||||
auto sample = S21->sample(i);
|
||||
p.imag_S21 = sample.y.imag();
|
||||
p.real_S21 = sample.y.real();
|
||||
p.frequency = sample.x;
|
||||
S.m21 = S21->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S22) {
|
||||
auto sample = S22->sample(i);
|
||||
p.imag_S22 = sample.y.imag();
|
||||
p.real_S22 = sample.y.real();
|
||||
p.frequency = sample.x;
|
||||
S.m22 = S22->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
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
|
||||
static unsigned lastPointNum;
|
||||
|
@ -17,15 +17,15 @@ class Deembedding : public QObject, public Savable
|
||||
Q_OBJECT
|
||||
public:
|
||||
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 removeOption(unsigned int index);
|
||||
void addOption(DeembeddingOption* option);
|
||||
void swapOptions(unsigned int index);
|
||||
std::vector<DeembeddingOption*>& getOptions() {return options;};
|
||||
std::vector<DeembeddingOption*>& getOptions() {return options;}
|
||||
nlohmann::json toJSON() override;
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
public slots:
|
||||
@ -42,7 +42,7 @@ private:
|
||||
TraceModel &tm;
|
||||
|
||||
bool measuring;
|
||||
std::vector<VNAData> measurements;
|
||||
std::vector<VirtualDevice::VNAMeasurement> measurements;
|
||||
QDialog *measurementDialog;
|
||||
Ui_DeembeddingMeasurementDialog *measurementUI;
|
||||
|
||||
|
@ -23,12 +23,12 @@ public:
|
||||
static DeembeddingOption *create(Type type);
|
||||
static QString getName(Type type);
|
||||
|
||||
virtual void transformDatapoint(VNAData &p) = 0;
|
||||
virtual void edit(){};
|
||||
virtual void transformDatapoint(VirtualDevice::VNAMeasurement &p) = 0;
|
||||
virtual void edit(){}
|
||||
virtual Type getType() = 0;
|
||||
|
||||
public slots:
|
||||
virtual void measurementCompleted(std::vector<VNAData> m){Q_UNUSED(m)};
|
||||
virtual void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m){Q_UNUSED(m)}
|
||||
signals:
|
||||
// Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself
|
||||
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.reference_impedance = impedance;
|
||||
//p.S = Sparam(ABCDparam(p.S, p.Z0), impedance);
|
||||
// TODO
|
||||
p.Z0 = impedance;
|
||||
}
|
||||
|
||||
nlohmann::json ImpedanceRenormalization::toJSON()
|
||||
|
@ -13,7 +13,7 @@ class ImpedanceRenormalization : public DeembeddingOption
|
||||
public:
|
||||
ImpedanceRenormalization();
|
||||
|
||||
void transformDatapoint(VNAData &p) override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement &p) override;
|
||||
Type getType() override { return Type::ImpedanceRenormalization;}
|
||||
nlohmann::json toJSON() override;
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
|
@ -26,10 +26,10 @@ MatchingNetwork::MatchingNetwork()
|
||||
addNetwork = true;
|
||||
}
|
||||
|
||||
void MatchingNetwork::transformDatapoint(VNAData &p)
|
||||
void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p)
|
||||
{
|
||||
auto S = p.S;
|
||||
auto measurement = ABCDparam(S, p.reference_impedance);
|
||||
auto S = p.toSparam(1, 2);
|
||||
auto measurement = ABCDparam(S, p.Z0);
|
||||
if(matching.count(p.frequency) == 0) {
|
||||
// this point is not calculated yet
|
||||
MatchingPoint m;
|
||||
@ -53,7 +53,7 @@ void MatchingNetwork::transformDatapoint(VNAData &p)
|
||||
// at this point the map contains the matching network effect
|
||||
auto m = matching[p.frequency];
|
||||
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()
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
|
||||
// DeembeddingOption interface
|
||||
public:
|
||||
void transformDatapoint(VNAData &p) override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement &p) override;
|
||||
void edit() override;
|
||||
Type getType() override {return Type::MatchingNetwork;}
|
||||
nlohmann::json toJSON() override;
|
||||
|
@ -29,7 +29,7 @@ PortExtension::PortExtension()
|
||||
kit = nullptr;
|
||||
}
|
||||
|
||||
void PortExtension::transformDatapoint(VNAData &d)
|
||||
void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d)
|
||||
{
|
||||
if(port1.enabled || port2.enabled) {
|
||||
if(port1.enabled) {
|
||||
@ -41,9 +41,9 @@ void PortExtension::transformDatapoint(VNAData &d)
|
||||
// convert from db to factor
|
||||
auto att = pow(10.0, -db_attennuation / 20.0);
|
||||
auto correction = polar<double>(att, phase);
|
||||
d.S.m11 /= correction * correction;
|
||||
d.S.m21 /= correction;
|
||||
d.S.m12 /= correction;
|
||||
d.measurements["S11"] /= correction * correction;
|
||||
d.measurements["S21"] /= correction;
|
||||
d.measurements["S12"] /= correction;
|
||||
}
|
||||
if(port2.enabled) {
|
||||
auto phase = -2 * M_PI * port2.delay * d.frequency;
|
||||
@ -54,9 +54,9 @@ void PortExtension::transformDatapoint(VNAData &d)
|
||||
// convert from db to factor
|
||||
auto att = pow(10.0, -db_attennuation / 20.0);
|
||||
auto correction = polar<double>(att, phase);
|
||||
d.S.m22 /= correction * correction;
|
||||
d.S.m21 /= correction;
|
||||
d.S.m12 /= correction;
|
||||
d.measurements["S22"] /= correction * correction;
|
||||
d.measurements["S21"] /= 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) {
|
||||
double last_phase = 0.0;
|
||||
@ -205,9 +205,9 @@ void PortExtension::measurementCompleted(std::vector<VNAData> m)
|
||||
// grab correct measurement
|
||||
complex<double> reflection;
|
||||
if(isPort1) {
|
||||
reflection = p.S.m11;
|
||||
reflection = p.measurements["S11"];
|
||||
} else {
|
||||
reflection = p.S.m22;
|
||||
reflection = p.measurements["S22"];
|
||||
}
|
||||
// remove calkit if specified
|
||||
if(!isIdeal) {
|
||||
|
@ -18,14 +18,14 @@ class PortExtension : public DeembeddingOption
|
||||
Q_OBJECT
|
||||
public:
|
||||
PortExtension();
|
||||
void transformDatapoint(VNAData& d) override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement& d) override;
|
||||
void setCalkit(Calkit *kit);
|
||||
Type getType() override {return Type::PortExtension;}
|
||||
nlohmann::json toJSON() override;
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
public slots:
|
||||
void edit() override;
|
||||
void measurementCompleted(std::vector<VNAData> m) override;
|
||||
void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m) override;
|
||||
|
||||
private:
|
||||
void startMeasurement();
|
||||
|
@ -15,11 +15,11 @@ TwoThru::TwoThru()
|
||||
Z0 = 50.0;
|
||||
}
|
||||
|
||||
void TwoThru::transformDatapoint(VNAData &p)
|
||||
void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p)
|
||||
{
|
||||
// correct measurement
|
||||
if(points.size() > 0) {
|
||||
Tparam meas(p.S);
|
||||
Tparam meas(p.toSparam(1,2));
|
||||
|
||||
Tparam inv1, inv2;
|
||||
if(p.frequency < points.front().freq) {
|
||||
@ -49,7 +49,7 @@ void TwoThru::transformDatapoint(VNAData &p)
|
||||
// perform correction
|
||||
Tparam corrected = inv1*meas*inv2;
|
||||
// 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) {
|
||||
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
|
||||
// create vectors of S parameters
|
||||
@ -229,10 +229,10 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
|
||||
// ignore possible DC point
|
||||
continue;
|
||||
}
|
||||
S11.push_back(m.S.m11);
|
||||
S12.push_back(m.S.m12);
|
||||
S21.push_back(m.S.m21);
|
||||
S22.push_back(m.S.m22);
|
||||
S11.push_back(m.measurements["S11"]);
|
||||
S12.push_back(m.measurements["S12"]);
|
||||
S21.push_back(m.measurements["S21"]);
|
||||
S22.push_back(m.measurements["S22"]);
|
||||
f.push_back(m.frequency);
|
||||
}
|
||||
auto n = f.size();
|
||||
@ -390,7 +390,7 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
|
||||
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;
|
||||
|
||||
@ -414,13 +414,13 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
|
||||
vector<Sparam> p;
|
||||
vector<double> f;
|
||||
for(auto d : data_2xthru) {
|
||||
p.push_back(d.S);
|
||||
p.push_back(d.toSparam(1, 2));
|
||||
f.push_back(d.frequency);
|
||||
}
|
||||
auto data_2xthru_Sparam = p;
|
||||
vector<Sparam> data_fix_dut_fix_Sparam;
|
||||
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
|
||||
@ -663,9 +663,9 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VNAData> da
|
||||
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) {
|
||||
int size = input.size();
|
||||
double freqStep = 0.0;
|
||||
@ -687,8 +687,8 @@ std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData>
|
||||
// needs to interpolate
|
||||
double freq = freqStep;
|
||||
while(freq <= input.back().frequency) {
|
||||
VNAData interp;
|
||||
auto it = lower_bound(input.begin(), input.end(), freq, [](const VNAData &lhs, const double f) -> bool {
|
||||
VirtualDevice::VNAMeasurement interp;
|
||||
auto it = lower_bound(input.begin(), input.end(), freq, [](const VirtualDevice::VNAMeasurement &lhs, const double f) -> bool {
|
||||
return lhs.frequency < f;
|
||||
});
|
||||
if(it->frequency == freq) {
|
||||
@ -699,12 +699,7 @@ std::vector<VNAData> TwoThru::interpolateEvenFrequencySteps(std::vector<VNAData>
|
||||
it--;
|
||||
auto low = *it;
|
||||
double alpha = (freq - low.frequency) / (high.frequency - low.frequency);
|
||||
interp.S.m11 = low.S.m11 * (1.0 - alpha) + high.S.m11 * 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 = low.interpolateTo(high, alpha);
|
||||
}
|
||||
interp.pointNum = it->pointNum;
|
||||
interp.frequency = freq;
|
||||
|
@ -16,7 +16,7 @@ class TwoThru : public DeembeddingOption
|
||||
public:
|
||||
TwoThru();
|
||||
|
||||
virtual void transformDatapoint(VNAData& p) override;
|
||||
virtual void transformDatapoint(VirtualDevice::VNAMeasurement& p) override;
|
||||
virtual void edit() override;
|
||||
virtual Type getType() override {return DeembeddingOption::Type::TwoThru;}
|
||||
nlohmann::json toJSON() override;
|
||||
@ -25,19 +25,19 @@ public:
|
||||
private slots:
|
||||
void startMeasurement();
|
||||
void updateGUI();
|
||||
void measurementCompleted(std::vector<VNAData> m) override;
|
||||
void measurementCompleted(std::vector<VirtualDevice::VNAMeasurement> m) override;
|
||||
private:
|
||||
using Point = struct {
|
||||
double freq;
|
||||
Tparam inverseP1, inverseP2;
|
||||
};
|
||||
|
||||
static std::vector<VNAData> interpolateEvenFrequencySteps(std::vector<VNAData> input);
|
||||
static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru);
|
||||
static std::vector<Point> calculateErrorBoxes(std::vector<VNAData> data_2xthru, std::vector<VNAData> data_fix_dut_fix, double z0);
|
||||
static std::vector<VirtualDevice::VNAMeasurement> interpolateEvenFrequencySteps(std::vector<VirtualDevice::VNAMeasurement> input);
|
||||
static std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru);
|
||||
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<VNAData> measurementsDUT;
|
||||
std::vector<VirtualDevice::VNAMeasurement> measurements2xthru;
|
||||
std::vector<VirtualDevice::VNAMeasurement> measurementsDUT;
|
||||
double Z0;
|
||||
std::vector<Point> points;
|
||||
bool measuring2xthru;
|
||||
|
@ -10,11 +10,11 @@ class TraceWidgetVNA : public TraceWidget
|
||||
public:
|
||||
TraceWidgetVNA(TraceModel &model, Calibration &cal, Deembedding &deembed, QWidget *parent = nullptr);
|
||||
protected slots:
|
||||
virtual void exportDialog() override {};
|
||||
virtual void exportDialog() override {}
|
||||
virtual void importDialog() override;
|
||||
|
||||
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
|
||||
Calibration &cal;
|
||||
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();
|
||||
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());
|
||||
}
|
||||
|
||||
VNAData Averaging::process(VNAData d)
|
||||
VirtualDevice::VNAMeasurement Averaging::process(VirtualDevice::VNAMeasurement d)
|
||||
{
|
||||
auto S11 = d.S.m11;
|
||||
auto S12 = d.S.m12;
|
||||
auto S21 = d.S.m21;
|
||||
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.measurements.size() != numMeasurements) {
|
||||
numMeasurements = d.measurements.size();
|
||||
reset(avg.size());
|
||||
}
|
||||
|
||||
if (d.pointNum < avg.size()) {
|
||||
// can compute average
|
||||
// get correct queue
|
||||
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();
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case Mode::Mean: {
|
||||
// calculate average
|
||||
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;
|
||||
}
|
||||
vector<complex<double>> data;
|
||||
for(auto m : d.measurements) {
|
||||
data.push_back(m.second);
|
||||
}
|
||||
process(d.pointNum, data);
|
||||
int i=0;
|
||||
for(auto &m : d.measurements) {
|
||||
m.second = data[i++];
|
||||
}
|
||||
|
||||
d.S = Sparam(S11, S12, S21, S22);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
VirtualDevice::SAMeasurement Averaging::process(VirtualDevice::SAMeasurement d)
|
||||
{
|
||||
if(d.measurements.size() != numMeasurements) {
|
||||
numMeasurements = d.measurements.size();
|
||||
reset(avg.size());
|
||||
}
|
||||
|
||||
if (d.pointNum == avg.size()) {
|
||||
// add moving average entry
|
||||
deque<vector<complex<double>>> deque;
|
||||
avg.push_back(deque);
|
||||
vector<complex<double>> data;
|
||||
for(auto m : d.measurements) {
|
||||
data.push_back(m.second);
|
||||
}
|
||||
|
||||
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) {
|
||||
sample.push_back(m.second);
|
||||
}
|
||||
deque->push_back(sample);
|
||||
if(deque->size() > averages) {
|
||||
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) {
|
||||
m.second = averagedResults.pop_front();
|
||||
}
|
||||
process(d.pointNum, data);
|
||||
int i=0;
|
||||
for(auto &m : d.measurements) {
|
||||
m.second = data[i++].real();
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -208,3 +87,80 @@ void Averaging::setMode(const 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
|
||||
#define AVERAGING_H
|
||||
|
||||
#include "Device/virtualdevice.h".h"
|
||||
#include "VNA/vnadata.h"
|
||||
#include "Device/virtualdevice.h"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
@ -19,7 +18,7 @@ public:
|
||||
Averaging();
|
||||
void reset(unsigned int points);
|
||||
void setAverages(unsigned int a);
|
||||
VNAData process(VNAData d);
|
||||
VirtualDevice::VNAMeasurement process(VirtualDevice::VNAMeasurement 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.
|
||||
// Returned values are in range 0 to averages
|
||||
@ -31,6 +30,8 @@ public:
|
||||
void setMode(const Mode &value);
|
||||
|
||||
private:
|
||||
void process(int pointNum, std::vector<std::complex<double> > &data);
|
||||
|
||||
std::vector<std::deque<std::vector<std::complex<double>>>> avg;
|
||||
int maxPoints;
|
||||
int numMeasurements;
|
||||
|
Loading…
Reference in New Issue
Block a user