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

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

View File

@ -15,15 +15,15 @@ using namespace std;
Calibration::Calibration()
{
// Create vectors for measurements
measurements[Measurement::Port1Open].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Port1Short].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Port1Load].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Port2Open].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Port2Short].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Port2Load].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Isolation].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Through].datapoints = vector<Protocol::Datapoint>();
measurements[Measurement::Line].datapoints = vector<Protocol::Datapoint>();
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>();
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, Protocol::Datapoint &d)
void Calibration::addMeasurement(Calibration::Measurement type, VNAData &d)
{
measurements[type].datapoints.push_back(d);
measurements[type].timestamp = QDateTime::currentDateTime();
}
void Calibration::addMeasurements(std::set<Calibration::Measurement> types, Protocol::Datapoint &d)
void Calibration::addMeasurements(std::set<Calibration::Measurement> types, VNAData &d)
{
for(auto t : types) {
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 = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11);
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11);
auto S22_open = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22);
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22);
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 S21_isolation = complex<double>(0,0);
auto S12_isolation = complex<double>(0,0);
if(isolation_measured) {
S21_isolation = complex<double>(measurements[Measurement::Isolation].datapoints[i].real_S21, measurements[Measurement::Isolation].datapoints[i].imag_S21);
S12_isolation = complex<double>(measurements[Measurement::Isolation].datapoints[i].real_S12, measurements[Measurement::Isolation].datapoints[i].imag_S12);
S21_isolation = measurements[Measurement::Isolation].datapoints[i].S.m21;
S12_isolation = measurements[Measurement::Isolation].datapoints[i].S.m12;
}
auto S11_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11);
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21);
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22);
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_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 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 = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11);
auto S11_short = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
auto S11_load = complex<double>(measurements[Measurement::Port1Load].datapoints[i].real_S11, measurements[Measurement::Port1Load].datapoints[i].imag_S11);
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;
// 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 = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22);
auto S22_short = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
auto S22_load = complex<double>(measurements[Measurement::Port2Load].datapoints[i].real_S22, measurements[Measurement::Port2Load].datapoints[i].imag_S22);
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;
// 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 = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21);
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
auto S21_through = measurements[Measurement::Through].datapoints[i].S.m21;
auto S12_through = measurements[Measurement::Through].datapoints[i].S.m12;
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 = complex<double>(measurements[Measurement::Through].datapoints[i].real_S11, measurements[Measurement::Through].datapoints[i].imag_S11);
auto S21_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S21, measurements[Measurement::Through].datapoints[i].imag_S21);
auto S22_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S22, measurements[Measurement::Through].datapoints[i].imag_S22);
auto S12_through = complex<double>(measurements[Measurement::Through].datapoints[i].real_S12, measurements[Measurement::Through].datapoints[i].imag_S12);
auto S11_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S11, measurements[Measurement::Line].datapoints[i].imag_S11);
auto S21_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S21, measurements[Measurement::Line].datapoints[i].imag_S21);
auto S22_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S22, measurements[Measurement::Line].datapoints[i].imag_S22);
auto S12_line = complex<double>(measurements[Measurement::Line].datapoints[i].real_S12, measurements[Measurement::Line].datapoints[i].imag_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_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 trl = kit.toTRL(p.frequency);
complex<double> S11_reflection, S22_reflection;
if(trl.reflectionIsNegative) {
// used short
S11_reflection = complex<double>(measurements[Measurement::Port1Short].datapoints[i].real_S11, measurements[Measurement::Port1Short].datapoints[i].imag_S11);
S22_reflection = complex<double>(measurements[Measurement::Port2Short].datapoints[i].real_S22, measurements[Measurement::Port2Short].datapoints[i].imag_S22);
S11_reflection = measurements[Measurement::Port1Short].datapoints[i].S.m11;
S22_reflection = measurements[Measurement::Port2Short].datapoints[i].S.m22;
} else {
// used open
S11_reflection = complex<double>(measurements[Measurement::Port1Open].datapoints[i].real_S11, measurements[Measurement::Port1Open].datapoints[i].imag_S11);
S22_reflection = complex<double>(measurements[Measurement::Port2Open].datapoints[i].real_S22, measurements[Measurement::Port2Open].datapoints[i].imag_S22);
S11_reflection = measurements[Measurement::Port1Open].datapoints[i].S.m11;
S22_reflection = measurements[Measurement::Port2Open].datapoints[i].S.m22;
}
// 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(Protocol::Datapoint &d)
void Calibration::correctMeasurement(VNAData &d)
{
if(type == Type::None) {
// No calibration data, do nothing
return;
}
// Convert measurements to complex variables
auto S11m = complex<double>(d.real_S11, d.imag_S11);
auto S21m = complex<double>(d.real_S21, d.imag_S21);
auto S22m = complex<double>(d.real_S22, d.imag_S22);
auto S12m = complex<double>(d.real_S12, d.imag_S12);
auto S11m = d.S.m11;
auto S21m = d.S.m21;
auto S22m = d.S.m22;
auto S12m = d.S.m12;
// find correct entry
auto p = getCalibrationPoint(d);
@ -459,14 +459,7 @@ void Calibration::correctMeasurement(Protocol::Datapoint &d)
- p.re11 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
S12 = ((S12m - p.re03) / p.re23e01 * (1.0 + (S11m - p.fe00) / p.fe10e01 * (p.fe11 - p.re11))) / denom;
d.real_S11 = S11.real();
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
d.S = Sparam(S11, S12, S21, S22);
}
void Calibration::correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22)
@ -741,13 +734,13 @@ std::vector<Trace *> Calibration::getMeasurementTraces()
Trace::Data d;
d.x = p.frequency;
if(prefix == "S11") {
d.y = complex<double>(p.real_S11, p.imag_S11);
d.y = p.S.m11;
} else if(prefix == "S12") {
d.y = complex<double>(p.real_S12, p.imag_S12);
d.y = p.S.m12;
} else if(prefix == "S21") {
d.y = complex<double>(p.real_S21, p.imag_S21);
d.y = p.S.m21;
} else {
d.y = complex<double>(p.real_S22, p.imag_S22);
d.y = p.S.m22;
}
t->addData(d, TraceMath::DataType::Frequency);
}
@ -790,7 +783,7 @@ bool Calibration::openFromFile(QString filename)
qDebug() << "Associated calibration kit expected in" << calkit_file;
try {
kit = Calkit::fromFile(calkit_file);
} catch (runtime_error e) {
} catch (runtime_error &e) {
InformationBox::ShowError("Missing calibration kit", "The calibration kit file associated with the selected calibration could not be parsed. The calibration might not be accurate. (" + QString(e.what()) + ")");
qWarning() << "Parsing of calibration kit failed while opening calibration file: " << e.what();
}
@ -809,7 +802,7 @@ bool Calibration::openFromFile(QString filename)
nlohmann::json j;
file >> j;
fromJSON(j);
} catch(exception e) {
} catch(exception &e) {
// json parsing failed, probably using a legacy file format
try {
file.clear();
@ -818,7 +811,7 @@ bool Calibration::openFromFile(QString filename)
InformationBox::ShowMessage("Loading calibration file", "The file \"" + filename + "\" is stored in a deprecated"
" calibration format. Future versions of this application might not support"
" it anymore. Please save the calibration to update to the new format");
} catch(exception e) {
} catch(exception &e) {
InformationBox::ShowError("File parsing error", e.what());
qWarning() << "Calibration file parsing failed: " << e.what();
return false;
@ -916,14 +909,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.real_S11;
j_point["S11_imag"] = p.imag_S11;
j_point["S12_real"] = p.real_S12;
j_point["S12_imag"] = p.imag_S12;
j_point["S21_real"] = p.real_S21;
j_point["S21_imag"] = p.imag_S21;
j_point["S22_real"] = p.real_S22;
j_point["S22_imag"] = p.imag_S22;
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_points.push_back(j_point);
}
j_measurement["points"] = j_points;
@ -964,17 +957,13 @@ void Calibration::fromJSON(nlohmann::json j)
}
int pointNum = 0;
for(auto j_p : j_m["points"]) {
Protocol::Datapoint p;
VNAData p;
p.pointNum = pointNum++;
p.frequency = j_p.value("frequency", 0.0);
p.real_S11 = j_p.value("S11_real", 0.0);
p.imag_S11 = j_p.value("S11_imag", 0.0);
p.real_S12 = j_p.value("S12_real", 0.0);
p.imag_S12 = j_p.value("S12_imag", 0.0);
p.real_S21 = j_p.value("S21_real", 0.0);
p.imag_S21 = j_p.value("S21_imag", 0.0);
p.real_S22 = j_p.value("S22_real", 0.0);
p.imag_S22 = j_p.value("S22_imag", 0.0);
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));
measurements[m].datapoints.push_back(p);
}
}
@ -997,24 +986,6 @@ QString Calibration::getCurrentCalibrationFile(){
return this->currentCalFile;
}
ostream& operator<<(ostream &os, const Calibration &c)
{
for(auto m : c.measurements) {
if(m.second.datapoints.size() > 0) {
os << c.MeasurementToString(m.first).toStdString() << endl;
os << m.second.timestamp.toSecsSinceEpoch() << endl;
os << m.second.datapoints.size() << endl;
for(auto p : m.second.datapoints) {
os << p.pointNum << " " << p.frequency << " ";
os << p.imag_S11 << " " << p.real_S11 << " " << p.imag_S21 << " " << p.real_S21 << " " << p.imag_S12 << " " << p.real_S12 << " " << p.imag_S22 << " " << p.real_S22;
os << endl;
}
}
}
os << Calibration::TypeToString(c.getType()).toStdString() << endl;
return os;
}
istream& operator >>(istream &in, Calibration &c)
{
// old file format did not contain port standard gender, set default
@ -1039,7 +1010,7 @@ istream& operator >>(istream &in, Calibration &c)
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(p);
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.");
@ -1097,7 +1068,7 @@ bool Calibration::SanityCheckSamples(const std::vector<Calibration::Measurement>
return true;
}
Calibration::Point Calibration::getCalibrationPoint(Protocol::Datapoint &d)
Calibration::Point Calibration::getCalibrationPoint(VNAData &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, Protocol::Datapoint &d);
void addMeasurements(std::set<Measurement> types, Protocol::Datapoint &d);
void addMeasurement(Measurement type, VNAData &d);
void addMeasurements(std::set<Measurement> types, VNAData &d);
enum class Type {
Port1SOL,
@ -63,7 +63,7 @@ public:
bool constructErrorTerms(Type type);
void resetErrorTerms();
void correctMeasurement(Protocol::Datapoint &d);
void correctMeasurement(VNAData &d);
void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
enum class InterpolationType {
@ -93,7 +93,6 @@ public:
const std::vector<Measurement> Measurements(Type type = Type::None, bool optional_included = true);
MeasurementInfo getMeasurementInfo(Measurement m);
friend std::ostream& operator<<(std::ostream& os, const Calibration& c);
friend std::istream& operator >> (std::istream &in, Calibration& c);
int nPoints() {
return points.size();
@ -142,7 +141,7 @@ private:
// Reverse error terms
std::complex<double> re33, re11, re23e32, re23e01, re22, re03, rex;
};
Point getCalibrationPoint(Protocol::Datapoint &d);
Point getCalibrationPoint(VNAData &d);
/*
* Constructs directivity, match and tracking correction factors from measurements of three distinct impedances
* Normally, an open, short and load are used (with ideal reflection coefficients of 1, -1 and 0 respectively).
@ -174,7 +173,7 @@ private:
class MeasurementData {
public:
QDateTime timestamp;
std::vector<Protocol::Datapoint> datapoints;
std::vector<VNAData> datapoints;
};
Type type;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@
#include "savable.h"
#include "Device/device.h"
#include "Traces/tracemodel.h"
#include <QWidget>
@ -14,6 +15,7 @@ public:
PortExtension,
TwoThru,
MatchingNetwork,
ImpedanceRenormalization,
// Add new deembedding options here, do not explicitly assign values and keep the Last entry at the last position
Last,
};
@ -21,12 +23,12 @@ public:
static DeembeddingOption *create(Type type);
static QString getName(Type type);
virtual void transformDatapoint(Protocol::Datapoint &p) = 0;
virtual void transformDatapoint(VNAData &p) = 0;
virtual void edit(){};
virtual Type getType() = 0;
public slots:
virtual void measurementCompleted(std::vector<Protocol::Datapoint> m){Q_UNUSED(m)};
virtual void measurementCompleted(std::vector<VNAData> 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,14 +18,14 @@ class PortExtension : public DeembeddingOption
Q_OBJECT
public:
PortExtension();
void transformDatapoint(Protocol::Datapoint& d) override;
void transformDatapoint(VNAData& 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<Protocol::Datapoint> m) override;
void measurementCompleted(std::vector<VNAData> m) override;
private:
void startMeasurement();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,12 +22,12 @@ void Averaging::setAverages(unsigned int a)
reset(avg.size());
}
Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
VNAData Averaging::process(VNAData d)
{
auto S11 = complex<double>(d.real_S11, d.imag_S11);
auto S12 = complex<double>(d.real_S12, d.imag_S12);
auto S21 = complex<double>(d.real_S21, d.imag_S21);
auto S22 = complex<double>(d.real_S22, d.imag_S22);
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
@ -99,14 +99,7 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
}
}
d.real_S11 = S11.real();
d.imag_S11 = S11.imag();
d.real_S12 = S12.real();
d.imag_S12 = S12.imag();
d.real_S21 = S21.real();
d.imag_S21 = S21.imag();
d.real_S22 = S22.real();
d.imag_S22 = S22.imag();
d.S = Sparam(S11, S12, S21, S22);
return d;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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