wrapper work

This commit is contained in:
Jan Käberich 2022-08-04 20:12:15 +02:00
parent f0a40417e4
commit a530cea085
30 changed files with 385 additions and 588 deletions

View File

@ -15,15 +15,15 @@ using namespace std;
Calibration::Calibration()
{
// 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);
@ -802,21 +798,11 @@ bool Calibration::openFromFile(QString filename)
nlohmann::json j;
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;
}
}
this->currentCalFile = filename; // if all ok, remember this
return true;
@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -118,7 +118,6 @@ HEADERS += \
VNA/Deembedding/twothru.h \
VNA/tracewidgetvna.h \
VNA/vna.h \
VNA/vnadata.h \
about.h \
appwindow.h \
averaging.h \

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -124,25 +124,15 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
}
VNAtrace = Trace::isVNAParameter(t.liveParameter());
if(VirtualDevice::getConnected()) {
if(VNAtrace) {
ui->CLiveParam->addItem("S11");
ui->CLiveParam->addItem("S12");
ui->CLiveParam->addItem("S21");
ui->CLiveParam->addItem("S22");
ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableVNAMeasurements());
} else {
ui->CLiveParam->addItem("Port 1");
ui->CLiveParam->addItem("Port 2");
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();

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -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;

View File

@ -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()

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -12,7 +12,7 @@ void Averaging::reset(unsigned int points)
{
avg.clear();
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();
vector<complex<double>> data;
for(auto m : d.measurements) {
data.push_back(m.second);
}
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];
process(d.pointNum, data);
int i=0;
for(auto &m : d.measurements) {
m.second = data[i++];
}
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;
}
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);
}
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;
vector<complex<double>> data;
for(auto m : d.measurements) {
sample.push_back(m.second);
data.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;
}
process(d.pointNum, data);
int i=0;
for(auto &m : d.measurements) {
m.second = averagedResults.pop_front();
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();
}
}
}

View File

@ -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;