Include mode/sweep/acquisition settings in setup files
This commit is contained in:
parent
cf22f40630
commit
68dc9842e9
Binary file not shown.
@ -245,6 +245,8 @@ This dock shows the debug output of the \vna{} (the same messages as on the inte
|
||||
\subsubsection{File Menu}
|
||||
Changing the default setup of the application can require a lot of configuration, especially if some of the more complicated math or de-embedding options are used. To simplify this process, setup-files can be saved and opened, which perform these steps automatically. A setup file contains all settings and configuration of these elements:
|
||||
\begin{itemize}
|
||||
\item Sweep and Acquisition settings (start/stop frequency, IF bandwidth, ...)
|
||||
\item The currently active mode (VNA, Signalgenerator or Spectrumanalyzer)
|
||||
\item Traces (Name, Color, Parameters, ...)
|
||||
\item Math operations applied to the traces
|
||||
\item Markers
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user