Include mode/sweep/acquisition settings in setup files

This commit is contained in:
Jan Käberich 2021-09-03 19:01:22 +02:00
parent cf22f40630
commit 68dc9842e9
13 changed files with 316 additions and 19 deletions

View file

@ -40,6 +40,19 @@ void Generator::initializeDevice()
updateDevice();
}
nlohmann::json Generator::toJSON()
{
return central->toJSON();
}
void Generator::fromJSON(nlohmann::json j)
{
if(j.is_null()) {
return;
}
central->fromJSON(j);
}
void Generator::updateDevice()
{
if(!window->getDevice() || Mode::getActiveMode() != this) {

View file

@ -13,8 +13,8 @@ public:
void initializeDevice() override;
// Nothing to do for now
virtual nlohmann::json toJSON() override {return nlohmann::json();};
virtual void fromJSON(nlohmann::json j) override {Q_UNUSED(j)};
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
private slots:
void updateDevice();

View file

@ -157,6 +157,44 @@ Protocol::GeneratorSettings SignalgeneratorWidget::getDeviceStatus()
return s;
}
nlohmann::json SignalgeneratorWidget::toJSON()
{
nlohmann::json j;
j["frequency"] = ui->frequency->value();
j["power"] = ui->levelSpin->value();
if(ui->EnablePort1->isChecked()) {
j["port"] = 1;
} else if(ui->EnablePort2->isChecked()) {
j["port"] = 2;
} else {
j["port"] = 0;
}
nlohmann::json sweep;
sweep["span"] = ui->span->value();
sweep["steps"] = ui->steps->value();
sweep["dwell"] = ui->dwell->value();
sweep["enabled"] = ui->EnabledSweep->isChecked();
j["sweep"] = sweep;
return j;
}
void SignalgeneratorWidget::fromJSON(nlohmann::json j)
{
setFrequency(j.value("frequency", ui->frequency->value()));
setLevel(j.value("power", ui->levelSpin->value()));
setPort(j.value("port", 0));
if(j.contains("sweep")) {
auto sweep = j["sweep"];
// extract sweep settings, keeping current values as default
ui->span->setValue(sweep.value("span", ui->span->value()));
ui->steps->setValue(sweep.value("steps", ui->steps->value()));
ui->dwell->setValue(sweep.value("dwell", ui->dwell->value()));
ui->EnabledSweep->setChecked(sweep.value("enabled", false));
} else {
ui->EnabledSweep->setChecked(false);
}
}
void SignalgeneratorWidget::setLevel(double level)
{
// TODO constrain to frequency dependent levels

View file

@ -3,12 +3,13 @@
#include <QWidget>
#include "Device/device.h"
#include "savable.h"
namespace Ui {
class SignalgeneratorWidget;
}
class SignalgeneratorWidget : public QWidget
class SignalgeneratorWidget : public QWidget, public Savable
{
Q_OBJECT
@ -17,6 +18,8 @@ public:
~SignalgeneratorWidget();
Protocol::GeneratorSettings getDeviceStatus();
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
signals:
void SettingsChanged();

View file

@ -181,7 +181,7 @@
<item row="0" column="1">
<widget class="SIUnitEdit" name="span">
<property name="text">
<string>0MHz</string>
<string/>
</property>
</widget>
</item>
@ -195,7 +195,7 @@
<item row="1" column="1">
<widget class="SIUnitEdit" name="steps">
<property name="text">
<string>100</string>
<string/>
</property>
</widget>
</item>
@ -209,7 +209,7 @@
<item row="2" column="1">
<widget class="SIUnitEdit" name="dwell">
<property name="text">
<string>100ms</string>
<string/>
</property>
</widget>
</item>
@ -226,7 +226,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>0MHz</string>
<string/>
</property>
<property name="readOnly">
<bool>true</bool>

View file

@ -297,6 +297,37 @@ void SpectrumAnalyzer::initializeDevice()
nlohmann::json SpectrumAnalyzer::toJSON()
{
nlohmann::json j;
// save current sweep/acquisition settings
nlohmann::json sweep;
nlohmann::json freq;
freq["start"] = settings.f_start;
freq["stop"] = settings.f_stop;
sweep["frequency"] = freq;
nlohmann::json acq;
acq["RBW"] = settings.RBW;
acq["window"] = WindowToString((Window) settings.WindowType).toStdString();
acq["detector"] = DetectorToString((Detector) settings.Detector).toStdString();
acq["signal ID"] = settings.SignalID ? true : false;
sweep["acquisition"] = acq;
nlohmann::json tracking;
tracking["enabled"] = settings.trackingGenerator ? true : false;
tracking["port"] = settings.trackingGeneratorPort ? 2 : 1;
tracking["offset"] = settings.trackingGeneratorOffset;
tracking["power"] = settings.trackingPower;
sweep["trackingGenerator"] = tracking;
if(normalize.active) {
nlohmann::json norm;
norm["start"] = normalize.f_start;
norm["stop"] = normalize.f_stop;
norm["points"] = normalize.points;
norm["level"] = normalize.Level->value();
norm["port1"] = normalize.port1Correction;
norm["port2"] = normalize.port2Correction;
sweep["normalization"] = norm;
}
j["sweep"] = sweep;
j["traces"] = traceModel.toJSON();
j["tiles"] = central->toJSON();
j["markers"] = markerModel->toJSON();
@ -305,6 +336,9 @@ nlohmann::json SpectrumAnalyzer::toJSON()
void SpectrumAnalyzer::fromJSON(nlohmann::json j)
{
if(j.is_null()) {
return;
}
if(j.contains("traces")) {
traceModel.fromJSON(j["traces"]);
}
@ -314,6 +348,63 @@ void SpectrumAnalyzer::fromJSON(nlohmann::json j)
if(j.contains("markers")) {
markerModel->fromJSON(j["markers"]);
}
if(j.contains("sweep")) {
// restore sweep settings
auto sweep = j["sweep"];
if(sweep.contains("frequency")) {
auto freq = sweep["frequency"];
SetStartFreq(freq.value("start", settings.f_start));
SetStartFreq(freq.value("start", settings.f_start));
}
if(sweep.contains("acquisition")) {
auto acq = sweep["acquisition"];
SetRBW(acq.value("RBW", settings.RBW));
auto w = WindowFromString(QString::fromStdString(acq.value("window", "")));
if(w == Window::Last) {
// invalid, keep current value
w = (Window) settings.WindowType;
}
SetWindow(w);
auto d = DetectorFromString(QString::fromStdString(acq.value("detector", "")));
if(d == Detector::Last) {
// invalid, keep current value
d = (Detector) settings.Detector;
}
SetDetector(d);
SetSignalID(acq.value("signal ID", settings.SignalID ? true : false));
}
if(sweep.contains("trackingGenerator")) {
auto tracking = sweep["trackingGenerator"];
SetTGEnabled(tracking.value("enabled", settings.trackingGenerator ? true : false));
int port = tracking.value("port", 1);
// Function expects 0 for port1, 1 for port2
SetTGPort(port - 1);
SetTGLevel(tracking.value("power", settings.trackingPower));
SetTGOffset(tracking.value("offset", settings.trackingGeneratorOffset));
}
if(sweep.contains("normalization")) {
auto norm = sweep["normalization"];
// restore normalization data
normalize.port1Correction.clear();
for(double p1 : norm["port1"]) {
normalize.port1Correction.push_back(p1);
}
normalize.port2Correction.clear();
for(double p2 : norm["port2"]) {
normalize.port2Correction.push_back(p2);
}
normalize.f_start = norm.value("start", normalize.f_start);
normalize.f_stop = norm.value("stop", normalize.f_stop);
normalize.points = norm.value("points", normalize.points);
normalize.Level->setValue(norm.value("level", normalize.Level->value()));
if((normalize.port1Correction.size() == normalize.points) && (normalize.port1Correction.size() == normalize.points)) {
// got the correct number of points
EnableNormalization(true);
} else {
EnableNormalization(false);
}
}
}
}
using namespace std;
@ -570,7 +661,7 @@ void SpectrumAnalyzer::SetTGEnabled(bool enabled)
void SpectrumAnalyzer::SetTGPort(int port)
{
if(port < 01 || port > 1) {
if(port < 0 || port > 1) {
return;
}
if(port != settings.trackingGeneratorPort) {
@ -971,3 +1062,48 @@ void SpectrumAnalyzer::updateGraphColors()
{
emit graphColorsChanged();
}
QString SpectrumAnalyzer::WindowToString(SpectrumAnalyzer::Window w)
{
switch(w) {
case Window::None: return "None";
case Window::Kaiser: return "Kaiser";
case Window::Hann: return "Hann";
case Window::FlatTop: return "FlatTop";
default: return "Unknown";
}
}
SpectrumAnalyzer::Window SpectrumAnalyzer::WindowFromString(QString s)
{
for(int i=0;i<(int)Window::Last;i++) {
if(WindowToString((Window) i) == s) {
return (Window) i;
}
}
// not found
return Window::Last;
}
QString SpectrumAnalyzer::DetectorToString(SpectrumAnalyzer::Detector d)
{
switch(d) {
case Detector::PPeak: return "+Peak";
case Detector::NPeak: return "-Peak";
case Detector::Sample: return "Sample";
case Detector::Normal: return "Normal";
case Detector::Average: return "Average";
default: return "Unknown";
}
}
SpectrumAnalyzer::Detector SpectrumAnalyzer::DetectorFromString(QString s)
{
for(int i=0;i<(int)Detector::Last;i++) {
if(DetectorToString((Detector) i) == s) {
return (Detector) i;
}
}
// not found
return Detector::Last;
}

View file

@ -32,7 +32,8 @@ private:
None = 0,
Kaiser = 1,
Hann = 2,
FlatTop = 3
FlatTop = 3,
Last
};
enum class Detector {
PPeak = 0,
@ -40,8 +41,14 @@ private:
Sample = 2,
Normal = 3,
Average = 4,
Last
};
static QString WindowToString(Window w);
static Window WindowFromString(QString s);
static QString DetectorToString(Detector d);
static Detector DetectorFromString(QString s);
private slots:
void NewDatapoint(Protocol::SpectrumAnalyzerResult d);
void StartImpedanceMatching();

View file

@ -560,6 +560,8 @@ Calibration::InterpolationType VNA::getCalInterpolation()
{
double f_min, f_max;
switch(settings.sweepType) {
case SweepType::Last:
// should never get here, use frequency values just in case
case SweepType::Frequency:
f_min = settings.Freq.start;
f_max = settings.Freq.stop;
@ -678,6 +680,23 @@ void VNA::shutdown()
nlohmann::json VNA::toJSON()
{
nlohmann::json j;
// save current sweep/acquisition settings
nlohmann::json sweep;
sweep["type"] = SweepTypeToString(settings.sweepType).toStdString();
nlohmann::json freq;
freq["start"] = settings.Freq.start;
freq["stop"] = settings.Freq.stop;
freq["power"] = settings.Freq.excitation_power;
sweep["frequency"] = freq;
nlohmann::json power;
power["start"] = settings.Power.start;
power["stop"] = settings.Power.stop;
power["frequency"] = settings.Power.frequency;
sweep["power"] = power;
sweep["points"] = settings.npoints;
sweep["IFBW"] = settings.bandwidth;
j["sweep"] = sweep;
j["traces"] = traceModel.toJSON();
j["tiles"] = central->toJSON();
j["markers"] = markerModel->toJSON();
@ -688,6 +707,9 @@ nlohmann::json VNA::toJSON()
void VNA::fromJSON(nlohmann::json j)
{
if(j.is_null()) {
return;
}
if(j.contains("traces")) {
traceModel.fromJSON(j["traces"]);
}
@ -703,6 +725,32 @@ void VNA::fromJSON(nlohmann::json j)
} else {
EnableDeembedding(false);
}
// sweep configuration has to go last sog graphs can catch events from changed sweep
if(j.contains("sweep")) {
auto sweep = j["sweep"];
// restore sweep settings, keep current value as default in case of missing entry
SetPoints(sweep.value("points", settings.npoints));
SetIFBandwidth(sweep.value("IFBW", settings.bandwidth));
if(sweep.contains("frequency")) {
auto freq = sweep["frequency"];
SetStartFreq(freq.value("start", settings.Freq.start));
SetStopFreq(freq.value("stop", settings.Freq.stop));
SetSourceLevel(freq.value("power", settings.Freq.excitation_power));
}
if(sweep.contains("power")) {
auto power = sweep["power"];
SetStartPower(power.value("start", settings.Power.start));
SetStopPower(power.value("stop", settings.Power.stop));
SetPowerSweepFrequency(power.value("frequency", settings.Power.frequency));
}
auto type = SweepTypeFromString(QString::fromStdString(sweep["type"]));
if(type == SweepType::Last) {
// default to frequency sweep
type = SweepType::Frequency;
}
SetSweepType(type);
}
}
using namespace std;
@ -735,6 +783,7 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
TraceMath::DataType type;
switch(settings.sweepType) {
case SweepType::Last:
case SweepType::Frequency:
type = TraceMath::DataType::Frequency;
break;
@ -793,16 +842,21 @@ void VNA::SettingsChanged(std::function<void (Device::TransmissionResult)> cb)
s.cdbm_excitation_stop = settings.Power.stop * 100;
}
if(window->getDevice() && Mode::getActiveMode() == this) {
window->getDevice()->Configure(s, [=](Device::TransmissionResult res){
// device received command, reset traces now
average.reset(s.points);
traceModel.clearLiveData();
UpdateAverageCount();
UpdateCalWidget();
if(cb) {
cb(res);
}
});
if(s.excitePort1 == 0 && s.excitePort2 == 0) {
// no signal at either port, just set the device to idel
window->getDevice()->SetIdle();
} else {
window->getDevice()->Configure(s, [=](Device::TransmissionResult res){
// device received command, reset traces now
average.reset(s.points);
traceModel.clearLiveData();
UpdateAverageCount();
UpdateCalWidget();
if(cb) {
cb(res);
}
});
}
}
emit traceModel.SpanChanged(s.f_start, s.f_stop);
}
@ -1374,3 +1428,23 @@ void VNA::updateGraphColors()
{
emit graphColorsChanged();
}
QString VNA::SweepTypeToString(VNA::SweepType sw)
{
switch(sw) {
case SweepType::Frequency: return "Frequency";
case SweepType::Power: return "Power";
default: return "Unknown";
}
}
VNA::SweepType VNA::SweepTypeFromString(QString s)
{
for(int i=0;i<(int)SweepType::Last;i++) {
if(SweepTypeToString((SweepType) i) == s) {
return (SweepType) i;
}
}
// not found
return SweepType::Last;
}

View file

@ -32,7 +32,12 @@ public:
enum class SweepType {
Frequency = 0,
Power = 1,
Last,
};
static QString SweepTypeToString(SweepType sw);
static SweepType SweepTypeFromString(QString s);
using Settings = struct {
SweepType sweepType;
struct {

View file

@ -911,6 +911,7 @@ void AppWindow::FrequencyCalibrationDialog()
nlohmann::json AppWindow::SaveSetup()
{
nlohmann::json j;
j["activeMode"] = Mode::getActiveMode()->getName().toStdString();
j["VNA"] = vna->toJSON();
j["Generator"] = generator->toJSON();
j["SpectrumAnalyzer"] = spectrumAnalyzer->toJSON();
@ -924,6 +925,16 @@ void AppWindow::LoadSetup(nlohmann::json j)
vna->fromJSON(j["VNA"]);
generator->fromJSON(j["Generator"]);
spectrumAnalyzer->fromJSON(j["SpectrumAnalyzer"]);
// activate the correct mode
QString modeName = QString::fromStdString(j.value("activeMode", ""));
std::vector<Mode*> modes = {vna, generator, spectrumAnalyzer};
for(auto m : modes) {
if(m->getName() == modeName) {
m->activate();
break;
}
}
}
Device *AppWindow::getDevice() const

View file

@ -88,6 +88,14 @@ void Mode::activate()
}
activeMode = this;
// force activation of correct pushbutton in case the mode switch was done via script/setup load.
// This will trigger a second activation of this mode in the signal of the button, but since it is
// already the active mode, this function will just return -> no recursion
for(auto b : modeButtonGroup->buttons()) {
if(b->text() == name) {
b->click();
}
}
if(window->getDevice()) {
initializeDevice();