Parial eCal dialog
This commit is contained in:
parent
00ef868671
commit
cb0e553a17
354
Software/PC_Application/Calibration/LibreCAL/caldevice.cpp
Normal file
354
Software/PC_Application/Calibration/LibreCAL/caldevice.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
#include "caldevice.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CalDevice::CalDevice(QString serial) :
|
||||
usb(new USBDevice(serial))
|
||||
{
|
||||
// Check device identification
|
||||
auto id = usb->Query("*IDN?");
|
||||
if(!id.startsWith("LibreCAL_")) {
|
||||
delete usb;
|
||||
throw std::runtime_error("Invalid response to *IDN?: "+id.toStdString());
|
||||
}
|
||||
|
||||
firmware = usb->Query(":FIRMWARE?");
|
||||
QString ports = usb->Query(":PORTS?");
|
||||
bool okay;
|
||||
numPorts = ports.toInt(&okay);
|
||||
if(!okay) {
|
||||
numPorts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CalDevice::~CalDevice()
|
||||
{
|
||||
delete usb;
|
||||
}
|
||||
|
||||
QString CalDevice::StandardToString(CalDevice::Standard s)
|
||||
{
|
||||
switch(s) {
|
||||
case Standard::Open: return "OPEN";
|
||||
case Standard::Short: return "SHORT";
|
||||
case Standard::Load: return "LOAD";
|
||||
case Standard::Through: return "THROUGH";
|
||||
case Standard::None: return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
CalDevice::Standard CalDevice::StandardFromString(QString s)
|
||||
{
|
||||
for(int i=0;i<=(int) Standard::None;i++) {
|
||||
if(s == StandardToString((Standard) i)) {
|
||||
return (Standard) i;
|
||||
}
|
||||
}
|
||||
return Standard::None;
|
||||
}
|
||||
|
||||
CalDevice::Standard CalDevice::getStandard(int port)
|
||||
{
|
||||
auto query = ":PORT? "+QString::number(port);
|
||||
auto response = usb->Query(query);
|
||||
return StandardFromString(response);
|
||||
}
|
||||
|
||||
bool CalDevice::setStandard(int port, CalDevice::Standard s)
|
||||
{
|
||||
auto cmd = ":PORT "+QString::number(port)+" "+StandardToString(s);
|
||||
return usb->Cmd(cmd);
|
||||
}
|
||||
|
||||
std::vector<CalDevice::Standard> CalDevice::availableStandards()
|
||||
{
|
||||
return {Standard::None, Standard::Open, Standard::Short, Standard::Load, Standard::Through};
|
||||
}
|
||||
|
||||
double CalDevice::getTemperature()
|
||||
{
|
||||
QString tempString = usb->Query(":TEMP?");
|
||||
bool okay;
|
||||
double temp = tempString.toDouble(&okay);
|
||||
if(!okay) {
|
||||
temp = 0.0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool CalDevice::stabilized()
|
||||
{
|
||||
auto stable = usb->Query(":TEMPerature:STABLE?");
|
||||
return stable == "TRUE";
|
||||
}
|
||||
|
||||
double CalDevice::getHeaterPower()
|
||||
{
|
||||
QString tempString = usb->Query(":HEATER:POWER?");
|
||||
bool okay;
|
||||
double power = tempString.toDouble(&okay);
|
||||
if(!okay) {
|
||||
power = 0.0;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
||||
QString CalDevice::serial()
|
||||
{
|
||||
return usb->serial();
|
||||
}
|
||||
|
||||
QString CalDevice::getFirmware() const
|
||||
{
|
||||
return firmware;
|
||||
}
|
||||
|
||||
int CalDevice::getNumPorts() const
|
||||
{
|
||||
return numPorts;
|
||||
}
|
||||
|
||||
void CalDevice::loadCoefficientSets(QStringList names)
|
||||
{
|
||||
coeffSets.clear();
|
||||
new std::thread(&CalDevice::loadCoefficientSetsThread, this, names);
|
||||
}
|
||||
|
||||
void CalDevice::saveCoefficientSets()
|
||||
{
|
||||
if(!hasModifiedCoefficients()) {
|
||||
// nothing to do, already done
|
||||
emit updateCoefficientsDone(true);
|
||||
} else {
|
||||
new std::thread(&CalDevice::saveCoefficientSetsThread, this);
|
||||
}
|
||||
}
|
||||
|
||||
void CalDevice::loadCoefficientSetsThread(QStringList names)
|
||||
{
|
||||
QStringList coeffList = getCoefficientSetNames();
|
||||
if(coeffList.empty()) {
|
||||
// something went wrong
|
||||
emit updateCoefficientsDone(false);
|
||||
return;
|
||||
}
|
||||
if(names.size() > 0) {
|
||||
// check if all the requested names are actually available
|
||||
for(auto n : names) {
|
||||
if(!coeffList.contains(n)) {
|
||||
// this coefficient does not exist
|
||||
emit updateCoefficientsDone(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
coeffList = names;
|
||||
}
|
||||
// get total number of coefficient points for accurate percentage calculation
|
||||
unsigned long totalPoints = 0;
|
||||
for(auto name : coeffList) {
|
||||
for(int i=1;i<=numPorts;i++) {
|
||||
totalPoints += usb->Query(":COEFF:NUM? "+name+" P"+QString::number(i)+"_OPEN").toInt();
|
||||
totalPoints += usb->Query(":COEFF:NUM? "+name+" P"+QString::number(i)+"_SHORT").toInt();
|
||||
totalPoints += usb->Query(":COEFF:NUM? "+name+" P"+QString::number(i)+"_LOAD").toInt();
|
||||
for(int j=i+1;j<=numPorts;j++) {
|
||||
totalPoints += usb->Query(":COEFF:NUM? "+name+" P"+QString::number(i)+QString::number(j)+"_THROUGH").toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned long readPoints = 0;
|
||||
int lastPercentage = 0;
|
||||
for(auto name : coeffList) {
|
||||
// create the coefficient set
|
||||
CoefficientSet set;
|
||||
set.name = name;
|
||||
set.ports = numPorts;
|
||||
// Read this coefficient set
|
||||
for(int i=1;i<=numPorts;i++) {
|
||||
auto createCoefficient = [&](QString setName, QString paramName) -> CoefficientSet::Coefficient* {
|
||||
int points = usb->Query(":COEFF:NUM? "+setName+" "+paramName).toInt();
|
||||
CoefficientSet::Coefficient *c = new CoefficientSet::Coefficient();
|
||||
if(paramName.endsWith("THROUGH")) {
|
||||
c->t = Touchstone(2);
|
||||
} else {
|
||||
c->t = Touchstone(1);
|
||||
}
|
||||
for(int i=0;i<points;i++) {
|
||||
QString pString = usb->Query(":COEFF:GET? "+setName+" "+paramName+" "+QString::number(i));
|
||||
QStringList values = pString.split(",");
|
||||
Touchstone::Datapoint p;
|
||||
p.frequency = values[0].toDouble() * 1e9;
|
||||
for(int j = 0;j<(values.size()-1)/2;j++) {
|
||||
double real = values[1+j*2].toDouble();
|
||||
double imag = values[2+j*2].toDouble();
|
||||
p.S.push_back(complex<double>(real, imag));
|
||||
}
|
||||
if(p.S.size() == 4) {
|
||||
// S21 and S12 are swapped in the touchstone file order (S21 goes first)
|
||||
// but Touchstone::AddDatapoint expects S11 S12 S21 S22 order. Swap to match that
|
||||
swap(p.S[1], p.S[2]);
|
||||
}
|
||||
c->t.AddDatapoint(p);
|
||||
readPoints++;
|
||||
int newPercentage = readPoints * 100 / totalPoints;
|
||||
if(newPercentage != lastPercentage) {
|
||||
lastPercentage = newPercentage;
|
||||
emit updateCoefficientsPercent(newPercentage);
|
||||
}
|
||||
}
|
||||
c->t.setFilename("LibreCAL/"+paramName);
|
||||
return c;
|
||||
};
|
||||
set.opens.push_back(createCoefficient(name, "P"+QString::number(i)+"_OPEN"));
|
||||
set.shorts.push_back(createCoefficient(name, "P"+QString::number(i)+"_SHORT"));
|
||||
set.loads.push_back(createCoefficient(name, "P"+QString::number(i)+"_LOAD"));
|
||||
for(int j=i+1;j<=numPorts;j++) {
|
||||
set.throughs.push_back(createCoefficient(name, "P"+QString::number(i)+QString::number(j)+"_THROUGH"));
|
||||
}
|
||||
}
|
||||
coeffSets.push_back(set);
|
||||
}
|
||||
emit updateCoefficientsDone(true);
|
||||
}
|
||||
|
||||
void CalDevice::saveCoefficientSetsThread()
|
||||
{
|
||||
// figure out how many points need to be transferred
|
||||
unsigned long totalPoints = 0;
|
||||
for(auto set : coeffSets) {
|
||||
for(auto c : set.opens) {
|
||||
if(c->modified) {
|
||||
totalPoints += c->t.points();
|
||||
}
|
||||
}
|
||||
for(auto c : set.shorts) {
|
||||
if(c->modified) {
|
||||
totalPoints += c->t.points();
|
||||
}
|
||||
}
|
||||
for(auto c : set.loads) {
|
||||
if(c->modified) {
|
||||
totalPoints += c->t.points();
|
||||
}
|
||||
}
|
||||
for(auto c : set.throughs) {
|
||||
if(c->modified) {
|
||||
totalPoints += c->t.points();
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned long transferredPoints = 0;
|
||||
int lastPercentage = 0;
|
||||
bool success = true;
|
||||
for(auto set : coeffSets) {
|
||||
auto createCoefficient = [&](QString setName, QString paramName, Touchstone &t, bool &modified) -> bool {
|
||||
if(!modified) {
|
||||
// no changes, nothing to do
|
||||
return true;
|
||||
}
|
||||
int points = t.points();
|
||||
if(points > 0) {
|
||||
// create the file
|
||||
if(!usb->Cmd(":COEFF:CREATE "+setName+" "+paramName)) {
|
||||
return false;
|
||||
}
|
||||
for(unsigned int i=0;i<points;i++) {
|
||||
auto point = t.point(i);
|
||||
if(point.S.size() == 4) {
|
||||
// S parameters in point are in S11 S12 S21 S22 order but the LibreCAL expects
|
||||
// S11 S21 S12 S22 (according to the two port touchstone format. Swap here.
|
||||
swap(point.S[1], point.S[2]);
|
||||
}
|
||||
QString cmd = ":COEFF:ADD "+QString::number(point.frequency / 1000000000.0);
|
||||
for(auto s : point.S) {
|
||||
cmd += " "+QString::number(s.real())+" "+QString::number(s.imag());
|
||||
}
|
||||
if(!usb->Cmd(cmd)) {
|
||||
return false;
|
||||
}
|
||||
transferredPoints++;
|
||||
int newPercentage = transferredPoints * 100 / totalPoints;
|
||||
if(newPercentage != lastPercentage) {
|
||||
lastPercentage = newPercentage;
|
||||
emit updateCoefficientsPercent(newPercentage);
|
||||
}
|
||||
}
|
||||
if(!usb->Cmd(":COEFF:FIN")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// no points, delete coefficient
|
||||
if(!usb->Cmd(":COEFF:DEL "+setName+" "+paramName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
modified = false;
|
||||
return true;
|
||||
};
|
||||
for(int i=1;i<=numPorts;i++) {
|
||||
success &= createCoefficient(set.name, "P"+QString::number(i)+"_OPEN", set.opens[i-1]->t, set.opens[i-1]->modified);
|
||||
success &= createCoefficient(set.name, "P"+QString::number(i)+"_SHORT", set.shorts[i-1]->t, set.shorts[i-1]->modified);
|
||||
success &= createCoefficient(set.name, "P"+QString::number(i)+"_LOAD", set.loads[i-1]->t, set.loads[i-1]->modified);
|
||||
for(int j=i+1;j<=numPorts;j++) {
|
||||
success &= createCoefficient(set.name, "P"+QString::number(i)+QString::number(j)+"_THROUGH", set.getThrough(i,j)->t, set.getThrough(i,j)->modified);
|
||||
}
|
||||
}
|
||||
}
|
||||
emit updateCoefficientsDone(success);
|
||||
}
|
||||
|
||||
std::vector<CalDevice::CoefficientSet> CalDevice::getCoefficientSets() const
|
||||
{
|
||||
return coeffSets;
|
||||
}
|
||||
|
||||
QStringList CalDevice::getCoefficientSetNames()
|
||||
{
|
||||
QString resp = usb->Query(":COEFF:LIST?");
|
||||
if(!resp.startsWith("FACTORY")) {
|
||||
return QStringList();
|
||||
}
|
||||
return resp.split(",");
|
||||
}
|
||||
|
||||
bool CalDevice::hasModifiedCoefficients()
|
||||
{
|
||||
for(auto set : coeffSets) {
|
||||
for(auto c : set.opens) {
|
||||
if(c->modified) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(auto c : set.shorts) {
|
||||
if(c->modified) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(auto c : set.loads) {
|
||||
if(c->modified) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(auto c : set.throughs) {
|
||||
if(c->modified) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CalDevice::CoefficientSet::Coefficient *CalDevice::CoefficientSet::getThrough(int port1, int port2) const
|
||||
{
|
||||
if(port1 > ports || port2 > ports || port1 >= port2) {
|
||||
return nullptr;
|
||||
}
|
||||
int index = port2 - port1 - 1;
|
||||
while(port1 > 1) {
|
||||
index += ports - port1 + 1;
|
||||
port1--;
|
||||
}
|
||||
return throughs[index];
|
||||
}
|
90
Software/PC_Application/Calibration/LibreCAL/caldevice.h
Normal file
90
Software/PC_Application/Calibration/LibreCAL/caldevice.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef CALDEVICE_H
|
||||
#define CALDEVICE_H
|
||||
|
||||
#include "usbdevice.h"
|
||||
#include "touchstone.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
|
||||
class CalDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CalDevice(QString serial);
|
||||
~CalDevice();
|
||||
|
||||
enum class Standard {
|
||||
Open,
|
||||
Short,
|
||||
Load,
|
||||
Through,
|
||||
None
|
||||
};
|
||||
|
||||
static QString StandardToString(Standard s);
|
||||
static Standard StandardFromString(QString s);
|
||||
|
||||
Standard getStandard(int port);
|
||||
bool setStandard(int port, Standard s);
|
||||
static std::vector<Standard> availableStandards();
|
||||
|
||||
double getTemperature();
|
||||
bool stabilized();
|
||||
double getHeaterPower();
|
||||
|
||||
QString serial();
|
||||
QString getFirmware() const;
|
||||
int getNumPorts() const;
|
||||
|
||||
class CoefficientSet {
|
||||
public:
|
||||
QString name;
|
||||
int ports;
|
||||
class Coefficient {
|
||||
public:
|
||||
Coefficient() : t(Touchstone(1)), modified(false) {}
|
||||
Touchstone t;
|
||||
bool modified;
|
||||
};
|
||||
|
||||
std::vector<Coefficient*> opens;
|
||||
std::vector<Coefficient*> shorts;
|
||||
std::vector<Coefficient*> loads;
|
||||
std::vector<Coefficient*> throughs;
|
||||
|
||||
Coefficient *getThrough(int port1, int port2) const;
|
||||
};
|
||||
|
||||
// Extracts the coefficients from the device. This is done with a dedicated thread.
|
||||
// Do not call any other functions until the update is finished. Process can be
|
||||
// monitored through the updateCoefficientsPercent and updateCoefficientsDone signals
|
||||
void loadCoefficientSets(QStringList names = QStringList());
|
||||
// Writes coefficient sets to the device. This will only write modified files to save
|
||||
// time. This is done with a dedicated thread.
|
||||
// Do not call any other functions until the update is finished. Process can be
|
||||
// monitored through the updateCoefficientsPercent and updateCoefficientsDone signals
|
||||
void saveCoefficientSets();
|
||||
std::vector<CoefficientSet> getCoefficientSets() const;
|
||||
|
||||
QStringList getCoefficientSetNames();
|
||||
|
||||
bool hasModifiedCoefficients();
|
||||
|
||||
signals:
|
||||
void updateCoefficientsPercent(int percent);
|
||||
// emitted when all coefficients have been received and it is safe to call all functions again
|
||||
void updateCoefficientsDone(bool success);
|
||||
|
||||
private:
|
||||
void loadCoefficientSetsThread(QStringList names = QStringList());
|
||||
void saveCoefficientSetsThread();
|
||||
|
||||
USBDevice *usb;
|
||||
QString firmware;
|
||||
int numPorts;
|
||||
|
||||
std::vector<CoefficientSet> coeffSets;
|
||||
};
|
||||
|
||||
#endif // CALDEVICE_H
|
261
Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp
Normal file
261
Software/PC_Application/Calibration/LibreCAL/librecaldialog.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
#include "librecaldialog.h"
|
||||
#include "ui_librecaldialog.h"
|
||||
|
||||
#include "caldevice.h"
|
||||
#include "usbdevice.h"
|
||||
#include "Device/virtualdevice.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <QFormLayout>
|
||||
|
||||
using namespace std;
|
||||
|
||||
LibreCALDialog::LibreCALDialog(Calibration *cal) :
|
||||
QDialog(nullptr),
|
||||
ui(new Ui::LibreCALDialog),
|
||||
cal(cal),
|
||||
device(nullptr),
|
||||
busy(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
createPortAssignmentUI();
|
||||
|
||||
connect(this, &LibreCALDialog::portAssignmentChanged, this, &LibreCALDialog::updateCalibrationStartStatus);
|
||||
|
||||
connect(ui->cbDevice, &QComboBox::currentTextChanged, [=](QString text) {
|
||||
if(device) {
|
||||
delete device;
|
||||
}
|
||||
device = new CalDevice(text);
|
||||
if(device) {
|
||||
createPortAssignmentUI();
|
||||
connect(device, &CalDevice::updateCoefficientsPercent, ui->progressCoeff, &QProgressBar::setValue);
|
||||
connect(device, &CalDevice::updateCoefficientsDone, [=](bool success){
|
||||
busy = false;
|
||||
if(success) {
|
||||
ui->progressCoeff->setValue(100);
|
||||
ui->lCoefficientStatus->setText("Coefficients loaded.");
|
||||
coeffSet = device->getCoefficientSets()[0];
|
||||
} else {
|
||||
ui->progressCal->setValue(0);
|
||||
ui->lCoefficientStatus->setText("Failed to load coefficients");
|
||||
}
|
||||
updateCalibrationStartStatus();
|
||||
});
|
||||
|
||||
ui->cbCoefficients->clear();
|
||||
ui->cbCoefficients->addItem("Select...");
|
||||
for(auto c : device->getCoefficientSetNames()) {
|
||||
ui->cbCoefficients->addItem(c);
|
||||
}
|
||||
ui->cbCoefficients->setEnabled(true);
|
||||
} else {
|
||||
ui->cbCoefficients->clear();
|
||||
ui->cbCoefficients->setEnabled(false);
|
||||
ui->start->setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->cbCoefficients, &QComboBox::currentTextChanged, [=](){
|
||||
// no coefficient set selected
|
||||
ui->progressCoeff->setValue(0);
|
||||
ui->lCoefficientStatus->setText("No coefficients loaded");
|
||||
coeffSet = CalDevice::CoefficientSet();
|
||||
updateCalibrationStartStatus();
|
||||
|
||||
if(ui->cbCoefficients->currentIndex() > 0) {
|
||||
if(!device) {
|
||||
qWarning() << "Coefficients selected without connected device";
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
ui->lCoefficientStatus->setText("Loading coefficients...");
|
||||
device->loadCoefficientSets({ui->cbCoefficients->currentText()});
|
||||
}
|
||||
});
|
||||
|
||||
auto deviceList = USBDevice::GetDevices();
|
||||
for(auto device : deviceList) {
|
||||
ui->cbDevice->addItem(device);
|
||||
}
|
||||
|
||||
connect(this, &QDialog::finished, [=](){
|
||||
delete device;
|
||||
device = nullptr;
|
||||
});
|
||||
|
||||
connect(ui->start, &QPushButton::clicked, this, &LibreCALDialog::startCalibration);
|
||||
|
||||
updateCalibrationStartStatus();
|
||||
updateDeviceStatus();
|
||||
connect(&updateTimer, &QTimer::timeout, this, &LibreCALDialog::updateDeviceStatus);
|
||||
updateTimer.start(1000);
|
||||
}
|
||||
|
||||
LibreCALDialog::~LibreCALDialog()
|
||||
{
|
||||
delete device;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void LibreCALDialog::updateCalibrationStartStatus()
|
||||
{
|
||||
bool canStart = true;
|
||||
QString status = "Ready to start";
|
||||
if(!device) {
|
||||
status = "Not connected to a LibreCAL device.";
|
||||
canStart = false;
|
||||
}
|
||||
set<int> usedCalPorts;
|
||||
if(canStart) {
|
||||
// Check port mapping for duplicate entries (and at least one used port)
|
||||
for(auto port : portAssignment) {
|
||||
if(port < 1) {
|
||||
// skip unused ports
|
||||
continue;
|
||||
}
|
||||
if(usedCalPorts.count(port)) {
|
||||
status = "LibreCAL port "+QString::number(port)+" is assigned to multiple VNA ports.";
|
||||
canStart = false;
|
||||
break;
|
||||
} else {
|
||||
usedCalPorts.insert(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(canStart) {
|
||||
// at least one port must be used
|
||||
if(usedCalPorts.size() == 0) {
|
||||
status = "At least one port must be assigned.";
|
||||
canStart = false;
|
||||
}
|
||||
}
|
||||
if(canStart) {
|
||||
// check if coefficients have been loaded
|
||||
if(coeffSet.opens.size() != device->getNumPorts()) {
|
||||
status = "Coefficients not loaded";
|
||||
canStart = false;
|
||||
}
|
||||
}
|
||||
if(canStart) {
|
||||
double coeffMinFreq = numeric_limits<double>::max();
|
||||
double coeffMaxFreq = numeric_limits<double>::lowest();
|
||||
|
||||
auto checkCoefficient = [&](CalDevice::CoefficientSet::Coefficient *c) -> bool {
|
||||
if(c->t.points() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if(c->t.minFreq() < coeffMinFreq) {
|
||||
coeffMinFreq = c->t.minFreq();
|
||||
}
|
||||
if(c->t.maxFreq() > coeffMaxFreq) {
|
||||
coeffMaxFreq = c->t.maxFreq();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// check if coefficients for all ports are available
|
||||
for(auto i : usedCalPorts) {
|
||||
// Check if OSL coefficients are there
|
||||
if(!checkCoefficient(coeffSet.opens[i-1])) {
|
||||
status = "Open coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.shorts[i-1])) {
|
||||
status = "Short coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.loads[i-1])) {
|
||||
status = "Load coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
for(auto j : usedCalPorts) {
|
||||
if(j <= i) {
|
||||
continue;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.getThrough(i,j))) {
|
||||
status = "Through coefficient for LibreCAL port "+QString::number(i)+" to "+QString::number(j)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->lCalibrationStatus->setText(status);
|
||||
ui->start->setEnabled(canStart);
|
||||
if(canStart) {
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : black; }");
|
||||
} else {
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::updateDeviceStatus()
|
||||
{
|
||||
if(!device) {
|
||||
ui->lDeviceStatus->setText("No LibreCAL connected");
|
||||
ui->lDeviceStatus->setStyleSheet("QLabel { color : red; }");
|
||||
return;
|
||||
}
|
||||
if(busy) {
|
||||
// can't update while busy reading coefficients
|
||||
return;
|
||||
}
|
||||
if(device->stabilized()) {
|
||||
ui->lDeviceStatus->setText("LibreCAL ready for calibration");
|
||||
ui->lDeviceStatus->setStyleSheet("QLabel { color : black; }");
|
||||
} else {
|
||||
ui->lDeviceStatus->setText("Heating up, please wait with calibration");
|
||||
ui->lDeviceStatus->setStyleSheet("QLabel { color : orange; }");
|
||||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::startCalibration()
|
||||
{
|
||||
ui->cbDevice->setEnabled(false);
|
||||
ui->cbCoefficients->setEnabled(false);
|
||||
ui->start->setEnabled(false);
|
||||
|
||||
ui->lCalibrationStatus->setText("Creating calibration kit from coefficients...");
|
||||
auto& kit = cal->getKit();
|
||||
kit = Calkit::fromLibreCAL(device, coeffSet);
|
||||
}
|
||||
|
||||
void LibreCALDialog::createPortAssignmentUI()
|
||||
{
|
||||
auto layout = static_cast<QFormLayout*>(ui->assignmentBox->layout());
|
||||
// Clear any possible previous elements
|
||||
portAssignment.clear();
|
||||
while(layout->rowCount() > 1) {
|
||||
layout->removeRow(1);
|
||||
}
|
||||
auto vnaPorts = VirtualDevice::getInfo(VirtualDevice::getConnected()).ports;
|
||||
portAssignment.resize(vnaPorts, 0);
|
||||
auto calPorts = 0;
|
||||
if(device) {
|
||||
calPorts = device->getNumPorts();
|
||||
}
|
||||
QStringList choices = {"Unused"};
|
||||
for(int i=1;i<=calPorts;i++) {
|
||||
choices.push_back("Port "+QString::number(i));
|
||||
}
|
||||
for(int p = 1;p<=vnaPorts;p++) {
|
||||
auto label = new QLabel("Port "+QString::number(p)+":");
|
||||
auto comboBox = new QComboBox();
|
||||
comboBox->addItems(choices);
|
||||
connect(comboBox, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
|
||||
portAssignment[p-1] = comboBox->currentIndex();
|
||||
emit portAssignmentChanged();
|
||||
});
|
||||
// try to set the default
|
||||
comboBox->setCurrentIndex(p);
|
||||
layout->addRow(label, comboBox);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#ifndef LIBRECALDIALOG_H
|
||||
#define LIBRECALDIALOG_H
|
||||
|
||||
#include "Calibration/calibration.h"
|
||||
#include "caldevice.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ui {
|
||||
class LibreCALDialog;
|
||||
}
|
||||
|
||||
class LibreCALDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LibreCALDialog(Calibration *cal);
|
||||
~LibreCALDialog();
|
||||
|
||||
private:
|
||||
signals:
|
||||
void portAssignmentChanged();
|
||||
private slots:
|
||||
void updateCalibrationStartStatus();
|
||||
void updateDeviceStatus();
|
||||
void startCalibration();
|
||||
private:
|
||||
void createPortAssignmentUI();
|
||||
Ui::LibreCALDialog *ui;
|
||||
Calibration *cal;
|
||||
CalDevice *device;
|
||||
CalDevice::CoefficientSet coeffSet;
|
||||
QTimer updateTimer;
|
||||
bool busy;
|
||||
std::vector<int> portAssignment;
|
||||
};
|
||||
|
||||
#endif // LIBRECALDIALOG_H
|
144
Software/PC_Application/Calibration/LibreCAL/librecaldialog.ui
Normal file
144
Software/PC_Application/Calibration/LibreCAL/librecaldialog.ui
Normal file
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LibreCALDialog</class>
|
||||
<widget class="QDialog" name="LibreCALDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>346</width>
|
||||
<height>395</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Electronic Calibration Dialog</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Device Selection</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Device:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbDevice"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lDeviceStatus">
|
||||
<property name="text">
|
||||
<string>DEVICE_STATUS_PLACEHOLDER</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Coefficients:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbCoefficients"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lCoefficientStatus">
|
||||
<property name="text">
|
||||
<string>COEFFICIENT_STATUS_PLACEHOLDER</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCoeff">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="assignmentBox">
|
||||
<property name="title">
|
||||
<string>Port Assignments</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>LibreVNA</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>LibreCAL</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Calibration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="start">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lCalibrationStatus">
|
||||
<property name="text">
|
||||
<string>CALIBRATION_STATUS_PLACEHOLDER</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCal">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
253
Software/PC_Application/Calibration/LibreCAL/usbdevice.cpp
Normal file
253
Software/PC_Application/Calibration/LibreCAL/usbdevice.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
#include "usbdevice.h"
|
||||
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
#include <mutex>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using USBID = struct {
|
||||
int VID;
|
||||
int PID;
|
||||
};
|
||||
static constexpr USBID IDs[] = {
|
||||
{0x0483, 0x4122},
|
||||
};
|
||||
|
||||
USBDevice::USBDevice(QString serial)
|
||||
{
|
||||
m_handle = nullptr;
|
||||
libusb_init(&m_context);
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
libusb_set_option(m_context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
SearchDevices([=](libusb_device_handle *handle, QString found_serial) -> bool {
|
||||
if(serial.isEmpty() || serial == found_serial) {
|
||||
// accept connection to this device
|
||||
m_serial = found_serial;
|
||||
m_handle = handle;
|
||||
// abort device search
|
||||
return false;
|
||||
} else {
|
||||
// not the requested device, continue search
|
||||
return true;
|
||||
}
|
||||
}, m_context, false);
|
||||
|
||||
if(!m_handle) {
|
||||
QString message = "No device found";
|
||||
if(!serial.isEmpty()) {
|
||||
// only show error message if specific device was requested
|
||||
InformationBox::ShowError("Error opening device", message);
|
||||
}
|
||||
libusb_exit(m_context);
|
||||
throw std::runtime_error(message.toStdString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Found the correct device, now connect
|
||||
/* claim the interface */
|
||||
int ret = libusb_claim_interface(m_handle, 2);
|
||||
if (ret < 0) {
|
||||
libusb_close(m_handle);
|
||||
/* Failed to open */
|
||||
QString message = "Failed to claim interface: \"";
|
||||
message.append(libusb_strerror((libusb_error) ret));
|
||||
message.append("\" Maybe you are already connected to this device?");
|
||||
qWarning() << message;
|
||||
InformationBox::ShowError("Error opening device", message);
|
||||
libusb_exit(m_context);
|
||||
throw std::runtime_error(message.toStdString());
|
||||
}
|
||||
qInfo() << "USB connection established" << flush;
|
||||
}
|
||||
|
||||
USBDevice::~USBDevice()
|
||||
{
|
||||
libusb_release_interface(m_handle, 2);
|
||||
libusb_close(m_handle);
|
||||
libusb_exit(m_context);
|
||||
}
|
||||
|
||||
bool USBDevice::Cmd(QString cmd)
|
||||
{
|
||||
QString rcv;
|
||||
bool success = send(cmd) && receive(&rcv);
|
||||
if(success) {
|
||||
// empty response expected by commad
|
||||
return rcv == "";
|
||||
} else {
|
||||
// failed to send/receive
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString USBDevice::Query(QString query)
|
||||
{
|
||||
if(send(query)) {
|
||||
QString rcv;
|
||||
if(receive(&rcv)) {
|
||||
return rcv;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
std::set<QString> USBDevice::GetDevices()
|
||||
{
|
||||
std::set<QString> serials;
|
||||
|
||||
libusb_context *ctx;
|
||||
libusb_init(&ctx);
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
SearchDevices([&serials](libusb_device_handle *, QString serial) -> bool {
|
||||
serials.insert(serial);
|
||||
return true;
|
||||
}, ctx, true);
|
||||
|
||||
libusb_exit(ctx);
|
||||
|
||||
return serials;
|
||||
}
|
||||
|
||||
void USBDevice::SearchDevices(std::function<bool (libusb_device_handle *, QString)> foundCallback, libusb_context *context, bool ignoreOpenError)
|
||||
{
|
||||
libusb_device **devList;
|
||||
auto ndevices = libusb_get_device_list(context, &devList);
|
||||
|
||||
for (ssize_t idx = 0; idx < ndevices; idx++) {
|
||||
int ret;
|
||||
libusb_device *device = devList[idx];
|
||||
libusb_device_descriptor desc = {};
|
||||
|
||||
ret = libusb_get_device_descriptor(device, &desc);
|
||||
if (ret) {
|
||||
/* some error occured */
|
||||
qCritical() << "Failed to get device descriptor: "
|
||||
<< libusb_strerror((libusb_error) ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool correctID = false;
|
||||
int numIDs = sizeof(IDs)/sizeof(IDs[0]);
|
||||
for(int i=0;i<numIDs;i++) {
|
||||
if(desc.idVendor == IDs[i].VID && desc.idProduct == IDs[i].PID) {
|
||||
correctID = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!correctID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to open the device */
|
||||
libusb_device_handle *handle = nullptr;
|
||||
ret = libusb_open(device, &handle);
|
||||
if (ret) {
|
||||
qDebug() << libusb_strerror((enum libusb_error) ret);
|
||||
/* Failed to open */
|
||||
if(!ignoreOpenError) {
|
||||
QString message = "Found potential device but failed to open usb connection: \"";
|
||||
message.append(libusb_strerror((libusb_error) ret));
|
||||
message.append("\" On Linux this is most likely caused by a missing udev rule. "
|
||||
"On Windows this most likely means that you are already connected to "
|
||||
"this device (is another instance of the application already runnning?)");
|
||||
qWarning() << message;
|
||||
InformationBox::ShowError("Error opening device", message);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
char c_product[256];
|
||||
char c_serial[256];
|
||||
libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
|
||||
(unsigned char*) c_serial, sizeof(c_serial));
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
|
||||
(unsigned char*) c_product, sizeof(c_product));
|
||||
if (ret > 0) {
|
||||
/* managed to read the product string */
|
||||
QString product(c_product);
|
||||
if (product == "LibreCAL") {
|
||||
// this is a match
|
||||
if(!foundCallback(handle, QString(c_serial))) {
|
||||
// abort search
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to get product descriptor: "
|
||||
<< libusb_strerror((libusb_error) ret);
|
||||
}
|
||||
libusb_close(handle);
|
||||
}
|
||||
libusb_free_device_list(devList, 1);
|
||||
}
|
||||
|
||||
bool USBDevice::send(const QString &s)
|
||||
{
|
||||
qDebug() << "Send:"<<s;
|
||||
unsigned char data[s.size()+2];
|
||||
memcpy(data, s.toLatin1().data(), s.size());
|
||||
memcpy(&data[s.size()], "\r\n", 2);
|
||||
int actual;
|
||||
auto r = libusb_bulk_transfer(m_handle, LIBUSB_ENDPOINT_OUT | 0x03, data, s.size() + 2, &actual, 0);
|
||||
if(r == 0 && actual == s.size() + 2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool USBDevice::receive(QString *s)
|
||||
{
|
||||
char data[512];
|
||||
memset(data, 0, sizeof(data));
|
||||
int actual;
|
||||
int rcvCnt = 0;
|
||||
bool endOfLineFound = false;
|
||||
int res;
|
||||
do {
|
||||
res = libusb_bulk_transfer(m_handle, LIBUSB_ENDPOINT_IN | 0x03, (unsigned char*) &data[rcvCnt], sizeof(data) - rcvCnt, &actual, 2000);
|
||||
for(int i=rcvCnt;i<rcvCnt+actual;i++) {
|
||||
if(i == 0) {
|
||||
continue;
|
||||
}
|
||||
if(data[i] == '\n' && data[i-1] == '\r') {
|
||||
endOfLineFound = true;
|
||||
data[i-1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcvCnt += actual;
|
||||
} while(res == 0 && !endOfLineFound);
|
||||
if(res == 0) {
|
||||
if(s) {
|
||||
*s = QString(data);
|
||||
qDebug() << "Receive:"<<*s;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool USBDevice::flushRX()
|
||||
{
|
||||
char data[512];
|
||||
// libusb_bulk_transfer(m_handle, LIBUSB_ENDPOINT_IN | 0x03, (unsigned char*) data, sizeof(data), &actual, 1);
|
||||
}
|
||||
|
||||
|
||||
QString USBDevice::serial() const
|
||||
{
|
||||
return m_serial;
|
||||
}
|
34
Software/PC_Application/Calibration/LibreCAL/usbdevice.h
Normal file
34
Software/PC_Application/Calibration/LibreCAL/usbdevice.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef USBDEVICE_H
|
||||
#define USBDEVICE_H
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <QString>
|
||||
#include <set>
|
||||
#include<functional>
|
||||
|
||||
class USBDevice
|
||||
{
|
||||
public:
|
||||
// connect to a CAL device. If serial is specified only connecting to this device, otherwise to the first one found
|
||||
USBDevice(QString serial = QString());
|
||||
~USBDevice();
|
||||
|
||||
bool Cmd(QString cmd);
|
||||
QString Query(QString query);
|
||||
QString serial() const;
|
||||
|
||||
// Returns serial numbers of all connected devices
|
||||
static std::set<QString> GetDevices();
|
||||
|
||||
private:
|
||||
static void SearchDevices(std::function<bool (libusb_device_handle *, QString)> foundCallback, libusb_context *context, bool ignoreOpenError);
|
||||
bool send(const QString &s);
|
||||
bool receive(QString *s);
|
||||
bool flushRX();
|
||||
libusb_device_handle *m_handle;
|
||||
libusb_context *m_context;
|
||||
|
||||
QString m_serial;
|
||||
};
|
||||
|
||||
#endif // DEVICE_H
|
@ -3,6 +3,7 @@
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
#include "Util/app_common.h"
|
||||
#include "unit.h"
|
||||
#include "LibreCAL/librecaldialog.h"
|
||||
|
||||
#include "Eigen/Dense"
|
||||
|
||||
@ -339,6 +340,11 @@ void Calibration::edit()
|
||||
updateCalibrationList();
|
||||
});
|
||||
|
||||
connect(ui->eCal, &QPushButton::clicked, [=](){
|
||||
auto d = new LibreCALDialog(this);
|
||||
d->show();
|
||||
});
|
||||
|
||||
QObject::connect(ui->table, &QTableWidget::currentCellChanged, updateTableEditButtons);
|
||||
|
||||
auto addMenu = new QMenu();
|
||||
|
@ -159,6 +159,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="eCal">
|
||||
<property name="text">
|
||||
<string>Electronic
|
||||
Calibration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -328,6 +328,47 @@ Calkit Calkit::fromFile(QString filename)
|
||||
return c;
|
||||
}
|
||||
|
||||
Calkit Calkit::fromLibreCAL(CalDevice *device, CalDevice::CoefficientSet s)
|
||||
{
|
||||
Calkit ret;
|
||||
ret.manufacturer = "LibreCAL ("+s.name+")";
|
||||
ret.serialnumber = device->serial();
|
||||
ret.description = "Automatically created from LibreCAL module";
|
||||
for(int i=1;i<=device->getNumPorts();i++) {
|
||||
if(s.opens[i-1]->t.points() > 0) {
|
||||
auto o = new CalStandard::Open();
|
||||
o->setName("Port "+QString::number(i)+" Open");
|
||||
o->setMeasurement(s.opens[i-1]->t);
|
||||
ret.standards.push_back(o);
|
||||
}
|
||||
if(s.shorts[i-1]->t.points() > 0) {
|
||||
auto o = new CalStandard::Short();
|
||||
o->setName("Port "+QString::number(i)+" Short");
|
||||
o->setMeasurement(s.shorts[i-1]->t);
|
||||
ret.standards.push_back(o);
|
||||
}
|
||||
if(s.loads[i-1]->t.points() > 0) {
|
||||
auto o = new CalStandard::Load();
|
||||
o->setName("Port "+QString::number(i)+" Load");
|
||||
o->setMeasurement(s.loads[i-1]->t);
|
||||
ret.standards.push_back(o);
|
||||
}
|
||||
for(int j=i+1;j<=device->getNumPorts();j++) {
|
||||
auto c = s.getThrough(i,j);
|
||||
if(!c) {
|
||||
continue;
|
||||
}
|
||||
if(c->t.points() > 0) {
|
||||
auto o = new CalStandard::Through();
|
||||
o->setName("Port "+QString::number(i)+" to "+QString::number(j)+" Through");
|
||||
o->setMeasurement(c->t);
|
||||
ret.standards.push_back(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Calkit::edit(std::function<void (void)> updateCal)
|
||||
{
|
||||
auto dialog = new CalkitDialog(*this);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "calstandard.h"
|
||||
#include "savable.h"
|
||||
|
||||
#include "LibreCAL/caldevice.h"
|
||||
|
||||
#include <string>
|
||||
#include <complex>
|
||||
#include <QDir>
|
||||
@ -41,6 +43,7 @@ public:
|
||||
|
||||
void toFile(QString filename);
|
||||
static Calkit fromFile(QString filename);
|
||||
static Calkit fromLibreCAL(CalDevice *device, CalDevice::CoefficientSet s);
|
||||
void edit(std::function<void(void)> updateCal = nullptr);
|
||||
|
||||
std::vector<CalStandard::Virtual *> getStandards() const;
|
||||
|
@ -86,6 +86,16 @@ unsigned long long Virtual::getID()
|
||||
return id;
|
||||
}
|
||||
|
||||
QString Virtual::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void Virtual::setName(const QString &value)
|
||||
{
|
||||
name = value;
|
||||
}
|
||||
|
||||
void OnePort::setMeasurement(const Touchstone &ts, int port)
|
||||
{
|
||||
if(!touchstone) {
|
||||
|
@ -43,6 +43,9 @@ public:
|
||||
|
||||
unsigned long long getID();
|
||||
|
||||
QString getName() const;
|
||||
void setName(const QString &value);
|
||||
|
||||
protected:
|
||||
QString name;
|
||||
double minFreq;
|
||||
|
@ -1,5 +1,8 @@
|
||||
HEADERS += \
|
||||
../VNA_embedded/Application/Communication/Protocol.hpp \
|
||||
Calibration/LibreCAL/caldevice.h \
|
||||
Calibration/LibreCAL/librecaldialog.h \
|
||||
Calibration/LibreCAL/usbdevice.h \
|
||||
Calibration/amplitudecaldialog.h \
|
||||
Calibration/calibration.h \
|
||||
Calibration/calibrationmeasurement.h \
|
||||
@ -139,6 +142,9 @@ HEADERS += \
|
||||
|
||||
SOURCES += \
|
||||
../VNA_embedded/Application/Communication/Protocol.cpp \
|
||||
Calibration/LibreCAL/caldevice.cpp \
|
||||
Calibration/LibreCAL/librecaldialog.cpp \
|
||||
Calibration/LibreCAL/usbdevice.cpp \
|
||||
Calibration/amplitudecaldialog.cpp \
|
||||
Calibration/calibration.cpp \
|
||||
Calibration/calibrationmeasurement.cpp \
|
||||
@ -276,6 +282,7 @@ FORMS += \
|
||||
Calibration/CalStandardOpenEditDialog.ui \
|
||||
Calibration/CalStandardShortEditDialog.ui \
|
||||
Calibration/CalStandardThroughEditDialog.ui \
|
||||
Calibration/LibreCAL/librecaldialog.ui \
|
||||
Calibration/addamplitudepointsdialog.ui \
|
||||
Calibration/amplitudecaldialog.ui \
|
||||
Calibration/automaticamplitudedialog.ui \
|
||||
|
@ -42,6 +42,8 @@ Trace::Trace(QString name, QColor color, QString live)
|
||||
mathCalcTimer.setSingleShot(true);
|
||||
connect(&mathCalcTimer, &QTimer::timeout, this, &Trace::calculateMath);
|
||||
|
||||
fromLivedata(LivedataType::Overwrite, live);
|
||||
|
||||
self.enabled = false;
|
||||
dataType = DataType::Frequency;
|
||||
connect(this, &Trace::typeChanged, [=](){
|
||||
|
@ -5,10 +5,6 @@
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "Tools/parameters.h"
|
||||
#include <complex>
|
||||
using namespace std;
|
||||
|
||||
static QApplication *app;
|
||||
static AppWindow *window;
|
||||
|
||||
@ -32,33 +28,7 @@ int main(int argc, char *argv[]) {
|
||||
window->getAppGitHash().left(9));
|
||||
|
||||
Device::RegisterTypes();
|
||||
|
||||
auto S11 = complex<double>(-0.5, 0.25);
|
||||
auto S22 = complex<double>(0.5, 0.15);
|
||||
auto S33 = complex<double>(0.8, -0.25);
|
||||
|
||||
auto S12 = complex<double>(0.1, 0);
|
||||
auto S21 = complex<double>(0.2, 0.3);
|
||||
|
||||
auto S13 = complex<double>(0.3, -0.2);
|
||||
auto S31 = complex<double>(0.4, 0.4);
|
||||
|
||||
auto S23 = complex<double>(0.5, 0.2);
|
||||
auto S32 = complex<double>(0.6, -0.2);
|
||||
|
||||
auto p12 = Sparam(S11, S12, S21, S22);
|
||||
auto p12_only = Sparam(0.0, S12, 1.0, 0.0);
|
||||
auto p13 = Sparam(S11, S13, S31, S33);
|
||||
auto p23 = Sparam(S22, S23, S32, S33);
|
||||
|
||||
// convert to 75 ohm
|
||||
auto p12_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
|
||||
auto p12_only_75 = Sparam(ABCDparam(p12_only, 50.0), 75.0);
|
||||
auto p13_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
|
||||
auto Zp23_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
|
||||
|
||||
auto p1 = Sparam(S11, 0.0, 0.0, 1.0);
|
||||
auto p1_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
|
||||
VirtualDevice::RegisterTypes();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
signal(SIGINT, tryExitGracefully);
|
||||
|
@ -445,3 +445,8 @@ void Touchstone::setReferenceImpedance(double value)
|
||||
{
|
||||
referenceImpedance = value;
|
||||
}
|
||||
|
||||
void Touchstone::setFilename(const QString &value)
|
||||
{
|
||||
filename = value;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
void reduceTo1Port(unsigned int port);
|
||||
unsigned int ports() { return m_ports; }
|
||||
QString getFilename() const;
|
||||
void setFilename(const QString &value);
|
||||
|
||||
virtual nlohmann::json toJSON();
|
||||
virtual void fromJSON(nlohmann::json j);
|
||||
@ -54,6 +55,7 @@ public:
|
||||
double getReferenceImpedance() const;
|
||||
void setReferenceImpedance(double value);
|
||||
|
||||
|
||||
private:
|
||||
unsigned int m_ports;
|
||||
double referenceImpedance;
|
||||
|
Loading…
Reference in New Issue
Block a user