Calibration SCPI API adjusted

This commit is contained in:
Jan Käberich 2022-10-01 02:05:30 +02:00
parent 9cf76c9681
commit 8dd747af62
7 changed files with 315 additions and 91 deletions

View File

@ -501,22 +501,44 @@ $$ S_{11}...S_{1n},S_{21}...S_{2n},...,S_{n1}...S_{nn} $$
\event{Sets the storage type of a trace}{VNA:TRACe:TYPE}{<trace>, either by name or by index\\<type>, options are OVERWRITE, MAXHOLD or MINHOLD}
\query{Queries the storage type of a trace}{VNA:TRACe:TYPE?}{<trace>, either by name or by index}{OVERWRITE, MAXHOLD or MINHOLD}
\subsubsection{VNA:CALibration:TYPE}
\event{Sets the calibration type. This command fails if the required measurements have not been taken yet}{VNA:CALibration:TYPE}{<type>, options are NONE, PORT\_1, PORT\_2, SOLT, NORMALIZE or TRL}
\query{Queries the currently active calibration type}{VNA:CALibration:TYPE?}{None}{NONE, PORT\_1, PORT\_2, SOLT, NORMALIZE or TRL}
\subsubsection{VNA:CALibration:ACTivate}
\event{Activates a specific calibration. This command fails if the required measurements have not been taken yet}{VNA:CALibration:ACTivate}{<type>}
\query{Queries the currently available calibration types}{VNA:CALibration:ACTivate?}{None}{comma-separated list of available calibration types}
\subsubsection{VNA:CALibration:MEASure}
\event{Starts a calibration measurement. This command fails if no device is connected, the VNA mode is not active or a calibration measurement is already in progress.}{VNA:CALibration:MEASure}{<type>, options are:\\
\hspace{1cm}PORT\_1\_OPEN\\
\hspace{1cm}PORT\_1\_SHORT\\
\hspace{1cm}PORT\_1\_LOAD\\
\hspace{1cm}PORT\_2\_OPEN\\
\hspace{1cm}PORT\_2\_SHORT\\
\hspace{1cm}PORT\_2\_LOAD\\
\subsubsection{VNA:CALibration:NUMber}
\query{Queries the number of available calibration measurements}{VNA:CALibration:NUMber?}{None}{<number of configured measurements>}
\subsubsection{VNA:CALibration:RESET}
\event{Resets the calibration. Deactivates the calibration and deletes all measurements.}{VNA:CALibration:RESET}{None}
\subsubsection{VNA:CALibration:ADD}
\event{Adds a new empty calibration measurement.}{VNA:CALibration:ADD}{<type> Measurement type, one of:\\
\hspace{1cm}OPEN\\
\hspace{1cm}SHORT\\
\hspace{1cm}LOAD\\
\hspace{1cm}THROUGH\\
\hspace{1cm}ISOLATION\\
\hspace{1cm}LINE\\
}
{[<standard>]}, calibration kit standard name, optional\\}
\subsubsection{VNA:CALibration:TYPE}
\query{Returns the type of the specified measurement}{VNA:CALibration:TYPE?}{<measurement number>}{Measurement type, one of:\\
\hspace{1cm}OPEN\\
\hspace{1cm}SHORT\\
\hspace{1cm}LOAD\\
\hspace{1cm}THROUGH\\
\hspace{1cm}ISOLATION\\}
\subsubsection{VNA:CALibration:PORT}
\event{Sets the port for the specified measurement}{VNA:CALibration:PORT}{<measurement number> <port number>}
\query{Returns the port for the specified measurement}{VNA:CALibration:PORT?}{<measurement number>}{<port number>}
\subsubsection{VNA:CALibration:STANDARD}
\event{Sets the calibration standard which will be used for the specified measurement}{VNA:CALibration:STANDARD}{<measurement number> <standard name>}
\query{Returns the standard name for the specified measurement}{VNA:CALibration:STANDARD?}{<measurement number>}{Name of used calibration standard (from calibration kit)}
\subsubsection{VNA:CALibration:MEASure}
\event{Starts a calibration measurement. This command fails if no device is connected, the VNA mode is not active or a calibration measurement is already in progress.}{VNA:CALibration:MEASure}{<measurement 1>,<measurement 2>,...}
Any number of measurements can be specified (by their number). These measurements will be taken simultaneously. This only works if they are measuring different ports (e.g. measure SHORT on port 1 and OPEN on port 2). If colliding measurements are specified (e.g. SHORT on port 1 and LOAD on port 1), an error is returned and no measurements are started.
\subsubsection{VNA:CALibration:BUSY}
\query{Queries whether a calibration measurement is ongoing}{VNA:CALibration:BUSY?}{None}{TRUE or FALSE}

View File

@ -36,8 +36,258 @@ bool operator==(const Calibration::CalType &lhs, const Calibration::CalType &rhs
}
Calibration::Calibration()
: SCPINode("CALibration")
{
caltype.type = Type::None;
unsavedChanges = false;
// create SCPI commands
add(new SCPICommand("ACTivate", [=](QStringList params) -> QString {
if(params.size() != 1) {
return SCPI::getResultName(SCPI::Result::Error);
} else {
auto availableCals = getAvailableCalibrations();
for(auto caltype : availableCals) {
if(caltype.getShortString().compare(params[0], Qt::CaseInsensitive) == 0) {
// found a match
// check if calibration can be activated
if(canCompute(caltype)) {
compute(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 availableCals = getAvailableCalibrations();
if(availableCals.size() == 0) {
return SCPI::getResultName(SCPI::Result::Empty);
}
auto ret = availableCals[0].getShortString();
for(unsigned int i=1;i<availableCals.size();i++) {
ret += ",";
ret += availableCals[i].getShortString();
}
return ret;
}));
add(new SCPICommand("NUMber", nullptr, [=](QStringList) -> QString {
return QString::number(measurements.size());
}));
add(new SCPICommand("RESET", [=](QStringList) -> QString {
reset();
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
add(new SCPICommand("ADD", [=](QStringList params) -> QString {
if(params.size() < 1) {
// no measurement type specified
return SCPI::getResultName(SCPI::Result::Error);
} else {
// parse measurement type
auto type = CalibrationMeasurement::Base::TypeFromString(params[0]);
auto newMeas = newMeasurement(type);
if(!newMeas) {
// failed to create this type of measurement
return SCPI::getResultName(SCPI::Result::Error);
}
if(params.size() == 2) {
// standard name given
CalStandard::Virtual *standard = nullptr;
for(auto s : newMeas->supportedStandards()) {
if(s->getName().compare(params[1], Qt::CaseInsensitive) == 0) {
// use this standard
standard = s;
}
}
if(!standard) {
// specified standard not available
return SCPI::getResultName(SCPI::Result::Error);
}
newMeas->setStandard(standard);
}
measurements.push_back(newMeas);
return SCPI::getResultName(SCPI::Result::Empty);
}
}, nullptr));
add(new SCPICommand("TYPE", nullptr, [=](QStringList params) -> QString {
if(params.size() < 1) {
// no measurement number specified
return SCPI::getResultName(SCPI::Result::Error);
} else {
bool okay;
unsigned int number = params[0].toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
}
return CalibrationMeasurement::Base::TypeToString(measurements[number]->getType());
}
}));
add(new SCPICommand("PORT", [=](QStringList params) -> QString {
if(params.size() < 1) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
} else {
bool okay;
unsigned int number = params[0].toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
}
auto meas = measurements[number];
auto onePort = dynamic_cast<CalibrationMeasurement::OnePort*>(meas);
if(onePort) {
if(params.size() != 2) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
}
bool okay;
int number = params[1].toInt(&okay);
if(!okay || number < 1 || number > VirtualDevice::getInfo(VirtualDevice::getConnected()).ports) {
// invalid port specified
return SCPI::getResultName(SCPI::Result::Error);
}
onePort->setPort(number);
return SCPI::getResultName(SCPI::Result::Empty);
}
auto twoPort = dynamic_cast<CalibrationMeasurement::TwoPort*>(meas);
if(twoPort) {
if(params.size() != 3) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
}
bool okay1;
int port1 = params[1].toInt(&okay1);
bool okay2;
int port2 = params[2].toInt(&okay2);
if(!okay1 || !okay2 || port1 < 1 || port2 > VirtualDevice::getInfo(VirtualDevice::getConnected()).ports
|| port2 < 1 || port2 > VirtualDevice::getInfo(VirtualDevice::getConnected()).ports) {
// invalid port specified
return SCPI::getResultName(SCPI::Result::Error);
}
twoPort->setPort1(port1);
twoPort->setPort2(port2);
return SCPI::getResultName(SCPI::Result::Empty);
}
return SCPI::getResultName(SCPI::Result::Error);
}
}, [=](QStringList params) -> QString {
if(params.size() != 1) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
} else {
bool okay;
unsigned int number = params[0].toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
}
auto meas = measurements[number];
auto onePort = dynamic_cast<CalibrationMeasurement::OnePort*>(meas);
if(onePort) {
return QString::number(onePort->getPort());
}
auto twoPort = dynamic_cast<CalibrationMeasurement::TwoPort*>(meas);
if(twoPort) {
return QString::number(twoPort->getPort1()) + " " + QString::number(twoPort->getPort2());
}
return SCPI::getResultName(SCPI::Result::Error);
}
}));
add(new SCPICommand("STANDARD", [=](QStringList params) -> QString {
if(params.size() != 2) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
} else {
bool okay;
unsigned int number = params[0].toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
}
auto meas = measurements[number];
for(auto s : meas->supportedStandards()) {
if(s->getName().compare(params[1], Qt::CaseInsensitive) == 0) {
// use this standard
meas->setStandard(s);
return SCPI::getResultName(SCPI::Result::Empty);
}
}
// specified standard not available
return SCPI::getResultName(SCPI::Result::Error);
}
}, [=](QStringList params) -> QString {
if(params.size() != 1) {
// invalid number of parameters
return SCPI::getResultName(SCPI::Result::Error);
} else {
bool okay;
unsigned int number = params[0].toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
}
auto s = measurements[number]->getStandard();
if(s) {
s->getName();
} else {
// no standard set
return "None";
}
}
}));
add(new SCPICommand("MEASure", [=](QStringList params) -> QString {
if(params.size() < 1 ) {
// no measurement specified
// TODO check if measurement is already running
return SCPI::getResultName(SCPI::Result::Error);
} else {
// assemble list of measurements to take
std::set<CalibrationMeasurement::Base*> m;
for(QString p : params) {
bool okay = false;
unsigned int number = p.toUInt(&okay);
if(!okay || number >= measurements.size()) {
// invalid measurement specified
return SCPI::getResultName(SCPI::Result::Error);
} else {
m.insert(measurements[number]);
}
}
if(CalibrationMeasurement::Base::canMeasureSimultaneously(m)) {
emit startMeasurements(m);
return SCPI::getResultName(SCPI::Result::Empty);
} else {
// can't start these measurements simultaneously
return SCPI::getResultName(SCPI::Result::Error);
}
}
}, nullptr));
add(new SCPICommand("SAVE", [=](QStringList params) -> QString {
if(params.size() != 1 || getCaltype().type == Calibration::Type::None) {
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::Error);
}
if(!toFile(params[0])) {
// some error when writing the calibration file
return SCPI::getResultName(SCPI::Result::Error);
}
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
add(new SCPICommand("LOAD", nullptr, [=](QStringList params) -> QString {
if(params.size() != 1) {
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::False);
}
if(!fromFile(params[0])) {
// some error when loading the calibration file
return SCPI::getResultName(SCPI::Result::False);
}
return SCPI::getResultName(SCPI::Result::True);
}));
}
QString Calibration::TypeToString(Calibration::Type type)
@ -284,7 +534,7 @@ void Calibration::edit()
ui->createDefault->blockSignals(false);
return;
}
measurements.clear();
deleteMeasurements();
}
createDefaultMeasurements((DefaultMeasurements) (ui->createDefault->currentIndex() - 1));
updateMeasurementTable();
@ -845,6 +1095,7 @@ bool Calibration::toFile(QString filename)
kit.toFile(calkit_file);
this->currentCalFile = calibration_file; // if all ok, remember this
unsavedChanges = false;
return true;
}
@ -888,6 +1139,7 @@ bool Calibration::fromFile(QString filename)
return false;
}
unsavedChanges = false;
return true;
}
@ -1012,10 +1264,7 @@ bool Calibration::compute(Calibration::CalType type)
void Calibration::reset()
{
for(auto m : measurements) {
delete m;
}
measurements.clear();
deleteMeasurements();
deactivate();
}
@ -1033,6 +1282,7 @@ void Calibration::addMeasurements(std::set<CalibrationMeasurement::Base *> m, co
for(auto meas : m) {
meas->addPoint(data);
}
unsavedChanges = true;
}
void Calibration::clearMeasurements(std::set<CalibrationMeasurement::Base *> m)
@ -1116,6 +1366,14 @@ void Calibration::createDefaultMeasurements(Calibration::DefaultMeasurements dm)
}
}
void Calibration::deleteMeasurements()
{
for(auto m : measurements) {
delete m;
}
measurements.clear();
}
bool Calibration::hasFrequencyOverlap(std::vector<CalibrationMeasurement::Base *> m, double *startFreq, double *stopFreq, int *points)
{
double minResolution = std::numeric_limits<double>::max();

View File

@ -5,8 +5,9 @@
#include "calibrationmeasurement.h"
#include "calkit.h"
#include "Traces/trace.h"
#include "scpi.h"
class Calibration : public QObject, public Savable
class Calibration : public QObject, public Savable, public SCPINode
{
Q_OBJECT
@ -115,6 +116,7 @@ private:
};
static QString DefaultMeasurementsToString(DefaultMeasurements dm);
void createDefaultMeasurements(DefaultMeasurements dm);
void deleteMeasurements();
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);
@ -145,6 +147,8 @@ private:
QString descriptiveCalName();
QString currentCalFile;
bool unsavedChanges;
};
#endif // CALIBRATION2_H

View File

@ -95,7 +95,7 @@ QString CalibrationMeasurement::Base::TypeToString(CalibrationMeasurement::Base:
CalibrationMeasurement::Base::Type CalibrationMeasurement::Base::TypeFromString(QString s)
{
for(int i=0;i<(int) Type::Last;i++) {
if(TypeToString((Type) i) == s) {
if(TypeToString((Type) i).compare(s, Qt::CaseInsensitive) == 0) {
return (Type) i;
}
}
@ -188,6 +188,11 @@ QDateTime CalibrationMeasurement::Base::getTimestamp() const
return timestamp;
}
CalStandard::Virtual* CalibrationMeasurement::Base::getStandard() const
{
return standard;
}
double CalibrationMeasurement::OnePort::minFreq()
{
if(points.size() > 0) {

View File

@ -54,6 +54,8 @@ public:
static bool canMeasureSimultaneously(std::set<Base *> measurements);
QDateTime getTimestamp() const;
CalStandard::Virtual *getStandard() const;
protected:
signals:
void standardChanged(CalStandard::Virtual* newStandard);
@ -101,7 +103,7 @@ protected:
signals:
void portChanged(int p);
protected:
int port;
int port; // starts at 1
std::vector<Point> points;
};
@ -182,7 +184,7 @@ signals:
void port2Changed(int p);
void reverseStandardChanged(bool r);
protected:
int port1, port2;
int port1, port2; // starts at 1
bool reverseStandard; // Set to true if standard is defined with ports swapped
std::vector<Point> points;
};

View File

@ -1403,77 +1403,10 @@ void VNA::SetupSCPI()
return QString::number(settings.Power.frequency, 'f', 0);
}));
SCPINode::add(traceWidget);
auto scpi_cal = new SCPINode("CALibration");
SCPINode::add(scpi_cal);
scpi_cal->add(new SCPICommand("TYPE", [=](QStringList params) -> QString {
if(params.size() != 1) {
return SCPI::getResultName(SCPI::Result::Error);
} 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.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 = cal.getCaltype().getShortString();
return ret;
}));
scpi_cal->add(new SCPICommand("MEASure", [=](QStringList params) -> QString {
if(params.size() != 1 || CalibrationMeasurementActive() || !window->getDevice() || isActive != true) {
// no measurement specified, still busy or invalid mode
return SCPI::getResultName(SCPI::Result::Error);
} else {
// 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));
scpi_cal->add(new SCPICommand("BUSy", nullptr, [=](QStringList) -> QString {
SCPINode::add(&cal);
cal.add(new SCPICommand("BUSy", nullptr, [=](QStringList) -> QString {
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 || cal.getCaltype().type == Calibration::Type::None) {
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::Error);
}
if(!cal.toFile(params[0])) {
// some error when writing the calibration file
return SCPI::getResultName(SCPI::Result::Error);
}
calEdited = false;
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
scpi_cal->add(new SCPICommand("LOAD", nullptr, [=](QStringList params) -> QString {
if(params.size() != 1) {
// no filename given or no calibration active
return SCPI::getResultName(SCPI::Result::False);
}
if(!cal.fromFile(params[0])) {
// some error when loading the calibration file
return SCPI::getResultName(SCPI::Result::False);
}
calEdited = false;
return SCPI::getResultName(SCPI::Result::True);
}));
}
void VNA::ConstrainAndUpdateFrequencies()