WIP: flexible calibration measurements
This commit is contained in:
parent
b442736cb5
commit
6e38aaddb8
84
Software/PC_Application/Calibration/calibration2.cpp
Normal file
84
Software/PC_Application/Calibration/calibration2.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "calibration2.h"
|
||||
#include "ui_calibrationdialogui.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMenu>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Calibration2::Calibration2()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Calibration2::edit()
|
||||
{
|
||||
auto d = new QDialog();
|
||||
auto ui = new Ui::CalibrationDialog;
|
||||
ui->setupUi(d);
|
||||
|
||||
QObject::connect(ui->bDelete, &QPushButton::clicked, [=](){
|
||||
auto row = ui->table->currentRow();
|
||||
if(row >= 0) {
|
||||
delete measurements[row];
|
||||
measurements.erase(measurements.begin() + row);
|
||||
// updateMeasurementTable();
|
||||
}
|
||||
});
|
||||
|
||||
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 >= 1) {
|
||||
swap(measurements[row], measurements[row-1]);
|
||||
ui->table->selectRow(row+1);
|
||||
// updateMeasurementTable();
|
||||
}
|
||||
});
|
||||
|
||||
// connect(ui->table, &QTableWidget::currentRowChanged, this, &CalibrationDialog::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;
|
||||
}
|
||||
|
||||
Calkit &Calibration2::getKit()
|
||||
{
|
||||
return kit;
|
||||
}
|
25
Software/PC_Application/Calibration/calibration2.h
Normal file
25
Software/PC_Application/Calibration/calibration2.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef CALIBRATION2_H
|
||||
#define CALIBRATION2_H
|
||||
|
||||
#include "savable.h"
|
||||
#include "calibrationmeasurement.h"
|
||||
#include "calkit.h"
|
||||
|
||||
class Calibration2 : public Savable
|
||||
{
|
||||
public:
|
||||
Calibration2();
|
||||
|
||||
void edit();
|
||||
|
||||
Calkit& getKit();
|
||||
|
||||
private:
|
||||
CalibrationMeasurement::Base *newMeasurement(CalibrationMeasurement::Base::Type type);
|
||||
|
||||
std::vector<CalibrationMeasurement::Base*> measurements;
|
||||
|
||||
Calkit kit;
|
||||
};
|
||||
|
||||
#endif // CALIBRATION2_H
|
247
Software/PC_Application/Calibration/calibrationdialogui.ui
Normal file
247
Software/PC_Application/Calibration/calibrationdialogui.ui
Normal file
@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CalibrationDialog</class>
|
||||
<widget class="QDialog" name="CalibrationDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>912</width>
|
||||
<height>438</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calibration Measurements</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Measurements</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create default measurements for:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 Port SOL calibration</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 Port SOLT calibration</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3 Port SOLT calibration</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4 Port SOLT calibration</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="table"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="bAdd">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-add" resource="../icons.qrc">
|
||||
<normaloff>:/icons/add.png</normaloff>:/icons/add.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bDelete">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-remove" resource="../icons.qrc">
|
||||
<normaloff>:/icons/remove.png</normaloff>:/icons/remove.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bMoveUp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-up" resource="../icons.qrc">
|
||||
<normaloff>:/icons/up.png</normaloff>:/icons/up.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bMoveDown">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-down" resource="../icons.qrc">
|
||||
<normaloff>:/icons/down.png</normaloff>:/icons/down.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="measure">
|
||||
<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="clearMeasurement">
|
||||
<property name="text">
|
||||
<string>Clear</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="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>186</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CalibrationDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CalibrationDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
331
Software/PC_Application/Calibration/calibrationmeasurement.cpp
Normal file
331
Software/PC_Application/Calibration/calibrationmeasurement.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
#include "calibrationmeasurement.h"
|
||||
#include "unit.h"
|
||||
#include "calibration2.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CalibrationMeasurement::Base::Base(Calibration2 *cal)
|
||||
: cal(cal)
|
||||
{
|
||||
standard = nullptr;
|
||||
timestamp = QDateTime();
|
||||
}
|
||||
|
||||
bool CalibrationMeasurement::Base::setFirstSupportedStandard()
|
||||
{
|
||||
// assign first valid standard
|
||||
for(auto s : cal->getKit().getStandards()) {
|
||||
if(supportedStandards().count(s->getType())) {
|
||||
setStandard(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CalibrationMeasurement::Base::setStandard(CalStandard::Virtual *standard)
|
||||
{
|
||||
if(standard) {
|
||||
if(supportedStandards().count(standard->getType())) {
|
||||
// can use this standard
|
||||
this->standard = standard;
|
||||
return true;
|
||||
} else {
|
||||
// can't use this standard, leave unchanged
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nullptr passed, remove currently used standard
|
||||
this->standard = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QString CalibrationMeasurement::Base::getStatistics()
|
||||
{
|
||||
if(numPoints() > 0) {
|
||||
QString data = QString::number(numPoints());
|
||||
data.append(" points from ");
|
||||
data.append(Unit::ToString(minFreq(), "Hz", " kMG"));
|
||||
data.append(" to ");
|
||||
data.append(Unit::ToString(maxFreq(), "Hz", " kMG"));
|
||||
return data;
|
||||
} else {
|
||||
return "Not available";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CalibrationMeasurement::Base::Type> CalibrationMeasurement::Base::availableTypes()
|
||||
{
|
||||
std::vector<Type> ret;
|
||||
for(int i=0;i<(int) Type::Last;i++) {
|
||||
ret.push_back((Type) i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString CalibrationMeasurement::Base::TypeToString(CalibrationMeasurement::Base::Type type)
|
||||
{
|
||||
switch(type) {
|
||||
case Type::Open: return "Open";
|
||||
case Type::Short: return "Short";
|
||||
case Type::Load: return "Load";
|
||||
case Type::Through: return "Through";
|
||||
case Type::Last: return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
CalibrationMeasurement::Base::Type CalibrationMeasurement::Base::TypeFromString(QString s)
|
||||
{
|
||||
for(int i=0;i<(int) Type::Last;i++) {
|
||||
if(TypeToString((Type) i) == s) {
|
||||
return (Type) i;
|
||||
}
|
||||
}
|
||||
return Type::Last;
|
||||
}
|
||||
|
||||
nlohmann::json CalibrationMeasurement::Base::toJSON()
|
||||
{
|
||||
nlohmann::json j;
|
||||
if(standard) {
|
||||
j["standard"] = standard->getID();
|
||||
}
|
||||
j["timestamp"] = timestamp.toSecsSinceEpoch();
|
||||
return j;
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::Base::fromJSON(nlohmann::json j)
|
||||
{
|
||||
if(j.contains("standard")) {
|
||||
// TODO find standard from ID
|
||||
}
|
||||
timestamp = QDateTime::fromSecsSinceEpoch(j.value("timestamp", 0));
|
||||
}
|
||||
|
||||
bool CalibrationMeasurement::Base::canMeasureSimultaneously(std::vector<CalibrationMeasurement::Base *> measurements)
|
||||
{
|
||||
std::set<int> usedPorts;
|
||||
for(auto m : measurements) {
|
||||
std::vector<int> ports;
|
||||
switch(m->getType()) {
|
||||
case Type::Open:
|
||||
case Type::Short:
|
||||
case Type::Load:
|
||||
// Uses one port
|
||||
ports.push_back(static_cast<OnePort*>(m)->getPort());
|
||||
break;
|
||||
case Type::Through:
|
||||
// Uses two ports
|
||||
ports.push_back(static_cast<TwoPort*>(m)->getPort1());
|
||||
ports.push_back(static_cast<TwoPort*>(m)->getPort2());
|
||||
break;
|
||||
}
|
||||
for(auto p : ports) {
|
||||
if(usedPorts.count(p)) {
|
||||
// port already used for another measurement
|
||||
return false;
|
||||
} else {
|
||||
usedPorts.insert(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we get here, no port collisions occurred
|
||||
return true;
|
||||
}
|
||||
|
||||
double CalibrationMeasurement::OnePort::minFreq()
|
||||
{
|
||||
if(points.size() > 0) {
|
||||
return points.front().frequency;
|
||||
} else {
|
||||
return numeric_limits<double>::max();
|
||||
}
|
||||
}
|
||||
|
||||
double CalibrationMeasurement::OnePort::maxFreq()
|
||||
{
|
||||
if(points.size() > 0) {
|
||||
return points.back().frequency;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::OnePort::clearPoints()
|
||||
{
|
||||
points.clear();
|
||||
timestamp = QDateTime();
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::OnePort::addPoint(const VirtualDevice::VNAMeasurement &m)
|
||||
{
|
||||
QString measurementName = "S"+QString::number(port)+QString::number(port);
|
||||
if(m.measurements.count(measurementName) > 0) {
|
||||
Point p;
|
||||
p.frequency = m.frequency;
|
||||
p.S = m.measurements.at(measurementName);
|
||||
points.push_back(p);
|
||||
timestamp = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json CalibrationMeasurement::OnePort::toJSON()
|
||||
{
|
||||
auto j = Base::toJSON();
|
||||
j["port"] = port;
|
||||
nlohmann::json jpoints;
|
||||
for(auto &p : points) {
|
||||
nlohmann::json jpoint;
|
||||
jpoint["frequency"] = p.frequency;
|
||||
jpoint["real"] = p.S.real();
|
||||
jpoint["imag"] = p.S.imag();
|
||||
jpoints.push_back(jpoint);
|
||||
}
|
||||
j["points"] = jpoints;
|
||||
return j;
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::OnePort::fromJSON(nlohmann::json j)
|
||||
{
|
||||
clearPoints();
|
||||
Base::fromJSON(j);
|
||||
port = j.value("port", 0);
|
||||
if(j.contains("points")) {
|
||||
for(auto jpoint : j["points"]) {
|
||||
Point p;
|
||||
p.frequency = jpoint.value("frequency", 0.0);
|
||||
p.S = complex<double>(jpoint.value("real", 0.0), jpoint.value("imag", 0.0));
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::complex<double> CalibrationMeasurement::OnePort::getMeasured(double frequency)
|
||||
{
|
||||
if(points.size() == 0 || frequency < points.front().frequency || frequency > points.back().frequency) {
|
||||
return numeric_limits<complex<double>>::quiet_NaN();
|
||||
}
|
||||
// frequency within points, interpolate
|
||||
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool {
|
||||
return lhs.frequency < rhs;
|
||||
});
|
||||
auto lowPoint = *lower;
|
||||
advance(lower, 1);
|
||||
auto highPoint = *lower;
|
||||
double alpha = (frequency - lowPoint.frequency) / (highPoint.frequency - lowPoint.frequency);
|
||||
complex<double> ret;
|
||||
return lowPoint.S * (1.0 - alpha) + highPoint.S * alpha;
|
||||
}
|
||||
|
||||
std::complex<double> CalibrationMeasurement::OnePort::getActual(double frequency)
|
||||
{
|
||||
return static_cast<CalStandard::OnePort*>(standard)->toS11(frequency);
|
||||
}
|
||||
|
||||
int CalibrationMeasurement::OnePort::getPort() const
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
double CalibrationMeasurement::TwoPort::minFreq()
|
||||
{
|
||||
if(points.size() > 0) {
|
||||
return points.front().frequency;
|
||||
} else {
|
||||
return numeric_limits<double>::max();
|
||||
}
|
||||
}
|
||||
|
||||
double CalibrationMeasurement::TwoPort::maxFreq()
|
||||
{
|
||||
if(points.size() > 0) {
|
||||
return points.back().frequency;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::TwoPort::clearPoints()
|
||||
{
|
||||
points.clear();
|
||||
timestamp = QDateTime();
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::TwoPort::addPoint(const VirtualDevice::VNAMeasurement &m)
|
||||
{
|
||||
Point p;
|
||||
p.frequency = m.frequency;
|
||||
p.S = m.toSparam(port1, port2);
|
||||
points.push_back(p);
|
||||
timestamp = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
nlohmann::json CalibrationMeasurement::TwoPort::toJSON()
|
||||
{
|
||||
auto j = Base::toJSON();
|
||||
j["port1"] = port1;
|
||||
j["port2"] = port2;
|
||||
nlohmann::json jpoints;
|
||||
for(auto &p : points) {
|
||||
nlohmann::json jpoint;
|
||||
jpoint["frequency"] = p.frequency;
|
||||
jpoint["Sparam"] = p.S.toJSON();
|
||||
jpoints.push_back(jpoint);
|
||||
}
|
||||
j["points"] = jpoints;
|
||||
return j;
|
||||
}
|
||||
|
||||
void CalibrationMeasurement::TwoPort::fromJSON(nlohmann::json j)
|
||||
{
|
||||
clearPoints();
|
||||
Base::fromJSON(j);
|
||||
port1 = j.value("port1", 0);
|
||||
port2 = j.value("port2", 0);
|
||||
if(j.contains("points")) {
|
||||
for(auto jpoint : j["points"]) {
|
||||
Point p;
|
||||
p.frequency = jpoint.value("frequency", 0.0);
|
||||
p.S.fromJSON(j["Sparam"]);
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sparam CalibrationMeasurement::TwoPort::getMeasured(double frequency)
|
||||
{
|
||||
if(points.size() == 0 || frequency < points.front().frequency || frequency > points.back().frequency) {
|
||||
return Sparam();
|
||||
}
|
||||
// frequency within points, interpolate
|
||||
auto lower = lower_bound(points.begin(), points.end(), frequency, [](const Point &lhs, double rhs) -> bool {
|
||||
return lhs.frequency < rhs;
|
||||
});
|
||||
auto lowPoint = *lower;
|
||||
advance(lower, 1);
|
||||
auto highPoint = *lower;
|
||||
double alpha = (frequency - lowPoint.frequency) / (highPoint.frequency - lowPoint.frequency);
|
||||
Sparam ret;
|
||||
ret.m11 = lowPoint.S.m11 * (1.0 - alpha) + highPoint.S.m11 * alpha;
|
||||
ret.m12 = lowPoint.S.m12 * (1.0 - alpha) + highPoint.S.m12 * alpha;
|
||||
ret.m21 = lowPoint.S.m21 * (1.0 - alpha) + highPoint.S.m21 * alpha;
|
||||
ret.m22 = lowPoint.S.m22 * (1.0 - alpha) + highPoint.S.m22 * alpha;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Sparam CalibrationMeasurement::TwoPort::getActual(double frequency)
|
||||
{
|
||||
return static_cast<CalStandard::TwoPort*>(standard)->toSparam(frequency);
|
||||
}
|
||||
|
||||
int CalibrationMeasurement::TwoPort::getPort2() const
|
||||
{
|
||||
return port2;
|
||||
}
|
||||
|
||||
int CalibrationMeasurement::TwoPort::getPort1() const
|
||||
{
|
||||
return port1;
|
||||
}
|
157
Software/PC_Application/Calibration/calibrationmeasurement.h
Normal file
157
Software/PC_Application/Calibration/calibrationmeasurement.h
Normal file
@ -0,0 +1,157 @@
|
||||
#ifndef CALIBRATIONMEASUREMENT_H
|
||||
#define CALIBRATIONMEASUREMENT_H
|
||||
|
||||
#include "calstandard.h"
|
||||
#include "Device/virtualdevice.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
class Calibration2;
|
||||
|
||||
namespace CalibrationMeasurement {
|
||||
|
||||
class Base : public Savable
|
||||
{
|
||||
public:
|
||||
Base(Calibration2 *cal);
|
||||
|
||||
enum class Type {
|
||||
Open,
|
||||
Short,
|
||||
Load,
|
||||
Through,
|
||||
Last,
|
||||
};
|
||||
|
||||
bool setFirstSupportedStandard();
|
||||
bool setStandard(CalStandard::Virtual *standard);
|
||||
|
||||
QString getStatistics();
|
||||
|
||||
virtual double minFreq() = 0;
|
||||
virtual double maxFreq() = 0;
|
||||
virtual unsigned int numPoints() = 0;
|
||||
|
||||
static std::vector<Type> availableTypes();
|
||||
static QString TypeToString(Type type);
|
||||
static Type TypeFromString(QString s);
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandards() = 0;
|
||||
virtual Type getType() = 0;
|
||||
virtual void clearPoints() = 0;
|
||||
virtual void addPoint(const VirtualDevice::VNAMeasurement &m) = 0;
|
||||
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
static bool canMeasureSimultaneously(std::vector<Base*> measurements);
|
||||
protected:
|
||||
CalStandard::Virtual *standard;
|
||||
QDateTime timestamp;
|
||||
Calibration2 *cal;
|
||||
};
|
||||
|
||||
class OnePort : public Base
|
||||
{
|
||||
public:
|
||||
OnePort(Calibration2 *cal) :
|
||||
Base(cal),
|
||||
port(0) {}
|
||||
|
||||
virtual double minFreq() override;
|
||||
virtual double maxFreq() override;
|
||||
virtual unsigned int numPoints() override {return points.size();}
|
||||
|
||||
virtual void clearPoints();
|
||||
virtual void addPoint(const VirtualDevice::VNAMeasurement &m);
|
||||
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
std::complex<double> getMeasured(double frequency);
|
||||
std::complex<double> getActual(double frequency);
|
||||
|
||||
int getPort() const;
|
||||
|
||||
protected:
|
||||
int port;
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
std::complex<double> S;
|
||||
};
|
||||
std::vector<Point> points;
|
||||
};
|
||||
|
||||
class Open : public OnePort
|
||||
{
|
||||
public:
|
||||
Open(Calibration2 *cal) :
|
||||
OnePort(cal){setFirstSupportedStandard();}
|
||||
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandards() override {return {CalStandard::Virtual::Type::Open};}
|
||||
virtual Type getType() override {return Type::Open;}
|
||||
};
|
||||
|
||||
class Short : public OnePort
|
||||
{
|
||||
public:
|
||||
Short(Calibration2 *cal) :
|
||||
OnePort(cal){setFirstSupportedStandard();}
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandards() override {return {CalStandard::Virtual::Type::Short};}
|
||||
virtual Type getType() override {return Type::Short;}
|
||||
};
|
||||
|
||||
class Load : public OnePort
|
||||
{
|
||||
public:
|
||||
Load(Calibration2 *cal) :
|
||||
OnePort(cal){setFirstSupportedStandard();}
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandards() override {return {CalStandard::Virtual::Type::Load};}
|
||||
virtual Type getType() override {return Type::Load;}
|
||||
};
|
||||
|
||||
class TwoPort : public Base
|
||||
{
|
||||
public:
|
||||
TwoPort(Calibration2 *cal) :
|
||||
Base(cal),
|
||||
port1(0),
|
||||
port2(0){}
|
||||
|
||||
virtual double minFreq() override;
|
||||
virtual double maxFreq() override;
|
||||
virtual unsigned int numPoints() override {return points.size();}
|
||||
|
||||
virtual void clearPoints();
|
||||
virtual void addPoint(const VirtualDevice::VNAMeasurement &m);
|
||||
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
Sparam getMeasured(double frequency);
|
||||
Sparam getActual(double frequency);
|
||||
|
||||
int getPort1() const;
|
||||
int getPort2() const;
|
||||
|
||||
protected:
|
||||
int port1, port2;
|
||||
class Point {
|
||||
public:
|
||||
double frequency;
|
||||
Sparam S;
|
||||
};
|
||||
std::vector<Point> points;
|
||||
};
|
||||
|
||||
class Through : public TwoPort
|
||||
{
|
||||
public:
|
||||
Through(Calibration2 *cal) :
|
||||
TwoPort(cal){setFirstSupportedStandard();}
|
||||
virtual std::set<CalStandard::Virtual::Type> supportedStandards() override {return {CalStandard::Virtual::Type::Through};}
|
||||
virtual Type getType() override {return Type::Through;}
|
||||
};
|
||||
|
||||
}
|
||||
#endif // CALIBRATIONMEASUREMENT_H
|
@ -417,3 +417,8 @@ void Calkit::clearStandards()
|
||||
}
|
||||
standards.clear();
|
||||
}
|
||||
|
||||
std::vector<CalStandard::Virtual *> Calkit::getStandards() const
|
||||
{
|
||||
return standards;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
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;
|
||||
|
||||
private:
|
||||
void clearStandards();
|
||||
QString manufacturer, serialnumber, description;
|
||||
|
@ -4,20 +4,31 @@
|
||||
#include "ui_CalStandardLoadEditDialog.h"
|
||||
#include "ui_CalStandardThroughEditDialog.h"
|
||||
#include "unit.h"
|
||||
#include "Util/util.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalStandard;
|
||||
|
||||
Virtual::Virtual(QString name) :
|
||||
name(name),
|
||||
minFreq(std::numeric_limits<double>::lowest()),
|
||||
maxFreq(std::numeric_limits<double>::max())
|
||||
{
|
||||
id = Util::random(numeric_limits<unsigned long long>::max());
|
||||
}
|
||||
|
||||
Virtual *Virtual::create(Virtual::Type type)
|
||||
{
|
||||
Virtual *ret = nullptr;
|
||||
switch(type) {
|
||||
case Type::Open: ret = new Open; break;
|
||||
case Type::Short: ret = new Short; break;
|
||||
case Type::Load: ret = new Load; break;
|
||||
case Type::Through: ret = new Through; break;
|
||||
case Type::Open: return new Open;
|
||||
case Type::Short: return new Short;
|
||||
case Type::Load: return new Load;
|
||||
case Type::Through: return new Through;
|
||||
case Type::Line: // TODO
|
||||
case Type::Last:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Virtual::Type> Virtual::availableTypes()
|
||||
@ -60,12 +71,19 @@ nlohmann::json Virtual::toJSON()
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["name"] = name.toStdString();
|
||||
j["id"] = id;
|
||||
return j;
|
||||
}
|
||||
|
||||
void Virtual::fromJSON(nlohmann::json j)
|
||||
{
|
||||
name = QString::fromStdString(j.value("name", ""));
|
||||
id = j.value("id", id);
|
||||
}
|
||||
|
||||
unsigned long long Virtual::getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void OnePort::setMeasurement(const Touchstone &ts, int port)
|
||||
|
@ -14,10 +14,7 @@ namespace CalStandard
|
||||
class Virtual : public Savable
|
||||
{
|
||||
public:
|
||||
Virtual(QString name = "") :
|
||||
name(name),
|
||||
minFreq(std::numeric_limits<double>::lowest()),
|
||||
maxFreq(std::numeric_limits<double>::max()){}
|
||||
Virtual(QString name = "");
|
||||
|
||||
enum class Type {
|
||||
Open,
|
||||
@ -44,10 +41,13 @@ public:
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
unsigned long long getID();
|
||||
|
||||
protected:
|
||||
QString name;
|
||||
double minFreq;
|
||||
double maxFreq;
|
||||
unsigned long long id;
|
||||
};
|
||||
|
||||
class OnePort : public Virtual
|
||||
|
@ -752,13 +752,13 @@ void VirtualDevice::checkIfAllTransmissionsComplete(std::function<void (bool)> c
|
||||
}
|
||||
}
|
||||
|
||||
Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2)
|
||||
Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2) const
|
||||
{
|
||||
Sparam S;
|
||||
S.m11 = measurements["S"+QString::number(port1)+QString::number(port1)];
|
||||
S.m12 = measurements["S"+QString::number(port1)+QString::number(port2)];
|
||||
S.m21 = measurements["S"+QString::number(port2)+QString::number(port1)];
|
||||
S.m22 = measurements["S"+QString::number(port2)+QString::number(port2)];
|
||||
S.m11 = measurements.at("S"+QString::number(port1)+QString::number(port1));
|
||||
S.m12 = measurements.at("S"+QString::number(port1)+QString::number(port2));
|
||||
S.m21 = measurements.at("S"+QString::number(port2)+QString::number(port1));
|
||||
S.m22 = measurements.at("S"+QString::number(port2)+QString::number(port2));
|
||||
return S;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
};
|
||||
std::map<QString, std::complex<double>> measurements;
|
||||
|
||||
Sparam toSparam(int port1, int port2);
|
||||
Sparam toSparam(int port1, int port2) const;
|
||||
void fromSparam(Sparam S, int port1, int port2);
|
||||
VNAMeasurement interpolateTo(const VNAMeasurement &to, double a);
|
||||
};
|
||||
|
@ -2,6 +2,8 @@ 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 \
|
||||
@ -142,6 +144,8 @@ 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 \
|
||||
@ -281,6 +285,7 @@ FORMS += \
|
||||
Calibration/addamplitudepointsdialog.ui \
|
||||
Calibration/amplitudecaldialog.ui \
|
||||
Calibration/automaticamplitudedialog.ui \
|
||||
Calibration/calibrationdialogui.ui \
|
||||
Calibration/calibrationtracedialog.ui \
|
||||
Calibration/calkitdialog.ui \
|
||||
Calibration/frequencycaldialog.ui \
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "parameters.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Sparam::Sparam(const Tparam &t) {
|
||||
m11 = t.m12 / t.m22;
|
||||
m21 = Type(1) / t.m22;
|
||||
@ -41,3 +43,25 @@ ABCDparam::ABCDparam(const Sparam &s, Type Z0)
|
||||
: ABCDparam(s, Z0, Z0)
|
||||
{
|
||||
}
|
||||
|
||||
nlohmann::json Parameters::toJSON()
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["m11_real"] = m11.real();
|
||||
j["m11_imag"] = m11.imag();
|
||||
j["m12_real"] = m12.real();
|
||||
j["m12_imag"] = m12.imag();
|
||||
j["m21_real"] = m21.real();
|
||||
j["m21_imag"] = m21.imag();
|
||||
j["m22_real"] = m22.real();
|
||||
j["m22_imag"] = m22.imag();
|
||||
return j;
|
||||
}
|
||||
|
||||
void Parameters::fromJSON(nlohmann::json j)
|
||||
{
|
||||
m11 = complex<double>(j.value("m11_real", 0.0), j.value("m11_imag", 0.0));
|
||||
m12 = complex<double>(j.value("m12_real", 0.0), j.value("m12_imag", 0.0));
|
||||
m21 = complex<double>(j.value("m21_real", 0.0), j.value("m21_imag", 0.0));
|
||||
m22 = complex<double>(j.value("m22_real", 0.0), j.value("m22_imag", 0.0));
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
#ifndef TPARAM_H
|
||||
#define TPARAM_H
|
||||
|
||||
#include "savable.h"
|
||||
|
||||
#include <complex>
|
||||
|
||||
using Type = std::complex<double>;
|
||||
|
||||
class Parameters {
|
||||
class Parameters : public Savable {
|
||||
public:
|
||||
Parameters(Type m11, Type m12, Type m21, Type m22)
|
||||
: m11(m11), m12(m12), m21(m21), m22(m22){}
|
||||
Parameters(){}
|
||||
|
||||
Type m11, m12, m21, m22;
|
||||
|
||||
nlohmann::json toJSON() override;
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
};
|
||||
|
||||
// forward declaration of parameter classes
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "preferences.h"
|
||||
|
||||
#include <random>
|
||||
#include <QVector2D>
|
||||
|
||||
void Util::unwrapPhase(std::vector<double> &phase, unsigned int start_index)
|
||||
@ -79,3 +80,13 @@ double Util::dBuVTodBm(double dBuV)
|
||||
double dBdiff = 10*log10(uVpower*1000);
|
||||
return dBuV + dBdiff;
|
||||
}
|
||||
|
||||
unsigned long long Util::random(unsigned long long max)
|
||||
{
|
||||
static std::random_device os_seed;
|
||||
static const unsigned long long seed = os_seed();
|
||||
static std::mt19937_64 generator(seed);
|
||||
|
||||
std::uniform_int_distribution<unsigned long long> distribute(0, max);
|
||||
return distribute(generator);
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ namespace Util {
|
||||
void linearRegression(const std::vector<double> &input, double &B_0, double &B_1);
|
||||
|
||||
double distanceToLine(QPointF point, QPointF l1, QPointF l2, QPointF *closestLinePoint = nullptr, double *pointRatio = nullptr);
|
||||
|
||||
unsigned long long random(unsigned long long max);
|
||||
}
|
||||
|
||||
#endif // UTILH_H
|
||||
|
Loading…
Reference in New Issue
Block a user