SCPI API for editing calibration kit standards

This commit is contained in:
Jan Käberich 2025-12-02 15:29:47 +01:00
parent fbef4b364f
commit 7bdbcde9be
9 changed files with 440 additions and 11 deletions

View file

@ -16,7 +16,7 @@ using json = nlohmann::json;
using namespace std;
Calkit::Calkit()
: SCPINode("KIT")
: SCPINode("KIT"), scpi_std("STAndard")
{
// set default values
filename = "";
@ -77,6 +77,53 @@ Calkit::Calkit()
return SCPI::getResultName(SCPI::Result::False);
}
}, false));
scpi_std.add(new SCPICommand("CLEAR", [=](QStringList params) -> QString {
Q_UNUSED(params);
setIdealDefault();
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
scpi_std.add(new SCPICommand("NUMber", nullptr, [=](QStringList params) -> QString {
Q_UNUSED(params);
return QString::number(standards.size());
}));
scpi_std.add(new SCPICommand("NEW", [=](QStringList params) -> QString {
if(params.size() != 2) {
return SCPI::getResultName(SCPI::Result::Error);
}
auto type = CalStandard::Virtual::TypeFromString(params[0]);
if(type == CalStandard::Virtual::Type::Last) {
return SCPI::getResultName(SCPI::Result::Error);
}
auto s = CalStandard::Virtual::create(type);
if(!s) {
return SCPI::getResultName(SCPI::Result::Error);
}
s->setName(params[1]);
addStandard(s);
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr, false));
scpi_std.add(new SCPICommand("DELete", [=](QStringList params) -> QString {
unsigned long long index;
if(!SCPI::paramToULongLong(params, 0, index)) {
return SCPI::getResultName(SCPI::Result::Error);
}
if(index < 1 || index > standards.size()) {
return SCPI::getResultName(SCPI::Result::Error);
}
removeStandard(standards[index-1]);
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
scpi_std.add(new SCPICommand("TYPE", nullptr, [=](QStringList params) -> QString {
unsigned long long index = 0;
if(!SCPI::paramToULongLong(params, 0, index)) {
return SCPI::getResultName(SCPI::Result::Error);
}
if(index < 1 || index > standards.size()) {
return SCPI::getResultName(SCPI::Result::Error);
}
return CalStandard::Virtual::TypeToString(standards[index-1]->getType()).replace(" ", "_");
}));
add(&scpi_std);
}
void Calkit::toFile(QString filename)
@ -382,6 +429,7 @@ Calkit Calkit::fromFile(QString filename)
file.close();
c.filename = filename;
c.updateSCPINames();
return c;
}
@ -407,6 +455,21 @@ void Calkit::clearStandards()
standards.clear();
}
void Calkit::updateSCPINames()
{
// Need to remove all standards from the subnode list first, otherwise
// name changes wouldn't work due to temporarily name collisions
for(auto &s : standards) {
scpi_std.remove(s);
}
unsigned int i=1;
for(auto &s : standards) {
s->changeName(QString::number(i));
scpi_std.add(s);
i++;
}
}
std::vector<CalStandard::Virtual *> Calkit::getStandards() const
{
return standards;
@ -428,6 +491,14 @@ void Calkit::addStandard(CalStandard::Virtual *s)
}
}
standards.push_back(s);
updateSCPINames();
}
void Calkit::removeStandard(CalStandard::Virtual *s)
{
standards.erase(std::remove(standards.begin(), standards.end(), s), standards.end());
delete s;
updateSCPINames();
}
nlohmann::json Calkit::toJSON()
@ -464,6 +535,7 @@ void Calkit::fromJSON(nlohmann::json j)
s->fromJSON(js["params"]);
addStandard(s);
}
updateSCPINames();
}
void Calkit::setIdealDefault()
@ -475,4 +547,5 @@ void Calkit::setIdealDefault()
addStandard(new CalStandard::Short("Ideal Short Standard", 50.0, 0, 0, 0, 0, 0, 0));
addStandard(new CalStandard::Load("Ideal Load Standard", 50.0, 0, 0, 50.0, 0, 0));
addStandard(new CalStandard::Through("Ideal Through Standard", 50.0, 0, 0));
updateSCPINames();
}

View file

@ -50,6 +50,7 @@ public:
std::vector<CalStandard::Virtual *> getStandards() const;
void addStandard(CalStandard::Virtual* s);
void removeStandard(CalStandard::Virtual* s);
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
@ -58,8 +59,10 @@ public:
private:
void clearStandards();
void updateSCPINames();
QString manufacturer, serialnumber, description;
QString filename;
SCPINode scpi_std;
std::vector<CalStandard::Virtual*> standards;
const std::vector<Savable::SettingDescription> descr = {{

View file

@ -27,8 +27,7 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
connect(ui->bDelete, &QPushButton::clicked, [=](){
auto row = ui->list->currentRow();
if(row >= 0) {
delete kit.standards[row];
kit.standards.erase(kit.standards.begin() + row);
kit.removeStandard(kit.standards[row]);
updateStandardList();
}
});
@ -39,6 +38,7 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
swap(kit.standards[row], kit.standards[row-1]);
ui->list->setCurrentRow(row-1);
updateStandardList();
kit.updateSCPINames();
}
});
@ -48,6 +48,7 @@ CalkitDialog::CalkitDialog(Calkit &c, QWidget *parent) :
swap(kit.standards[row], kit.standards[row+1]);
ui->list->setCurrentRow(row+1);
updateStandardList();
kit.updateSCPINames();
}
});

View file

@ -12,6 +12,7 @@ using namespace std;
using namespace CalStandard;
Virtual::Virtual(QString name) :
SCPINode(name),
name(name),
minFreq(std::numeric_limits<double>::lowest()),
maxFreq(std::numeric_limits<double>::max())
@ -60,7 +61,7 @@ QString Virtual::TypeToString(Virtual::Type type)
Virtual::Type Virtual::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;
}
}
@ -101,6 +102,11 @@ void Virtual::setName(const QString &value)
name = value;
}
void Virtual::setupSCPI()
{
addStringParameter("NAME", name);
}
void OnePort::setMeasurement(const Touchstone &ts, int port)
{
if(!touchstone) {
@ -142,10 +148,35 @@ void OnePort::fromJSON(nlohmann::json j)
}
}
void OnePort::setupSCPI()
{
add(new SCPICommand("FILE", [=](QStringList params) -> QString {
if(params.size() < 1) {
return SCPI::getResultName(SCPI::Result::Error);
}
try {
auto ts = Touchstone::fromFile(params[0].toStdString());
unsigned long long index = 0;
if(params.size() == 2) {
if(!SCPI::paramToULongLong(params, 1, index)) {
return SCPI::getResultName(SCPI::Result::Error);
}
}
setMeasurement(ts, index-1);
return SCPI::getResultName(SCPI::Result::Empty);
} catch(const std::exception& e) {
// failed to load file
return SCPI::getResultName(SCPI::Result::Error);
}
}, nullptr, false));
Virtual::setupSCPI();
}
Open::Open()
{
Z0 = 50.0;
delay = loss = C0 = C1 = C2 = C3 = 0.0;
setupSCPI();
}
std::complex<double> Open::toS11(double freq)
@ -263,10 +294,23 @@ void Open::fromJSON(nlohmann::json j)
C3 = j.value("C3", 0.0);
}
void Open::setupSCPI()
{
addDoubleParameter("Z0", Z0, true, true, [=](){clearMeasurement();});
addDoubleParameter("DELAY", delay, true, true, [=](){clearMeasurement();});
addDoubleParameter("LOSS", loss, true, true, [=](){clearMeasurement();});
addDoubleParameter("C0", C0, true, true, [=](){clearMeasurement();});
addDoubleParameter("C1", C1, true, true, [=](){clearMeasurement();});
addDoubleParameter("C2", C2, true, true, [=](){clearMeasurement();});
addDoubleParameter("C3", C3, true, true, [=](){clearMeasurement();});
OnePort::setupSCPI();
}
Short::Short()
{
Z0 = 50.0;
delay = loss = L0 = L1 = L2 = L3 = 0.0;
setupSCPI();
}
std::complex<double> Short::toS11(double freq)
@ -378,12 +422,25 @@ void Short::fromJSON(nlohmann::json j)
L3 = j.value("L3", 0.0);
}
void Short::setupSCPI()
{
addDoubleParameter("Z0", Z0, true, true, [=](){clearMeasurement();});
addDoubleParameter("DELAY", delay, true, true, [=](){clearMeasurement();});
addDoubleParameter("LOSS", loss, true, true, [=](){clearMeasurement();});
addDoubleParameter("L0", L0, true, true, [=](){clearMeasurement();});
addDoubleParameter("L1", L1, true, true, [=](){clearMeasurement();});
addDoubleParameter("L2", L2, true, true, [=](){clearMeasurement();});
addDoubleParameter("L3", L3, true, true, [=](){clearMeasurement();});
OnePort::setupSCPI();
}
Load::Load()
{
Z0 = 50.0;
resistance = 50.0;
delay = Cparallel = Lseries = 0;
Cfirst = true;
setupSCPI();
}
std::complex<double> Load::toS11(double freq)
@ -519,6 +576,18 @@ void Load::fromJSON(nlohmann::json j)
Cfirst = j.value("Cfirst", true);
}
void Load::setupSCPI()
{
addDoubleParameter("Z0", Z0, true, true, [=](){clearMeasurement();});
addDoubleParameter("DELAY", delay, true, true, [=](){clearMeasurement();});
addDoubleParameter("LOSS", loss, true, true, [=](){clearMeasurement();});
addDoubleParameter("RESistance", resistance, true, true, [=](){clearMeasurement();});
addDoubleParameter("CPARallel", Cparallel, true, true, [=](){clearMeasurement();});
addDoubleParameter("LSERies", Lseries, true, true, [=](){clearMeasurement();});
addBoolParameter("CFIRST", Cfirst, true, true, [=](){clearMeasurement();});
OnePort::setupSCPI();
}
void TwoPort::setMeasurement(const Touchstone &ts, int port1, int port2)
{
if(!touchstone) {
@ -560,11 +629,37 @@ void TwoPort::fromJSON(nlohmann::json j)
}
}
void TwoPort::setupSCPI()
{
add(new SCPICommand("FILE", [=](QStringList params) -> QString {
if(params.size() != 3) {
return SCPI::getResultName(SCPI::Result::Error);
}
try {
auto ts = Touchstone::fromFile(params[0].toStdString());
unsigned long long index1, index2 = 0;
if(!SCPI::paramToULongLong(params, 1, index1)) {
return SCPI::getResultName(SCPI::Result::Error);
}
if(!SCPI::paramToULongLong(params, 2, index1)) {
return SCPI::getResultName(SCPI::Result::Error);
}
setMeasurement(ts, index1-1, index2-1);
return SCPI::getResultName(SCPI::Result::Empty);
} catch(const std::exception& e) {
// failed to load file
return SCPI::getResultName(SCPI::Result::Error);
}
}, nullptr, false));
Virtual::setupSCPI();
}
Through::Through()
{
Z0 = 50.0;
delay = 0.0;
loss = 0.0;
setupSCPI();
}
Sparam Through::toSparam(double freq)
@ -675,9 +770,18 @@ void Through::fromJSON(nlohmann::json j)
loss = j.value("loss", 0.0);
}
void Through::setupSCPI()
{
addDoubleParameter("Z0", Z0, true, true, [=](){clearMeasurement();});
addDoubleParameter("DELAY", delay, true, true, [=](){clearMeasurement();});
addDoubleParameter("LOSS", loss, true, true, [=](){clearMeasurement();});
TwoPort::setupSCPI();
}
Reflect::Reflect()
{
isShort = true;
setupSCPI();
}
std::complex<double> Reflect::toS11(double freq)
@ -724,10 +828,17 @@ bool Reflect::getIsShort() const
return isShort;
}
void Reflect::setupSCPI()
{
addBoolParameter("SHORT", isShort, true, true, [=](){clearMeasurement();});
OnePort::setupSCPI();
}
Line::Line()
{
Z0 = 50.0;
setDelay(0.0);
setupSCPI();
}
Sparam Line::toSparam(double freq)
@ -800,3 +911,10 @@ void Line::setDelay(double delay)
minFreq = 1.0 / delay * 20 / 360;
maxFreq = 1.0 / delay * 160 / 360;
}
void Line::setupSCPI()
{
addDoubleParameter("Z0", Z0, true, true, [=](){clearMeasurement();});
addDoubleParameter("DELAY", delay, true, true, [=](){clearMeasurement();});
TwoPort::setupSCPI();
}

View file

@ -4,6 +4,7 @@
#include "savable.h"
#include "touchstone.h"
#include "Tools/parameters.h"
#include "scpi.h"
#include <complex>
#include <functional>
@ -11,7 +12,7 @@
namespace CalStandard
{
class Virtual : public QObject, public Savable
class Virtual : public QObject, public Savable, public SCPINode
{
Q_OBJECT
public:
@ -53,6 +54,7 @@ signals:
void deleted();
protected:
void setupSCPI();
QString name;
double minFreq;
double maxFreq;
@ -75,6 +77,7 @@ public:
virtual void fromJSON(nlohmann::json j) override;
protected:
void setupSCPI();
Touchstone *touchstone;
};
@ -85,7 +88,7 @@ class Open : public OnePort
public:
Open();
Open(QString name, double Z0, double delay, double loss, double C0, double C1, double C2, double C3)
: OnePort(name), Z0(Z0), delay(delay), loss(loss), C0(C0), C1(C1), C2(C2), C3(C3){}
: OnePort(name), Z0(Z0), delay(delay), loss(loss), C0(C0), C1(C1), C2(C2), C3(C3){setupSCPI();}
virtual std::complex<double> toS11(double freq) override;
virtual void edit(std::function<void(void)> finishedCallback = nullptr) override;
@ -93,6 +96,7 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
private:
void setupSCPI();
double Z0, delay, loss, C0, C1, C2, C3;
};
@ -101,7 +105,7 @@ class Short : public OnePort
public:
Short();
Short(QString name, double Z0, double delay, double loss, double L0, double L1, double L2, double L3)
: OnePort(name), Z0(Z0), delay(delay), loss(loss), L0(L0), L1(L1), L2(L2), L3(L3){}
: OnePort(name), Z0(Z0), delay(delay), loss(loss), L0(L0), L1(L1), L2(L2), L3(L3){setupSCPI();}
virtual std::complex<double> toS11(double freq) override;
virtual void edit(std::function<void(void)> finishedCallback = nullptr) override;
@ -109,6 +113,7 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
private:
void setupSCPI();
double Z0, delay, loss, L0, L1, L2, L3;
};
@ -117,7 +122,7 @@ class Load : public OnePort
public:
Load();
Load(QString name, double Z0, double delay, double loss, double resistance, double Cparallel, double Lseries, bool Cfirst = true)
: OnePort(name), Z0(Z0), delay(delay), loss(loss), resistance(resistance), Cparallel(Cparallel), Lseries(Lseries), Cfirst(Cfirst){}
: OnePort(name), Z0(Z0), delay(delay), loss(loss), resistance(resistance), Cparallel(Cparallel), Lseries(Lseries), Cfirst(Cfirst){setupSCPI();}
virtual std::complex<double> toS11(double freq) override;
virtual void edit(std::function<void(void)> finishedCallback = nullptr) override;
@ -125,6 +130,7 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
private:
void setupSCPI();
double Z0, delay, loss, resistance, Cparallel, Lseries;
bool Cfirst;
};
@ -144,6 +150,7 @@ public:
bool getIsShort() const;
private:
void setupSCPI();
bool isShort;
};
@ -164,6 +171,7 @@ public:
virtual void fromJSON(nlohmann::json j) override;
protected:
void setupSCPI();
Touchstone *touchstone;
};
@ -172,7 +180,7 @@ class Through : public TwoPort
public:
Through();
Through(QString name, double Z0, double delay, double loss)
: TwoPort(name), Z0(Z0), delay(delay), loss(loss){}
: TwoPort(name), Z0(Z0), delay(delay), loss(loss){setupSCPI();}
virtual Sparam toSparam(double freq) override;
virtual void edit(std::function<void(void)> finishedCallback = nullptr) override;
@ -180,6 +188,7 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
private:
void setupSCPI();
double Z0, delay, loss;
};
@ -188,7 +197,7 @@ class Line : public TwoPort
public:
Line();
Line(QString name, double Z0, double delay)
: TwoPort(name), Z0(Z0), delay(delay){}
: TwoPort(name), Z0(Z0), delay(delay){setupSCPI();}
virtual Sparam toSparam(double freq) override;
virtual void edit(std::function<void(void)> finishedCallback = nullptr) override;
@ -197,6 +206,7 @@ public:
virtual void fromJSON(nlohmann::json j) override;
private:
void setDelay(double delay);
void setupSCPI();
double Z0, delay;
};

View file

@ -344,6 +344,26 @@ bool SCPINode::addBoolParameter(QString name, bool &param, bool gettable, bool s
return add(new SCPICommand(name, cmd, query));
}
bool SCPINode::addStringParameter(QString name, QString &param, bool gettable, bool settable, std::function<void ()> setCallback)
{
auto cmd = settable ? [&param, setCallback](QStringList params) -> QString {
if(params.size() == 1) {
param = params[0];
if(setCallback) {
setCallback();
}
return SCPI::getResultName(SCPI::Result::Empty);
} else {
return SCPI::getResultName(SCPI::Result::Error);
}
} : (std::function<QString(QStringList)>) nullptr;
auto query = gettable ? [=](QStringList params) -> QString {
Q_UNUSED(params)
return param;
} : (std::function<QString(QStringList)>) nullptr;
return add(new SCPICommand(name, cmd, query));
}
bool SCPINode::changeName(QString newname)
{
if(newname == name) {

View file

@ -44,6 +44,7 @@ public:
bool addDoubleParameter(QString name, double &param, bool gettable = true, bool settable = true, std::function<void(void)> setCallback = nullptr);
bool addUnsignedIntParameter(QString name, unsigned int &param, bool gettable = true, bool settable = true, std::function<void(void)> setCallback = nullptr);
bool addBoolParameter(QString name, bool &param, bool gettable = true, bool settable = true, std::function<void(void)> setCallback = nullptr);
bool addStringParameter(QString name, QString &param, bool gettable = true, bool settable = true, std::function<void(void)> setCallback = nullptr);
bool changeName(QString newname);
QString leafName() {return name.split(":").back();}