WIP: make de-embedding and calibration work with arbitrary number of ports
This commit is contained in:
parent
8301448343
commit
9cf76c9681
@ -45,6 +45,7 @@ QString Calibration::TypeToString(Calibration::Type type)
|
||||
switch(type) {
|
||||
case Type::None: return "None";
|
||||
case Type::SOLT: return "SOLT";
|
||||
case Type::ThroughNormalization: return "ThroughNormalization";
|
||||
case Type::Last: return "Invalid";
|
||||
}
|
||||
}
|
||||
@ -134,6 +135,18 @@ void Calibration::correctMeasurement(VirtualDevice::VNAMeasurement &d)
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::correctTraces(std::map<QString, Trace *> traceSet)
|
||||
{
|
||||
auto points = Trace::assembleDatapoints(traceSet);
|
||||
if(points.size()) {
|
||||
// succeeded in assembling datapoints
|
||||
for(auto &p : points) {
|
||||
correctMeasurement(p);
|
||||
}
|
||||
Trace::fillFromDatapoints(traceSet, points);
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::edit()
|
||||
{
|
||||
auto d = new QDialog();
|
||||
@ -390,8 +403,7 @@ CalibrationMeasurement::Base *Calibration::newMeasurement(CalibrationMeasurement
|
||||
return m;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::computeSOLT(double f)
|
||||
{
|
||||
Calibration::Point Calibration::createInitializedPoint(double f) {
|
||||
Point point;
|
||||
point.frequency = f;
|
||||
// resize vectors
|
||||
@ -405,6 +417,12 @@ Calibration::Point Calibration::computeSOLT(double f)
|
||||
fill(point.L.begin(), point.L.end(), vector<complex<double>>(caltype.usedPorts.size()));
|
||||
fill(point.T.begin(), point.T.end(), vector<complex<double>>(caltype.usedPorts.size()));
|
||||
fill(point.I.begin(), point.I.end(), vector<complex<double>>(caltype.usedPorts.size()));
|
||||
return point;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::computeSOLT(double f)
|
||||
{
|
||||
Point point = createInitializedPoint(f);
|
||||
|
||||
// Calculate SOL coefficients
|
||||
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
|
||||
@ -464,6 +482,47 @@ Calibration::Point Calibration::computeSOLT(double f)
|
||||
return point;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::computeThroughNormalization(double f)
|
||||
{
|
||||
Point point = createInitializedPoint(f);
|
||||
|
||||
// Calculate SOL coefficients
|
||||
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
|
||||
// use ideal coefficients
|
||||
point.D[i] = 0.0;
|
||||
point.S[i] = 0.0;
|
||||
point.R[i] = 1.0;
|
||||
}
|
||||
// calculate forward match and transmission
|
||||
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
|
||||
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
|
||||
if(i == j) {
|
||||
// this is the exciting port, SOL error box used here
|
||||
continue;
|
||||
}
|
||||
auto p1 = caltype.usedPorts[i];
|
||||
auto p2 = caltype.usedPorts[j];
|
||||
// grab measurement and calkit through definitions
|
||||
auto throughForward = static_cast<CalibrationMeasurement::Through*>(findMeasurement(CalibrationMeasurement::Base::Type::Through, p1, p2));
|
||||
auto throughReverse = static_cast<CalibrationMeasurement::Through*>(findMeasurement(CalibrationMeasurement::Base::Type::Through, p2, p1));
|
||||
complex<double> S11, S21;
|
||||
Sparam Sideal;
|
||||
if(throughForward) {
|
||||
S21 = throughForward->getMeasured(f).m21;
|
||||
Sideal = throughForward->getActual(f);
|
||||
} else if(throughReverse) {
|
||||
S21 = throughReverse->getMeasured(f).m12;
|
||||
Sideal = throughReverse->getActual(f);
|
||||
swap(Sideal.m12, Sideal.m21);
|
||||
}
|
||||
point.L[i][j] = 0.0;
|
||||
point.T[i][j] = S21 / Sideal.m21;
|
||||
point.I[i][j] = 0.0;
|
||||
}
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
Calibration::CalType Calibration::getCaltype() const
|
||||
{
|
||||
return caltype;
|
||||
@ -504,12 +563,151 @@ Calibration::InterpolationType Calibration::getInterpolation(double f_start, dou
|
||||
|
||||
std::vector<Trace *> Calibration::getErrorTermTraces()
|
||||
{
|
||||
return vector<Trace*>(); // TODO
|
||||
vector<Trace*> ret;
|
||||
if(points.size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
|
||||
auto p = caltype.usedPorts[i];
|
||||
auto tDir = new Trace("Directivity_Port"+QString::number(p));
|
||||
tDir->setReflection(true);
|
||||
tDir->setCalibration();
|
||||
auto tSM = new Trace("SourceMatch_Port"+QString::number(p));
|
||||
tSM->setReflection(true);
|
||||
tSM->setCalibration();
|
||||
auto tRT = new Trace("ReflectionTracking_Port"+QString::number(p));
|
||||
tRT->setReflection(false);
|
||||
tRT->setCalibration();
|
||||
for(auto p : points) {
|
||||
Trace::Data td;
|
||||
td.x = p.frequency;
|
||||
td.y = p.D[i];
|
||||
tDir->addData(td, Trace::DataType::Frequency);
|
||||
td.y = p.S[i];
|
||||
tSM->addData(td, Trace::DataType::Frequency);
|
||||
td.y = p.R[i];
|
||||
tRT->addData(td, Trace::DataType::Frequency);
|
||||
}
|
||||
ret.push_back(tDir);
|
||||
ret.push_back(tSM);
|
||||
ret.push_back(tRT);
|
||||
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
|
||||
if(i==j) {
|
||||
continue;
|
||||
}
|
||||
auto p2 = caltype.usedPorts[j];
|
||||
auto tRM = new Trace("ReceiverMatch_"+QString::number(p)+QString::number(p2));
|
||||
tRM->setReflection(true);
|
||||
tRM->setCalibration();
|
||||
auto tTT = new Trace("TransmissionTracking_"+QString::number(p)+QString::number(p2));
|
||||
tTT->setReflection(false);
|
||||
tTT->setCalibration();
|
||||
auto tTI = new Trace("TransmissionIsolation_"+QString::number(p)+QString::number(p2));
|
||||
tTI->setReflection(false);
|
||||
tTI->setCalibration();
|
||||
for(auto p : points) {
|
||||
Trace::Data td;
|
||||
td.x = p.frequency;
|
||||
td.y = p.L[i][j];
|
||||
tRM->addData(td, Trace::DataType::Frequency);
|
||||
td.y = p.T[i][j];
|
||||
tTT->addData(td, Trace::DataType::Frequency);
|
||||
td.y = p.I[i][j];
|
||||
tTI->addData(td, Trace::DataType::Frequency);
|
||||
}
|
||||
ret.push_back(tRM);
|
||||
ret.push_back(tTT);
|
||||
ret.push_back(tTI);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<Trace *> Calibration::getMeasurementTraces()
|
||||
{
|
||||
return vector<Trace*>(); // TODO
|
||||
vector<Trace*> ret;
|
||||
for(auto m : measurements) {
|
||||
switch(m->getType()) {
|
||||
case CalibrationMeasurement::Base::Type::Open:
|
||||
case CalibrationMeasurement::Base::Type::Short:
|
||||
case CalibrationMeasurement::Base::Type::Load: {
|
||||
auto onePort = static_cast<CalibrationMeasurement::OnePort*>(m);
|
||||
auto t = new Trace(CalibrationMeasurement::Base::TypeToString(onePort->getType())+"_Port"+QString::number(onePort->getPort()));
|
||||
t->setCalibration();
|
||||
t->setReflection(true);
|
||||
for(auto d : onePort->getPoints()) {
|
||||
Trace::Data td;
|
||||
td.x = d.frequency;
|
||||
td.y = d.S;
|
||||
t->addData(td, Trace::DataType::Frequency);
|
||||
}
|
||||
ret.push_back(t);
|
||||
}
|
||||
break;
|
||||
case CalibrationMeasurement::Base::Type::Through: {
|
||||
auto twoPort = static_cast<CalibrationMeasurement::TwoPort*>(m);
|
||||
auto ts11 = new Trace(CalibrationMeasurement::Base::TypeToString(twoPort->getType())+"_Port"+QString::number(twoPort->getPort1())+QString::number(twoPort->getPort2())+"_S11");
|
||||
auto ts12 = new Trace(CalibrationMeasurement::Base::TypeToString(twoPort->getType())+"_Port"+QString::number(twoPort->getPort1())+QString::number(twoPort->getPort2())+"_S12");
|
||||
auto ts21 = new Trace(CalibrationMeasurement::Base::TypeToString(twoPort->getType())+"_Port"+QString::number(twoPort->getPort1())+QString::number(twoPort->getPort2())+"_S21");
|
||||
auto ts22 = new Trace(CalibrationMeasurement::Base::TypeToString(twoPort->getType())+"_Port"+QString::number(twoPort->getPort1())+QString::number(twoPort->getPort2())+"_S22");
|
||||
ts11->setCalibration();
|
||||
ts11->setReflection(true);
|
||||
ts12->setCalibration();
|
||||
ts12->setReflection(false);
|
||||
ts21->setCalibration();
|
||||
ts21->setReflection(false);
|
||||
ts22->setCalibration();
|
||||
ts22->setReflection(true);
|
||||
for(auto d : twoPort->getPoints()) {
|
||||
Trace::Data td;
|
||||
td.x = d.frequency;
|
||||
td.y = d.S.m11;
|
||||
ts11->addData(td, Trace::DataType::Frequency);
|
||||
td.y = d.S.m12;
|
||||
ts12->addData(td, Trace::DataType::Frequency);
|
||||
td.y = d.S.m21;
|
||||
ts21->addData(td, Trace::DataType::Frequency);
|
||||
td.y = d.S.m22;
|
||||
ts22->addData(td, Trace::DataType::Frequency);
|
||||
}
|
||||
ret.push_back(ts11);
|
||||
ret.push_back(ts12);
|
||||
ret.push_back(ts21);
|
||||
ret.push_back(ts22);
|
||||
}
|
||||
break;
|
||||
case CalibrationMeasurement::Base::Type::Isolation: {
|
||||
auto iso = static_cast<CalibrationMeasurement::Isolation*>(m);
|
||||
int ports = iso->getPoints()[0].S.size();
|
||||
// Create the traces
|
||||
vector<vector<Trace*>> traces;
|
||||
traces.resize(ports);
|
||||
for(int i=0;i<ports;i++) {
|
||||
for(int j=0;j<ports;j++) {
|
||||
auto t = new Trace(CalibrationMeasurement::Base::TypeToString(iso->getType())+"_S"+QString::number(i+1)+QString::number(j+1));
|
||||
t->setCalibration();
|
||||
t->setReflection(i==j);
|
||||
traces[i].push_back(t);
|
||||
// also add to main return vector
|
||||
ret.push_back(t);
|
||||
}
|
||||
}
|
||||
// Fill the traces
|
||||
for(auto p : iso->getPoints()) {
|
||||
Trace::Data td;
|
||||
td.x = p.frequency;
|
||||
for(int i=0;i<p.S.size();i++) {
|
||||
for(int j=0;j<p.S[i].size();j++) {
|
||||
td.y = p.S[i][j];
|
||||
traces[i][j]->addData(td, Trace::DataType::Frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString Calibration::getCurrentCalibrationFile()
|
||||
@ -735,15 +933,15 @@ std::vector<Calibration::Type> Calibration::getTypes()
|
||||
|
||||
bool Calibration::canCompute(Calibration::CalType type, double *startFreq, double *stopFreq, int *points)
|
||||
{
|
||||
using RequiredMeasurements = struct {
|
||||
CalibrationMeasurement::Base::Type type;
|
||||
int port1, port2;
|
||||
};
|
||||
vector<RequiredMeasurements> required;
|
||||
switch(type.type) {
|
||||
case Type::None:
|
||||
return true; // Always possible to reset the calibration
|
||||
case Type::SOLT: {
|
||||
using RequiredMeasurements = struct {
|
||||
CalibrationMeasurement::Base::Type type;
|
||||
int port1, port2;
|
||||
};
|
||||
vector<RequiredMeasurements> required;
|
||||
case Type::SOLT:
|
||||
// SOL measurements for every port
|
||||
for(auto p : type.usedPorts) {
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Short, .port1 = p});
|
||||
@ -756,6 +954,17 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Through, .port1 = i, .port2 = j});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::ThroughNormalization:
|
||||
// through measurements between all ports
|
||||
for(int i=1;i<=type.usedPorts.size();i++) {
|
||||
for(int j=i+1;j<=type.usedPorts.size();j++) {
|
||||
required.push_back({.type = CalibrationMeasurement::Base::Type::Through, .port1 = i, .port2 = j});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(required.size() > 0) {
|
||||
vector<CalibrationMeasurement::Base*> foundMeasurements;
|
||||
for(auto m : required) {
|
||||
auto meas = findMeasurement(m.type, m.port1, m.port2);
|
||||
@ -767,8 +976,6 @@ bool Calibration::canCompute(Calibration::CalType type, double *startFreq, doubl
|
||||
}
|
||||
}
|
||||
return hasFrequencyOverlap(foundMeasurements, startFreq, stopFreq, points);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -816,6 +1023,7 @@ int Calibration::minimumPorts(Calibration::Type type)
|
||||
{
|
||||
switch(type) {
|
||||
case Type::SOLT: return 1;
|
||||
case Type::ThroughNormalization: return 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ public:
|
||||
enum class Type {
|
||||
None,
|
||||
SOLT,
|
||||
ThroughNormalization,
|
||||
Last,
|
||||
};
|
||||
class CalType {
|
||||
@ -36,6 +37,7 @@ public:
|
||||
|
||||
// Applies calculated calibration coefficients to measurement data
|
||||
void correctMeasurement(VirtualDevice::VNAMeasurement &d);
|
||||
void correctTraces(std::map<QString, Trace*> traceSet);
|
||||
|
||||
// Starts the calibration edit dialog, allowing the user to make/delete measurements
|
||||
void edit();
|
||||
@ -123,8 +125,8 @@ private:
|
||||
public:
|
||||
double frequency;
|
||||
std::vector<std::complex<double>> D; // Directivity
|
||||
std::vector<std::complex<double>> R; // Source Match
|
||||
std::vector<std::complex<double>> S; // Reflection tracking
|
||||
std::vector<std::complex<double>> R; // Reflection tracking
|
||||
std::vector<std::complex<double>> S; // Source Match
|
||||
std::vector<std::vector<std::complex<double>>> L; // Receiver Match
|
||||
std::vector<std::vector<std::complex<double>>> T; // Transmission tracking
|
||||
std::vector<std::vector<std::complex<double>>> I; // Transmission isolation
|
||||
@ -132,7 +134,9 @@ private:
|
||||
};
|
||||
std::vector<Point> points;
|
||||
|
||||
Point createInitializedPoint(double f);
|
||||
Point computeSOLT(double f);
|
||||
Point computeThroughNormalization(double f);
|
||||
|
||||
std::vector<CalibrationMeasurement::Base*> measurements;
|
||||
|
||||
|
@ -328,6 +328,11 @@ void CalibrationMeasurement::OnePort::setPort(int p)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CalibrationMeasurement::OnePort::Point> CalibrationMeasurement::OnePort::getPoints() const
|
||||
{
|
||||
return points;
|
||||
}
|
||||
|
||||
double CalibrationMeasurement::TwoPort::minFreq()
|
||||
{
|
||||
if(points.size() > 0) {
|
||||
@ -529,6 +534,11 @@ void CalibrationMeasurement::TwoPort::setReverseStandard(bool reverse)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CalibrationMeasurement::TwoPort::Point> CalibrationMeasurement::TwoPort::getPoints() const
|
||||
{
|
||||
return points;
|
||||
}
|
||||
|
||||
int CalibrationMeasurement::TwoPort::getPort1() const
|
||||
{
|
||||
return port1;
|
||||
@ -658,3 +668,8 @@ std::complex<double> CalibrationMeasurement::Isolation::getMeasured(double frequ
|
||||
return p.S[portRcv][portSrc];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CalibrationMeasurement::Isolation::Point> CalibrationMeasurement::Isolation::getPoints() const
|
||||
{
|
||||
return points;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef CALIBRATIONMEASUREMENT_H
|
||||
#ifndef CALIBRATIONMEASUREMENT_H
|
||||
#define CALIBRATIONMEASUREMENT_H
|
||||
|
||||
#include "calstandard.h"
|
||||
@ -83,6 +83,13 @@ public:
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
std::complex<double> S;
|
||||
};
|
||||
std::vector<Point> getPoints() const;
|
||||
|
||||
std::complex<double> getMeasured(double frequency);
|
||||
std::complex<double> getActual(double frequency);
|
||||
|
||||
@ -95,11 +102,6 @@ signals:
|
||||
void portChanged(int p);
|
||||
protected:
|
||||
int port;
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
std::complex<double> S;
|
||||
};
|
||||
std::vector<Point> points;
|
||||
};
|
||||
|
||||
@ -156,12 +158,20 @@ public:
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
Sparam S;
|
||||
};
|
||||
std::vector<Point> getPoints() const;
|
||||
|
||||
Sparam getMeasured(double frequency);
|
||||
Sparam getActual(double frequency);
|
||||
|
||||
int getPort1() const;
|
||||
int getPort2() const;
|
||||
|
||||
|
||||
public slots:
|
||||
void setPort1(int p);
|
||||
void setPort2(int p);
|
||||
@ -174,11 +184,6 @@ signals:
|
||||
protected:
|
||||
int port1, port2;
|
||||
bool reverseStandard; // Set to true if standard is defined with ports swapped
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
Sparam S;
|
||||
};
|
||||
std::vector<Point> points;
|
||||
};
|
||||
|
||||
@ -211,17 +216,19 @@ public:
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
std::vector<std::vector<std::complex<double>>> S;
|
||||
};
|
||||
std::vector<Point> getPoints() const;
|
||||
|
||||
std::complex<double> getMeasured(double frequency, unsigned int portRcv, unsigned int portSrc);
|
||||
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandardTypes() override {return {};}
|
||||
virtual Type getType() override {return Type::Isolation;}
|
||||
|
||||
protected:
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
std::vector<std::vector<std::complex<double>>> S;
|
||||
};
|
||||
std::vector<Point> points;
|
||||
};
|
||||
|
||||
|
@ -7,13 +7,12 @@ ManualCalibrationDialog::ManualCalibrationDialog(const TraceModel &model, Calibr
|
||||
ui(new Ui::ManualCalibrationDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto traceSelector = new SparamTraceSelector(model, 2);
|
||||
auto traceSelector = new SparamTraceSelector(model, cal->getCaltype().usedPorts);
|
||||
ui->verticalLayout->insertWidget(1, traceSelector, 1.0);
|
||||
ui->buttonBox->setEnabled(false);
|
||||
connect(traceSelector, &SparamTraceSelector::selectionValid, ui->buttonBox, &QDialogButtonBox::setEnabled);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=]() {
|
||||
auto t = traceSelector->getTraces();
|
||||
// cal->correctTraces(*t[0], *t[1], *t[2], *t[3]); // TODO
|
||||
cal->correctTraces(traceSelector->getTraces());
|
||||
accept();
|
||||
});
|
||||
}
|
||||
|
@ -5,42 +5,39 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
SparamTraceSelector::SparamTraceSelector(const TraceModel &model, unsigned int num_ports, bool empty_allowed, std::set<unsigned int> skip)
|
||||
SparamTraceSelector::SparamTraceSelector(const TraceModel &model, std::vector<int> used_ports, bool empty_allowed)
|
||||
: model(model),
|
||||
num_ports(num_ports),
|
||||
used_ports(used_ports),
|
||||
empty_allowed(empty_allowed)
|
||||
{
|
||||
// Create comboboxes
|
||||
auto layout = new QFormLayout;
|
||||
setLayout(layout);
|
||||
for(unsigned int i=0;i<num_ports;i++) {
|
||||
for(unsigned int j=0;j<num_ports;j++) {
|
||||
auto label = new QLabel("S"+QString::number(i+1)+QString::number(j+1)+":");
|
||||
auto box = new QComboBox();
|
||||
connect(box, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) {
|
||||
traceSelectionChanged(box);
|
||||
});
|
||||
boxes.push_back(box);
|
||||
layout->addRow(label, box);
|
||||
if(skip.count(i*num_ports + j)) {
|
||||
label->setVisible(false);
|
||||
box->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createGUI();
|
||||
setInitialChoices();
|
||||
}
|
||||
|
||||
std::vector<Trace*> SparamTraceSelector::getTraces()
|
||||
SparamTraceSelector::SparamTraceSelector(const TraceModel &model, std::set<int> used_ports, bool empty_allowed)
|
||||
: model(model),
|
||||
empty_allowed(empty_allowed)
|
||||
{
|
||||
vector<Trace*> ret;
|
||||
for(auto b : boxes) {
|
||||
if(b->currentIndex() == 0) {
|
||||
ret.push_back(nullptr);
|
||||
} else {
|
||||
auto trace = qvariant_cast<Trace*>(b->itemData(b->currentIndex()));
|
||||
ret.push_back(trace);
|
||||
// create vector from set
|
||||
std::copy(used_ports.begin(), used_ports.end(), std::back_inserter(this->used_ports));
|
||||
createGUI();
|
||||
setInitialChoices();
|
||||
}
|
||||
|
||||
std::map<QString, Trace*> SparamTraceSelector::getTraces()
|
||||
{
|
||||
std::map<QString, Trace*> ret;
|
||||
for(unsigned int i=0;i<used_ports.size();i++) {
|
||||
for(unsigned int j=0;j<used_ports.size();j++) {
|
||||
auto b = boxes[i*used_ports.size()+j];
|
||||
Trace *t;
|
||||
if(b->currentIndex() == 0) {
|
||||
t = nullptr;
|
||||
} else {
|
||||
t = qvariant_cast<Trace*>(b->itemData(b->currentIndex()));
|
||||
}
|
||||
QString name = "S"+QString::number(used_ports[i])+QString::number(used_ports[j]);
|
||||
ret[name] = t;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -48,7 +45,7 @@ std::vector<Trace*> SparamTraceSelector::getTraces()
|
||||
|
||||
void SparamTraceSelector::setInitialChoices()
|
||||
{
|
||||
for(unsigned int i=0;i<num_ports*num_ports;i++) {
|
||||
for(unsigned int i=0;i<used_ports.size()*used_ports.size();i++) {
|
||||
boxes[i]->blockSignals(true);
|
||||
boxes[i]->clear();
|
||||
boxes[i]->addItem("None");
|
||||
@ -61,7 +58,7 @@ void SparamTraceSelector::setInitialChoices()
|
||||
// can't select empty traces
|
||||
continue;
|
||||
}
|
||||
bool reflectionRequired = i%(num_ports+1) == 0 ? true : false;
|
||||
bool reflectionRequired = i%(used_ports.size()+1) == 0 ? true : false;
|
||||
if(reflectionRequired != t->isReflection()) {
|
||||
// invalid S parameter
|
||||
continue;
|
||||
@ -106,7 +103,7 @@ void SparamTraceSelector::traceSelectionChanged(QComboBox *cb)
|
||||
text.chop(2);
|
||||
if(text.endsWith("S")) {
|
||||
// tracename ended in Sxx, probably other traces with matching prefix available
|
||||
for(unsigned int i=0;i<num_ports*num_ports;i++) {
|
||||
for(unsigned int i=0;i<used_ports.size()*used_ports.size();i++) {
|
||||
auto b = boxes[i];
|
||||
if(b == cb) {
|
||||
// skip this box
|
||||
@ -115,7 +112,7 @@ void SparamTraceSelector::traceSelectionChanged(QComboBox *cb)
|
||||
for(int j=0;j<b->count();j++) {
|
||||
auto candidate = b->itemText(j);
|
||||
// check if correct parameter
|
||||
QString expectedSparam = QString::number(i/num_ports+1)+QString::number(i%num_ports+1);
|
||||
QString expectedSparam = QString::number(i/used_ports.size()+1)+QString::number(i%used_ports.size()+1);
|
||||
if(!candidate.endsWith(expectedSparam)) {
|
||||
// wrong S parameter, skip
|
||||
continue;
|
||||
@ -170,3 +167,21 @@ void SparamTraceSelector::traceSelectionChanged(QComboBox *cb)
|
||||
emit selectionValid(valid);
|
||||
}
|
||||
}
|
||||
|
||||
void SparamTraceSelector::createGUI()
|
||||
{
|
||||
// Create comboboxes
|
||||
auto layout = new QFormLayout;
|
||||
setLayout(layout);
|
||||
for(unsigned int i=0;i<used_ports.size();i++) {
|
||||
for(unsigned int j=0;j<used_ports.size();j++) {
|
||||
auto label = new QLabel("S"+QString::number(used_ports[i])+QString::number(used_ports[j])+":");
|
||||
auto box = new QComboBox();
|
||||
connect(box, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) {
|
||||
traceSelectionChanged(box);
|
||||
});
|
||||
boxes.push_back(box);
|
||||
layout->addRow(label, box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "tracemodel.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
|
||||
@ -11,12 +13,13 @@ class SparamTraceSelector : public QWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SparamTraceSelector(const TraceModel &model, unsigned int num_ports, bool empty_allowed = false, std::set<unsigned int> skip = {});
|
||||
SparamTraceSelector(const TraceModel &model, std::vector<int> used_ports, bool empty_allowed = false);
|
||||
SparamTraceSelector(const TraceModel &model, std::set<int> used_ports, bool empty_allowed = false);
|
||||
|
||||
bool isValid();
|
||||
|
||||
std::vector<Trace*> getTraces();
|
||||
unsigned int getPoints() { return points;};
|
||||
std::map<QString, Trace*> getTraces();
|
||||
unsigned int getPoints() { return points;}
|
||||
|
||||
signals:
|
||||
void selectionValid(bool valid);
|
||||
@ -24,12 +27,13 @@ signals:
|
||||
private:
|
||||
void setInitialChoices();
|
||||
void traceSelectionChanged(QComboBox *cb);
|
||||
void createGUI();
|
||||
|
||||
const TraceModel &model;
|
||||
std::vector<QComboBox*> boxes;
|
||||
unsigned int num_ports;
|
||||
bool empty_allowed;
|
||||
|
||||
std::vector<int> used_ports;
|
||||
unsigned int points;
|
||||
double minFreq, maxFreq;
|
||||
bool valid;
|
||||
|
@ -260,24 +260,24 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter)
|
||||
return lastTraceName;
|
||||
}
|
||||
|
||||
void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VirtualDevice::VNAMeasurement> &data)
|
||||
void Trace::fillFromDatapoints(std::map<QString, Trace *> traceSet, const std::vector<VirtualDevice::VNAMeasurement> &data)
|
||||
{
|
||||
S11.clear();
|
||||
S12.clear();
|
||||
S21.clear();
|
||||
S22.clear();
|
||||
// remove all previous points
|
||||
for(auto m : traceSet) {
|
||||
m.second->clear();
|
||||
}
|
||||
// add new points to traces
|
||||
for(auto d : data) {
|
||||
Trace::Data td;
|
||||
auto S = d.toSparam(1, 2);
|
||||
td.x = d.frequency;
|
||||
td.y = S.m11;
|
||||
S11.addData(td, DataType::Frequency);
|
||||
td.y = S.m12;
|
||||
S12.addData(td, DataType::Frequency);
|
||||
td.y = S.m21;
|
||||
S21.addData(td, DataType::Frequency);
|
||||
td.y = S.m22;
|
||||
S22.addData(td, DataType::Frequency);
|
||||
for(auto m : d.measurements) {
|
||||
td.y = m.second;
|
||||
QString measurement = m.first;
|
||||
if(traceSet.count(measurement)) {
|
||||
traceSet[measurement]->addData(td, DataType::Frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -894,20 +894,16 @@ std::vector<Trace *> Trace::createFromCSV(CSV &csv)
|
||||
return traces;
|
||||
}
|
||||
|
||||
std::vector<VirtualDevice::VNAMeasurement> Trace::assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22)
|
||||
std::vector<VirtualDevice::VNAMeasurement> Trace::assembleDatapoints(std::map<QString, Trace *> traceSet)
|
||||
{
|
||||
vector<VirtualDevice::VNAMeasurement> 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);
|
||||
traces.push_back(&S21);
|
||||
traces.push_back(&S22);
|
||||
unsigned int samples = traceSet.begin()->second->size();
|
||||
auto impedance = traceSet.begin()->second->getReferenceImpedance();
|
||||
vector<double> freqs;
|
||||
for(const auto t : traces) {
|
||||
for(auto m : traceSet) {
|
||||
const Trace *t = m.second;
|
||||
if(t->size() != samples) {
|
||||
qWarning() << "Selected traces do not have the same size";
|
||||
return ret;
|
||||
@ -939,10 +935,11 @@ std::vector<VirtualDevice::VNAMeasurement> Trace::assembleDatapoints(const Trace
|
||||
// Checks passed, assemble datapoints
|
||||
for(unsigned int i=0;i<samples;i++) {
|
||||
VirtualDevice::VNAMeasurement d;
|
||||
d.measurements["S11"] = S11.sample(i).y;
|
||||
d.measurements["S12"] = S12.sample(i).y;
|
||||
d.measurements["S21"] = S21.sample(i).y;
|
||||
d.measurements["S22"] = S22.sample(i).y;
|
||||
for(auto m : traceSet) {
|
||||
QString measurement = m.first;
|
||||
const Trace *t = m.second;
|
||||
d.measurements[measurement] = t->sample(i).y;
|
||||
}
|
||||
d.pointNum = i;
|
||||
d.frequency = freqs[i];
|
||||
ret.push_back(d);
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
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<VirtualDevice::VNAMeasurement> &data);
|
||||
static void fillFromDatapoints(std::map<QString, Trace*> traceSet, const std::vector<VirtualDevice::VNAMeasurement> &data);
|
||||
void fromLivedata(LivedataType type, QString param);
|
||||
void fromMath();
|
||||
QString name() { return _name; }
|
||||
@ -137,7 +137,7 @@ public:
|
||||
|
||||
// Assembles datapoints as received from the VNA from four S parameter traces. Requires that all traces are in the frequency domain,
|
||||
// have the same number of samples and their samples must be at the same frequencies across all traces
|
||||
static std::vector<VirtualDevice::VNAMeasurement> assembleDatapoints(const Trace &S11, const Trace &S12, const Trace &S21, const Trace &S22);
|
||||
static std::vector<VirtualDevice::VNAMeasurement> assembleDatapoints(std::map<QString, Trace *> traceSet);
|
||||
|
||||
static LivedataType TypeFromString(QString s);
|
||||
static QString TypeToString(LivedataType t);
|
||||
|
@ -232,7 +232,7 @@ void TracePolarChart::draw(QPainter &p) {
|
||||
}
|
||||
|
||||
if(dropPending) {
|
||||
// TODO adjust coords due to shifted restore
|
||||
// adjust coords due to shifted restore
|
||||
p.setOpacity(0.5);
|
||||
p.setBrush(Qt::white);
|
||||
p.setPen(Qt::white);
|
||||
|
@ -328,7 +328,7 @@ void TraceSmithChart::draw(QPainter &p) {
|
||||
}
|
||||
}
|
||||
if(dropPending) {
|
||||
// TODO adjust coords due to shifted restore
|
||||
// adjust coords due to shifted restore
|
||||
p.setOpacity(0.5);
|
||||
p.setBrush(Qt::white);
|
||||
p.setPen(Qt::white);
|
||||
|
@ -30,7 +30,7 @@ void Deembedding::measurementCompleted()
|
||||
measurementUI = nullptr;
|
||||
}
|
||||
|
||||
void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22)
|
||||
void Deembedding::startMeasurementDialog(DeembeddingOption *option)
|
||||
{
|
||||
measurements.clear();
|
||||
measurementDialog = new QDialog;
|
||||
@ -42,20 +42,7 @@ void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22)
|
||||
});
|
||||
|
||||
// add the trace selector
|
||||
set<unsigned int> skip;
|
||||
if(!S11) {
|
||||
skip.insert(0);
|
||||
}
|
||||
if(!S12) {
|
||||
skip.insert(1);
|
||||
}
|
||||
if(!S21) {
|
||||
skip.insert(2);
|
||||
}
|
||||
if(!S22) {
|
||||
skip.insert(3);
|
||||
}
|
||||
auto traceChooser = new SparamTraceSelector(tm, 2, false, skip);
|
||||
auto traceChooser = new SparamTraceSelector(tm, option->getAffectedPorts());
|
||||
ui->horizontalLayout_2->insertWidget(0, traceChooser, 1);
|
||||
|
||||
connect(traceChooser, &SparamTraceSelector::selectionValid, ui->buttonBox, &QDialogButtonBox::setEnabled);
|
||||
@ -70,33 +57,8 @@ void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22)
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
|
||||
// create datapoints from individual traces
|
||||
measurements.clear();
|
||||
auto t = traceChooser->getTraces();
|
||||
auto S11 = t[0];
|
||||
auto S12 = t[1];
|
||||
auto S21 = t[2];
|
||||
auto S22 = t[3];
|
||||
for(unsigned int i=0;i<traceChooser->getPoints();i++) {
|
||||
VirtualDevice::VNAMeasurement p;
|
||||
p.pointNum = i;
|
||||
p.Z0 = 0;
|
||||
p.dBm = 0;
|
||||
Sparam S;
|
||||
if(S11) {
|
||||
S.m11 = S11->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S12) {
|
||||
S.m12 = S12->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S21) {
|
||||
S.m21 = S21->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
if(S22) {
|
||||
S.m22 = S22->sample(i).y;
|
||||
p.frequency = S11->sample(i).x;
|
||||
}
|
||||
auto points = Trace::assembleDatapoints(traceChooser->getTraces());
|
||||
for(auto p : points) {
|
||||
measurements.push_back(p);
|
||||
}
|
||||
measurementCompleted();
|
||||
@ -151,15 +113,15 @@ void Deembedding::Deembed(VirtualDevice::VNAMeasurement &d)
|
||||
}
|
||||
}
|
||||
|
||||
void Deembedding::Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22)
|
||||
void Deembedding::Deembed(std::map<QString, Trace *> traceSet)
|
||||
{
|
||||
auto points = Trace::assembleDatapoints(S11, S12, S21, S22);
|
||||
auto points = Trace::assembleDatapoints(traceSet);
|
||||
if(points.size()) {
|
||||
// succeeded in assembling datapoints
|
||||
for(auto &p : points) {
|
||||
Deembed(p);
|
||||
}
|
||||
Trace::fillFromDatapoints(S11, S12, S21, S22, points);
|
||||
Trace::fillFromDatapoints(traceSet, points);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,9 +146,9 @@ void Deembedding::addOption(DeembeddingOption *option)
|
||||
options.erase(pos);
|
||||
}
|
||||
});
|
||||
connect(option, &DeembeddingOption::triggerMeasurement, [=](bool S11, bool S12, bool S21, bool S22) {
|
||||
connect(option, &DeembeddingOption::triggerMeasurement, [=]() {
|
||||
measuringOption = option;
|
||||
startMeasurementDialog(S11, S12, S21, S22);
|
||||
startMeasurementDialog(option);
|
||||
});
|
||||
emit optionAdded();
|
||||
}
|
||||
@ -199,6 +161,16 @@ void Deembedding::swapOptions(unsigned int index)
|
||||
std::swap(options[index], options[index+1]);
|
||||
}
|
||||
|
||||
std::set<int> Deembedding::getAffectedPorts()
|
||||
{
|
||||
set<int> ret;
|
||||
for(auto o : options) {
|
||||
auto affected = o->getAffectedPorts();
|
||||
ret.insert(affected.begin(), affected.end());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
nlohmann::json Deembedding::toJSON()
|
||||
{
|
||||
nlohmann::json list;
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "Traces/tracemodel.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include <QComboBox>
|
||||
@ -20,11 +22,14 @@ public:
|
||||
~Deembedding(){}
|
||||
|
||||
void Deembed(VirtualDevice::VNAMeasurement &d);
|
||||
void Deembed(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
|
||||
void Deembed(std::map<QString, Trace*> traceSet);
|
||||
|
||||
void removeOption(unsigned int index);
|
||||
void addOption(DeembeddingOption* option);
|
||||
void swapOptions(unsigned int index);
|
||||
|
||||
std::set<int> getAffectedPorts();
|
||||
|
||||
std::vector<DeembeddingOption*>& getOptions() {return options;}
|
||||
nlohmann::json toJSON() override;
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
@ -36,7 +41,7 @@ signals:
|
||||
void allOptionsCleared();
|
||||
private:
|
||||
void measurementCompleted();
|
||||
void startMeasurementDialog(bool S11, bool S12, bool S21, bool S22);
|
||||
void startMeasurementDialog(DeembeddingOption *option);
|
||||
std::vector<DeembeddingOption*> options;
|
||||
DeembeddingOption *measuringOption;
|
||||
TraceModel &tm;
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
static DeembeddingOption *create(Type type);
|
||||
static QString getName(Type type);
|
||||
|
||||
virtual std::set<int> getAffectedPorts() = 0;
|
||||
virtual void transformDatapoint(VirtualDevice::VNAMeasurement &p) = 0;
|
||||
virtual void edit(){}
|
||||
virtual Type getType() = 0;
|
||||
@ -33,7 +34,7 @@ signals:
|
||||
// Deembedding option may selfdestruct if not applicable with current settings. It should emit this signal before deleting itself
|
||||
void deleted(DeembeddingOption *option);
|
||||
|
||||
void triggerMeasurement(bool S11 = true, bool S12 = true, bool S21 = true, bool S22 = true);
|
||||
void triggerMeasurement();
|
||||
};
|
||||
|
||||
#endif // DEEMBEDDING_H
|
||||
|
@ -15,6 +15,15 @@ ImpedanceRenormalization::ImpedanceRenormalization()
|
||||
|
||||
}
|
||||
|
||||
std::set<int> ImpedanceRenormalization::getAffectedPorts()
|
||||
{
|
||||
set<int> ret;
|
||||
for(int i=1;i<=VirtualDevice::getInfo(VirtualDevice::getConnected()).ports;i++) {
|
||||
ret.insert(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ImpedanceRenormalization::transformDatapoint(VirtualDevice::VNAMeasurement &p)
|
||||
{
|
||||
std::map<QString, std::complex<double>> transformed;
|
||||
|
@ -13,6 +13,7 @@ class ImpedanceRenormalization : public DeembeddingOption
|
||||
public:
|
||||
ImpedanceRenormalization();
|
||||
|
||||
std::set<int> getAffectedPorts() override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement &p) override;
|
||||
Type getType() override { return Type::ImpedanceRenormalization;}
|
||||
nlohmann::json toJSON() override;
|
||||
|
@ -7,13 +7,12 @@ ManualDeembeddingDialog::ManualDeembeddingDialog(const TraceModel &model, Deembe
|
||||
ui(new Ui::ManualDeembeddingDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto traceSelector = new SparamTraceSelector(model, 2);
|
||||
auto traceSelector = new SparamTraceSelector(model, deemb->getAffectedPorts());
|
||||
ui->verticalLayout->insertWidget(1, traceSelector, 1.0);
|
||||
ui->buttonBox->setEnabled(false);
|
||||
connect(traceSelector, &SparamTraceSelector::selectionValid, ui->buttonBox, &QDialogButtonBox::setEnabled);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=]() {
|
||||
auto t = traceSelector->getTraces();
|
||||
deemb->Deembed(*t[0], *t[1], *t[2], *t[3]);
|
||||
deemb->Deembed(traceSelector->getTraces());
|
||||
accept();
|
||||
});
|
||||
}
|
||||
|
@ -27,6 +27,11 @@ MatchingNetwork::MatchingNetwork()
|
||||
port = 1;
|
||||
}
|
||||
|
||||
std::set<int> MatchingNetwork::getAffectedPorts()
|
||||
{
|
||||
return {port};
|
||||
}
|
||||
|
||||
void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p)
|
||||
{
|
||||
auto S = p.toSparam(1, 2);
|
||||
@ -106,12 +111,12 @@ void MatchingNetwork::edit()
|
||||
p1->setMinimumSize(portWidth, 151);
|
||||
p1->setMaximumSize(portWidth, 151);
|
||||
p1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
p1->setStyleSheet("image: url(:/icons/port1.png);");
|
||||
p1->setStyleSheet("image: url(:/icons/port.png);");
|
||||
auto DUT = new QWidget();
|
||||
DUT->setMinimumSize(DUTWidth, 151);
|
||||
DUT->setMaximumSize(DUTWidth, 151);
|
||||
DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
DUT->setStyleSheet("image: url(:/icons/DUT.png);");
|
||||
DUT->setStyleSheet("image: url(:/icons/DUT_onePort.png);");
|
||||
|
||||
layout->addWidget(p1);
|
||||
for(auto w : network) {
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
|
||||
// DeembeddingOption interface
|
||||
public:
|
||||
std::set<int> getAffectedPorts() override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement &p) override;
|
||||
void edit() override;
|
||||
Type getType() override {return Type::MatchingNetwork;}
|
||||
|
@ -24,6 +24,11 @@ PortExtension::PortExtension()
|
||||
kit = nullptr;
|
||||
}
|
||||
|
||||
std::set<int> PortExtension::getAffectedPorts()
|
||||
{
|
||||
return {port};
|
||||
}
|
||||
|
||||
void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d)
|
||||
{
|
||||
auto phase = -2 * M_PI * ext.delay * d.frequency;
|
||||
@ -72,6 +77,8 @@ void PortExtension::edit()
|
||||
ui->DCloss->setValue(ext.DCloss);
|
||||
ui->Loss->setValue(ext.loss);
|
||||
ui->Frequency->setValue(ext.frequency);
|
||||
ui->port->setValue(port);
|
||||
ui->port->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports);
|
||||
if(!kit) {
|
||||
ui->calkit->setEnabled(false);
|
||||
}
|
||||
@ -97,6 +104,9 @@ void PortExtension::edit()
|
||||
ui->Time->setValueQuiet(ui->Distance->value() / (newval * c));
|
||||
updateValuesFromUI();
|
||||
});
|
||||
connect(ui->port, qOverload<int>(&QSpinBox::valueChanged), [=](){
|
||||
port = ui->port->value();
|
||||
});
|
||||
connect(ui->DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI);
|
||||
connect(ui->Loss, &SIUnitEdit::valueChanged, updateValuesFromUI);
|
||||
connect(ui->Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI);
|
||||
|
@ -18,6 +18,7 @@ class PortExtension : public DeembeddingOption
|
||||
Q_OBJECT
|
||||
public:
|
||||
PortExtension();
|
||||
std::set<int> getAffectedPorts() override;
|
||||
void transformDatapoint(VirtualDevice::VNAMeasurement& d) override;
|
||||
void setCalkit(Calkit *kit);
|
||||
Type getType() override {return Type::PortExtension;}
|
||||
|
@ -17,6 +17,11 @@ TwoThru::TwoThru()
|
||||
port2 = 2;
|
||||
}
|
||||
|
||||
std::set<int> TwoThru::getAffectedPorts()
|
||||
{
|
||||
return {port1, port2};
|
||||
}
|
||||
|
||||
void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p)
|
||||
{
|
||||
// correct measurement
|
||||
|
@ -16,6 +16,7 @@ class TwoThru : public DeembeddingOption
|
||||
public:
|
||||
TwoThru();
|
||||
|
||||
std::set<int> getAffectedPorts() override;
|
||||
virtual void transformDatapoint(VirtualDevice::VNAMeasurement& p) override;
|
||||
virtual void edit() override;
|
||||
virtual Type getType() override {return DeembeddingOption::Type::TwoThru;}
|
||||
|
@ -20,7 +20,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>You imported a two-port touchstone file, do you want to apply the currently active calibration or de-embed the data?</string>
|
||||
<string>You imported a touchstone file, do you want to apply the currently active calibration or de-embed the data?</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
@ -55,6 +55,7 @@ void TraceWidgetVNA::importDialog()
|
||||
if (!filename.isEmpty()) {
|
||||
try {
|
||||
std::vector<Trace*> traces;
|
||||
int touchstonePorts = 0;
|
||||
QString prefix = QString();
|
||||
if(filename.endsWith(".csv")) {
|
||||
auto csv = CSV::fromFile(filename);
|
||||
@ -63,6 +64,7 @@ void TraceWidgetVNA::importDialog()
|
||||
// must be a touchstone file
|
||||
auto t = Touchstone::fromFile(filename.toStdString());
|
||||
traces = Trace::createFromTouchstone(t);
|
||||
touchstonePorts = t.ports();
|
||||
}
|
||||
// contruct prefix from filename
|
||||
prefix = filename;
|
||||
@ -78,44 +80,51 @@ void TraceWidgetVNA::importDialog()
|
||||
if(AppWindow::showGUI()) {
|
||||
i->show();
|
||||
}
|
||||
if(filename.endsWith(".s2p")) {
|
||||
// potential candidate to process via calibration/de-embedding
|
||||
connect(i, &TraceImportDialog::importFinsished, [=](const std::vector<Trace*> &traces) {
|
||||
if(traces.size() == 4) {
|
||||
// all traces imported, can calculate calibration/de-embedding
|
||||
bool calAvailable = cal.getNumPoints() > 0;
|
||||
bool deembedAvailable = deembed.getOptions().size() > 0;
|
||||
if(calAvailable || deembedAvailable) {
|
||||
// check if user wants to apply either one to the imported traces
|
||||
auto dialog = new QDialog();
|
||||
auto ui = new Ui::s2pImportOptions;
|
||||
ui->setupUi(dialog);
|
||||
connect(dialog, &QDialog::finished, [=](){
|
||||
delete ui;
|
||||
});
|
||||
ui->applyCal->setEnabled(calAvailable);
|
||||
ui->deembed->setEnabled(deembedAvailable);
|
||||
bool applyCal = false;
|
||||
bool applyDeembed = false;
|
||||
connect(ui->applyCal, &QCheckBox::toggled, [&](bool checked) {
|
||||
applyCal = checked;
|
||||
});
|
||||
connect(ui->deembed, &QCheckBox::toggled, [&](bool checked) {
|
||||
applyDeembed = checked;
|
||||
});
|
||||
if(AppWindow::showGUI()) {
|
||||
dialog->exec();
|
||||
}
|
||||
if(applyCal) {
|
||||
// cal.correctTraces(*traces[0], *traces[1], *traces[2], *traces[3]); // TODO
|
||||
}
|
||||
if(applyDeembed) {
|
||||
deembed.Deembed(*traces[0], *traces[1], *traces[2], *traces[3]);
|
||||
// potential candidate to process via calibration/de-embedding
|
||||
connect(i, &TraceImportDialog::importFinsished, [=](const std::vector<Trace*> &traces) {
|
||||
if(traces.size() == touchstonePorts*touchstonePorts) {
|
||||
// all traces imported, can calculate calibration/de-embedding
|
||||
bool calAvailable = cal.getNumPoints() > 0;
|
||||
bool deembedAvailable = deembed.getOptions().size() > 0;
|
||||
if(calAvailable || deembedAvailable) {
|
||||
// check if user wants to apply either one to the imported traces
|
||||
auto dialog = new QDialog();
|
||||
auto ui = new Ui::s2pImportOptions;
|
||||
ui->setupUi(dialog);
|
||||
connect(dialog, &QDialog::finished, [=](){
|
||||
delete ui;
|
||||
});
|
||||
ui->applyCal->setEnabled(calAvailable);
|
||||
ui->deembed->setEnabled(deembedAvailable);
|
||||
bool applyCal = false;
|
||||
bool applyDeembed = false;
|
||||
connect(ui->applyCal, &QCheckBox::toggled, [&](bool checked) {
|
||||
applyCal = checked;
|
||||
});
|
||||
connect(ui->deembed, &QCheckBox::toggled, [&](bool checked) {
|
||||
applyDeembed = checked;
|
||||
});
|
||||
if(AppWindow::showGUI()) {
|
||||
dialog->exec();
|
||||
}
|
||||
// assemble trace set
|
||||
std::map<QString, Trace*> set;
|
||||
for(int i=1;i<=touchstonePorts;i++) {
|
||||
for(int j=1;j<=touchstonePorts;j++) {
|
||||
QString name = "S"+QString::number(i)+QString::number(j);
|
||||
int index = (i-1)*touchstonePorts+(j-1);
|
||||
set[name] = traces[index];
|
||||
}
|
||||
}
|
||||
if(applyCal) {
|
||||
cal.correctTraces(set);
|
||||
}
|
||||
if(applyDeembed) {
|
||||
deembed.Deembed(set);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch(const std::exception& e) {
|
||||
InformationBox::ShowError("Failed to import file", QString("Attempt to import file ended with error: \"") + e.what()+"\"");
|
||||
}
|
||||
|
@ -573,8 +573,23 @@ void AppWindow::SetupSCPI()
|
||||
if(!vdevice) {
|
||||
return QString("0/0/0");
|
||||
} else if(vdevice->isCompoundDevice()) {
|
||||
// TODO
|
||||
return QString();
|
||||
// show highest temperature of all devices
|
||||
int maxTempSource = 0;
|
||||
int maxTempLO = 0;
|
||||
int maxTempMCU = 0;
|
||||
for(auto dev : vdevice->getDevices()) {
|
||||
auto status = dev->StatusV1();
|
||||
if(status.temp_source > maxTempSource) {
|
||||
maxTempSource = status.temp_source;
|
||||
}
|
||||
if(status.temp_LO1 > maxTempLO) {
|
||||
maxTempLO = status.temp_LO1;
|
||||
}
|
||||
if(status.temp_MCU > maxTempMCU) {
|
||||
maxTempMCU = status.temp_MCU;
|
||||
}
|
||||
}
|
||||
return QString::number(maxTempSource)+"/"+QString::number(maxTempLO)+"/"+QString::number(maxTempMCU);
|
||||
} else {
|
||||
auto dev = vdevice->getDevice();
|
||||
return QString::number(dev->StatusV1().temp_source)+"/"+QString::number(dev->StatusV1().temp_LO1)+"/"+QString::number(dev->StatusV1().temp_MCU);
|
||||
|
@ -67,5 +67,7 @@
|
||||
<file>icons/compound_V1_Ref_Middle.png</file>
|
||||
<file>icons/compound_V1_Ref_Right.png</file>
|
||||
<file>icons/compound_V1_USB.png</file>
|
||||
<file>icons/DUT_onePort.png</file>
|
||||
<file>icons/port.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 275 B |
BIN
Software/PC_Application/icons/DUT_onePort.png
Normal file
BIN
Software/PC_Application/icons/DUT_onePort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 909 B |
BIN
Software/PC_Application/icons/port.png
Normal file
BIN
Software/PC_Application/icons/port.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Loading…
Reference in New Issue
Block a user