switched to new calibration implementation

This commit is contained in:
Jan Käberich 2022-08-29 20:07:07 +02:00
parent dced8105f2
commit 0e0173f62a
23 changed files with 1260 additions and 2718 deletions

View File

@ -12,6 +12,7 @@
#include <QMessageBox>
#include <QFileDialog>
#include <fstream>
#include <iomanip>
#include <CustomWidgets/informationbox.h>
using namespace std;

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +1,71 @@
#ifndef CALIBRATION_H
#define CALIBRATION_H
#ifndef CALIBRATION2_H
#define CALIBRATION2_H
#include "Device/device.h"
#include "savable.h"
#include "calibrationmeasurement.h"
#include "calkit.h"
#include "Traces/tracemodel.h"
#include "Traces/trace.h"
#include <complex>
#include <vector>
#include <map>
#include <iostream>
#include <iomanip>
#include <QDateTime>
#include <savable.h>
class Calibration : public Savable
class Calibration : public QObject, public Savable
{
Q_OBJECT
public:
Calibration();
enum class Measurement {
Port1Open,
Port1Short,
Port1Load,
Port2Open,
Port2Short,
Port2Load,
Isolation,
Through,
Line,
Last,
};
enum class Standard {
Open,
Short,
Load,
Through,
Any,
};
static Standard getPort1Standard(Measurement m);
static Standard getPort2Standard(Measurement m);
void clearMeasurements();
void clearMeasurements(std::set<Measurement> types);
void clearMeasurement(Measurement type);
void addMeasurement(Measurement type, VirtualDevice::VNAMeasurement &d);
void addMeasurements(std::set<Measurement> types, VirtualDevice::VNAMeasurement &d);
enum class Type {
Port1SOL,
Port2SOL,
FullSOLT,
TransmissionNormalization,
TRL,
None,
SOLT,
Last,
};
class CalType {
public:
Type type;
std::vector<int> usedPorts;
QString getReadableDescription();
QString getShortString();
static CalType fromShortString(QString s);
bool calculationPossible(Type type);
bool constructErrorTerms(Type type);
void resetErrorTerms();
friend bool operator==(const CalType &lhs, const CalType &rhs);
};
static QString TypeToString(Type type);
static Type TypeFromString(QString s);
// Applies calculated calibration coefficients to measurement data
void correctMeasurement(VirtualDevice::VNAMeasurement &d);
void correctTraces(Trace &S11, Trace &S12, Trace &S21, Trace &S22);
// Starts the calibration edit dialog, allowing the user to make/delete measurements
void edit();
Calkit& getKit();
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
bool toFile(QString filename = QString());
bool fromFile(QString filename = QString());
// Returns all possible calibration types/port permutations for the currently connected device.
// If no device is connected, a two-port device is assumed
static std::vector<CalType> getAvailableCalibrations();
// Returns vector of all calibration types (without 'Last')
static std::vector<Type> getTypes();
// Checks whether all measurements for a specific calibration are available.
// If pointer to the frequency/points variables are given, the start/stop frequency and number of points the calibration will have after the calculation is stored there
bool canCompute(CalType type, double *startFreq = nullptr, double *stopFreq = nullptr, int *points = nullptr);
// Resets the calibration (deletes all measurements and calculated coefficients)
void reset();
// Returns the minimum number of ports for a given calibration type.
// E.g. the SOL(T) calibration can work with only one port, a through normalization requires at least two
static int minimumPorts(Type type);
// Adds a new measurement point (data) to all calibration measurements (m)
void addMeasurements(std::set<CalibrationMeasurement::Base*> m, const VirtualDevice::VNAMeasurement &data);
// Deletes all datapoints in the calibration measurements (m)
void clearMeasurements(std::set<CalibrationMeasurement::Base*> m);
CalType getCaltype() const;
enum class InterpolationType {
Unchanged, // Nothing has changed, settings and calibration points match
@ -74,119 +75,70 @@ public:
NoCalibration, // No calibration available
};
InterpolationType getInterpolation(double f_start, double f_stop, int points);
static Measurement MeasurementFromString(QString s);
static QString MeasurementToString(Measurement m);
static Type TypeFromString(QString s);
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();
const std::vector<Measurement> Measurements(Type type = Type::None, bool optional_included = true);
MeasurementInfo getMeasurementInfo(Measurement m);
friend std::istream& operator >> (std::istream &in, Calibration& c);
int nPoints() {
return points.size();
}
InterpolationType getInterpolation(double f_start, double f_stop, int npoints);
std::vector<Trace*> getErrorTermTraces();
std::vector<Trace*> getMeasurementTraces();
bool openFromFile(QString filename = QString());
bool saveToFile(QString filename = QString());
Type getType() const;
Calkit& getCalibrationKit();
void setCalibrationKit(const Calkit &value);
enum class PortStandard {
Male,
Female,
};
void setPortStandard(int port, PortStandard standard);
PortStandard getPortStandard(int port);
bool getThroughZeroLength() const;
void setThroughZeroLength(bool value);
QString getCurrentCalibrationFile();
double getMinFreq();
double getMaxFreq();
int getNumPoints();
nlohmann::json toJSON() override;
void fromJSON(nlohmann::json j) override;
public slots:
// Call once all datapoints of the current span have been added
void measurementsComplete();
// Attempts to calculate the calibration coefficients. If not enough measurements are available, false is returned and the currently used coefficients are not changed
bool compute(CalType type);
// Deactivates the calibration, resets the calibration coefficients. Calibration measurements are NOT deleted.
void deactivate();
signals:
// emitted when the measurement of a set of calibration measurements should be started
void startMeasurements(std::set<CalibrationMeasurement::Base*> m);
// emitted whenever a measurement is complete (triggered by calling measurementsComplete())
void measurementsUpdated();
// emitted when calibration coefficients were calculated/updated successfully
void activated(CalType type);
// emitted when the calibrationo coefficients were reset
void deactivated();
private:
void construct12TermPoints();
void constructPort1SOL();
void constructPort2SOL();
void constructTransmissionNormalization();
void constructTRL();
bool SanityCheckSamples(const std::vector<Measurement> &requiredMeasurements);
class Point
{
enum class DefaultMeasurements {
SOL1Port,
SOLT2Port,
SOLT3Port,
SOLT4Port,
Last
};
static QString DefaultMeasurementsToString(DefaultMeasurements dm);
void createDefaultMeasurements(DefaultMeasurements dm);
bool hasFrequencyOverlap(std::vector<CalibrationMeasurement::Base*> m, double *startFreq = nullptr, double *stopFreq = nullptr, int *points = nullptr);
CalibrationMeasurement::Base* findMeasurement(CalibrationMeasurement::Base::Type type, int port1 = 0, int port2 = 0);
CalibrationMeasurement::Base *newMeasurement(CalibrationMeasurement::Base::Type type);
class Point {
public:
double frequency;
// Forward error terms
std::complex<double> fe00, fe11, fe10e01, fe10e32, fe22, fe30, fex;
// Reverse error terms
std::complex<double> re33, re11, re23e32, re23e01, re22, re03, rex;
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::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
Point interpolate(const Point &to, double alpha);
};
Point getCalibrationPoint(VirtualDevice::VNAMeasurement &d);
/*
* Constructs directivity, match and tracking correction factors from measurements of three distinct impedances
* Normally, an open, short and load are used (with ideal reflection coefficients of 1, -1 and 0 respectively).
* 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));
void computeIsolation(std::complex<double> x0_m,
std::complex<double> x1_m,
std::complex<double> reverse_match,
std::complex<double> reverse_tracking,
std::complex<double> reverse_directivity,
std::complex<double> x0,
std::complex<double> x1,
std::complex<double> &internal_isolation,
std::complex<double> &external_isolation);
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<VirtualDevice::VNAMeasurement> datapoints;
};
Type type;
std::map<Measurement, MeasurementData> measurements;
double minFreq, maxFreq;
std::vector<Point> points;
Point computeSOLT(double f);
std::vector<CalibrationMeasurement::Base*> measurements;
Calkit kit;
CalType caltype;
QString descriptiveCalName();
QString currentCalFile;
PortStandard port1Standard, port2Standard;
bool throughZeroLength;
};
#endif // CALIBRATION_H
#endif // CALIBRATION2_H

View File

@ -1,686 +0,0 @@
#include "calibration2.h"
#include "ui_calibrationdialogui.h"
#include "CustomWidgets/informationbox.h"
#include "Util/app_common.h"
#include "Eigen/Dense"
#include <QDialog>
#include <QMenu>
#include <QStyle>
#include <QDebug>
using namespace std;
using Eigen::MatrixXcd;
Calibration2::Calibration2()
{
caltype.type = Type::None;
}
void Calibration2::correctMeasurement(VirtualDevice::VNAMeasurement &d)
{
if(caltype.type == Type::None) {
// no calibration active, nothing to do
return;
}
// formulas from "Multi-Port Calibration Techniques for Differential Parameter Measurements with Network Analyzers", variable names also losely follow this document
MatrixXcd S(caltype.usedPorts.size(), caltype.usedPorts.size());
MatrixXcd a(caltype.usedPorts.size(), caltype.usedPorts.size());
MatrixXcd b(caltype.usedPorts.size(), caltype.usedPorts.size());
// Grab measurements (easier to access by index later)
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
auto pSrc = caltype.usedPorts[i];
auto pRcv = caltype.usedPorts[j];
auto name = "S"+QString::number(pRcv)+QString::number(pSrc);
if(d.measurements.count(name) == 0) {
qWarning() << "Missing measurement for calibration:" << name;
return;
} else {
S(j,i) = d.measurements[name];
}
}
}
// gab point and interpolate
Point p;
if(d.frequency <= points.front().frequency) {
p = points.front();
} else if(d.frequency >= points.back().frequency) {
p = points.back();
} else {
// needs to interpolate
auto lower = lower_bound(points.begin(), points.end(), d.frequency, [](const Point &lhs, double rhs) -> bool {
return lhs.frequency < rhs;
});
auto highPoint = *lower;
auto lowPoint = *prev(lower);
double alpha = (d.frequency - lowPoint.frequency) / (highPoint.frequency - lowPoint.frequency);
p = lowPoint.interpolate(highPoint, alpha);
}
// assemble a (L) and b (K) matrices
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
if(i == j) {
// calculate incident and reflected wave at the exciting port
a(j,i) = 1.0 + p.S[i]/p.R[i]*(S(j,i) - p.D[i]*1.0);
b(j,i) = (1.0 / p.R[i]) * (S(j,i) - p.D[i]*1.0);
} else {
// calculate incident and reflected wave at the receiving port
a(j,i) = p.L[i][j]*S(j,i) / p.T[i][j];
b(j,i) = S(j,i) / p.T[i][j];
}
}
}
S = b * a.inverse();
// extract measurement from matrix and store back into VNAMeasurement
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
for(unsigned int j=0;j<caltype.usedPorts.size();j++) {
auto pSrc = caltype.usedPorts[i];
auto pRcv = caltype.usedPorts[j];
auto name = "S"+QString::number(pRcv)+QString::number(pSrc);
d.measurements[name] = S(j,i);
}
}
}
void Calibration2::edit()
{
auto d = new QDialog();
d->setAttribute(Qt::WA_DeleteOnClose);
auto ui = new Ui::CalibrationDialog;
ui->setupUi(d);
ui->calMinFreq->setUnit("Hz");
ui->calMinFreq->setPrecision(4);
ui->calMinFreq->setPrefixes(" kMG");
ui->calMaxFreq->setUnit("Hz");
ui->calMaxFreq->setPrecision(4);
ui->calMaxFreq->setPrefixes(" kMG");
int ports = 2;
if(VirtualDevice::getConnected()) {
ports = VirtualDevice::getConnected()->getInfo().ports;
}
// generate all possible calibration with the connected device
vector<CalType> availableCals;
for(auto t : getTypes()) {
CalType cal;
cal.type = t;
auto minPorts = minimumPorts(t);
for(int pnum = minPorts;pnum <= ports;pnum++) {
std::string bitmask(pnum, 1);
bitmask.resize(ports, 0);
// assemble selected ports and permute bitmask
do {
vector<int> usedPorts;
for (int i = 0; i < ports; ++i) {
if (bitmask[i]) {
usedPorts.push_back(i+1);
}
}
cal.usedPorts = usedPorts;
availableCals.push_back(cal);
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
}
for(auto c : availableCals) {
ui->calibrationList->addItem(c.getDescription());
}
auto updateCalibrationList = [=](){
auto style = QApplication::style();
for(int i=0;i<availableCals.size();i++) {
QIcon icon;
if(canCompute(availableCals[i])) {
icon = style->standardIcon(QStyle::SP_DialogApplyButton);
} else {
icon = style->standardIcon(QStyle::SP_MessageBoxCritical);
}
ui->calibrationList->item(i)->setIcon(icon);
}
};
updateCalibrationList();
connect(ui->calibrationList, &QListWidget::doubleClicked, [=](const QModelIndex &index) {
auto row = index.row();
auto cal = availableCals[row];
if(canCompute(cal)) {
compute(cal);
ui->activeCalibration->setText(cal.getDescription());
ui->calMinFreq->setValue(points.front().frequency);
ui->calMaxFreq->setValue(points.back().frequency);
ui->calPoints->setValue(points.size());
}
});
ui->table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
auto updateTableEditButtons = [=](){
ui->bDelete->setEnabled(ui->table->currentRow() >= 0);
ui->bMoveUp->setEnabled(ui->table->currentRow() >= 1);
ui->bMoveDown->setEnabled(ui->table->currentRow() >= 0 && ui->table->currentRow() < ui->table->rowCount() - 1);
};
auto updateMeasurementTable = [=](){
int row = ui->table->currentRow();
ui->table->clear();
ui->table->setColumnCount(5);
ui->table->setHorizontalHeaderItem(0, new QTableWidgetItem("Type"));
ui->table->setHorizontalHeaderItem(1, new QTableWidgetItem("Calkit Standard"));
ui->table->setHorizontalHeaderItem(2, new QTableWidgetItem("Settings"));
ui->table->setHorizontalHeaderItem(3, new QTableWidgetItem("Statistics"));
ui->table->setHorizontalHeaderItem(4, new QTableWidgetItem("Timestamp"));
ui->table->setRowCount(measurements.size());
for(unsigned int i=0;i<measurements.size();i++){
ui->table->setItem(i, 0, new QTableWidgetItem(CalibrationMeasurement::Base::TypeToString(measurements[i]->getType())));
ui->table->setCellWidget(i, 1, measurements[i]->createStandardWidget());
ui->table->setCellWidget(i, 2, measurements[i]->createSettingsWidget());
ui->table->setItem(i, 3, new QTableWidgetItem(measurements[i]->getStatistics()));
ui->table->setItem(i, 4, new QTableWidgetItem(measurements[i]->getTimestamp().toString()));
}
ui->table->selectRow(row);
updateTableEditButtons();
};
ui->createDefault->addItem(" ");
for(unsigned int i=0;i<(int) DefaultMeasurements::Last;i++) {
ui->createDefault->addItem(DefaultMeasurementsToString((DefaultMeasurements) i));
}
QObject::connect(ui->createDefault, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
if(measurements.size() > 0) {
if(!InformationBox::AskQuestion("Create default entries?", "Do you want to remove all existing entries and create default calibration measurements instead?", true)) {
// user aborted
return;
}
measurements.clear();
}
createDefaultMeasurements((DefaultMeasurements) (ui->createDefault->currentIndex() - 1));
updateMeasurementTable();
updateCalibrationList();
ui->createDefault->blockSignals(true);
ui->createDefault->setCurrentIndex(0);
ui->createDefault->blockSignals(false);
});
QObject::connect(ui->bDelete, &QPushButton::clicked, [=](){
auto selected = ui->table->selectionModel()->selectedRows();
set<CalibrationMeasurement::Base*> toDelete;
for(auto s : selected) {
toDelete.insert(measurements[s.row()]);
}
while(toDelete.size() > 0) {
for(unsigned int i=0;i<measurements.size();i++) {
if(toDelete.count(measurements[i])) {
// this measurement should be deleted
delete measurements[i];
toDelete.erase(measurements[i]);
measurements.erase(measurements.begin() + i);
}
}
}
updateMeasurementTable();
updateCalibrationList();
});
QObject::connect(ui->bMoveUp, &QPushButton::clicked, [=](){
auto row = ui->table->currentRow();
if(row >= 1) {
swap(measurements[row], measurements[row-1]);
ui->table->selectRow(row-1);
updateMeasurementTable();
}
});
QObject::connect(ui->bMoveDown, &QPushButton::clicked, [=](){
auto row = ui->table->currentRow();
if(row >= 0) {
swap(measurements[row], measurements[row+1]);
ui->table->selectRow(row+1);
updateMeasurementTable();
}
});
connect(ui->measure, &QPushButton::clicked, [=](){
std::set<CalibrationMeasurement::Base*> m;
auto selected = ui->table->selectionModel()->selectedRows();
for(auto s : selected) {
m.insert(measurements[s.row()]);
}
if(!CalibrationMeasurement::Base::canMeasureSimultaneously(m)) {
InformationBox::ShowError("Unable to measure", "Different selected measurements require the same port, unable to perform measurement");
return;
}
emit startMeasurements(m);
});
connect(this, &Calibration2::measurementsUpdated, d, [=](){
updateMeasurementTable();
updateCalibrationList();
});
connect(ui->clearMeasurement, &QPushButton::clicked, [=](){
auto selected = ui->table->selectionModel()->selectedRows();
for(auto s : selected) {
measurements[s.row()]->clearPoints();
}
updateMeasurementTable();
updateCalibrationList();
});
QObject::connect(ui->table, &QTableWidget::currentCellChanged, updateTableEditButtons);
auto addMenu = new QMenu();
for(auto t : CalibrationMeasurement::Base::availableTypes()) {
auto action = new QAction(CalibrationMeasurement::Base::TypeToString(t));
QObject::connect(action, &QAction::triggered, [=](){
auto newMeas = newMeasurement(t);
if(newMeas) {
measurements.push_back(newMeas);
updateMeasurementTable();
}
});
addMenu->addAction(action);
}
ui->bAdd->setMenu(addMenu);
updateMeasurementTable();
d->show();
}
CalibrationMeasurement::Base *Calibration2::newMeasurement(CalibrationMeasurement::Base::Type type)
{
CalibrationMeasurement::Base *m = nullptr;
switch(type) {
case CalibrationMeasurement::Base::Type::Open: m = new CalibrationMeasurement::Open(this); break;
case CalibrationMeasurement::Base::Type::Short: m = new CalibrationMeasurement::Short(this); break;
case CalibrationMeasurement::Base::Type::Load: m = new CalibrationMeasurement::Load(this); break;
case CalibrationMeasurement::Base::Type::Through: m = new CalibrationMeasurement::Through(this); break;
}
return m;
}
Calibration2::Point Calibration2::computeSOLT(double f)
{
Point point;
point.frequency = f;
// resize vectors
point.D.resize(caltype.usedPorts.size());
point.R.resize(caltype.usedPorts.size());
point.S.resize(caltype.usedPorts.size());
point.L.resize(caltype.usedPorts.size());
point.T.resize(caltype.usedPorts.size());
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()));
// Calculate SOL coefficients
for(unsigned int i=0;i<caltype.usedPorts.size();i++) {
auto p = caltype.usedPorts[i];
auto _short = static_cast<CalibrationMeasurement::Short*>(findMeasurement(CalibrationMeasurement::Base::Type::Short, p));
auto open = static_cast<CalibrationMeasurement::Open*>(findMeasurement(CalibrationMeasurement::Base::Type::Open, p));
auto load = static_cast<CalibrationMeasurement::Load*>(findMeasurement(CalibrationMeasurement::Base::Type::Load, p));
auto s_m = _short->getMeasured(f);
auto o_m = open->getMeasured(f);
auto l_m = load->getMeasured(f);
auto s_c = _short->getActual(f);
auto o_c = open->getActual(f);
auto l_c = load->getActual(f);
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);
point.D[i] = (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;
point.S[i] = (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;
point.R[i] = point.D[i] * point.S[i] - delta;
}
// 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 through = static_cast<CalibrationMeasurement::Through*>(findMeasurement(CalibrationMeasurement::Base::Type::Through, p1, p2));
auto S11 = through->getMeasured(f).m11;
auto S21 = through->getMeasured(f).m21;
auto Sideal = through->getActual(f);
auto deltaS = Sideal.m11*Sideal.m22 - Sideal.m21 * Sideal.m12;
auto isolation = complex<double>(0.0, 0.0);
point.L[i][j] = ((S11 - point.D[i])*(1.0 - point.S[i] * Sideal.m11)-Sideal.m11*point.R[i])
/ ((S11 - point.D[i])*(Sideal.m22-point.S[i]*deltaS)-deltaS*point.R[i]);
point.T[i][j] = (S21 - isolation)*(1.0 - point.S[i]*Sideal.m11 - point.L[i][j]*Sideal.m22 + point.S[i]*point.L[i][j]*deltaS) / Sideal.m21;
}
}
return point;
}
Calkit &Calibration2::getKit()
{
return kit;
}
nlohmann::json Calibration2::toJSON()
{
nlohmann::json j;
nlohmann::json jmeasurements;
for(auto m : measurements) {
nlohmann::json jmeas;
jmeas["type"] = m->getType();
jmeas["data"] = m->toJSON();
jmeasurements.push_back(jmeas);
}
j["measurements"] = jmeasurements;
j["calkit"] = kit.toJSON();
j["version"] = qlibrevnaApp->applicationVersion().toStdString();
if(VirtualDevice::getConnected()) {
j["device"] = VirtualDevice::getConnected()->serial();
}
return j;
}
void Calibration2::fromJSON(nlohmann::json j)
{
if(j.contains("calkit")) {
kit.fromJSON(j["calkit"]);
}
if(j.contains("measurements")) {
for(auto jm : j["measurements"]) {
auto type = CalibrationMeasurement::Base::TypeFromString(jm.value("type", ""));
auto m = newMeasurement(type);
m->fromJSON(jm["data"]);
measurements.push_back(m);
}
}
}
std::vector<Calibration2::Type> Calibration2::getTypes()
{
vector<Type> types;
// Start at index 1, skip Type::None
for(int i=1;i<(int) Type::Last;i++) {
types.push_back((Type) i);
}
return types;
}
bool Calibration2::canCompute(Calibration2::CalType type, double *startFreq, double *stopFreq, int *points)
{
switch(type.type) {
case Type::SOLT: {
using RequiredMeasurements = struct {
CalibrationMeasurement::Base::Type type;
int port1, port2;
};
vector<RequiredMeasurements> required;
// SOL measurements for every port
for(auto p : type.usedPorts) {
required.push_back({.type = CalibrationMeasurement::Base::Type::Short, .port1 = p});
required.push_back({.type = CalibrationMeasurement::Base::Type::Open, .port1 = p});
required.push_back({.type = CalibrationMeasurement::Base::Type::Load, .port1 = p});
}
// 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});
}
}
vector<CalibrationMeasurement::Base*> foundMeasurements;
for(auto m : required) {
auto meas = findMeasurement(m.type, m.port1, m.port2);
if(!meas) {
// missing measurement
return false;
} else {
foundMeasurements.push_back(meas);
}
}
return hasFrequencyOverlap(foundMeasurements, startFreq, stopFreq, points);
}
break;
}
return false;
}
bool Calibration2::compute(Calibration2::CalType type)
{
double start, stop;
int numPoints;
if(!canCompute(type, &start, &stop, &numPoints)) {
return false;
}
caltype = type;
try {
points.clear();
for(int i=0;i<numPoints;i++) {
double f = start + (stop - start) * i / (numPoints - 1);
Point p;
switch(type.type) {
case Type::SOLT: p = computeSOLT(f); break;
}
points.push_back(p);
}
} catch (exception &e) {
points.clear();
caltype.usedPorts.clear();
}
return true;
}
int Calibration2::minimumPorts(Calibration2::Type type)
{
switch(type) {
case Type::SOLT: return 1;
}
return -1;
}
void Calibration2::deleteMeasurements()
{
for(auto m : measurements) {
delete m;
}
measurements.clear();
}
void Calibration2::addMeasurements(std::set<CalibrationMeasurement::Base *> m, const VirtualDevice::VNAMeasurement &data)
{
for(auto meas : m) {
meas->addPoint(data);
}
}
void Calibration2::clearMeasurements(std::set<CalibrationMeasurement::Base *> m)
{
for(auto meas : m) {
meas->clearPoints();
}
}
void Calibration2::measurementsComplete()
{
emit measurementsUpdated();
}
QString Calibration2::DefaultMeasurementsToString(Calibration2::DefaultMeasurements dm)
{
switch(dm) {
case DefaultMeasurements::SOL1Port: return "1 Port SOL";
case DefaultMeasurements::SOLT2Port: return "2 Port SOLT";
case DefaultMeasurements::SOLT3Port: return "3 Port SOLT";
case DefaultMeasurements::SOLT4Port: return "4 Port SOLT";
}
}
void Calibration2::createDefaultMeasurements(Calibration2::DefaultMeasurements dm)
{
auto createSOL = [=](int port) {
auto _short = new CalibrationMeasurement::Short(this);
_short->setPort(port);
measurements.push_back(_short);
auto open = new CalibrationMeasurement::Open(this);
open->setPort(port);
measurements.push_back(open);
auto load = new CalibrationMeasurement::Load(this);
load->setPort(port);
measurements.push_back(load);
};
auto createThrough = [=](int port1, int port2) {
auto through = new CalibrationMeasurement::Through(this);
through->setPort1(port1);
through->setPort2(port2);
measurements.push_back(through);
};
switch(dm) {
case DefaultMeasurements::SOL1Port:
createSOL(1);
break;
case DefaultMeasurements::SOLT2Port:
createSOL(1);
createSOL(2);
createThrough(1, 2);
break;
case DefaultMeasurements::SOLT3Port:
createSOL(1);
createSOL(2);
createSOL(3);
createThrough(1, 2);
createThrough(1, 3);
createThrough(2, 3);
break;
case DefaultMeasurements::SOLT4Port:
createSOL(1);
createSOL(2);
createSOL(3);
createSOL(4);
createThrough(1, 2);
createThrough(1, 3);
createThrough(1, 4);
createThrough(2, 3);
createThrough(2, 4);
createThrough(3, 4);
break;
}
}
bool Calibration2::hasFrequencyOverlap(std::vector<CalibrationMeasurement::Base *> m, double *startFreq, double *stopFreq, int *points)
{
double minResolution = std::numeric_limits<double>::max();
double minFreq = 0;
double maxFreq = std::numeric_limits<double>::max();
for(auto meas : m) {
if(meas->numPoints() < 2) {
return false;
}
auto resolution = (meas->maxFreq() - meas->minFreq()) / (meas->numPoints() - 1);
if(meas->maxFreq() < maxFreq) {
maxFreq = meas->maxFreq();
}
if(meas->minFreq() > minFreq) {
minFreq = meas->minFreq();
}
if(resolution < minResolution) {
minResolution = resolution;
}
}
if(startFreq) {
*startFreq = minFreq;
}
if(stopFreq) {
*stopFreq = maxFreq;
}
if(points) {
*points = (maxFreq - minFreq) / minResolution + 1;
}
if(maxFreq > minFreq) {
return true;
} else {
return false;
}
}
CalibrationMeasurement::Base *Calibration2::findMeasurement(CalibrationMeasurement::Base::Type type, int port1, int port2)
{
for(auto m : measurements) {
if(m->getType() != type) {
continue;
}
auto onePort = dynamic_cast<CalibrationMeasurement::OnePort*>(m);
if(onePort) {
if(onePort->getPort() != port1) {
continue;
}
}
auto twoPort = dynamic_cast<CalibrationMeasurement::TwoPort*>(m);
if(twoPort) {
if(twoPort->getPort1() != port1 || twoPort->getPort2() != port2) {
continue;
}
}
// if we get here, we have a match
return m;
}
return nullptr;
}
QString Calibration2::CalType::getDescription()
{
switch(type) {
case Type::SOLT:
if(usedPorts.size() == 1) {
return "SOL, Port: "+QString::number(usedPorts[0]);
} else {
QString ret = "SOLT, Ports: [";
for(auto p : usedPorts) {
ret += QString::number(p)+",";
}
// remove the last trailing comma
ret.chop(1);
ret += "]";
return ret;
}
}
}
Calibration2::Point Calibration2::Point::interpolate(const Calibration2::Point &to, double alpha)
{
Point ret;
ret.frequency = frequency * (1.0-alpha) + to.frequency * alpha;
ret.D.resize(D.size());
for(unsigned int i=0;i<D.size();i++) {
ret.D[i] = D[i] * (1.0-alpha) + to.D[i] * alpha;
}
ret.R.resize(R.size());
for(unsigned int i=0;i<R.size();i++) {
ret.R[i] = R[i] * (1.0-alpha) + to.R[i] * alpha;
}
ret.S.resize(S.size());
for(unsigned int i=0;i<S.size();i++) {
ret.S[i] = S[i] * (1.0-alpha) + to.S[i] * alpha;
}
ret.T.resize(T.size());
for(unsigned int i=0;i<T.size();i++) {
ret.T[i].resize(T[i].size());
for(unsigned int j=0;j<T[i].size();j++) {
ret.T[i][j] = T[i][j] * (1.0 - alpha) + to.T[i][j] * alpha;
}
}
ret.L.resize(L.size());
for(unsigned int i=0;i<L.size();i++) {
ret.L[i].resize(L[i].size());
for(unsigned int j=0;j<L[i].size();j++) {
ret.L[i][j] = L[i][j] * (1.0 - alpha) + to.L[i][j] * alpha;
}
}
return ret;
}

View File

@ -1,81 +0,0 @@
#ifndef CALIBRATION2_H
#define CALIBRATION2_H
#include "savable.h"
#include "calibrationmeasurement.h"
#include "calkit.h"
class Calibration2 : public QObject, public Savable
{
Q_OBJECT
public:
Calibration2();
enum class Type {
None,
SOLT,
Last,
};
class CalType {
public:
Type type;
std::vector<int> usedPorts;
QString getDescription();
};
void correctMeasurement(VirtualDevice::VNAMeasurement &d);
void edit();
Calkit& getKit();
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
static std::vector<Type> getTypes();
bool canCompute(CalType type, double *startFreq = nullptr, double *stopFreq = nullptr, int *points = nullptr);
bool compute(CalType type);
static int minimumPorts(Type type);
void deleteMeasurements();
void addMeasurements(std::set<CalibrationMeasurement::Base*> m, const VirtualDevice::VNAMeasurement &data);
void clearMeasurements(std::set<CalibrationMeasurement::Base*> m);
public slots:
void measurementsComplete();
signals:
void startMeasurements(std::set<CalibrationMeasurement::Base*> m);
void measurementsUpdated();
private:
enum class DefaultMeasurements {
SOL1Port,
SOLT2Port,
SOLT3Port,
SOLT4Port,
Last
};
static QString DefaultMeasurementsToString(DefaultMeasurements dm);
void createDefaultMeasurements(DefaultMeasurements dm);
bool hasFrequencyOverlap(std::vector<CalibrationMeasurement::Base*> m, double *startFreq = nullptr, double *stopFreq = nullptr, int *points = nullptr);
CalibrationMeasurement::Base* findMeasurement(CalibrationMeasurement::Base::Type type, int port1 = 0, int port2 = 0);
CalibrationMeasurement::Base *newMeasurement(CalibrationMeasurement::Base::Type type);
class Point {
public:
double frequency;
std::vector<std::complex<double>> D, R, S;
std::vector<std::vector<std::complex<double>>> L, T;
Point interpolate(const Point &to, double alpha);
};
std::vector<Point> points;
Point computeSOLT(double f);
std::vector<CalibrationMeasurement::Base*> measurements;
Calkit kit;
CalType caltype;
};
#endif // CALIBRATION2_H

View File

@ -1,6 +1,6 @@
#include "calibrationmeasurement.h"
#include "unit.h"
#include "calibration2.h"
#include "calibration.h"
#include <QDateTime>
#include <QComboBox>
@ -9,7 +9,7 @@
using namespace std;
CalibrationMeasurement::Base::Base(Calibration2 *cal)
CalibrationMeasurement::Base::Base(Calibration *cal)
: cal(cal)
{
standard = nullptr;
@ -86,6 +86,7 @@ QString CalibrationMeasurement::Base::TypeToString(CalibrationMeasurement::Base:
case Type::Short: return "Short";
case Type::Load: return "Load";
case Type::Through: return "Through";
case Type::Isolation: return "Isolation";
case Type::Last: return "Invalid";
}
}
@ -137,7 +138,15 @@ nlohmann::json CalibrationMeasurement::Base::toJSON()
void CalibrationMeasurement::Base::fromJSON(nlohmann::json j)
{
if(j.contains("standard")) {
// TODO find standard from ID
auto standards = cal->getKit().getStandards();
standard = nullptr;
unsigned long long id = j.value("standard", 0ULL);
for(auto s : standards) {
if(s->getID() == id) {
setStandard(s);
break;
}
}
}
timestamp = QDateTime::fromSecsSinceEpoch(j.value("timestamp", 0));
}
@ -441,7 +450,7 @@ void CalibrationMeasurement::TwoPort::fromJSON(nlohmann::json j)
for(auto jpoint : j["points"]) {
Point p;
p.frequency = jpoint.value("frequency", 0.0);
p.S.fromJSON(j["Sparam"]);
p.S.fromJSON(jpoint["Sparam"]);
points.push_back(p);
}
}
@ -498,3 +507,128 @@ int CalibrationMeasurement::TwoPort::getPort1() const
{
return port1;
}
double CalibrationMeasurement::Isolation::minFreq()
{
if(points.size() > 0) {
return points.front().frequency;
} else {
return numeric_limits<double>::max();
}
}
double CalibrationMeasurement::Isolation::maxFreq()
{
if(points.size() > 0) {
return points.back().frequency;
} else {
return 0;
}
}
unsigned int CalibrationMeasurement::Isolation::numPoints()
{
return points.size();
}
void CalibrationMeasurement::Isolation::clearPoints()
{
points.clear();
timestamp = QDateTime();
}
void CalibrationMeasurement::Isolation::addPoint(const VirtualDevice::VNAMeasurement &m)
{
Point p;
p.frequency = m.frequency;
for(auto &meas : m.measurements) {
QString name = meas.first;
unsigned int rcv = name.mid(1, 1).toInt() - 1;
unsigned int src = name.mid(2, 1).toInt() - 1;
if(rcv >= p.S.size()) {
p.S.resize(rcv + 1);
}
if(src >= p.S[rcv].size()) {
p.S[rcv].resize(src + 1);
}
p.S[rcv][src] = meas.second;
}
points.push_back(p);
timestamp = QDateTime::currentDateTimeUtc();
}
QWidget *CalibrationMeasurement::Isolation::createStandardWidget()
{
return new QLabel("Terminate all ports");
}
QWidget *CalibrationMeasurement::Isolation::createSettingsWidget()
{
return new QLabel("No settings available");
}
nlohmann::json CalibrationMeasurement::Isolation::toJSON()
{
auto j = Base::toJSON();
nlohmann::json jpoints;
for(auto &p : points) {
nlohmann::json jpoint;
jpoint["frequency"] = p.frequency;
nlohmann::json jdest;
for(auto dst : p.S) {
nlohmann::json jsrc;
for(auto src : dst) {
nlohmann::json jiso;
jiso["real"] = src.real();
jiso["imag"] = src.imag();
jsrc.push_back(jiso);
}
jdest.push_back(jsrc);
}
jpoint["S"] = jdest;
jpoints.push_back(jpoint);
}
j["points"] = jpoints;
return j;
}
void CalibrationMeasurement::Isolation::fromJSON(nlohmann::json j)
{
clearPoints();
Base::fromJSON(j);
if(j.contains("points")) {
for(auto jpoint : j["points"]) {
Point p;
p.frequency = jpoint.value("frequency", 0.0);
if(jpoint.contains("S")) {
for(auto jdest : jpoint["S"]) {
p.S.push_back(vector<complex<double>>());
for(auto jsrc : jdest) {
auto S = complex<double>(jsrc.value("real", 0.0), jsrc.value("imag", 0.0));
p.S.back().push_back(S);
}
}
}
points.push_back(p);
}
}
}
std::complex<double> CalibrationMeasurement::Isolation::getMeasured(double frequency, unsigned int portRcv, unsigned int portSrc)
{
if(points.size() == 0 || frequency < points.front().frequency || frequency > points.back().frequency) {
return numeric_limits<complex<double>>::quiet_NaN();
}
portRcv--;
portSrc--;
// find correct point, no interpolation yet
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool {
return lhs.frequency < rhs;
});
Point p = *lower;
if(portRcv >= p.S.size() || portSrc >= p.S[portRcv].size()) {
return numeric_limits<complex<double>>::quiet_NaN();
} else {
return p.S[portRcv][portSrc];
}
}

View File

@ -1,4 +1,4 @@
#ifndef CALIBRATIONMEASUREMENT_H
#ifndef CALIBRATIONMEASUREMENT_H
#define CALIBRATIONMEASUREMENT_H
#include "calstandard.h"
@ -7,7 +7,7 @@
#include <QDateTime>
#include <QObject>
class Calibration2;
class Calibration;
namespace CalibrationMeasurement {
@ -15,19 +15,20 @@ class Base : public QObject, public Savable
{
Q_OBJECT
public:
Base(Calibration2 *cal);
Base(Calibration *cal);
enum class Type {
Open,
Short,
Load,
Through,
Isolation,
Last,
};
std::vector<CalStandard::Virtual*> supportedStandards();
bool setFirstSupportedStandard();
bool setStandard(CalStandard::Virtual *standard);
virtual bool setFirstSupportedStandard();
virtual bool setStandard(CalStandard::Virtual *standard);
QString getStatistics();
@ -59,14 +60,14 @@ signals:
protected:
CalStandard::Virtual *standard;
QDateTime timestamp;
Calibration2 *cal;
Calibration *cal;
};
class OnePort : public Base
{
Q_OBJECT
public:
OnePort(Calibration2 *cal) :
OnePort(Calibration *cal) :
Base(cal),
port(0) {}
@ -106,7 +107,7 @@ class Open : public OnePort
{
Q_OBJECT
public:
Open(Calibration2 *cal) :
Open(Calibration *cal) :
OnePort(cal){setFirstSupportedStandard();}
virtual std::set<CalStandard::Virtual::Type> supportedStandardTypes() override {return {CalStandard::Virtual::Type::Open};}
@ -117,7 +118,7 @@ class Short : public OnePort
{
Q_OBJECT
public:
Short(Calibration2 *cal) :
Short(Calibration *cal) :
OnePort(cal){setFirstSupportedStandard();}
virtual std::set<CalStandard::Virtual::Type> supportedStandardTypes() override {return {CalStandard::Virtual::Type::Short};}
virtual Type getType() override {return Type::Short;}
@ -127,7 +128,7 @@ class Load : public OnePort
{
Q_OBJECT
public:
Load(Calibration2 *cal) :
Load(Calibration *cal) :
OnePort(cal){setFirstSupportedStandard();}
virtual std::set<CalStandard::Virtual::Type> supportedStandardTypes() override {return {CalStandard::Virtual::Type::Load};}
virtual Type getType() override {return Type::Load;}
@ -137,7 +138,7 @@ class TwoPort : public Base
{
Q_OBJECT
public:
TwoPort(Calibration2 *cal) :
TwoPort(Calibration *cal) :
Base(cal),
port1(0),
port2(0){}
@ -181,11 +182,44 @@ class Through : public TwoPort
{
Q_OBJECT
public:
Through(Calibration2 *cal) :
Through(Calibration *cal) :
TwoPort(cal){setFirstSupportedStandard();}
virtual std::set<CalStandard::Virtual::Type> supportedStandardTypes() override {return {CalStandard::Virtual::Type::Through};}
virtual Type getType() override {return Type::Through;}
};
class Isolation : public Base
{
public:
Isolation(Calibration *cal) :
Base(cal){}
virtual double minFreq() override;
virtual double maxFreq() override;
virtual unsigned int numPoints() override;
virtual void clearPoints();
virtual void addPoint(const VirtualDevice::VNAMeasurement &m);
virtual QWidget* createStandardWidget() override;
virtual QWidget* createSettingsWidget() override;
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
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;
};
}
#endif // CALIBRATIONMEASUREMENT_H

View File

@ -1,207 +0,0 @@
#include "calibrationtracedialog.h"
#include "ui_calibrationtracedialog.h"
#include "measurementmodel.h"
#include "CustomWidgets/informationbox.h"
#include <QStyle>
CalibrationTraceDialog::CalibrationTraceDialog(Calibration *cal, double f_min, double f_max, 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, 80);
ui->tableView->setColumnWidth(2, 350);
ui->tableView->setColumnWidth(3, 320);
ui->tableView->setColumnWidth(4, 160);
UpdateCalibrationStatus();
auto updateThroughStandardUI = [=](){
if(cal->getPortStandard(1) == cal->getPortStandard(2)) {
// same gender on both ports, can't use zero length through
ui->throughCalkit->click();
ui->throughZero->setEnabled(false);
ui->throughCalkit->setEnabled(false);
} else {
// user may select option for through
ui->throughZero->setEnabled(true);
ui->throughCalkit->setEnabled(true);
}
model->genderUpdated();
};
connect(ui->port1Group, qOverload<int>(&QButtonGroup::buttonClicked), [=](){
if(ui->port1Male->isChecked()) {
cal->setPortStandard(1, Calibration::PortStandard::Male);
} else {
cal->setPortStandard(1, Calibration::PortStandard::Female);
}
updateThroughStandardUI();
UpdateCalibrationStatus();
});
connect(ui->port2Group, qOverload<int>(&QButtonGroup::buttonClicked), [=](){
if(ui->port2Male->isChecked()) {
cal->setPortStandard(2, Calibration::PortStandard::Male);
} else {
cal->setPortStandard(2, Calibration::PortStandard::Female);
}
updateThroughStandardUI();
UpdateCalibrationStatus();
});
connect(ui->throughGroup, qOverload<int>(&QButtonGroup::buttonClicked), [=](){
if(ui->throughZero->isChecked()) {
cal->setThroughZeroLength(true);
} else {
cal->setThroughZeroLength(false);
}
UpdateCalibrationStatus();
});
// hide selector if calkit does not have separate male/female standards
if(!cal->getCalibrationKit().hasSeparateMaleFemaleStandards()) {
ui->port1Standards->hide();
ui->port2Standards->hide();
ui->throughStandard->hide();
ui->tableView->hideColumn((int) MeasurementModel::ColIndex::Gender);
// default selection is male
ui->port1Male->click();
ui->port2Male->click();
ui->throughCalkit->click();
} else {
// separate standards defined
if(cal->getPortStandard(1) == Calibration::PortStandard::Male) {
ui->port1Male->setChecked(true);
} else {
ui->port1Female->setChecked(true);
}
if(cal->getPortStandard(2) == Calibration::PortStandard::Male) {
ui->port2Male->setChecked(true);
} else {
ui->port2Female->setChecked(true);
}
if(cal->getThroughZeroLength()) {
ui->throughZero->setChecked(true);
} else {
ui->throughCalkit->setChecked(true);
}
updateThroughStandardUI();
}
// Check calibration kit span
if(type != Calibration::Type::None) {
auto kit = cal->getCalibrationKit();
auto isTRL = type == Calibration::Type::TRL;
if(isTRL && (kit.minFreqTRL() > f_min || kit.maxFreqTRL() < f_max)) {
// TODO check SOLT frequency range depending on selected male/female kit
InformationBox::ShowMessage("Warning", "The calibration kit does not completely cover the currently selected span. "
"Applying a calibration will not be possible for any measurements taken with these settings.");
}
}
}
CalibrationTraceDialog::~CalibrationTraceDialog()
{
delete ui;
}
void CalibrationTraceDialog::measurementsComplete(std::set<Calibration::Measurement> m)
{
for(auto t : m) {
measurementComplete(t);
}
}
void CalibrationTraceDialog::measurementComplete(Calibration::Measurement m)
{
model->measurementUpdated(m);
UpdateCalibrationStatus();
}
void CalibrationTraceDialog::UpdateCalibrationStatus()
{
if(!cal->calculationPossible(cal->getType())) {
// some trace for the current calibration was deleted
cal->resetErrorTerms();
emit calibrationInvalidated();
} else {
// update error terms as a measurement might have changed
cal->constructErrorTerms(cal->getType());
}
ui->bApply->setEnabled(cal->calculationPossible(requestedType));
}
void CalibrationTraceDialog::on_bDelete_clicked()
{
auto selected = ui->tableView->selectionModel()->selectedRows();
for(auto s : selected) {
cal->clearMeasurement(measurements[s.row()]);
model->measurementUpdated(measurements[s.row()]);
}
UpdateCalibrationStatus();
}
void CalibrationTraceDialog::on_bMeasure_clicked()
{
std::set<Calibration::Measurement> m;
auto selected = ui->tableView->selectionModel()->selectedRows();
for(auto s : selected) {
m.insert(measurements[s.row()]);
}
// check if incompatible measurements are selected
auto p1Standard = Calibration::Standard::Any;
auto p2Standard = Calibration::Standard::Any;
bool okay = true;
for(auto type : m) {
auto p1Required = Calibration::getPort1Standard(type);
auto p2Required = Calibration::getPort2Standard(type);
if(p1Required != Calibration::Standard::Any) {
if(p1Standard == Calibration::Standard::Any) {
// first calibration measurement type that needs a specific standard
p1Standard = p1Required;
} else if(p1Required != p1Standard) {
// needs different standard than other measurement that has also been selected
okay = false;
break;
}
}
// same check for port 2
if(p2Required != Calibration::Standard::Any) {
if(p2Standard == Calibration::Standard::Any) {
// first calibration measurement type that needs a specific standard
p2Standard = p2Required;
} else if(p2Required != p2Standard) {
// needs different standard than other measurement that has also been selected
okay = false;
break;
}
}
}
if(!okay) {
// these measurements should not be taken at once, get user confirmation before continuing
okay = InformationBox::AskQuestion("Confirm selection", "The selected calibration measurements require different standards. Are you sure you want to measure them at the same time?", false);
}
if(okay) {
emit triggerMeasurements(m);
}
}
void CalibrationTraceDialog::on_bApply_clicked()
{
emit applyCalibration(requestedType);
accept();
}

View File

@ -1,44 +0,0 @@
#ifndef CALIBRATIONTRACEDIALOG_H
#define CALIBRATIONTRACEDIALOG_H
#include "calibration.h"
#include "measurementmodel.h"
#include "Device/device.h"
#include <QDialog>
namespace Ui {
class CalibrationTraceDialog;
}
class CalibrationTraceDialog : public QDialog
{
Q_OBJECT
public:
explicit CalibrationTraceDialog(Calibration *cal, double f_min, double f_max, Calibration::Type type = Calibration::Type::None);
~CalibrationTraceDialog();
public slots:
void measurementsComplete(std::set<Calibration::Measurement> m);
void measurementComplete(Calibration::Measurement m);
signals:
void triggerMeasurements(std::set<Calibration::Measurement> m);
void applyCalibration(Calibration::Type type);
void calibrationInvalidated();
private slots:
void on_bDelete_clicked();
void on_bMeasure_clicked();
void on_bApply_clicked();
private:
void UpdateCalibrationStatus();
Ui::CalibrationTraceDialog *ui;
Calibration *cal;
Calibration::Type requestedType;
std::vector<Calibration::Measurement> measurements;
MeasurementModel *model;
};
#endif // CALIBRATIONTRACEDIALOG_H

View File

@ -1,207 +0,0 @@
<?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>1079</width>
<height>578</height>
</rect>
</property>
<property name="windowTitle">
<string>Calibration Measurements</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QGroupBox" name="port1Standards">
<property name="title">
<string>Port 1 Standards</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="port1Male">
<property name="text">
<string>Male</string>
</property>
<attribute name="buttonGroup">
<string notr="true">port1Group</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="port1Female">
<property name="text">
<string>Female</string>
</property>
<attribute name="buttonGroup">
<string notr="true">port1Group</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="port2Standards">
<property name="title">
<string>Port 2 Standards</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QRadioButton" name="port2Male">
<property name="text">
<string>Male</string>
</property>
<attribute name="buttonGroup">
<string notr="true">port2Group</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="port2Female">
<property name="text">
<string>Female</string>
</property>
<attribute name="buttonGroup">
<string notr="true">port2Group</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="throughStandard">
<property name="title">
<string>Through Standard</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QRadioButton" name="throughCalkit">
<property name="text">
<string>From calibration kit</string>
</property>
<attribute name="buttonGroup">
<string notr="true">throughGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="throughZero">
<property name="text">
<string>Zero-length through</string>
</property>
<attribute name="buttonGroup">
<string notr="true">throughGroup</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<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" resource="../icons.qrc">
<normaloff>:/icons/play.png</normaloff>:/icons/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bDelete">
<property name="text">
<string>Delete</string>
</property>
<property name="icon">
<iconset theme="edit-delete" resource="../icons.qrc">
<normaloff>:/icons/trash.png</normaloff>:/icons/trash.png</iconset>
</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>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/ok.png</normaloff>:/icons/ok.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../icons.qrc"/>
</resources>
<connections/>
<buttongroups>
<buttongroup name="port1Group"/>
<buttongroup name="port2Group"/>
<buttongroup name="throughGroup"/>
</buttongroups>
</ui>

View File

@ -341,51 +341,6 @@ void Calkit::edit(std::function<void (void)> updateCal)
}
}
bool Calkit::hasSeparateMaleFemaleStandards()
{
return true; // TODO delete function
}
class Calkit::SOLT Calkit::toSOLT(double frequency, bool male_standards)
{
return SOLT(); // TODO delete function
}
class Calkit::TRL Calkit::toTRL(double)
{
return TRL(); // TODO delete function
}
double Calkit::minFreqTRL()
{
return 0; // TODO delete function
}
double Calkit::maxFreqTRL()
{
return std::numeric_limits<double>::max(); // TODO delete function
}
double Calkit::minFreqSOLT(bool male_standards)
{
return 0; // TODO delete function
}
double Calkit::maxFreqSOLT(bool male_standards)
{
return std::numeric_limits<double>::max(); // TODO delete function
}
bool Calkit::checkIfValid(double min_freq, double max_freq, bool isTRL, bool include_male, bool include_female)
{
return true; // TODO delete function
}
bool Calkit::isTRLReflectionShort() const
{
return true; // TODO delete function
}
void Calkit::clearStandards()
{
for(auto s : standards) {
@ -416,6 +371,7 @@ nlohmann::json Calkit::toJSON()
void Calkit::fromJSON(nlohmann::json j)
{
clearStandards();
Savable::parseJSON(j, descr);
for(auto js : j["standards"]) {
if(!js.contains("type") || !js.contains("params")) {

View File

@ -42,15 +42,6 @@ public:
void toFile(QString filename);
static Calkit fromFile(QString filename);
void edit(std::function<void(void)> updateCal = nullptr);
bool hasSeparateMaleFemaleStandards();
SOLT toSOLT(double frequency, bool male_standards = true);
TRL toTRL(double frequency);
double minFreqTRL();
double maxFreqTRL();
double minFreqSOLT(bool male_standards = true);
double maxFreqSOLT(bool male_standards = true);
bool checkIfValid(double min_freq, double max_freq, bool isTRL, bool include_male, bool include_female);
bool isTRLReflectionShort() const;
std::vector<CalStandard::Virtual *> getStandards() const;

View File

@ -13,7 +13,7 @@ ManualCalibrationDialog::ManualCalibrationDialog(const TraceModel &model, Calibr
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]);
// cal->correctTraces(*t[0], *t[1], *t[2], *t[3]); // TODO
accept();
});
}

View File

@ -1,122 +0,0 @@
#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 (int) ColIndex::Last;
}
QVariant MeasurementModel::data(const QModelIndex &index, int role) const
{
auto info = cal->getMeasurementInfo(measurements[index.row()]);
if(role == Qt::DisplayRole) {
switch((ColIndex) index.column()) {
case ColIndex::Name:
return info.name;
break;
case ColIndex::Gender:
switch(measurements[index.row()]) {
case Calibration::Measurement::Port1Load:
case Calibration::Measurement::Port1Open:
case Calibration::Measurement::Port1Short:
if(cal->getPortStandard(1) == Calibration::PortStandard::Male) {
return "Male";
} else {
return "Female";
}
break;
case Calibration::Measurement::Port2Load:
case Calibration::Measurement::Port2Open:
case Calibration::Measurement::Port2Short:
if(cal->getPortStandard(2) == Calibration::PortStandard::Male) {
return "Male";
} else {
return "Female";
}
break;
default:
return "";
}
break;
case ColIndex::Description:
return info.prerequisites;
break;
case ColIndex::Data:
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 ColIndex::Date:
return info.timestamp.toString("dd.MM.yyyy hh:mm:ss");
break;
case ColIndex::Last:
return "";
}
} else if(role == Qt::SizeHintRole) {
switch((ColIndex) index.column()) {
case ColIndex::Name: return 200; break;
case ColIndex::Gender: return 150; break;
case ColIndex::Description: return 500; break;
case ColIndex::Data: return 300; break;
case ColIndex::Date: return 300; 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((ColIndex) section) {
case ColIndex::Name: return "Type"; break;
case ColIndex::Gender: return "Gender"; break;
case ColIndex::Description: return "Prerequisites"; break;
case ColIndex::Data: return "Statistics"; break;
case ColIndex::Date: return "Timestamp"; 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, (int) ColIndex::Last - 1));
}
}
void MeasurementModel::genderUpdated()
{
emit dataChanged(index(0, (int) ColIndex::Gender), index(rowCount() - 1, (int) ColIndex::Gender));
}

View File

@ -1,39 +0,0 @@
#ifndef MEASUREMENTMODEL_H
#define MEASUREMENTMODEL_H
#include "calibration.h"
#include <QObject>
#include <QWidget>
#include <QAbstractTableModel>
class MeasurementModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum class ColIndex {
Name,
Gender,
Description,
Data,
Date,
Last
};
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);
void genderUpdated();
private:
Calibration *cal;
std::vector<Calibration::Measurement> measurements;
};
#endif // MEASUREMENTMODEL_H

View File

@ -2,15 +2,12 @@ HEADERS += \
../VNA_embedded/Application/Communication/Protocol.hpp \
Calibration/amplitudecaldialog.h \
Calibration/calibration.h \
Calibration/calibration2.h \
Calibration/calibrationmeasurement.h \
Calibration/calibrationtracedialog.h \
Calibration/calkit.h \
Calibration/calkitdialog.h \
Calibration/calstandard.h \
Calibration/frequencycaldialog.h \
Calibration/manualcalibrationdialog.h \
Calibration/measurementmodel.h \
Calibration/receivercaldialog.h \
Calibration/sourcecaldialog.h \
CustomWidgets/colorpickerbutton.h \
@ -144,15 +141,12 @@ SOURCES += \
../VNA_embedded/Application/Communication/Protocol.cpp \
Calibration/amplitudecaldialog.cpp \
Calibration/calibration.cpp \
Calibration/calibration2.cpp \
Calibration/calibrationmeasurement.cpp \
Calibration/calibrationtracedialog.cpp \
Calibration/calkit.cpp \
Calibration/calkitdialog.cpp \
Calibration/calstandard.cpp \
Calibration/frequencycaldialog.cpp \
Calibration/manualcalibrationdialog.cpp \
Calibration/measurementmodel.cpp \
Calibration/receivercaldialog.cpp \
Calibration/sourcecaldialog.cpp \
CustomWidgets/colorpickerbutton.cpp \
@ -286,7 +280,6 @@ FORMS += \
Calibration/amplitudecaldialog.ui \
Calibration/automaticamplitudedialog.ui \
Calibration/calibrationdialogui.ui \
Calibration/calibrationtracedialog.ui \
Calibration/calkitdialog.ui \
Calibration/frequencycaldialog.ui \
Calibration/manualcalibrationdialog.ui \

View File

@ -12,7 +12,6 @@
#include "CustomWidgets/siunitedit.h"
#include "Traces/Marker/markerwidget.h"
#include "Tools/impedancematchdialog.h"
#include "Calibration/calibrationtracedialog.h"
#include "ui_main.h"
#include "Device/virtualdevice.h"
#include "preferences.h"

View File

@ -211,13 +211,14 @@ void PortExtension::measurementCompleted(std::vector<VirtualDevice::VNAMeasureme
}
// remove calkit if specified
if(!isIdeal) {
complex<double> calStandard;
auto standards = kit->toSOLT(p.frequency);
if(isOpen) {
calStandard = standards.Open;
} else {
calStandard = standards.Short;
}
complex<double> calStandard = 1.0;
// TODO
// auto standards = kit->toSOLT(p.frequency);
// if(isOpen) {
// calStandard = standards.Open;
// } else {
// calStandard = standards.Short;
// }
// remove effect of calibration standard
reflection /= calStandard;
}

View File

@ -83,7 +83,7 @@ void TraceWidgetVNA::importDialog()
connect(i, &TraceImportDialog::importFinsished, [=](const std::vector<Trace*> &traces) {
if(traces.size() == 4) {
// all traces imported, can calculate calibration/de-embedding
bool calAvailable = cal.nPoints() > 0;
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
@ -107,7 +107,7 @@ void TraceWidgetVNA::importDialog()
dialog->exec();
}
if(applyCal) {
cal.correctTraces(*traces[0], *traces[1], *traces[2], *traces[3]);
// cal.correctTraces(*traces[0], *traces[1], *traces[2], *traces[3]); // TODO
}
if(applyDeembed) {
deembed.Deembed(*traces[0], *traces[1], *traces[2], *traces[3]);

View File

@ -12,7 +12,6 @@
#include "CustomWidgets/siunitedit.h"
#include "Traces/Marker/markerwidget.h"
#include "Tools/impedancematchdialog.h"
#include "Calibration/calibrationtracedialog.h"
#include "ui_main.h"
#include "Device/firmwareupdatedialog.h"
#include "preferences.h"
@ -59,7 +58,6 @@ VNA::VNA(AppWindow *window, QString name)
{
averages = 1;
singleSweep = false;
calValid = false;
calMeasuring = false;
calWaitFirst = false;
calDialog.reset();
@ -89,27 +87,23 @@ VNA::VNA(AppWindow *window, QString name)
});
connect(saveCal, &QAction::triggered, [=](){
if(cal.saveToFile()) {
if(cal.toFile()) {
calEdited = false;
UpdateStatusbar();
}
});
connect(&cal2, &Calibration2::startMeasurements, this, &VNA::StartCalibrationMeasurements);
connect(&cal, &Calibration::startMeasurements, this, &VNA::StartCalibrationMeasurements);
auto calDisable = calMenu->addAction("Disabled");
calDisable->setCheckable(true);
calDisable->setChecked(true);
calMenu->addSeparator();
auto calData = calMenu->addAction("Calibration Measurements");
connect(calData, &QAction::triggered, [=](){
cal2.edit();
cal.edit();
// StartCalibrationDialog();
});
auto calEditKit = calMenu->addAction("Edit Calibration Kit");
connect(calEditKit, &QAction::triggered, [=](){
cal2.getKit().edit();
cal.getKit().edit();
// cal.getCalibrationKit().edit([=](){
// if(calValid) {
// ApplyCalibration(cal.getType());
@ -394,42 +388,42 @@ VNA::VNA(AppWindow *window, QString name)
auto cbEnableCal = new QCheckBox;
tb_cal->addWidget(cbEnableCal);
auto cbType = new QComboBox();
auto calMenuGroup = new QActionGroup(this);
calMenuGroup->addAction(calDisable);
for(auto type : Calibration::Types()) {
cbType->addItem(Calibration::TypeToString(type), (int) type);
auto menuAction = new QAction(Calibration::TypeToString(type), calMenu);
calMenuGroup->addAction(menuAction);
connect(menuAction, &QAction::triggered, [=](){
ApplyCalibration(type);
});
connect(this, &VNA::CalibrationApplied, [=](Calibration::Type applied){
if(type == applied) {
menuAction->setChecked(true);
auto updateCalComboBox = [=](){
auto cals = cal.getAvailableCalibrations();
cbType->blockSignals(true);
cbType->clear();
for(auto c : cals) {
if(c.type == Calibration::Type::None) {
continue;
}
});
menuAction->setCheckable(true);
calMenu->insertAction(calDisable, menuAction);
cbType->addItem(c.getShortString());
}
cbType->setCurrentText(cal.getCaltype().getShortString());
cbType->blockSignals(false);
};
connect(this, &VNA::deviceInitialized, updateCalComboBox);
updateCalComboBox();
auto calToolbarLambda = [=]() {
if(cbEnableCal->isChecked()) {
// Get requested calibration type from combobox
ApplyCalibration((Calibration::Type) cbType->itemData(cbType->currentIndex()).toInt());
ApplyCalibration(Calibration::CalType::fromShortString(cbType->currentText()));
} else {
DisableCalibration();
}
};
// Calibration connections
connect(this, &VNA::CalibrationApplied, this, &VNA::UpdateStatusbar);
connect(this, &VNA::CalibrationDisabled, this, &VNA::UpdateStatusbar);
connect(&cal, &Calibration::activated, this, &VNA::UpdateStatusbar);
connect(&cal, &Calibration::deactivated, this, &VNA::UpdateStatusbar);
connect(cbEnableCal, &QCheckBox::stateChanged, calToolbarLambda);
connect(cbType, qOverload<int>(&QComboBox::currentIndexChanged), calToolbarLambda);
connect(this, &VNA::CalibrationDisabled, [=](){
connect(&cal, &Calibration::deactivated, [=](){
cbType->blockSignals(true);
cbEnableCal->blockSignals(true);
calDisable->setChecked(true);
cbEnableCal->setCheckState(Qt::CheckState::Unchecked);
// visually indicate loss of calibration
// cal. file unknown at this moment
@ -441,16 +435,10 @@ VNA::VNA(AppWindow *window, QString name)
calApplyToTraces->setEnabled(false);
saveCal->setEnabled(false);
});
connect(calDisable, &QAction::triggered, this, &VNA::DisableCalibration);
connect(this, &VNA::CalibrationApplied, [=](Calibration::Type applied){
connect(&cal, &Calibration::activated, [=](Calibration::CalType applied){
cbType->blockSignals(true);
cbEnableCal->blockSignals(true);
for(int i=0;i<cbType->count();i++) {
if(cbType->itemData(i).toInt() == (int) applied) {
cbType->setCurrentIndex(i);
break;
}
}
cbType->setCurrentText(applied.getShortString());
cbEnableCal->setCheckState(Qt::CheckState::Checked);
// restore default look of widget
// on hover, show name of active cal. file
@ -506,11 +494,6 @@ VNA::VNA(AppWindow *window, QString name)
toolbars.insert(tb_cal);
// auto tb_portExtension = portExtension.createToolbar();
// window->addToolBar(tb_portExtension);
// toolbars.insert(tb_portExtension);
markerModel = new MarkerModel(traceModel, this);
auto tracesDock = new QDockWidget("Traces");
@ -590,7 +573,7 @@ Calibration::InterpolationType VNA::getCalInterpolation()
QString VNA::getCalStyle()
{
Calibration::InterpolationType interpol = getCalInterpolation();
auto interpol = getCalInterpolation();
QString style = "";
switch (interpol)
{
@ -612,7 +595,7 @@ QString VNA::getCalStyle()
QString VNA::getCalToolTip()
{
Calibration::InterpolationType interpol = getCalInterpolation();
auto interpol = getCalInterpolation();
QString txt = "";
switch (interpol)
{
@ -657,9 +640,7 @@ void VNA::initializeDevice()
auto filename = s.value(key).toString();
qDebug() << "Attempting to load default calibration file " << filename;
if(QFile::exists(filename)) {
if(cal.openFromFile(filename)) {
ApplyCalibration(cal.getType());
// portExtension.setCalkit(&cal.getCalibrationKit());
if(cal.fromFile(filename)) {
qDebug() << "Calibration successful from " << filename;
} else {
qDebug() << "Calibration not successfull from: " << filename;
@ -674,6 +655,7 @@ void VNA::initializeDevice()
}
// Configure initial state of device
SettingsChanged();
emit deviceInitialized();
}
void VNA::deviceDisconnected()
@ -683,10 +665,10 @@ void VNA::deviceDisconnected()
void VNA::shutdown()
{
if(calEdited && calValid) {
if(calEdited && cal.getCaltype().type != Calibration::Type::None) {
auto save = InformationBox::AskQuestion("Save calibration?", "The calibration contains data that has not been saved yet. Do you want to save it before exiting?", false);
if(save) {
cal.saveToFile();
cal.toFile();
}
}
}
@ -820,19 +802,18 @@ void VNA::NewDatapoint(VirtualDevice::VNAMeasurement m)
// this is the last averaging sweep, use values for calibration
if(!calWaitFirst || m_avg.pointNum == 0) {
calWaitFirst = false;
cal2.addMeasurements(calMeasurements, m_avg);
cal.addMeasurements(calMeasurements, m_avg);
if(m_avg.pointNum == settings.npoints - 1) {
calMeasuring = false;
cal2.measurementsComplete();
cal.measurementsComplete();
}
}
}
int percentage = (((average.currentSweep() - 1) * 100) + (m_avg.pointNum + 1) * 100 / settings.npoints) / averages;
calDialog.setValue(percentage);
}
// if(calValid) {
cal2.correctMeasurement(m_avg);
// }
cal.correctMeasurement(m_avg);
if(deembedding_active) {
deembedding.Deembed(m_avg);
@ -1170,39 +1151,30 @@ void VNA::ExcitationRequired()
}
}
void VNA::DisableCalibration(bool force)
void VNA::DisableCalibration()
{
if(calValid || force) {
calValid = false;
cal.resetErrorTerms();
emit CalibrationDisabled();
}
cal.deactivate();
}
void VNA::ApplyCalibration(Calibration::Type type)
void VNA::ApplyCalibration(Calibration::CalType type)
{
if(cal.calculationPossible(type)) {
if(cal.canCompute(type)) {
try {
if(cal.constructErrorTerms(type)) {
calValid = true;
emit CalibrationApplied(type);
} else {
DisableCalibration(true);
}
cal.compute(type);
} catch (runtime_error &e) {
InformationBox::ShowError("Calibration failure", e.what());
DisableCalibration(true);
DisableCalibration();
}
} else {
if(settings.sweepType == SweepType::Frequency) {
// Not all required traces available
InformationBox::ShowMessageBlocking("Missing calibration measurements", "Not all calibration measurements for this type of calibration have been taken. The calibration can be enabled after the missing measurements have been acquired.");
DisableCalibration(true);
StartCalibrationDialog(type);
DisableCalibration();
cal.edit();
} else {
// Not all required traces available
InformationBox::ShowMessageBlocking("Missing calibration measurements", "Not all calibration measurements for this type of calibration have been taken. Please switch to frequency sweep to take these measurements.");
DisableCalibration(true);
DisableCalibration();
}
}
}
@ -1216,7 +1188,7 @@ void VNA::StartCalibrationMeasurements(std::set<CalibrationMeasurement::Base*> m
StopSweep();
calMeasurements = m;
// Delete any already captured data of this measurement
cal2.clearMeasurements(m);
cal.clearMeasurements(m);
calWaitFirst = true;
// show messagebox
QString text = "Measuring ";
@ -1237,7 +1209,7 @@ void VNA::StartCalibrationMeasurements(std::set<CalibrationMeasurement::Base*> m
connect(&calDialog, &QProgressDialog::canceled, [=]() {
// the user aborted the calibration measurement
calMeasuring = false;
cal2.clearMeasurements(calMeasurements);
cal.clearMeasurements(calMeasurements);
});
// Trigger sweep to start from beginning
SettingsChanged(true, [=](bool){
@ -1430,25 +1402,24 @@ void VNA::SetupSCPI()
if(params.size() != 1) {
return SCPI::getResultName(SCPI::Result::Error);
} else {
auto type = Calibration::TypeFromString(params[0].replace('_', ' '));
if(type == Calibration::Type::Last) {
// failed to parse string
return SCPI::getResultName(SCPI::Result::Error);
} else if(type == Calibration::Type::None) {
DisableCalibration();
} else {
auto availableCals = cal.getAvailableCalibrations();
for(auto caltype : availableCals) {
if(caltype.getShortString().compare(params[0], Qt::CaseInsensitive) == 0) {
// found a match
// check if calibration can be activated
if(cal.calculationPossible(type)) {
ApplyCalibration(type);
if(cal.canCompute(caltype)) {
ApplyCalibration(caltype);
} else {
return SCPI::getResultName(SCPI::Result::Error);
}
}
}
// if we get here, the supplied parameter did not match any of the available calibrations
return SCPI::getResultName(SCPI::Result::Error);
}
return SCPI::getResultName(SCPI::Result::Empty);
}, [=](QStringList) -> QString {
auto ret = Calibration::TypeToString(cal.getType());
ret.replace(' ', '_');
auto ret = cal.getCaltype().getShortString();
return ret;
}));
scpi_cal->add(new SCPICommand("MEASure", [=](QStringList params) -> QString {
@ -1456,15 +1427,16 @@ void VNA::SetupSCPI()
// no measurement specified, still busy or invalid mode
return SCPI::getResultName(SCPI::Result::Error);
} else {
auto meas = Calibration::MeasurementFromString(params[0].replace('_', ' '));
if(meas == Calibration::Measurement::Last) {
// failed to parse string
return SCPI::getResultName(SCPI::Result::Error);
} else {
std::set<Calibration::Measurement> m;
m.insert(meas);
// StartCalibrationMeasurements(m); // TODO
}
// TODO
// auto meas = Calibration::MeasurementFromString(params[0].replace('_', ' '));
// if(meas == Calibration::Measurement::Last) {
// // failed to parse string
// return SCPI::getResultName(SCPI::Result::Error);
// } else {
// std::set<Calibration::Measurement> m;
// m.insert(meas);
//// StartCalibrationMeasurements(m);
// }
}
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
@ -1472,11 +1444,11 @@ void VNA::SetupSCPI()
return CalibrationMeasurementActive() ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
}));
scpi_cal->add(new SCPICommand("SAVE", [=](QStringList params) -> QString {
if(params.size() != 1 || !calValid) {
if(params.size() != 1 || cal.getCaltype().type == Calibration::Type::None) {
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::Error);
}
if(!cal.saveToFile(params[0])) {
if(!cal.toFile(params[0])) {
// some error when writing the calibration file
return SCPI::getResultName(SCPI::Result::Error);
}
@ -1488,15 +1460,10 @@ void VNA::SetupSCPI()
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::False);
}
if(!cal.openFromFile(params[0])) {
if(!cal.fromFile(params[0])) {
// some error when loading the calibration file
return SCPI::getResultName(SCPI::Result::False);
}
if(cal.getType() == Calibration::Type::None) {
DisableCalibration();
} else {
ApplyCalibration(cal.getType());
}
calEdited = false;
return SCPI::getResultName(SCPI::Result::True);
}));
@ -1577,20 +1544,6 @@ void VNA::StopSweep()
}
}
void VNA::StartCalibrationDialog(Calibration::Type type)
{
auto traceDialog = new CalibrationTraceDialog(&cal, settings.Freq.start, settings.Freq.stop, type);
// connect(traceDialog, &CalibrationTraceDialog::triggerMeasurements, this, &VNA::StartCalibrationMeasurements);
connect(traceDialog, &CalibrationTraceDialog::applyCalibration, this, &VNA::ApplyCalibration);
connect(traceDialog, &CalibrationTraceDialog::calibrationInvalidated, [=](){
DisableCalibration(true);
InformationBox::ShowMessageBlocking("Calibration disabled", "The currently active calibration is no longer supported by the available measurements and was disabled.");
});
if(AppWindow::showGUI()) {
traceDialog->show();
}
}
void VNA::UpdateCalWidget()
{
calLabel->setStyleSheet(getCalStyle());
@ -1730,7 +1683,7 @@ VNA::SweepType VNA::SweepTypeFromString(QString s)
void VNA::UpdateStatusbar()
{
if(calValid) {
if(cal.getCaltype().type != Calibration::Type::None) {
QFileInfo fi(cal.getCurrentCalibrationFile());
auto filename = fi.fileName();
if(filename.isEmpty()) {
@ -1753,13 +1706,6 @@ void VNA::SetSingleSweep(bool single)
bool VNA::LoadCalibration(QString filename)
{
cal.openFromFile(filename);
cal.fromFile(filename);
calEdited = false;
if(cal.getType() == Calibration::Type::None) {
DisableCalibration();
return false;
} else {
ApplyCalibration(cal.getType());
return true;
}
}

View File

@ -8,7 +8,7 @@
#include "Deembedding/deembedding.h"
#include "scpi.h"
#include "Traces/tracewidget.h"
#include "Calibration/calibration2.h"
#include "Calibration/calibration.h"
#include <QObject>
#include <QWidget>
@ -105,8 +105,8 @@ private slots:
void SetAveraging(unsigned int averages);
void ExcitationRequired();
// Calibration
void DisableCalibration(bool force = false);
void ApplyCalibration(Calibration::Type type);
void DisableCalibration();
void ApplyCalibration(Calibration::CalType type);
void StartCalibrationMeasurements(std::set<CalibrationMeasurement::Base*> m);
@ -121,7 +121,6 @@ private:
void LoadSweepSettings();
void StoreSweepSettings();
void StopSweep();
void StartCalibrationDialog(Calibration::Type type = Calibration::Type::None);
void UpdateCalWidget();
void createDefaultTracesAndGraphs(int ports);
@ -140,9 +139,8 @@ private:
// Calibration
Calibration cal;
Calibration2 cal2;
bool changingSettings;
bool calValid;
// bool calValid;
bool calEdited;
std::set<CalibrationMeasurement::Base*> calMeasurements;
bool calMeasuring;
@ -168,6 +166,7 @@ private:
TileWidget *central;
signals:
void deviceInitialized();
void dataChanged();
void sweepTypeChanged(SweepType sw);
void startFreqChanged(double freq);
@ -185,9 +184,6 @@ signals:
void startPowerChanged(double level);
void stopPowerChanged(double level);
void powerSweepFrequencyChanged(double freq);
void CalibrationDisabled();
void CalibrationApplied(Calibration::Type type);
};
#endif // VNA_H

View File

@ -12,7 +12,6 @@
#include "CustomWidgets/siunitedit.h"
#include "Traces/Marker/markerwidget.h"
#include "Tools/impedancematchdialog.h"
#include "Calibration/calibrationtracedialog.h"
#include "ui_main.h"
#include "Device/firmwareupdatedialog.h"
#include "preferences.h"
@ -55,6 +54,7 @@
#include <QFile>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <QDateTime>
#include <QCommandLineParser>

View File

@ -3,7 +3,6 @@
#include "Device/virtualdevice.h"
#include "Traces/traceplot.h"
#include "Calibration/calibration.h"
#include "Traces/tracemodel.h"
#include "Traces/Marker/markermodel.h"
#include "averaging.h"