switched to new calibration implementation
This commit is contained in:
parent
dced8105f2
commit
0e0173f62a
@ -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
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
@ -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>
|
@ -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")) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
@ -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
|
@ -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 \
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user