Save calibration kit as json

This commit is contained in:
Jan Käberich 2020-11-08 14:30:19 +01:00
parent 1dab72238b
commit 68f660ff1c
7 changed files with 25956 additions and 270 deletions

View File

@ -4,6 +4,7 @@ HEADERS += \
Calibration/calibrationtracedialog.h \
Calibration/calkit.h \
Calibration/calkitdialog.h \
Calibration/json.hpp \
Calibration/measurementmodel.h \
CustomWidgets/colorpickerbutton.h \
CustomWidgets/siunitedit.h \
@ -33,6 +34,7 @@ HEADERS += \
Traces/tracewidget.h \
Traces/tracexyplot.h \
Traces/xyplotaxisdialog.h \
Util/qpointervariant.h \
VNA/portextension.h \
VNA/vna.h \
appwindow.h \

View File

@ -4,7 +4,10 @@
#include <iomanip>
#include "calkitdialog.h"
#include <math.h>
#include "json.hpp"
#include <QMessageBox>
using json = nlohmann::json;
using namespace std;
Calkit::Calkit()
@ -14,79 +17,50 @@ Calkit::Calkit()
ts_through(nullptr),
ts_cached(false)
{
open_Z0 = 50.0;
open_delay = 0.0;
open_loss = 0.0;
open_C0 = 0.0;
open_C1 = 0.0;
open_C2 = 0.0;
open_C3 = 0.0;
short_Z0 = 50.0;
short_delay = 0.0;
short_loss = 0.0;
short_L0 = 0.0;
short_L1 = 0.0;
short_L2 = 0.0;
short_L3 = 0.0;
load_Z0 = 50.0;
through_Z0 = 50.0;
through_delay = 0.0;
through_loss = 0.0;
open_measurements = false;
short_measurements = false;
load_measurements = false;
through_measurements = false;
open_file = "";
short_file = "";
load_file = "";
through_file = "";
open_Sparam = 0;
short_Sparam = 0;
load_Sparam = 0;
through_Sparam1 = 0;
through_Sparam2 = 1;
TRL_through_Z0 = 50.0;
TRL_reflection_short = true;
TRL_line_delay = 74;
TRL_line_maxfreq = 6000000000;
TRL_line_minfreq = 751000000;
// set default values
for(auto e : json_descr) {
e.var.setValue(e.def);
}
}
Calkit::Calkit(const Calkit &c) :
// only copy standard definitions, leave cache state and json_descr pointers at default values
SOLT(c.SOLT),
TRL(c.TRL)
{
}
#include <QDebug>
void Calkit::toFile(std::string filename)
{
TransformPathsToRelative(QString::fromStdString(filename));
json j;
for(auto e : json_descr) {
auto list = e.name.split("/");
auto *json_entry = &j;
while(list.size() > 0) {
json_entry = &(*json_entry)[list.takeFirst().toStdString()];
}
// json library does not now about QVariant, handle used cases
auto val = e.var.value();
qDebug() << val << endl;
switch(static_cast<QMetaType::Type>(val.type())) {
case QMetaType::Double: *json_entry = val.toDouble(); break;
case QMetaType::Int: *json_entry = val.toInt(); break;
case QMetaType::Bool: *json_entry = val.toBool(); break;
case QMetaType::QString: *json_entry = val.toString().toStdString(); break;
default:
throw runtime_error("Unimplemented metatype");
}
}
ofstream file;
file.open(filename);
file << std::fixed << std::setprecision(12);
file << open_measurements << "\n" << short_measurements << "\n" << load_measurements << "\n" << through_measurements << "\n";
file << open_Z0 << "\n" << open_delay << "\n" << open_loss << "\n" << open_C0 << "\n" << open_C1 << "\n" << open_C2 << "\n" << open_C3 << "\n";
file << short_Z0 << "\n" << short_delay << "\n" << short_loss << "\n" << short_L0 << "\n" << short_L1 << "\n" << short_L2 << "\n" << short_L3 << "\n";
file << load_Z0 << "\n";
file << through_Z0 << "\n" << through_delay << "\n" << through_loss << "\n";
if(open_measurements) {
file << open_file << "\n" << open_Sparam << "\n";
}
if(short_measurements) {
file << short_file << "\n" << short_Sparam << "\n";
}
if(load_measurements) {
file << load_file << "\n" << load_Sparam << "\n";
}
if(through_measurements) {
file << through_file << "\n" << through_Sparam1 << "\n" << through_Sparam2 << "\n";
}
file << TRL_through_Z0 << "\n";
file << TRL_reflection_short << "\n";
file << TRL_line_delay << "\n";
file << TRL_line_minfreq << "\n";
file << TRL_line_maxfreq << "\n";
file << setw(4) << j << endl;
file.close();
TransformPathsToAbsolute(QString::fromStdString(filename));
}
static QString readLine(ifstream &file) {
@ -97,57 +71,113 @@ static QString readLine(ifstream &file) {
Calkit Calkit::fromFile(std::string filename)
{
Calkit c;
auto c = Calkit();
ifstream file;
file.open(filename);
if(!file.is_open()) {
throw runtime_error("Unable to open file");
}
c.open_measurements = readLine(file).toInt();
c.short_measurements = readLine(file).toInt();
c.load_measurements = readLine(file).toInt();
c.through_measurements = readLine(file).toInt();
c.open_Z0 = readLine(file).toDouble();
c.open_delay = readLine(file).toDouble();
c.open_loss = readLine(file).toDouble();
c.open_C0 = readLine(file).toDouble();
c.open_C1 = readLine(file).toDouble();
c.open_C2 = readLine(file).toDouble();
c.open_C3 = readLine(file).toDouble();
c.short_Z0 = readLine(file).toDouble();
c.short_delay = readLine(file).toDouble();
c.short_loss = readLine(file).toDouble();
c.short_L0 = readLine(file).toDouble();
c.short_L1 = readLine(file).toDouble();
c.short_L2 = readLine(file).toDouble();
c.short_L3 = readLine(file).toDouble();
c.load_Z0 = readLine(file).toDouble();
c.through_Z0 = readLine(file).toDouble();
c.through_delay = readLine(file).toDouble();
c.through_loss = readLine(file).toDouble();
if(c.open_measurements) {
c.open_file = readLine(file).toStdString();
c.open_Sparam = readLine(file).toInt();
json j;
file >> j;
if(j.contains("SOLT")) {
// calkit file uses json format, parse
for(auto e : c.json_descr) {
auto list = e.name.split("/");
auto *json_entry = &j;
bool entry_exists = true;
while(list.size() > 0) {
auto key = list.takeFirst().toStdString();
if((*json_entry).contains(key)) {
json_entry = &(*json_entry)[key];
} else {
entry_exists = false;
break;
}
}
if(!entry_exists) {
// missing entry in json file, nothing to do (default values already set in constructor)
continue;
}
// json library does not now about QVariant, handle used cases
auto val = e.var.value();
switch(static_cast<QMetaType::Type>(val.type())) {
case QMetaType::Double: e.var.setValue((*json_entry).get<double>()); break;
case QMetaType::Int: e.var.setValue((*json_entry).get<int>()); break;
case QMetaType::Bool: e.var.setValue((*json_entry).get<bool>()); break;
case QMetaType::QString: {
auto s = QString::fromStdString((*json_entry).get<string>());
qDebug() << s;
e.var.setValue(s);
qDebug() << e.var.value();
}
break;
default:
throw runtime_error("Unimplemented metatype");
}
}
} else {
// legacy file format, return to beginning of file
file.clear();
file.seekg(0);
c.SOLT.Open.useMeasurements = readLine(file).toInt();
c.SOLT.Short.useMeasurements = readLine(file).toInt();
c.SOLT.Load.useMeasurements = readLine(file).toInt();
c.SOLT.Through.useMeasurements = readLine(file).toInt();
c.SOLT.Open.Z0 = readLine(file).toDouble();
c.SOLT.Open.delay = readLine(file).toDouble();
c.SOLT.Open.loss = readLine(file).toDouble();
c.SOLT.Open.C0 = readLine(file).toDouble();
c.SOLT.Open.C1 = readLine(file).toDouble();
c.SOLT.Open.C2 = readLine(file).toDouble();
c.SOLT.Open.C3 = readLine(file).toDouble();
c.SOLT.Short.Z0 = readLine(file).toDouble();
c.SOLT.Short.delay = readLine(file).toDouble();
c.SOLT.Short.loss = readLine(file).toDouble();
c.SOLT.Short.L0 = readLine(file).toDouble();
c.SOLT.Short.L1 = readLine(file).toDouble();
c.SOLT.Short.L2 = readLine(file).toDouble();
c.SOLT.Short.L3 = readLine(file).toDouble();
c.SOLT.Load.Z0 = readLine(file).toDouble();
c.SOLT.Through.Z0 = readLine(file).toDouble();
c.SOLT.Through.delay = readLine(file).toDouble();
c.SOLT.Through.loss = readLine(file).toDouble();
if(c.SOLT.Open.useMeasurements) {
c.SOLT.Open.file = readLine(file);
c.SOLT.Open.Sparam = readLine(file).toInt();
}
if(c.SOLT.Short.useMeasurements) {
c.SOLT.Short.file = readLine(file);
c.SOLT.Short.Sparam = readLine(file).toInt();
}
if(c.SOLT.Load.useMeasurements) {
c.SOLT.Load.file = readLine(file);
c.SOLT.Load.Sparam = readLine(file).toInt();
}
if(c.SOLT.Through.useMeasurements) {
c.SOLT.Through.file = readLine(file);
c.SOLT.Through.Sparam1 = readLine(file).toInt();
c.SOLT.Through.Sparam2 = readLine(file).toInt();
}
c.TRL.Through.Z0 = readLine(file).toDouble();
c.TRL.Reflection.isShort = readLine(file).toDouble();
c.TRL.Line.delay = readLine(file).toDouble();
c.TRL.Line.minFreq = readLine(file).toDouble();
c.TRL.Line.maxFreq = readLine(file).toDouble();
auto msg = new QMessageBox();
msg->setWindowTitle("Loading calkit file");
msg->setText("The file \"" + QString::fromStdString(filename) + "\" is stored in a deprecated"
" calibration kit format. Future versions of this application might not support"
" it anymore. Please save the calibration kit to update to the new format");
msg->setStandardButtons(QMessageBox::Ok);
msg->exec();
}
if(c.short_measurements) {
c.short_file = readLine(file).toStdString();
c.short_Sparam = readLine(file).toInt();
}
if(c.load_measurements) {
c.load_file = readLine(file).toStdString();
c.load_Sparam = readLine(file).toInt();
}
if(c.through_measurements) {
c.through_file = readLine(file).toStdString();
c.through_Sparam1 = readLine(file).toInt();
c.through_Sparam2 = readLine(file).toInt();
}
c.TRL_through_Z0 = readLine(file).toDouble();
c.TRL_reflection_short = readLine(file).toDouble();
c.TRL_line_delay = readLine(file).toDouble();
c.TRL_line_minfreq = readLine(file).toDouble();
c.TRL_line_maxfreq = readLine(file).toDouble();
file.close();
c.TransformPathsToAbsolute(QString::fromStdString(filename));
return c;
}
@ -157,22 +187,22 @@ void Calkit::edit()
dialog->show();
}
Calkit::SOLT Calkit::toSOLT(double frequency)
class Calkit::SOLT Calkit::toSOLT(double frequency)
{
fillTouchstoneCache();
SOLT ref;
if(load_measurements) {
class SOLT ref;
if(SOLT.Load.useMeasurements) {
ref.Load = ts_load->interpolate(frequency).S[0];
} else {
auto imp_load = complex<double>(load_Z0, 0);
auto imp_load = complex<double>(SOLT.Load.Z0, 0);
ref.Load = (imp_load - complex<double>(50.0)) / (imp_load + complex<double>(50.0));
}
if(open_measurements) {
if(SOLT.Open.useMeasurements) {
ref.Open = ts_open->interpolate(frequency).S[0];
} else {
// calculate fringing capacitance for open
double Cfringing = open_C0 * 1e-15 + open_C1 * 1e-27 * frequency + open_C2 * 1e-36 * pow(frequency, 2) + open_C3 * 1e-45 * pow(frequency, 3);
double Cfringing = SOLT.Open.C0 * 1e-15 + SOLT.Open.C1 * 1e-27 * frequency + SOLT.Open.C2 * 1e-36 * pow(frequency, 2) + SOLT.Open.C3 * 1e-45 * pow(frequency, 3);
// convert to impedance
if (Cfringing == 0) {
// special case to avoid issues with infinity
@ -182,30 +212,30 @@ Calkit::SOLT Calkit::toSOLT(double frequency)
ref.Open = (imp_open - complex<double>(50.0)) / (imp_open + complex<double>(50.0));
}
// transform the delay into a phase shift for the given frequency
double open_phaseshift = -2 * M_PI * frequency * 2 * open_delay * 1e-12;
double open_att_db = open_loss * 1e9 * 4.3429 * 2 * open_delay * 1e-12 / open_Z0 * sqrt(frequency / 1e9);
double open_phaseshift = -2 * M_PI * frequency * 2 * SOLT.Open.delay * 1e-12;
double open_att_db = SOLT.Open.loss * 1e9 * 4.3429 * 2 * SOLT.Open.delay * 1e-12 / SOLT.Open.Z0 * sqrt(frequency / 1e9);
double open_att = pow(10.0, -open_att_db / 10.0);
auto open_correction = polar<double>(open_att, open_phaseshift);
ref.Open *= open_correction;
}
if(short_measurements) {
if(SOLT.Short.useMeasurements) {
ref.Short = ts_short->interpolate(frequency).S[0];
} else {
// calculate inductance for short
double Lseries = short_L0 * 1e-12 + short_L1 * 1e-24 * frequency + short_L2 * 1e-33 * pow(frequency, 2) + short_L3 * 1e-42 * pow(frequency, 3);
double Lseries = SOLT.Short.L0 * 1e-12 + SOLT.Short.L1 * 1e-24 * frequency + SOLT.Short.L2 * 1e-33 * pow(frequency, 2) + SOLT.Short.L3 * 1e-42 * pow(frequency, 3);
// convert to impedance
auto imp_short = complex<double>(0, frequency * 2 * M_PI * Lseries);
ref.Short = (imp_short - complex<double>(50.0)) / (imp_short + complex<double>(50.0));
// transform the delay into a phase shift for the given frequency
double short_phaseshift = -2 * M_PI * frequency * 2 * short_delay * 1e-12;
double short_att_db = short_loss * 1e9 * 4.3429 * 2 * short_delay * 1e-12 / short_Z0 * sqrt(frequency / 1e9);;
double short_phaseshift = -2 * M_PI * frequency * 2 * SOLT.Short.delay * 1e-12;
double short_att_db = SOLT.Short.loss * 1e9 * 4.3429 * 2 * SOLT.Short.delay * 1e-12 / SOLT.Short.Z0 * sqrt(frequency / 1e9);;
double short_att = pow(10.0, -short_att_db / 10.0);
auto short_correction = polar<double>(short_att, short_phaseshift);
ref.Short *= short_correction;
}
if(through_measurements) {
if(SOLT.Through.useMeasurements) {
auto interp = ts_through->interpolate(frequency);
ref.ThroughS11 = interp.S[0];
ref.ThroughS12 = interp.S[1];
@ -213,8 +243,8 @@ Calkit::SOLT Calkit::toSOLT(double frequency)
ref.ThroughS22 = interp.S[3];
} else {
// calculate effect of through
double through_phaseshift = -2 * M_PI * frequency * through_delay * 1e-12;
double through_att_db = through_loss * 1e9 * 4.3429 * through_delay * 1e-12 / through_Z0 * sqrt(frequency / 1e9);;
double through_phaseshift = -2 * M_PI * frequency * SOLT.Through.delay * 1e-12;
double through_att_db = SOLT.Through.loss * 1e9 * 4.3429 * SOLT.Through.delay * 1e-12 / SOLT.Through.Z0 * sqrt(frequency / 1e9);;
double through_att = pow(10.0, -through_att_db / 10.0);
ref.ThroughS12 = polar<double>(through_att, through_phaseshift);
// Assume symmetric and perfectly matched through for other parameters
@ -226,11 +256,11 @@ Calkit::SOLT Calkit::toSOLT(double frequency)
return ref;
}
Calkit::TRL Calkit::toTRL(double)
class Calkit::TRL Calkit::toTRL(double)
{
TRL trl;
class TRL trl;
// reflection coefficent sign depends on whether an open or short is used
trl.reflectionIsNegative = TRL_reflection_short;
trl.reflectionIsNegative = TRL.Reflection.isShort;
// assume ideal through for now
trl.ThroughS11 = 0.0;
trl.ThroughS12 = 1.0;
@ -239,10 +269,10 @@ Calkit::TRL Calkit::toTRL(double)
return trl;
}
double Calkit::minFreq(bool TRL)
double Calkit::minFreq(bool trl)
{
if(TRL) {
return TRL_line_minfreq;
if(trl) {
return TRL.Line.minFreq;
} else {
fillTouchstoneCache();
double min = 0;
@ -261,10 +291,10 @@ double Calkit::minFreq(bool TRL)
}
}
double Calkit::maxFreq(bool TRL)
double Calkit::maxFreq(bool trl)
{
if(TRL) {
return TRL_line_maxfreq;
if(trl) {
return TRL.Line.maxFreq;
} else {
fillTouchstoneCache();
double max = std::numeric_limits<double>::max();
@ -285,7 +315,34 @@ double Calkit::maxFreq(bool TRL)
bool Calkit::isTRLReflectionShort() const
{
return TRL_reflection_short;
return TRL.Reflection.isShort;
}
void Calkit::TransformPathsToRelative(QFileInfo d)
{
vector<QString*> filenames = {&SOLT.Short.file, &SOLT.Open.file, &SOLT.Load.file, &SOLT.Through.file};
for(auto f : filenames) {
if(f->isEmpty()) {
continue;
}
if(QFileInfo(*f).isAbsolute()) {
*f = d.dir().relativeFilePath(*f);
}
}
}
void Calkit::TransformPathsToAbsolute(QFileInfo d)
{
vector<QString*> filenames = {&SOLT.Short.file, &SOLT.Open.file, &SOLT.Load.file, &SOLT.Through.file};
for(auto f : filenames) {
if(f->isEmpty()) {
continue;
}
if(QFileInfo(*f).isRelative()) {
auto absDir = QDir(d.dir().path() + "/" + *f);
*f = absDir.absolutePath();
}
}
}
void Calkit::clearTouchstoneCache()
@ -306,25 +363,25 @@ void Calkit::fillTouchstoneCache()
if(ts_cached) {
return;
}
if(open_measurements) {
if(SOLT.Open.useMeasurements) {
ts_open = new Touchstone(1);
*ts_open = Touchstone::fromFile(open_file);
ts_open->reduceTo1Port(open_Sparam);
*ts_open = Touchstone::fromFile(SOLT.Open.file.toStdString());
ts_open->reduceTo1Port(SOLT.Open.Sparam);
}
if(short_measurements) {
if(SOLT.Short.useMeasurements) {
ts_short = new Touchstone(1);
*ts_short = Touchstone::fromFile(short_file);
ts_open->reduceTo1Port(short_Sparam);
*ts_short = Touchstone::fromFile(SOLT.Short.file.toStdString());
ts_open->reduceTo1Port(SOLT.Short.Sparam);
}
if(load_measurements) {
if(SOLT.Load.useMeasurements) {
ts_load = new Touchstone(1);
*ts_load = Touchstone::fromFile(load_file);
ts_open->reduceTo1Port(load_Sparam);
*ts_load = Touchstone::fromFile(SOLT.Load.file.toStdString());
ts_open->reduceTo1Port(SOLT.Load.Sparam);
}
if(through_measurements) {
if(SOLT.Through.useMeasurements) {
ts_through = new Touchstone(2);
*ts_through = Touchstone::fromFile(through_file);
ts_through->reduceTo2Port(through_Sparam1, through_Sparam2);
*ts_through = Touchstone::fromFile(SOLT.Through.file.toStdString());
ts_through->reduceTo2Port(SOLT.Through.Sparam1, SOLT.Through.Sparam2);
}
ts_cached = true;
}

View File

@ -4,12 +4,21 @@
#include <string>
#include <complex>
#include "touchstone.h"
#include "Util/qpointervariant.h"
#include <QDir>
class Calkit
{
friend class CalkitDialog;
public:
Calkit();
Calkit(const Calkit& c);
Calkit& operator=(const Calkit& other)
{
this->SOLT = other.SOLT;
this->TRL = other.TRL;
return *this;
}
class SOLT {
public:
@ -30,36 +39,106 @@ public:
void edit();
SOLT toSOLT(double frequency);
TRL toTRL(double frequency);
double minFreq(bool TRL = false);
double maxFreq(bool TRL = false);
double minFreq(bool trl = false);
double maxFreq(bool trl = false);
bool isTRLReflectionShort() const;
private:
void TransformPathsToRelative(QFileInfo d);
void TransformPathsToAbsolute(QFileInfo d);
// SOLT standard definitions
double open_Z0, open_delay, open_loss, open_C0, open_C1, open_C2, open_C3;
double short_Z0, short_delay, short_loss, short_L0, short_L1, short_L2, short_L3;
double load_Z0;
double through_Z0, through_delay, through_loss;
// coefficients/measurement file switch
bool open_measurements;
bool short_measurements;
bool load_measurements;
bool through_measurements;
// TRL standard definitions
double TRL_through_Z0;
bool TRL_reflection_short;
double TRL_line_delay;
double TRL_line_minfreq;
double TRL_line_maxfreq;
std::string open_file, short_file, load_file, through_file;
int open_Sparam, short_Sparam, load_Sparam, through_Sparam1, through_Sparam2;
struct {
struct {
double Z0, delay, loss, C0, C1, C2, C3;
QString file;
bool useMeasurements;
int Sparam;
} Open;
struct {
double Z0, delay, loss, L0, L1, L2, L3;
QString file;
bool useMeasurements;
int Sparam;
} Short;
struct {
double Z0;
QString file;
bool useMeasurements;
int Sparam;
} Load;
struct {
double Z0, delay, loss;
QString file;
bool useMeasurements;
int Sparam1, Sparam2;
} Through;
} SOLT;
struct {
struct {
double Z0;
} Through;
struct {
bool isShort;
} Reflection;
struct {
double delay, minFreq, maxFreq;
} Line;
} TRL;
bool startDialogWithSOLT;
Touchstone *ts_open, *ts_short, *ts_load, *ts_through;
bool ts_cached;
using JSONDescription = struct _jsondescr {
QPointerVariant var;
QString name;
QVariant def;
};
const std::array<JSONDescription, 37> json_descr = {{
{&SOLT.Open.Z0, "SOLT/Open/Param/Z0", 50.0},
{&SOLT.Open.delay, "SOLT/Open/Param/Delay", 0.0},
{&SOLT.Open.loss, "SOLT/Open/Param/Loss", 0.0},
{&SOLT.Open.C0, "SOLT/Open/Param/C0", 0.0},
{&SOLT.Open.C1, "SOLT/Open/Param/C1", 0.0},
{&SOLT.Open.C2, "SOLT/Open/Param/C2", 0.0},
{&SOLT.Open.C3, "SOLT/Open/Param/C3", 0.0},
{&SOLT.Open.useMeasurements, "SOLT/Open/Measurements/Use", false},
{&SOLT.Open.file, "SOLT/Open/Measurements/File", ""},
{&SOLT.Open.Sparam, "SOLT/Open/Measurements/Port", 0},
{&SOLT.Short.Z0, "SOLT/Short/Param/Z0", 50.0},
{&SOLT.Short.delay, "SOLT/Short/Param/Delay", 0.0},
{&SOLT.Short.loss, "SOLT/Short/Param/Loss", 0.0},
{&SOLT.Short.L0, "SOLT/Short/Param/L0", 0.0},
{&SOLT.Short.L1, "SOLT/Short/Param/L1", 0.0},
{&SOLT.Short.L2, "SOLT/Short/Param/L2", 0.0},
{&SOLT.Short.L3, "SOLT/Short/Param/L3", 0.0},
{&SOLT.Short.useMeasurements, "SOLT/Short/Measurements/Use", false},
{&SOLT.Short.file, "SOLT/Short/Measurements/File", ""},
{&SOLT.Short.Sparam, "SOLT/Short/Measurements/Port", 0},
{&SOLT.Load.Z0, "SOLT/Load/Param/Z0", 50.0},
{&SOLT.Load.useMeasurements, "SOLT/Load/Measurements/Use", false},
{&SOLT.Load.file, "SOLT/Load/Measurements/File", ""},
{&SOLT.Load.Sparam, "SOLT/Load/Measurements/Port", 0},
{&SOLT.Through.Z0, "SOLT/Through/Param/Z0", 50.0},
{&SOLT.Through.delay, "SOLT/Through/Param/Delay", 0.0},
{&SOLT.Through.loss, "SOLT/Through/Param/Loss", 0.0},
{&SOLT.Through.useMeasurements, "SOLT/Through/Measurements/Use", false},
{&SOLT.Through.file, "SOLT/Through/Measurements/File", ""},
{&SOLT.Through.Sparam1, "SOLT/Through/Measurements/Port1", 0},
{&SOLT.Through.Sparam2, "SOLT/Through/Measurements/Port2", 1},
{&TRL.Through.Z0, "TRL/Through/Z0", 50.0},
{&TRL.Reflection.isShort, "TRL/Reflect/isShort", false},
{&TRL.Line.delay, "TRL/Line/Delay", 74.0},
{&TRL.Line.minFreq, "TRL/Line/minFreq", 751000000.0},
{&TRL.Line.maxFreq, "TRL/Line/maxFreq", 6000000000.0},
{&startDialogWithSOLT, "StartDialogWithSOLT", true}
}};
void clearTouchstoneCache();
void fillTouchstoneCache();
};

View File

@ -50,15 +50,15 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
updateEntries();
connect(ui->TRL_line_min, &SIUnitEdit::valueChanged, [=](double newval){
ownKit.TRL_line_minfreq = newval;
ownKit.TRL.Line.minFreq = newval;
updateEntries();
});
connect(ui->TRL_line_max, &SIUnitEdit::valueChanged, [=](double newval){
ownKit.TRL_line_maxfreq = newval;
ownKit.TRL.Line.maxFreq = newval;
updateEntries();
});
connect(ui->TRL_line_delay, &QLineEdit::editingFinished, [=](){
ownKit.TRL_line_delay = ui->TRL_line_delay->text().toDouble();
ownKit.TRL.Line.delay = ui->TRL_line_delay->text().toDouble();
updateEntries();
});
@ -137,136 +137,144 @@ CalkitDialog::~CalkitDialog()
void CalkitDialog::parseEntries()
{
// type
ownKit.open_measurements = ui->open_measurement->isChecked();
ownKit.short_measurements = ui->short_measurement->isChecked();
ownKit.load_measurements = ui->load_measurement->isChecked();
ownKit.through_measurements = ui->through_measurement->isChecked();
ownKit.SOLT.Open.useMeasurements = ui->open_measurement->isChecked();
ownKit.SOLT.Short.useMeasurements = ui->short_measurement->isChecked();
ownKit.SOLT.Load.useMeasurements = ui->load_measurement->isChecked();
ownKit.SOLT.Through.useMeasurements = ui->through_measurement->isChecked();
// coefficients
ownKit.open_Z0 = ui->open_Z0->text().toDouble();
ownKit.open_delay = ui->open_delay->text().toDouble();
ownKit.open_loss = ui->open_loss->text().toDouble();
ownKit.open_C0 = ui->open_C0->text().toDouble();
ownKit.open_C1 = ui->open_C1->text().toDouble();
ownKit.open_C2 = ui->open_C2->text().toDouble();
ownKit.open_C3 = ui->open_C3->text().toDouble();
ownKit.SOLT.Open.Z0 = ui->open_Z0->text().toDouble();
ownKit.SOLT.Open.delay = ui->open_delay->text().toDouble();
ownKit.SOLT.Open.loss = ui->open_loss->text().toDouble();
ownKit.SOLT.Open.C0 = ui->open_C0->text().toDouble();
ownKit.SOLT.Open.C1 = ui->open_C1->text().toDouble();
ownKit.SOLT.Open.C2 = ui->open_C2->text().toDouble();
ownKit.SOLT.Open.C3 = ui->open_C3->text().toDouble();
ownKit.short_Z0 = ui->short_Z0->text().toDouble();
ownKit.short_delay = ui->short_delay->text().toDouble();
ownKit.short_loss = ui->short_loss->text().toDouble();
ownKit.short_L0 = ui->short_L0->text().toDouble();
ownKit.short_L1 = ui->short_L1->text().toDouble();
ownKit.short_L2 = ui->short_L2->text().toDouble();
ownKit.short_L3 = ui->short_L3->text().toDouble();
ownKit.SOLT.Short.Z0 = ui->short_Z0->text().toDouble();
ownKit.SOLT.Short.delay = ui->short_delay->text().toDouble();
ownKit.SOLT.Short.loss = ui->short_loss->text().toDouble();
ownKit.SOLT.Short.L0 = ui->short_L0->text().toDouble();
ownKit.SOLT.Short.L1 = ui->short_L1->text().toDouble();
ownKit.SOLT.Short.L2 = ui->short_L2->text().toDouble();
ownKit.SOLT.Short.L3 = ui->short_L3->text().toDouble();
ownKit.load_Z0 = ui->load_Z0->text().toDouble();
ownKit.SOLT.Load.Z0 = ui->load_Z0->text().toDouble();
ownKit.through_Z0 = ui->through_Z0->text().toDouble();
ownKit.through_delay = ui->through_delay->text().toDouble();
ownKit.through_loss = ui->through_loss->text().toDouble();
ownKit.SOLT.Through.Z0 = ui->through_Z0->text().toDouble();
ownKit.SOLT.Through.delay = ui->through_delay->text().toDouble();
ownKit.SOLT.Through.loss = ui->through_loss->text().toDouble();
// file
ownKit.open_file = ui->open_touchstone->getFilename().toStdString();
ownKit.short_file = ui->short_touchstone->getFilename().toStdString();
ownKit.load_file = ui->load_touchstone->getFilename().toStdString();
ownKit.through_file = ui->through_touchstone->getFilename().toStdString();
ownKit.SOLT.Open.file = ui->open_touchstone->getFilename();
ownKit.SOLT.Short.file = ui->short_touchstone->getFilename();
ownKit.SOLT.Load.file = ui->load_touchstone->getFilename();
ownKit.SOLT.Through.file = ui->through_touchstone->getFilename();
ownKit.open_Sparam = ui->open_touchstone->getPorts()[0];
ownKit.short_Sparam = ui->short_touchstone->getPorts()[0];
ownKit.load_Sparam = ui->load_touchstone->getPorts()[0];
ownKit.through_Sparam1 = ui->through_touchstone->getPorts()[0];
ownKit.through_Sparam2 = ui->through_touchstone->getPorts()[1];
ownKit.SOLT.Open.Sparam = ui->open_touchstone->getPorts()[0];
ownKit.SOLT.Short.Sparam = ui->short_touchstone->getPorts()[0];
ownKit.SOLT.Load.Sparam = ui->load_touchstone->getPorts()[0];
ownKit.SOLT.Through.Sparam1 = ui->through_touchstone->getPorts()[0];
ownKit.SOLT.Through.Sparam2 = ui->through_touchstone->getPorts()[1];
// TRL
ownKit.TRL_through_Z0 = ui->TRL_through_Z0->text().toDouble();
ownKit.TRL_reflection_short = ui->TRL_R_short->isChecked();
ownKit.TRL_line_delay = ui->TRL_line_delay->text().toDouble();
ownKit.TRL_line_minfreq = ui->TRL_line_min->value();
ownKit.TRL_line_maxfreq = ui->TRL_line_max->value();
ownKit.TRL.Through.Z0 = ui->TRL_through_Z0->text().toDouble();
ownKit.TRL.Reflection.isShort = ui->TRL_R_short->isChecked();
ownKit.TRL.Line.delay = ui->TRL_line_delay->text().toDouble();
ownKit.TRL.Line.minFreq = ui->TRL_line_min->value();
ownKit.TRL.Line.maxFreq = ui->TRL_line_max->value();
ownKit.startDialogWithSOLT = ui->tabWidget->currentIndex() == 0;
}
void CalkitDialog::updateEntries()
{
// Coefficients
ui->open_Z0->setText(QString::number(ownKit.open_Z0));
ui->open_delay->setText(QString::number(ownKit.open_delay));
ui->open_loss->setText(QString::number(ownKit.open_loss));
ui->open_C0->setText(QString::number(ownKit.open_C0));
ui->open_C1->setText(QString::number(ownKit.open_C1));
ui->open_C2->setText(QString::number(ownKit.open_C2));
ui->open_C3->setText(QString::number(ownKit.open_C3));
ui->open_Z0->setText(QString::number(ownKit.SOLT.Open.Z0));
ui->open_delay->setText(QString::number(ownKit.SOLT.Open.delay));
ui->open_loss->setText(QString::number(ownKit.SOLT.Open.loss));
ui->open_C0->setText(QString::number(ownKit.SOLT.Open.C0));
ui->open_C1->setText(QString::number(ownKit.SOLT.Open.C1));
ui->open_C2->setText(QString::number(ownKit.SOLT.Open.C2));
ui->open_C3->setText(QString::number(ownKit.SOLT.Open.C3));
ui->short_Z0->setText(QString::number(ownKit.short_Z0));
ui->short_delay->setText(QString::number(ownKit.short_delay));
ui->short_loss->setText(QString::number(ownKit.short_loss));
ui->short_L0->setText(QString::number(ownKit.short_L0));
ui->short_L1->setText(QString::number(ownKit.short_L1));
ui->short_L2->setText(QString::number(ownKit.short_L2));
ui->short_L3->setText(QString::number(ownKit.short_L3));
ui->short_Z0->setText(QString::number(ownKit.SOLT.Short.Z0));
ui->short_delay->setText(QString::number(ownKit.SOLT.Short.delay));
ui->short_loss->setText(QString::number(ownKit.SOLT.Short.loss));
ui->short_L0->setText(QString::number(ownKit.SOLT.Short.L0));
ui->short_L1->setText(QString::number(ownKit.SOLT.Short.L1));
ui->short_L2->setText(QString::number(ownKit.SOLT.Short.L2));
ui->short_L3->setText(QString::number(ownKit.SOLT.Short.L3));
ui->load_Z0->setText(QString::number(ownKit.load_Z0));
ui->load_Z0->setText(QString::number(ownKit.SOLT.Load.Z0));
ui->through_Z0->setText(QString::number(ownKit.through_Z0));
ui->through_delay->setText(QString::number(ownKit.through_delay));
ui->through_loss->setText(QString::number(ownKit.through_loss));
ui->through_Z0->setText(QString::number(ownKit.SOLT.Through.Z0));
ui->through_delay->setText(QString::number(ownKit.SOLT.Through.delay));
ui->through_loss->setText(QString::number(ownKit.SOLT.Through.loss));
// Measurements
ui->open_touchstone->setFile(QString::fromStdString(ownKit.open_file));
ui->open_touchstone->selectPort(0, ownKit.open_Sparam);
ui->open_touchstone->setFile(ownKit.SOLT.Open.file);
ui->open_touchstone->selectPort(0, ownKit.SOLT.Open.Sparam);
ui->short_touchstone->setFile(QString::fromStdString(ownKit.short_file));
ui->short_touchstone->selectPort(0, ownKit.short_Sparam);
ui->short_touchstone->setFile(ownKit.SOLT.Short.file);
ui->short_touchstone->selectPort(0, ownKit.SOLT.Short.Sparam);
ui->load_touchstone->setFile(QString::fromStdString(ownKit.load_file));
ui->load_touchstone->selectPort(0, ownKit.load_Sparam);
ui->load_touchstone->setFile(ownKit.SOLT.Load.file);
ui->load_touchstone->selectPort(0, ownKit.SOLT.Load.Sparam);
ui->through_touchstone->setFile(QString::fromStdString(ownKit.through_file));
ui->through_touchstone->selectPort(0, ownKit.through_Sparam1);
ui->through_touchstone->selectPort(1, ownKit.through_Sparam2);
ui->through_touchstone->setFile(ownKit.SOLT.Through.file);
ui->through_touchstone->selectPort(0, ownKit.SOLT.Through.Sparam1);
ui->through_touchstone->selectPort(1, ownKit.SOLT.Through.Sparam2);
// Type
if (ownKit.open_measurements) {
if (ownKit.SOLT.Open.useMeasurements) {
ui->open_measurement->click();
} else {
ui->open_coefficients->click();
}
if (ownKit.short_measurements) {
if (ownKit.SOLT.Short.useMeasurements) {
ui->short_measurement->click();
} else {
ui->short_coefficients->click();
}
if (ownKit.load_measurements) {
if (ownKit.SOLT.Load.useMeasurements) {
ui->load_measurement->click();
} else {
ui->load_coefficients->click();
}
if (ownKit.through_measurements) {
if (ownKit.SOLT.Through.useMeasurements) {
ui->through_measurement->click();
} else {
ui->through_coefficients->click();
}
// TRL
ui->TRL_through_Z0->setText(QString::number(ownKit.TRL_through_Z0));
if(ownKit.TRL_reflection_short) {
ui->TRL_through_Z0->setText(QString::number(ownKit.TRL.Through.Z0));
if(ownKit.TRL.Reflection.isShort) {
ui->TRL_R_short->setChecked(true);
} else {
ui->TRL_R_open->setChecked(true);
}
ui->TRL_line_delay->setText(QString::number(ownKit.TRL_line_delay));
ui->TRL_line_min->setValueQuiet(ownKit.TRL_line_minfreq);
ui->TRL_line_max->setValueQuiet(ownKit.TRL_line_maxfreq);
ui->TRL_line_delay->setText(QString::number(ownKit.TRL.Line.delay));
ui->TRL_line_min->setValueQuiet(ownKit.TRL.Line.minFreq);
ui->TRL_line_max->setValueQuiet(ownKit.TRL.Line.maxFreq);
// Check if line length is appropriate for frequencies
auto minDelay = 20.0/(ownKit.TRL_line_minfreq * 360.0) * 1e12;
auto maxDelay = 160.0/(ownKit.TRL_line_maxfreq * 360.0) * 1e12;
if(ownKit.TRL_line_delay < minDelay) {
auto minDelay = 20.0/(ownKit.TRL.Line.minFreq * 360.0) * 1e12;
auto maxDelay = 160.0/(ownKit.TRL.Line.maxFreq * 360.0) * 1e12;
if(ownKit.TRL.Line.delay < minDelay) {
ui->TRL_line_warning->setText("Line too short, minimum required delay is "+QString::number(minDelay, 'g', 3) + "ps");
} else if(ownKit.TRL_line_delay > maxDelay) {
} else if(ownKit.TRL.Line.delay > maxDelay) {
ui->TRL_line_warning->setText("Line too long, maximum allowed delay is "+QString::number(maxDelay, 'g', 3) + "ps");
} else {
ui->TRL_line_warning->clear();
}
if (ownKit.startDialogWithSOLT) {
ui->tabWidget->setCurrentIndex(0);
} else {
ui->tabWidget->setCurrentIndex(1);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
#ifndef QPOINTERVARIANT_H
#define QPOINTERVARIANT_H
#include <QVariant>
class QPointerVariant {
public:
template <typename T> QPointerVariant(T *ptr)
: ptr(static_cast<void*>(ptr)),
variant(QVariant(*ptr)){};
void setValue(const QVariant &value) {
auto destType = variant.type();
if(!value.canConvert(destType)) {
throw std::runtime_error("Unable to convert QVariant to requested type");
}
variant = value;
variant.convert(destType);
QMetaType mt(destType);
mt.construct(ptr, variant.constData());
}
QVariant value() {
return QVariant(variant.type(), ptr);
}
private:
void *ptr;
QVariant variant;
};
#endif // QPOINTERVARIANT_H

View File

@ -4,29 +4,7 @@
#include <QDialog>
#include <QVariant>
#include <exception>
class QPointerVariant {
public:
template <typename T> QPointerVariant(T *ptr)
: ptr(static_cast<void*>(ptr)),
variant(QVariant(*ptr)){};
void setValue(const QVariant &value) {
auto destType = variant.type();
if(!value.canConvert(destType)) {
throw std::runtime_error("Unable to convert QVariant to requested type");
}
variant = value;
variant.convert(destType);
QMetaType mt(destType);
mt.construct(ptr, variant.constData());
}
QVariant value() {
return QVariant(variant.type(), ptr);
}
private:
void *ptr;
QVariant variant;
};
#include "Util/qpointervariant.h"
class Preferences {
public: