mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-05 06:25:16 +00:00
PC Application: partial firmware update dialog
This commit is contained in:
parent
8c8749accd
commit
07ba714f1f
134 changed files with 13954 additions and 7 deletions
666
Software/PC_Application/Calibration/calibration.cpp
Normal file
666
Software/PC_Application/Calibration/calibration.cpp
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
#include "calibration.h"
|
||||
#include <algorithm>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Calibration::Calibration()
|
||||
{
|
||||
// Creator 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>();
|
||||
|
||||
type = Type::None;
|
||||
}
|
||||
|
||||
void Calibration::clearMeasurements()
|
||||
{
|
||||
for(auto m : measurements) {
|
||||
m.second.datapoints.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::clearMeasurement(Calibration::Measurement type)
|
||||
{
|
||||
measurements[type].datapoints.clear();
|
||||
measurements[type].timestamp = QDateTime();
|
||||
}
|
||||
|
||||
void Calibration::addMeasurement(Calibration::Measurement type, Protocol::Datapoint &d)
|
||||
{
|
||||
measurements[type].datapoints.push_back(d);
|
||||
measurements[type].timestamp = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
bool Calibration::calculationPossible(Calibration::Type type)
|
||||
{
|
||||
std::vector<Measurement> requiredMeasurements;
|
||||
switch(type) {
|
||||
case Type::Port1SOL:
|
||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
||||
break;
|
||||
case Type::Port2SOL:
|
||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
||||
break;
|
||||
case Type::FullSOLT:
|
||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
||||
requiredMeasurements.push_back(Measurement::Through);
|
||||
break;
|
||||
case Type::None:
|
||||
return false;
|
||||
}
|
||||
return SanityCheckSamples(requiredMeasurements);
|
||||
}
|
||||
|
||||
bool Calibration::constructErrorTerms(Calibration::Type type)
|
||||
{
|
||||
if(!calculationPossible(type)) {
|
||||
return false;
|
||||
}
|
||||
if(minFreq < kit.minFreq() || maxFreq > kit.maxFreq()) {
|
||||
// Calkit does not support complete calibration range
|
||||
QMessageBox::critical(nullptr, "Unable to perform calibration", "The calibration kit does not support the complete span. Please choose a different calibration kit or a narrower span.");
|
||||
return false;
|
||||
}
|
||||
switch(type) {
|
||||
case Type::Port1SOL:
|
||||
constructPort1SOL();
|
||||
break;
|
||||
case Type::Port2SOL:
|
||||
constructPort2SOL();
|
||||
break;
|
||||
case Type::FullSOLT:
|
||||
construct12TermPoints();
|
||||
break;
|
||||
case Type::None:
|
||||
break;
|
||||
}
|
||||
this->type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Calibration::resetErrorTerms()
|
||||
{
|
||||
type = Type::None;
|
||||
points.clear();
|
||||
}
|
||||
|
||||
void Calibration::construct12TermPoints()
|
||||
{
|
||||
std::vector<Measurement> requiredMeasurements;
|
||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
||||
requiredMeasurements.push_back(Measurement::Through);
|
||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
||||
throw runtime_error("Missing/wrong calibration measurement");
|
||||
}
|
||||
requiredMeasurements.push_back(Measurement::Isolation);
|
||||
bool isolation_measured = SanityCheckSamples(requiredMeasurements);
|
||||
|
||||
// If we get here the calibration measurements are all okay
|
||||
points.clear();
|
||||
for(unsigned int i = 0;i<measurements[Measurement::Port1Open].datapoints.size();i++) {
|
||||
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 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);
|
||||
}
|
||||
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 actual = kit.toReflection(p.frequency);
|
||||
// Forward calibration
|
||||
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
||||
p.fe30 = S21_isolation;
|
||||
// See page 17 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
||||
// Formulas for S11M and S21M solved for e22 and e10e32
|
||||
auto deltaS = actual.ThroughS11*actual.ThroughS22 - actual.ThroughS21 * actual.ThroughS12;
|
||||
p.fe22 = ((S11_through - p.fe00)*(1.0 - p.fe11 * actual.ThroughS11)-actual.ThroughS11*p.fe10e01)
|
||||
/ ((S11_through - p.fe00)*(actual.ThroughS22-p.fe11*deltaS)-deltaS*p.fe10e01);
|
||||
p.fe10e32 = (S21_through - p.fe30)*(1.0 - p.fe11*actual.ThroughS11 - p.fe22*actual.ThroughS22 + p.fe11*p.fe22*deltaS) / actual.ThroughS21;
|
||||
// Reverse calibration
|
||||
computeSOL(S22_short, S22_open, S22_load, p.re33, p.re22, p.re23e32, actual.Open, actual.Short, actual.Load);
|
||||
p.re03 = S12_isolation;
|
||||
p.re11 = ((S22_through - p.re33)*(1.0 - p.re22 * actual.ThroughS22)-actual.ThroughS22*p.re23e32)
|
||||
/ ((S22_through - p.re33)*(actual.ThroughS11-p.re22*deltaS)-deltaS*p.re23e32);
|
||||
p.re23e01 = (S12_through - p.re03)*(1.0 - p.re11*actual.ThroughS11 - p.re22*actual.ThroughS22 + p.re11*p.re22*deltaS) / actual.ThroughS12;
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::constructPort1SOL()
|
||||
{
|
||||
std::vector<Measurement> requiredMeasurements;
|
||||
requiredMeasurements.push_back(Measurement::Port1Open);
|
||||
requiredMeasurements.push_back(Measurement::Port1Short);
|
||||
requiredMeasurements.push_back(Measurement::Port1Load);
|
||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
||||
throw runtime_error("Missing/wrong calibration measurement");
|
||||
}
|
||||
|
||||
// If we get here the calibration measurements are all okay
|
||||
points.clear();
|
||||
for(unsigned int i = 0;i<measurements[Measurement::Port1Open].datapoints.size();i++) {
|
||||
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);
|
||||
// OSL port1
|
||||
auto actual = kit.toReflection(p.frequency);
|
||||
// See page 19 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
||||
computeSOL(S11_short, S11_open, S11_load, p.fe00, p.fe11, p.fe10e01, actual.Open, actual.Short, actual.Load);
|
||||
// All other calibration coefficients to ideal values
|
||||
p.fe30 = 0.0;
|
||||
p.fe22 = 0.0;
|
||||
p.fe10e32 = 1.0;
|
||||
p.re33 = 0.0;
|
||||
p.re22 = 0.0;
|
||||
p.re23e32 = 1.0;
|
||||
p.re03 = 0.0;
|
||||
p.re11 = 0.0;
|
||||
p.re23e01 = 1.0;
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::constructPort2SOL()
|
||||
{
|
||||
std::vector<Measurement> requiredMeasurements;
|
||||
requiredMeasurements.push_back(Measurement::Port2Open);
|
||||
requiredMeasurements.push_back(Measurement::Port2Short);
|
||||
requiredMeasurements.push_back(Measurement::Port2Load);
|
||||
if(!SanityCheckSamples(requiredMeasurements)) {
|
||||
throw runtime_error("Missing/wrong calibration measurement");
|
||||
}
|
||||
|
||||
// If we get here the calibration measurements are all okay
|
||||
points.clear();
|
||||
for(unsigned int i = 0;i<measurements[Measurement::Port2Open].datapoints.size();i++) {
|
||||
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);
|
||||
// OSL port2
|
||||
auto actual = kit.toReflection(p.frequency);
|
||||
// See page 19 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
||||
computeSOL(S22_short, S22_open, S22_load, p.re33, p.re22, p.re23e32, actual.Open, actual.Short, actual.Load);
|
||||
// All other calibration coefficients to ideal values
|
||||
p.fe30 = 0.0;
|
||||
p.fe22 = 0.0;
|
||||
p.fe10e32 = 1.0;
|
||||
p.fe00 = 0.0;
|
||||
p.fe11 = 0.0;
|
||||
p.fe10e01 = 1.0;
|
||||
p.re03 = 0.0;
|
||||
p.re11 = 0.0;
|
||||
p.re23e01 = 1.0;
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Calibration::correctMeasurement(Protocol::Datapoint &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);
|
||||
|
||||
// find correct entry
|
||||
auto p = getCalibrationPoint(d);
|
||||
|
||||
// equations from page 20 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
||||
auto denom = (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11) * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
||||
- (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01 * p.fe22 * p.re11;
|
||||
auto S11 = ((S11m - p.fe00) / p.fe10e01 * (1.0 + (S22m - p.re33) / p.re23e32 * p.re22)
|
||||
- p.fe22 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
||||
auto S21 = ((S21m - p.fe30) / p.fe10e32 * (1.0 + (S22m - p.re33) / p.re23e32 * (p.re22 - p.fe22))) / denom;
|
||||
auto S22 = ((S22m - p.re33) / p.re23e32 * (1.0 + (S11m - p.fe00) / p.fe10e01 * p.fe11)
|
||||
- p.re11 * (S21m - p.fe30) / p.fe10e32 * (S12m - p.re03) / p.re23e01) / denom;
|
||||
auto 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();
|
||||
}
|
||||
|
||||
Calibration::InterpolationType Calibration::getInterpolation(Protocol::SweepSettings settings)
|
||||
{
|
||||
if(!points.size()) {
|
||||
return InterpolationType::NoCalibration;
|
||||
}
|
||||
if(settings.f_start < points.front().frequency || settings.f_stop > points.back().frequency) {
|
||||
return InterpolationType::Extrapolate;
|
||||
}
|
||||
// Either exact or interpolation, check individual frequencies
|
||||
uint32_t f_step = (settings.f_stop - settings.f_start) / (settings.points - 1);
|
||||
for(uint64_t f = settings.f_start; f <= settings.f_stop; f += f_step) {
|
||||
if(find_if(points.begin(), points.end(), [&f](const Point& p){
|
||||
return abs(f - p.frequency) < 100;
|
||||
}) == points.end()) {
|
||||
return InterpolationType::Interpolate;
|
||||
}
|
||||
}
|
||||
// if we get here all frequency points were matched
|
||||
if(points.front().frequency == settings.f_start && points.back().frequency == settings.f_stop) {
|
||||
return InterpolationType::Unchanged;
|
||||
} else {
|
||||
return InterpolationType::Exact;
|
||||
}
|
||||
}
|
||||
|
||||
QString Calibration::MeasurementToString(Calibration::Measurement m)
|
||||
{
|
||||
switch(m) {
|
||||
case Measurement::Port1Open:
|
||||
return "Port 1 Open";
|
||||
case Measurement::Port1Short:
|
||||
return "Port 1 Short";
|
||||
case Measurement::Port1Load:
|
||||
return "Port 1 Load";
|
||||
case Measurement::Port2Open:
|
||||
return "Port 2 Open";
|
||||
case Measurement::Port2Short:
|
||||
return "Port 2 Short";
|
||||
case Measurement::Port2Load:
|
||||
return "Port 2 Load";
|
||||
case Measurement::Through:
|
||||
return "Through";
|
||||
case Measurement::Isolation:
|
||||
return "Isolation";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
QString Calibration::TypeToString(Calibration::Type t)
|
||||
{
|
||||
switch(t) {
|
||||
case Type::Port1SOL: return "Port 1"; break;
|
||||
case Type::Port2SOL: return "Port 2"; break;
|
||||
case Type::FullSOLT: return "SOLT"; break;
|
||||
default: return "None"; break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Calibration::Type> Calibration::Types()
|
||||
{
|
||||
const std::vector<Calibration::Type> ret = {Type::Port1SOL, Type::Port2SOL, Type::FullSOLT};
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::vector<Calibration::Measurement> Calibration::Measurements(Calibration::Type type)
|
||||
{
|
||||
switch(type) {
|
||||
case Type::FullSOLT:
|
||||
case Type::None:
|
||||
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load, Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load, Measurement::Through, Measurement::Isolation};
|
||||
break;
|
||||
case Type::Port1SOL:
|
||||
return {Measurement::Port1Short, Measurement::Port1Open, Measurement::Port1Load};
|
||||
break;
|
||||
case Type::Port2SOL:
|
||||
return {Measurement::Port2Short, Measurement::Port2Open, Measurement::Port2Load};
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Calibration::MeasurementInfo Calibration::getMeasurementInfo(Calibration::Measurement m)
|
||||
{
|
||||
MeasurementInfo info;
|
||||
switch(m) {
|
||||
case Measurement::Port1Short:
|
||||
info.name = "Port 1 short";
|
||||
info.prerequisites = "Short standard connected to port 1, port 2 open";
|
||||
break;
|
||||
case Measurement::Port1Open:
|
||||
info.name = "Port 1 open";
|
||||
info.prerequisites = "Open standard connected to port 1, port 2 open";
|
||||
break;
|
||||
case Measurement::Port1Load:
|
||||
info.name = "Port 1 load";
|
||||
info.prerequisites = "Load standard connected to port 1, port 2 open";
|
||||
break;
|
||||
case Measurement::Port2Short:
|
||||
info.name = "Port 2 short";
|
||||
info.prerequisites = "Port 1 open, short standard connected to port 2";
|
||||
break;
|
||||
case Measurement::Port2Open:
|
||||
info.name = "Port 2 open";
|
||||
info.prerequisites = "Port 1 open, open standard connected to port 2";
|
||||
break;
|
||||
case Measurement::Port2Load:
|
||||
info.name = "Port 2 load";
|
||||
info.prerequisites = "Port 1 open, load standard connected to port 2";
|
||||
break;
|
||||
case Measurement::Through:
|
||||
info.name = "Through";
|
||||
info.prerequisites = "Port 1 connected to port 2 via through standard";
|
||||
break;
|
||||
case Measurement::Isolation:
|
||||
info.name = "Isolation";
|
||||
info.prerequisites = "Both ports terminated into 50 ohm";
|
||||
}
|
||||
info.points = measurements[m].datapoints.size();
|
||||
if(info.points > 0) {
|
||||
info.fmin = measurements[m].datapoints.front().frequency;
|
||||
info.fmax = measurements[m].datapoints.back().frequency;
|
||||
info.points = measurements[m].datapoints.size();
|
||||
}
|
||||
info.timestamp = measurements[m].timestamp;
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<Trace *> Calibration::getErrorTermTraces()
|
||||
{
|
||||
std::vector<Trace*> traces;
|
||||
const QString traceNames[12] = {"e00", "F_e11", "e10e01", "e10e32", "F_e22", "e30", "e33", "R_e11", "e23e32", "e23e01", "R_e22", "e03"};
|
||||
constexpr bool reflection[12] = {true, true, false, false, true, false, true, true, false, false, true, false};
|
||||
for(int i=0;i<12;i++) {
|
||||
auto t = new Trace(traceNames[i], Qt::red);
|
||||
t->setCalibration(true);
|
||||
t->setReflection(reflection[i]);
|
||||
traces.push_back(t);
|
||||
}
|
||||
for(auto p : points) {
|
||||
Trace::Data d;
|
||||
d.frequency = p.frequency;
|
||||
for(int i=0;i<12;i++) {
|
||||
switch(i) {
|
||||
case 0: d.S = p.fe00; break;
|
||||
case 1: d.S = p.fe11; break;
|
||||
case 2: d.S = p.fe10e01; break;
|
||||
case 3: d.S = p.fe10e32; break;
|
||||
case 4: d.S = p.fe22; break;
|
||||
case 5: d.S = p.fe30; break;
|
||||
case 6: d.S = p.re33; break;
|
||||
case 7: d.S = p.re11; break;
|
||||
case 8: d.S = p.re23e32; break;
|
||||
case 9: d.S = p.re23e01; break;
|
||||
case 10: d.S = p.re22; break;
|
||||
case 11: d.S = p.re03; break;
|
||||
}
|
||||
traces[i]->addData(d);
|
||||
}
|
||||
}
|
||||
return traces;
|
||||
}
|
||||
|
||||
bool Calibration::openFromFile(QString filename)
|
||||
{
|
||||
if(filename.isEmpty()) {
|
||||
filename = QFileDialog::getOpenFileName(nullptr, "Load calibration data", "", "Calibration files (*.cal)", nullptr, QFileDialog::DontUseNativeDialog);
|
||||
if(filename.isEmpty()) {
|
||||
// aborted selection
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to load associated calibration kit first (needs to be available when performing calibration)
|
||||
auto calkit_file = filename;
|
||||
auto dotPos = calkit_file.lastIndexOf('.');
|
||||
if(dotPos >= 0) {
|
||||
calkit_file.truncate(dotPos);
|
||||
}
|
||||
calkit_file.append(".calkit");
|
||||
try {
|
||||
kit = Calkit::fromFile(calkit_file.toStdString());
|
||||
} catch (runtime_error e) {
|
||||
QMessageBox::warning(nullptr, "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()) + ")");
|
||||
}
|
||||
|
||||
ifstream file;
|
||||
file.open(filename.toStdString());
|
||||
try {
|
||||
file >> *this;
|
||||
} catch(runtime_error e) {
|
||||
QMessageBox::warning(nullptr, "File parsing error", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Calibration::saveToFile(QString filename)
|
||||
{
|
||||
if(filename.isEmpty()) {
|
||||
filename = QFileDialog::getSaveFileName(nullptr, "Save calibration data", "", "Calibration files (*.cal)", nullptr, QFileDialog::DontUseNativeDialog);
|
||||
if(filename.isEmpty()) {
|
||||
// aborted selection
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// strip any potential file name extension and set default
|
||||
auto dotPos = filename.lastIndexOf('.');
|
||||
if(dotPos >= 0) {
|
||||
filename.truncate(dotPos);
|
||||
}
|
||||
auto calibration_file = filename;
|
||||
calibration_file.append(".cal");
|
||||
ofstream file;
|
||||
file.open(calibration_file.toStdString());
|
||||
file << *this;
|
||||
|
||||
auto calkit_file = filename;
|
||||
calkit_file.append(".calkit");
|
||||
kit.toFile(calkit_file.toStdString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
std::string line;
|
||||
while(getline(in, line)) {
|
||||
for(auto m : Calibration::Measurements()) {
|
||||
if(Calibration::MeasurementToString(m) == QString::fromStdString(line)) {
|
||||
// this is the correct measurement
|
||||
c.clearMeasurement(m);
|
||||
uint timestamp;
|
||||
in >> timestamp;
|
||||
c.measurements[m].timestamp = QDateTime::fromSecsSinceEpoch(timestamp);
|
||||
unsigned int points;
|
||||
in >> points;
|
||||
for(unsigned int i=0;i<points;i++) {
|
||||
Protocol::Datapoint p;
|
||||
in >> p.pointNum >> p.frequency;
|
||||
in >> p.imag_S11 >> p.real_S11 >> p.imag_S21 >> p.real_S21 >> p.imag_S12 >> p.real_S12 >> p.imag_S22 >> p.real_S22;
|
||||
c.measurements[m].datapoints.push_back(p);
|
||||
if(in.eof() || in.bad() || in.fail()) {
|
||||
c.clearMeasurement(m);
|
||||
throw runtime_error("Failed to parse measurement \"" + line + "\", aborting calibration data import.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(auto t : Calibration::Types()) {
|
||||
if(Calibration::TypeToString(t) == QString::fromStdString(line)) {
|
||||
// try to apply this calibration type
|
||||
if(c.calculationPossible(t)) {
|
||||
c.constructErrorTerms(t);
|
||||
} else {
|
||||
throw runtime_error("Incomplete calibration data, the requested \"" + line + "\"-Calibration could not be performed.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
bool Calibration::SanityCheckSamples(std::vector<Calibration::Measurement> &requiredMeasurements)
|
||||
{
|
||||
// sanity check measurements, all need to be of the same size with the same frequencies (except for isolation which may be empty)
|
||||
vector<uint64_t> freqs;
|
||||
for(auto type : requiredMeasurements) {
|
||||
auto m = measurements[type];
|
||||
if(m.datapoints.size() == 0) {
|
||||
// empty required measurement
|
||||
return false;
|
||||
}
|
||||
if(freqs.size() == 0) {
|
||||
// this is the first measurement, create frequency vector
|
||||
for(auto p : m.datapoints) {
|
||||
freqs.push_back(p.frequency);
|
||||
}
|
||||
} else {
|
||||
// compare with already assembled frequency vector
|
||||
if(m.datapoints.size() != freqs.size()) {
|
||||
return false;
|
||||
}
|
||||
for(unsigned int i=0;i<freqs.size();i++) {
|
||||
if(m.datapoints[i].frequency != freqs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
minFreq = freqs.front();
|
||||
maxFreq = freqs.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
Calibration::Point Calibration::getCalibrationPoint(Protocol::Datapoint &d)
|
||||
{
|
||||
if(!points.size()) {
|
||||
throw runtime_error("No calibration points available");
|
||||
}
|
||||
if(d.frequency <= points.front().frequency) {
|
||||
// use first point even for lower frequencies
|
||||
return points.front();
|
||||
}
|
||||
if(d.frequency >= points.back().frequency) {
|
||||
// use last point even for higher frequencies
|
||||
return points.back();
|
||||
}
|
||||
auto p = lower_bound(points.begin(), points.end(), d.frequency, [](Point p, uint64_t freq) -> bool {
|
||||
return p.frequency < freq;
|
||||
});
|
||||
if(p->frequency == d.frequency) {
|
||||
// Exact match, return point
|
||||
return *p;
|
||||
}
|
||||
// need to interpolate
|
||||
auto high = p;
|
||||
p--;
|
||||
auto low = p;
|
||||
double alpha = (d.frequency - low->frequency) / (high->frequency - low->frequency);
|
||||
Point ret;
|
||||
ret.frequency = d.frequency;
|
||||
ret.fe00 = low->fe00 * (1 - alpha) + high->fe00 * alpha;
|
||||
ret.fe11 = low->fe11 * (1 - alpha) + high->fe11 * alpha;
|
||||
ret.fe22 = low->fe22 * (1 - alpha) + high->fe22 * alpha;
|
||||
ret.fe30 = low->fe30 * (1 - alpha) + high->fe30 * alpha;
|
||||
ret.re03 = low->re03 * (1 - alpha) + high->re03 * alpha;
|
||||
ret.re11 = low->re11 * (1 - alpha) + high->re11 * alpha;
|
||||
ret.re22 = low->re22 * (1 - alpha) + high->re22 * alpha;
|
||||
ret.re33 = low->re33 * (1 - alpha) + high->re33 * alpha;
|
||||
ret.fe10e01 = low->fe10e01 * (1 - alpha) + high->fe10e01 * alpha;
|
||||
ret.fe10e32 = low->fe10e32 * (1 - alpha) + high->fe10e32 * alpha;
|
||||
ret.re23e01 = low->re23e01 * (1 - alpha) + high->re23e01 * alpha;
|
||||
ret.re23e32 = low->re23e32 * (1 - alpha) + high->re23e32 * alpha;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Calibration::computeSOL(std::complex<double> s_m, std::complex<double> o_m, std::complex<double> l_m,
|
||||
std::complex<double> &directivity, std::complex<double> &match, std::complex<double> &tracking,
|
||||
std::complex<double> o_c, std::complex<double> s_c, std::complex<double> l_c)
|
||||
{
|
||||
// equations from page 13 of http://www2.electron.frba.utn.edu.ar/~jcecconi/Bibliografia/04%20-%20Param_S_y_VNA/Network_Analyzer_Error_Models_and_Calibration_Methods.pdf
|
||||
// solved while taking non ideal o/s/l standards into account
|
||||
auto denom = l_c * o_c * (o_m - l_m) + l_c * s_c * (l_m - s_m) + o_c * s_c * (s_m - o_m);
|
||||
directivity = (l_c * o_m * (s_m * (o_c - s_c) + l_m * s_c) - l_c * o_c * l_m * s_m + o_c * l_m * s_c * (s_m - o_m)) / denom;
|
||||
match = (l_c * (o_m - s_m) + o_c * (s_m - l_m) + s_c * (l_m - o_m)) / denom;
|
||||
auto delta = (l_c * l_m * (o_m - s_m) + o_c * o_m * (s_m - l_m) + s_c * s_m * (l_m - o_m)) / denom;
|
||||
tracking = directivity * match - delta;
|
||||
}
|
||||
|
||||
std::complex<double> Calibration::correctSOL(std::complex<double> measured, std::complex<double> directivity, std::complex<double> match, std::complex<double> tracking)
|
||||
{
|
||||
return (measured - directivity) / (measured * match - directivity * match + tracking);
|
||||
}
|
||||
|
||||
Calkit &Calibration::getCalibrationKit()
|
||||
{
|
||||
return kit;
|
||||
}
|
||||
|
||||
void Calibration::setCalibrationKit(const Calkit &value)
|
||||
{
|
||||
kit = value;
|
||||
}
|
||||
|
||||
Calibration::Type Calibration::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
136
Software/PC_Application/Calibration/calibration.h
Normal file
136
Software/PC_Application/Calibration/calibration.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#ifndef CALIBRATION_H
|
||||
#define CALIBRATION_H
|
||||
|
||||
#include "Device/device.h"
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "calkit.h"
|
||||
#include "Traces/tracemodel.h"
|
||||
#include <QDateTime>
|
||||
#include "calkit.h"
|
||||
|
||||
class Calibration
|
||||
{
|
||||
public:
|
||||
Calibration();
|
||||
|
||||
enum class Measurement {
|
||||
Port1Open,
|
||||
Port1Short,
|
||||
Port1Load,
|
||||
Port2Open,
|
||||
Port2Short,
|
||||
Port2Load,
|
||||
Isolation,
|
||||
Through,
|
||||
};
|
||||
void clearMeasurements();
|
||||
void clearMeasurement(Measurement type);
|
||||
void addMeasurement(Measurement type, Protocol::Datapoint &d);
|
||||
|
||||
enum class Type {
|
||||
Port1SOL,
|
||||
Port2SOL,
|
||||
FullSOLT,
|
||||
None,
|
||||
};
|
||||
|
||||
|
||||
bool calculationPossible(Type type);
|
||||
bool constructErrorTerms(Type type);
|
||||
void resetErrorTerms();
|
||||
|
||||
void correctMeasurement(Protocol::Datapoint &d);
|
||||
|
||||
enum class InterpolationType {
|
||||
Unchanged, // Nothing has changed, settings and calibration points match
|
||||
Exact, // Every frequency point in settings has an exact calibration point (but there are more calibration points outside of the sweep)
|
||||
Interpolate, // Every point in the sweep can be interpolated between two calibration points
|
||||
Extrapolate, // At least one point in sweep is outside of the calibration and has to be extrapolated
|
||||
NoCalibration, // No calibration available
|
||||
};
|
||||
|
||||
InterpolationType getInterpolation(Protocol::SweepSettings settings);
|
||||
|
||||
static QString MeasurementToString(Measurement m);
|
||||
static QString TypeToString(Type t);
|
||||
|
||||
class MeasurementInfo {
|
||||
public:
|
||||
QString name, prerequisites;
|
||||
double fmin, fmax;
|
||||
unsigned int points;
|
||||
QDateTime timestamp;
|
||||
};
|
||||
|
||||
static const std::vector<Type> Types();
|
||||
static const std::vector<Measurement> Measurements(Type type = Type::None);
|
||||
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();
|
||||
}
|
||||
|
||||
std::vector<Trace*> getErrorTermTraces();
|
||||
|
||||
bool openFromFile(QString filename = QString());
|
||||
bool saveToFile(QString filename = QString());
|
||||
Type getType() const;
|
||||
|
||||
Calkit& getCalibrationKit();
|
||||
void setCalibrationKit(const Calkit &value);
|
||||
|
||||
private:
|
||||
void construct12TermPoints();
|
||||
void constructPort1SOL();
|
||||
void constructPort2SOL();
|
||||
bool SanityCheckSamples(std::vector<Measurement> &requiredMeasurements);
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
double frequency;
|
||||
// Forward error terms
|
||||
std::complex<double> fe00, fe11, fe10e01, fe10e32, fe22, fe30;
|
||||
// Reverse error terms
|
||||
std::complex<double> re33, re11, re23e32, re23e01, re22, re03;
|
||||
};
|
||||
Point getCalibrationPoint(Protocol::Datapoint &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).
|
||||
* The actual reflection coefficients can be passed on as optional arguments to take into account the non-ideal
|
||||
* calibration kit.
|
||||
*/
|
||||
void computeSOL(std::complex<double> s_m,
|
||||
std::complex<double> o_m,
|
||||
std::complex<double> l_m,
|
||||
std::complex<double> &directivity,
|
||||
std::complex<double> &match,
|
||||
std::complex<double> &tracking,
|
||||
std::complex<double> o_c = std::complex<double>(1.0, 0),
|
||||
std::complex<double> s_c = std::complex<double>(-1.0, 0),
|
||||
std::complex<double> l_c = std::complex<double>(0, 0));
|
||||
std::complex<double> correctSOL(std::complex<double> measured,
|
||||
std::complex<double> directivity,
|
||||
std::complex<double> match,
|
||||
std::complex<double> tracking);
|
||||
class MeasurementData {
|
||||
public:
|
||||
QDateTime timestamp;
|
||||
std::vector<Protocol::Datapoint> datapoints;
|
||||
};
|
||||
Type type;
|
||||
|
||||
std::map<Measurement, MeasurementData> measurements;
|
||||
double minFreq, maxFreq;
|
||||
std::vector<Point> points;
|
||||
|
||||
Calkit kit;
|
||||
};
|
||||
|
||||
#endif // CALIBRATION_H
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#include "calibrationtracedialog.h"
|
||||
#include "ui_calibrationtracedialog.h"
|
||||
#include "measurementmodel.h"
|
||||
#include <QStyle>
|
||||
|
||||
CalibrationTraceDialog::CalibrationTraceDialog(Calibration *cal, Calibration::Type type) :
|
||||
QDialog(nullptr),
|
||||
ui(new Ui::CalibrationTraceDialog),
|
||||
cal(cal),
|
||||
requestedType(type)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->bApply->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton));
|
||||
measurements = cal->Measurements(type);
|
||||
if(requestedType == Calibration::Type::None) {
|
||||
ui->bApply->setVisible(false);
|
||||
}
|
||||
model = new MeasurementModel(cal, measurements);
|
||||
ui->tableView->setModel(model);
|
||||
ui->tableView->setColumnWidth(0, 100);
|
||||
ui->tableView->setColumnWidth(1, 350);
|
||||
ui->tableView->setColumnWidth(2, 320);
|
||||
ui->tableView->setColumnWidth(3, 160);
|
||||
UpdateApplyButton();
|
||||
}
|
||||
|
||||
CalibrationTraceDialog::~CalibrationTraceDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::measurementComplete(Calibration::Measurement m)
|
||||
{
|
||||
model->measurementUpdated(m);
|
||||
UpdateApplyButton();
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::UpdateApplyButton()
|
||||
{
|
||||
ui->bApply->setEnabled(cal->calculationPossible(requestedType));
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::on_bDelete_clicked()
|
||||
{
|
||||
auto measurement = measurements[ui->tableView->currentIndex().row()];
|
||||
cal->clearMeasurement(measurement);
|
||||
model->measurementUpdated(measurement);
|
||||
UpdateApplyButton();
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::on_bMeasure_clicked()
|
||||
{
|
||||
auto measurement = measurements[ui->tableView->currentIndex().row()];
|
||||
emit triggerMeasurement(measurement);
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::on_bApply_clicked()
|
||||
{
|
||||
emit applyCalibration(requestedType);
|
||||
accept();
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::on_bOpen_clicked()
|
||||
{
|
||||
cal->openFromFile();
|
||||
UpdateApplyButton();
|
||||
emit applyCalibration(cal->getType());
|
||||
}
|
||||
|
||||
void CalibrationTraceDialog::on_bSave_clicked()
|
||||
{
|
||||
cal->saveToFile();
|
||||
}
|
||||
44
Software/PC_Application/Calibration/calibrationtracedialog.h
Normal file
44
Software/PC_Application/Calibration/calibrationtracedialog.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef CALIBRATIONTRACEDIALOG_H
|
||||
#define CALIBRATIONTRACEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "calibration.h"
|
||||
#include "measurementmodel.h"
|
||||
|
||||
namespace Ui {
|
||||
class CalibrationTraceDialog;
|
||||
}
|
||||
|
||||
class CalibrationTraceDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CalibrationTraceDialog(Calibration *cal, Calibration::Type type = Calibration::Type::None);
|
||||
~CalibrationTraceDialog();
|
||||
|
||||
public slots:
|
||||
void measurementComplete(Calibration::Measurement m);
|
||||
signals:
|
||||
void triggerMeasurement(Calibration::Measurement m);
|
||||
void applyCalibration(Calibration::Type type);
|
||||
|
||||
private slots:
|
||||
void on_bDelete_clicked();
|
||||
void on_bMeasure_clicked();
|
||||
void on_bApply_clicked();
|
||||
|
||||
void on_bOpen_clicked();
|
||||
|
||||
void on_bSave_clicked();
|
||||
|
||||
private:
|
||||
void UpdateApplyButton();
|
||||
Ui::CalibrationTraceDialog *ui;
|
||||
Calibration *cal;
|
||||
Calibration::Type requestedType;
|
||||
std::vector<Calibration::Measurement> measurements;
|
||||
MeasurementModel *model;
|
||||
};
|
||||
|
||||
#endif // CALIBRATIONTRACEDIALOG_H
|
||||
116
Software/PC_Application/Calibration/calibrationtracedialog.ui
Normal file
116
Software/PC_Application/Calibration/calibrationtracedialog.ui
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CalibrationTraceDialog</class>
|
||||
<widget class="QDialog" name="CalibrationTraceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1066</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calibration Traces</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView">
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="bMeasure">
|
||||
<property name="text">
|
||||
<string>Measure</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-delete">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bOpen">
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-open"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bSave">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-save"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bApply">
|
||||
<property name="text">
|
||||
<string>Apply Calibration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
290
Software/PC_Application/Calibration/calkit.cpp
Normal file
290
Software/PC_Application/Calibration/calkit.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
#include "calkit.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include "calkitdialog.h"
|
||||
#include <math.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Calkit::Calkit()
|
||||
: ts_open(nullptr),
|
||||
ts_short(nullptr),
|
||||
ts_load(nullptr),
|
||||
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;
|
||||
}
|
||||
|
||||
void Calkit::toFile(std::string filename)
|
||||
{
|
||||
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.close();
|
||||
}
|
||||
|
||||
Calkit Calkit::fromFile(std::string filename)
|
||||
{
|
||||
Calkit c;
|
||||
ifstream file;
|
||||
file.open(filename);
|
||||
if(!file.is_open()) {
|
||||
throw runtime_error("Unable to open file");
|
||||
}
|
||||
file >> c.open_measurements;
|
||||
file >> c.short_measurements;
|
||||
file >> c.load_measurements;
|
||||
file >> c.through_measurements;
|
||||
file >> c.open_Z0;
|
||||
file >> c.open_delay;
|
||||
file >> c.open_loss;
|
||||
file >> c.open_C0;
|
||||
file >> c.open_C1;
|
||||
file >> c.open_C2;
|
||||
file >> c.open_C3;
|
||||
file >> c.short_Z0;
|
||||
file >> c.short_delay;
|
||||
file >> c.short_loss;
|
||||
file >> c.short_L0;
|
||||
file >> c.short_L1;
|
||||
file >> c.short_L2;
|
||||
file >> c.short_L3;
|
||||
file >> c.load_Z0;
|
||||
file >> c.through_Z0;
|
||||
file >> c.through_delay;
|
||||
file >> c.through_loss;
|
||||
if(c.open_measurements) {
|
||||
file >> c.open_file;
|
||||
file >> c.open_Sparam;
|
||||
}
|
||||
if(c.short_measurements) {
|
||||
file >> c.short_file;
|
||||
file >> c.short_Sparam;
|
||||
}
|
||||
if(c.load_measurements) {
|
||||
file >> c.load_file;
|
||||
file >> c.load_Sparam;
|
||||
}
|
||||
if(c.through_measurements) {
|
||||
file >> c.through_file;
|
||||
file >> c.through_Sparam1;
|
||||
file >> c.through_Sparam2;
|
||||
}
|
||||
file.close();
|
||||
return c;
|
||||
}
|
||||
|
||||
void Calkit::edit()
|
||||
{
|
||||
auto dialog = new CalkitDialog(*this);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
Calkit::Reflection Calkit::toReflection(double frequency)
|
||||
{
|
||||
fillTouchstoneCache();
|
||||
Reflection ref;
|
||||
if(load_measurements) {
|
||||
ref.Load = ts_load->interpolate(frequency).S[0];
|
||||
} else {
|
||||
auto imp_load = complex<double>(load_Z0, 0);
|
||||
ref.Load = (imp_load - complex<double>(50.0)) / (imp_load + complex<double>(50.0));
|
||||
}
|
||||
|
||||
if(open_measurements) {
|
||||
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);
|
||||
// convert to impedance
|
||||
if (Cfringing == 0) {
|
||||
// special case to avoid issues with infinity
|
||||
ref.Open = complex<double>(1.0, 0);
|
||||
} else {
|
||||
auto imp_open = complex<double>(0, -1.0 / (frequency * 2 * M_PI * Cfringing));
|
||||
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 * open_delay * 1e-12;
|
||||
double open_att_db = open_loss * 1e9 * 4.3429 * open_delay * 1e-12 / 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) {
|
||||
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);
|
||||
// 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 * short_delay * 1e-12;
|
||||
double short_att_db = short_loss * 1e9 * 4.3429 * short_delay * 1e-12 / 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) {
|
||||
auto interp = ts_through->interpolate(frequency);
|
||||
ref.ThroughS11 = interp.S[0];
|
||||
ref.ThroughS12 = interp.S[1];
|
||||
ref.ThroughS21 = interp.S[2];
|
||||
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_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
|
||||
ref.ThroughS21 = ref.ThroughS12;
|
||||
ref.ThroughS11 = 0.0;
|
||||
ref.ThroughS22 = 0.0;
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
double Calkit::minFreq()
|
||||
{
|
||||
fillTouchstoneCache();
|
||||
double min = std::numeric_limits<double>::min();
|
||||
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
||||
// find the highest minimum frequency in all measurement files
|
||||
for(auto ts : ts_list) {
|
||||
if(!ts) {
|
||||
// this calibration standard is defined by coefficients, no minimum frequency
|
||||
continue;
|
||||
}
|
||||
if(ts->minFreq() > min) {
|
||||
min = ts->minFreq();
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
double Calkit::maxFreq()
|
||||
{
|
||||
fillTouchstoneCache();
|
||||
double max = std::numeric_limits<double>::max();
|
||||
array<Touchstone*, 4> ts_list = {ts_open, ts_short, ts_load, ts_through};
|
||||
// find the highest minimum frequency in all measurement files
|
||||
for(auto ts : ts_list) {
|
||||
if(!ts) {
|
||||
// this calibration standard is defined by coefficients, no minimum frequency
|
||||
continue;
|
||||
}
|
||||
if(ts->maxFreq() < max) {
|
||||
max = ts->maxFreq();
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
void Calkit::clearTouchstoneCache()
|
||||
{
|
||||
if(ts_open) {
|
||||
delete ts_open;
|
||||
ts_open = nullptr;
|
||||
}
|
||||
if(ts_short) {
|
||||
delete ts_short;
|
||||
ts_short = nullptr;
|
||||
}
|
||||
if(ts_load) {
|
||||
delete ts_load;
|
||||
ts_load = nullptr;
|
||||
}
|
||||
if(ts_through) {
|
||||
delete ts_through;
|
||||
ts_through = nullptr;
|
||||
}
|
||||
ts_cached = false;
|
||||
}
|
||||
|
||||
void Calkit::fillTouchstoneCache()
|
||||
{
|
||||
if(ts_cached) {
|
||||
return;
|
||||
}
|
||||
if(open_measurements) {
|
||||
ts_open = new Touchstone(1);
|
||||
*ts_open = Touchstone::fromFile(open_file);
|
||||
ts_open->reduceTo1Port(open_Sparam);
|
||||
}
|
||||
if(short_measurements) {
|
||||
ts_short = new Touchstone(1);
|
||||
*ts_short = Touchstone::fromFile(short_file);
|
||||
ts_open->reduceTo1Port(short_Sparam);
|
||||
}
|
||||
if(load_measurements) {
|
||||
ts_load = new Touchstone(1);
|
||||
*ts_load = Touchstone::fromFile(load_file);
|
||||
ts_open->reduceTo1Port(load_Sparam);
|
||||
}
|
||||
if(through_measurements) {
|
||||
ts_through = new Touchstone(2);
|
||||
*ts_through = Touchstone::fromFile(through_file);
|
||||
ts_through->reduceTo2Port(through_Sparam1, through_Sparam2);
|
||||
}
|
||||
ts_cached = true;
|
||||
}
|
||||
50
Software/PC_Application/Calibration/calkit.h
Normal file
50
Software/PC_Application/Calibration/calkit.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef CALKIT_H
|
||||
#define CALKIT_H
|
||||
|
||||
#include <string>
|
||||
#include <complex>
|
||||
#include "touchstone.h"
|
||||
|
||||
class Calkit
|
||||
{
|
||||
friend class CalkitDialog;
|
||||
public:
|
||||
Calkit();
|
||||
|
||||
class Reflection {
|
||||
public:
|
||||
std::complex<double> Open;
|
||||
std::complex<double> Short;
|
||||
std::complex<double> Load;
|
||||
std::complex<double> ThroughS11, ThroughS12, ThroughS21, ThroughS22;
|
||||
};
|
||||
|
||||
void toFile(std::string filename);
|
||||
static Calkit fromFile(std::string filename);
|
||||
void edit();
|
||||
Reflection toReflection(double frequency);
|
||||
double minFreq();
|
||||
double maxFreq();
|
||||
private:
|
||||
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;
|
||||
|
||||
std::string open_file, short_file, load_file, through_file;
|
||||
int open_Sparam, short_Sparam, load_Sparam, through_Sparam1, through_Sparam2;
|
||||
|
||||
Touchstone *ts_open, *ts_short, *ts_load, *ts_through;
|
||||
bool ts_cached;
|
||||
|
||||
void clearTouchstoneCache();
|
||||
void fillTouchstoneCache();
|
||||
};
|
||||
|
||||
#endif // CALKIT_H
|
||||
219
Software/PC_Application/Calibration/calkitdialog.cpp
Normal file
219
Software/PC_Application/Calibration/calkitdialog.cpp
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
#include "calkitdialog.h"
|
||||
#include "ui_calkitdialog.h"
|
||||
#include <QPushButton>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <fstream>
|
||||
#include <touchstone.h>
|
||||
#include <QtGlobal>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CalkitDialog),
|
||||
open_ok(true),
|
||||
short_ok(true),
|
||||
load_ok(true),
|
||||
through_ok(true),
|
||||
editKit(c)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->OpenType->setId(ui->open_coefficients, 0);
|
||||
ui->OpenType->setId(ui->open_measurement, 1);
|
||||
|
||||
ui->ShortType->setId(ui->short_coefficients, 0);
|
||||
ui->ShortType->setId(ui->short_measurement, 1);
|
||||
|
||||
ui->LoadType->setId(ui->load_coefficients, 0);
|
||||
ui->LoadType->setId(ui->load_measurement, 1);
|
||||
|
||||
ui->ThroughType->setId(ui->through_coefficients, 0);
|
||||
ui->ThroughType->setId(ui->through_measurement, 1);
|
||||
|
||||
ui->open_touchstone->setPorts(1);
|
||||
ui->short_touchstone->setPorts(1);
|
||||
ui->load_touchstone->setPorts(1);
|
||||
ui->through_touchstone->setPorts(2);
|
||||
|
||||
editKit.clearTouchstoneCache();
|
||||
ownKit = editKit;
|
||||
updateEntries();
|
||||
|
||||
auto UpdateStatus = [=]() {
|
||||
bool ok = true;
|
||||
if(ui->open_measurement->isChecked() && !ui->open_touchstone->getStatus()) {
|
||||
ok = false;
|
||||
}
|
||||
if(ui->short_measurement->isChecked() && !ui->short_touchstone->getStatus()) {
|
||||
ok = false;
|
||||
}
|
||||
if(ui->load_measurement->isChecked() && !ui->load_touchstone->getStatus()) {
|
||||
ok = false;
|
||||
}
|
||||
if(ui->through_measurement->isChecked() && !ui->through_touchstone->getStatus()) {
|
||||
ok = false;
|
||||
}
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
|
||||
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(ok);
|
||||
};
|
||||
|
||||
connect(ui->open_touchstone, &TouchstoneImport::statusChanged, UpdateStatus);
|
||||
connect(ui->short_touchstone, &TouchstoneImport::statusChanged, UpdateStatus);
|
||||
connect(ui->load_touchstone, &TouchstoneImport::statusChanged, UpdateStatus);
|
||||
connect(ui->through_touchstone, &TouchstoneImport::statusChanged, UpdateStatus);
|
||||
|
||||
connect(ui->OpenType, qOverload<int>(&QButtonGroup::buttonClicked), [=](int) {
|
||||
UpdateStatus();
|
||||
});
|
||||
connect(ui->ShortType, qOverload<int>(&QButtonGroup::buttonClicked), [=](int) {
|
||||
UpdateStatus();
|
||||
});
|
||||
connect(ui->LoadType, qOverload<int>(&QButtonGroup::buttonClicked), [=](int) {
|
||||
UpdateStatus();
|
||||
});
|
||||
connect(ui->ThroughType, qOverload<int>(&QButtonGroup::buttonClicked), [=](int) {
|
||||
UpdateStatus();
|
||||
});
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, [this]() {
|
||||
parseEntries();
|
||||
editKit = ownKit;
|
||||
delete this;
|
||||
});
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, [this]() {
|
||||
delete this;
|
||||
});
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Open), &QPushButton::clicked, [=](){
|
||||
auto filename = QFileDialog::getOpenFileName(this, "Open calibration kit coefficients", "", "Calibration kit files (*.calkit)", nullptr, QFileDialog::DontUseNativeDialog);
|
||||
if(filename.length() > 0) {
|
||||
ownKit = Calkit::fromFile(filename.toStdString());
|
||||
updateEntries();
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=](){
|
||||
auto filename = QFileDialog::getSaveFileName(this, "Save calibration kit coefficients", "", "Calibration kit files (*.calkit)", nullptr, QFileDialog::DontUseNativeDialog);
|
||||
if(filename.length() > 0) {
|
||||
parseEntries();
|
||||
ownKit.toFile(filename.toStdString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CalkitDialog::~CalkitDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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.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.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();
|
||||
|
||||
// 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.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];
|
||||
}
|
||||
|
||||
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->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->load_Z0->setText(QString::number(ownKit.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));
|
||||
|
||||
// Measurements
|
||||
ui->open_touchstone->setFile(QString::fromStdString(ownKit.open_file));
|
||||
ui->open_touchstone->selectPort(0, ownKit.open_Sparam);
|
||||
|
||||
ui->short_touchstone->setFile(QString::fromStdString(ownKit.short_file));
|
||||
ui->short_touchstone->selectPort(0, ownKit.short_Sparam);
|
||||
|
||||
ui->load_touchstone->setFile(QString::fromStdString(ownKit.load_file));
|
||||
ui->load_touchstone->selectPort(0, ownKit.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);
|
||||
|
||||
// Type
|
||||
if (ownKit.open_measurements) {
|
||||
ui->open_measurement->click();
|
||||
} else {
|
||||
ui->open_coefficients->click();
|
||||
}
|
||||
|
||||
if (ownKit.short_measurements) {
|
||||
ui->short_measurement->click();
|
||||
} else {
|
||||
ui->short_coefficients->click();
|
||||
}
|
||||
|
||||
if (ownKit.load_measurements) {
|
||||
ui->load_measurement->click();
|
||||
} else {
|
||||
ui->load_coefficients->click();
|
||||
}
|
||||
|
||||
if (ownKit.through_measurements) {
|
||||
ui->through_measurement->click();
|
||||
} else {
|
||||
ui->through_coefficients->click();
|
||||
}
|
||||
}
|
||||
33
Software/PC_Application/Calibration/calkitdialog.h
Normal file
33
Software/PC_Application/Calibration/calkitdialog.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef CALKITDIALOG_H
|
||||
#define CALKITDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractButton>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "calkit.h"
|
||||
|
||||
namespace Ui {
|
||||
class CalkitDialog;
|
||||
}
|
||||
|
||||
class CalkitDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CalkitDialog(Calkit &c, QWidget *parent = nullptr);
|
||||
~CalkitDialog();
|
||||
|
||||
private:
|
||||
void parseEntries();
|
||||
void updateEntries();
|
||||
Ui::CalkitDialog *ui;
|
||||
|
||||
bool open_ok, short_ok, load_ok, through_ok;
|
||||
|
||||
Calkit ownKit;
|
||||
Calkit &editKit;
|
||||
};
|
||||
|
||||
#endif // CALKITDIALOG_H
|
||||
601
Software/PC_Application/Calibration/calkitdialog.ui
Normal file
601
Software/PC_Application/Calibration/calkitdialog.ui
Normal file
|
|
@ -0,0 +1,601 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CalkitDialog</class>
|
||||
<widget class="QDialog" name="CalkitDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1121</width>
|
||||
<height>345</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calibration Kit Coefficients</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="open_coefficients">
|
||||
<property name="text">
|
||||
<string>Coefficients</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">OpenType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="open_measurement">
|
||||
<property name="text">
|
||||
<string>Measurement file</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">OpenType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="open_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Offset delay [ps]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="open_delay"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Offset loss [GΩ/s]: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="open_loss"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>C0 [10<sup>-15</sup>F]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="open_C0"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>C1 [10<sup>-27</sup>F/Hz]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="open_C1"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>C2 [10<sup>-36</sup>F/Hz<sup>2</sup>]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="open_C2"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>C0 [10<sup>-45</sup>F/Hz<sup>3</sup>]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="open_C3"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="open_Z0"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Z0 [Ω]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0">
|
||||
<item>
|
||||
<widget class="TouchstoneImport" name="open_touchstone" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Short</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="short_coefficients">
|
||||
<property name="text">
|
||||
<string>Coefficients</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">ShortType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="short_measurement">
|
||||
<property name="text">
|
||||
<string>Measurement file</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">ShortType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="short_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Offset delay [ps]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="short_delay"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Offset loss [GΩ/s]: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="short_loss"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>L0 [10<span style=" vertical-align:super;">-12</span>F]:</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="short_L0"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>L1 [10<span style=" vertical-align:super;">-24</span>F/Hz]:</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="short_L1"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>L2 [10<span style=" vertical-align:super;">-33</span>F/Hz<span style=" vertical-align:super;">2</span>]:</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="short_L2"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>L3 [10<span style=" vertical-align:super;">-42</span>F/Hz<span style=" vertical-align:super;">3</span>]:</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="short_L3"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="short_Z0"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Z0 [Ω]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0">
|
||||
<item>
|
||||
<widget class="TouchstoneImport" name="short_touchstone" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="load_coefficients">
|
||||
<property name="text">
|
||||
<string>Coefficients</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">LoadType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="load_measurement">
|
||||
<property name="text">
|
||||
<string>Measurement file</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">LoadType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="load_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>Z0 [Ω]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="load_Z0"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_6">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6" stretch="0">
|
||||
<item>
|
||||
<widget class="TouchstoneImport" name="load_touchstone" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Through</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="through_coefficients">
|
||||
<property name="text">
|
||||
<string>Coefficients</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">ThroughType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="through_measurement">
|
||||
<property name="text">
|
||||
<string>Measurement file</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">ThroughType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="through_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_7">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_35">
|
||||
<property name="text">
|
||||
<string>Z0 [Ω]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="through_Z0"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Offset delay [ps]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="through_delay"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Offset loss [GΩ/s]: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="through_loss"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_8">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8" stretch="0">
|
||||
<item>
|
||||
<widget class="TouchstoneImport" name="through_touchstone" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TouchstoneImport</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>CustomWidgets/touchstoneimport.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>open_Z0</tabstop>
|
||||
<tabstop>open_delay</tabstop>
|
||||
<tabstop>open_loss</tabstop>
|
||||
<tabstop>open_C0</tabstop>
|
||||
<tabstop>open_C1</tabstop>
|
||||
<tabstop>open_C2</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>OpenType</sender>
|
||||
<signal>buttonClicked(int)</signal>
|
||||
<receiver>open_stack</receiver>
|
||||
<slot>setCurrentIndex(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>141</x>
|
||||
<y>187</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ShortType</sender>
|
||||
<signal>buttonClicked(int)</signal>
|
||||
<receiver>short_stack</receiver>
|
||||
<slot>setCurrentIndex(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>420</x>
|
||||
<y>187</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>LoadType</sender>
|
||||
<signal>buttonClicked(int)</signal>
|
||||
<receiver>load_stack</receiver>
|
||||
<slot>setCurrentIndex(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>699</x>
|
||||
<y>187</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ThroughType</sender>
|
||||
<signal>buttonClicked(int)</signal>
|
||||
<receiver>through_stack</receiver>
|
||||
<slot>setCurrentIndex(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>978</x>
|
||||
<y>187</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="LoadType"/>
|
||||
<buttongroup name="OpenType"/>
|
||||
<buttongroup name="ShortType"/>
|
||||
<buttongroup name="ThroughType"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
88
Software/PC_Application/Calibration/measurementmodel.cpp
Normal file
88
Software/PC_Application/Calibration/measurementmodel.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#include "measurementmodel.h"
|
||||
#include "../unit.h"
|
||||
#include <algorithm>
|
||||
|
||||
MeasurementModel::MeasurementModel(Calibration *cal, std::vector<Calibration::Measurement> measurements) :
|
||||
QAbstractTableModel(),
|
||||
cal(cal),
|
||||
measurements(measurements)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int MeasurementModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return measurements.size();
|
||||
}
|
||||
|
||||
int MeasurementModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return ColIndexLast;
|
||||
}
|
||||
|
||||
QVariant MeasurementModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
auto info = cal->getMeasurementInfo(measurements[index.row()]);
|
||||
if(role == Qt::DisplayRole) {
|
||||
switch(index.column()) {
|
||||
case ColIndexName:
|
||||
return info.name;
|
||||
break;
|
||||
case ColIndexDescription:
|
||||
return info.prerequisites;
|
||||
break;
|
||||
case ColIndexData:
|
||||
if(info.points > 0) {
|
||||
QString data = QString::number(info.points);
|
||||
data.append(" points from ");
|
||||
data.append(Unit::ToString(info.fmin, "Hz", " kMG"));
|
||||
data.append(" to ");
|
||||
data.append(Unit::ToString(info.fmax, "Hz", " kMG"));
|
||||
return data;
|
||||
} else {
|
||||
return "Not available";
|
||||
}
|
||||
break;
|
||||
case ColIndexDate:
|
||||
return info.timestamp.toString("dd.MM.yyyy hh:mm:ss");
|
||||
break;
|
||||
}
|
||||
} else if(role == Qt::SizeHintRole) {
|
||||
switch(index.column()) {
|
||||
case ColIndexName: return 200; break;
|
||||
case ColIndexDescription: return 500; break;
|
||||
case ColIndexData: return 300; break;
|
||||
case ColIndexDate: return 300; break;
|
||||
case ColIndexStatusSymbol: return 150; break;
|
||||
default: return QVariant(); break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant MeasurementModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch(section) {
|
||||
case ColIndexName: return "Type"; break;
|
||||
case ColIndexDescription: return "Prerequisites"; break;
|
||||
case ColIndexData: return "Statistics"; break;
|
||||
case ColIndexDate: return "Timestamp"; break;
|
||||
case ColIndexStatusSymbol: return "Status"; break;
|
||||
default: return QVariant(); break;
|
||||
}
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void MeasurementModel::measurementUpdated(Calibration::Measurement m)
|
||||
{
|
||||
// find correct index in vector
|
||||
auto it = std::find(measurements.begin(), measurements.end(), m);
|
||||
if(it != measurements.end()) {
|
||||
int row = it - measurements.begin();
|
||||
emit dataChanged(index(row, 0), index(row, ColIndexLast - 1));
|
||||
}
|
||||
}
|
||||
36
Software/PC_Application/Calibration/measurementmodel.h
Normal file
36
Software/PC_Application/Calibration/measurementmodel.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef MEASUREMENTMODEL_H
|
||||
#define MEASUREMENTMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QAbstractTableModel>
|
||||
#include "calibration.h"
|
||||
|
||||
class MeasurementModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MeasurementModel(Calibration *cal, std::vector<Calibration::Measurement> measurements);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public slots:
|
||||
void measurementUpdated(Calibration::Measurement m);
|
||||
|
||||
private:
|
||||
enum {
|
||||
ColIndexName,
|
||||
ColIndexDescription,
|
||||
ColIndexData,
|
||||
ColIndexDate,
|
||||
ColIndexStatusSymbol,
|
||||
ColIndexLast
|
||||
};
|
||||
Calibration *cal;
|
||||
std::vector<Calibration::Measurement> measurements;
|
||||
};
|
||||
|
||||
#endif // MEASUREMENTMODEL_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue