Improve load time of setup files by omitting excessive device configuration

This commit is contained in:
Jan Käberich 2022-10-30 12:07:59 +01:00
parent 2f5cbc80e9
commit eff18a22e8
7 changed files with 213 additions and 173 deletions

View File

@ -64,6 +64,11 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
normalize.measure = nullptr;
normalize.enable = nullptr;
configurationTimer.setSingleShot(true);
connect(&configurationTimer, &QTimer::timeout, this, [=](){
ConfigureDevice();
});
traceModel.setSource(TraceModel::DataSource::SA);
// Create default traces
@ -543,77 +548,7 @@ void SpectrumAnalyzer::NewDatapoint(VirtualDevice::SAMeasurement m)
void SpectrumAnalyzer::SettingsChanged()
{
if(running) {
changingSettings = true;
if(settings.freqStop - settings.freqStart >= 1000 || settings.freqStop - settings.freqStart <= 0) {
settings.points = 1001;
} else {
settings.points = settings.freqStop - settings.freqStart + 1;
}
if(settings.trackingGenerator && settings.freqStop >= 25000000) {
// Check point spacing.
// The highband PLL used as the tracking generator is not able to reach every frequency exactly. This
// could lead to sharp drops in the spectrum at certain frequencies. If the span is wide enough with
// respect to the point number, it is ensured that every displayed point has at least one sample with
// a reachable PLL frequency in it. Display a warning message if this is not the case with the current
// settings.
auto pointSpacing = (settings.freqStop - settings.freqStart) / (settings.points - 1);
// The frequency resolution of the PLL is frequency dependent (due to PLL divider).
// This code assumes some knowledge of the actual hardware and probably should be moved
// onto the device at some point
double minSpacing = 25000;
auto stop = settings.freqStop;
while(stop <= 3000000000) {
minSpacing /= 2;
stop *= 2;
}
if(pointSpacing < minSpacing) {
auto requiredMinSpan = minSpacing * (settings.points - 1);
auto message = QString() + "Due to PLL limitations, the tracking generator can not reach every frequency exactly. "
"With your current span, this could result in the signal not being detected at some bands. A minimum"
" span of " + Unit::ToString(requiredMinSpan, "Hz", " kMG") + " is recommended at this stop frequency.";
InformationBox::ShowMessage("Warning", message, "TrackingGeneratorSpanTooSmallWarning");
}
}
if(normalize.active) {
// check if normalization is still valid
if(normalize.f_start != settings.freqStart || normalize.f_stop != settings.freqStop || normalize.points != settings.points) {
// normalization was taken at different settings, disable
EnableNormalization(false);
InformationBox::ShowMessage("Information", "Normalization was disabled because the span has been changed");
}
}
if(window->getDevice() && isActive) {
window->getDevice()->setSA(settings, [=](bool){
// device received command
changingSettings = false;
});
emit sweepStarted();
} else {
// no device, unable to start sweep
emit sweepStopped();
changingSettings = false;
}
average.reset(settings.points);
UpdateAverageCount();
traceModel.clearLiveData();
emit traceModel.SpanChanged(settings.freqStart, settings.freqStop);
} else {
if(window->getDevice()) {
changingSettings = true;
// single sweep finished
window->getDevice()->setIdle([=](bool){
emit sweepStopped();
changingSettings = false;
});
} else {
emit sweepStopped();
changingSettings = false;
}
}
configurationTimer.start(100);
}
void SpectrumAnalyzer::SetStartFreq(double freq)
@ -718,7 +653,9 @@ void SpectrumAnalyzer::SetSingleSweep(bool single)
singleSweep = single;
emit singleSweepChanged(single);
}
SettingsChanged();
if(single) {
Run();
}
}
void SpectrumAnalyzer::SetRBW(double bandwidth)
@ -888,13 +825,88 @@ void SpectrumAnalyzer::SetNormalizationLevel(double level)
void SpectrumAnalyzer::Run()
{
running = true;
SettingsChanged();
ConfigureDevice();
}
void SpectrumAnalyzer::Stop()
{
running = false;
SettingsChanged();
ConfigureDevice();
}
void SpectrumAnalyzer::ConfigureDevice()
{
if(running) {
changingSettings = true;
if(settings.freqStop - settings.freqStart >= 1000 || settings.freqStop - settings.freqStart <= 0) {
settings.points = 1001;
} else {
settings.points = settings.freqStop - settings.freqStart + 1;
}
if(settings.trackingGenerator && settings.freqStop >= 25000000) {
// Check point spacing.
// The highband PLL used as the tracking generator is not able to reach every frequency exactly. This
// could lead to sharp drops in the spectrum at certain frequencies. If the span is wide enough with
// respect to the point number, it is ensured that every displayed point has at least one sample with
// a reachable PLL frequency in it. Display a warning message if this is not the case with the current
// settings.
auto pointSpacing = (settings.freqStop - settings.freqStart) / (settings.points - 1);
// The frequency resolution of the PLL is frequency dependent (due to PLL divider).
// This code assumes some knowledge of the actual hardware and probably should be moved
// onto the device at some point
double minSpacing = 25000;
auto stop = settings.freqStop;
while(stop <= 3000000000) {
minSpacing /= 2;
stop *= 2;
}
if(pointSpacing < minSpacing) {
auto requiredMinSpan = minSpacing * (settings.points - 1);
auto message = QString() + "Due to PLL limitations, the tracking generator can not reach every frequency exactly. "
"With your current span, this could result in the signal not being detected at some bands. A minimum"
" span of " + Unit::ToString(requiredMinSpan, "Hz", " kMG") + " is recommended at this stop frequency.";
InformationBox::ShowMessage("Warning", message, "TrackingGeneratorSpanTooSmallWarning");
}
}
if(normalize.active) {
// check if normalization is still valid
if(normalize.f_start != settings.freqStart || normalize.f_stop != settings.freqStop || normalize.points != settings.points) {
// normalization was taken at different settings, disable
EnableNormalization(false);
InformationBox::ShowMessage("Information", "Normalization was disabled because the span has been changed");
}
}
if(window->getDevice() && isActive) {
window->getDevice()->setSA(settings, [=](bool){
// device received command
changingSettings = false;
});
emit sweepStarted();
} else {
// no device, unable to start sweep
emit sweepStopped();
changingSettings = false;
}
average.reset(settings.points);
UpdateAverageCount();
traceModel.clearLiveData();
emit traceModel.SpanChanged(settings.freqStart, settings.freqStop);
} else {
if(window->getDevice()) {
changingSettings = true;
// single sweep finished
window->getDevice()->setIdle([=](bool){
emit sweepStopped();
changingSettings = false;
});
} else {
emit sweepStopped();
changingSettings = false;
}
}
}
void SpectrumAnalyzer::SetupSCPI()

View File

@ -73,6 +73,7 @@ private slots:
void Run();
void Stop();
void ConfigureDevice();
private:
void SetupSCPI();
@ -89,6 +90,8 @@ private:
unsigned int averages;
bool singleSweep;
bool running;
QTimer configurationTimer;
double firstPointTime; // timestamp of the first point in the sweep, only use when zerospan is used
TraceModel traceModel;
TraceWidget *traceWidget;

View File

@ -69,6 +69,11 @@ VNA::VNA(AppWindow *window, QString name)
traceModel.setSource(TraceModel::DataSource::VNA);
configurationTimer.setSingleShot(true);
connect(&configurationTimer, &QTimer::timeout, this, [=](){
ConfigureDevice();
});
// Create default traces
createDefaultTracesAndGraphs(2);
@ -886,7 +891,7 @@ void VNA::NewDatapoint(VirtualDevice::VNAMeasurement m)
} else {
settings.activeSegment = 0;
}
SettingsChanged(false);
SettingsChanged();
}
}
@ -895,95 +900,9 @@ void VNA::UpdateAverageCount()
lAverages->setText(QString::number(average.getLevel()) + "/");
}
void VNA::SettingsChanged(bool resetTraces, std::function<void (bool)> cb)
void VNA::SettingsChanged()
{
if(running) {
if (resetTraces) {
settings.activeSegment = 0;
}
changingSettings = true;
// assemble VNA protocol settings
VirtualDevice::VNASettings s = {};
s.IFBW = settings.bandwidth;
if(Preferences::getInstance().Acquisition.alwaysExciteAllPorts) {
for(unsigned int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
s.excitedPorts.push_back(i);
}
} else {
for(unsigned int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
if(traceModel.PortExcitationRequired(i))
s.excitedPorts.push_back(i);
}
}
settings.excitedPorts = s.excitedPorts;
double start = settings.sweepType == SweepType::Frequency ? settings.Freq.start : settings.Power.start;
double stop = settings.sweepType == SweepType::Frequency ? settings.Freq.stop : settings.Power.stop;
int npoints = settings.npoints;
emit traceModel.SpanChanged(start, stop);
if (settings.segments > 1) {
// more than one segment, adjust start/stop
npoints = ceil((double) settings.npoints / settings.segments);
unsigned int segmentStartPoint = npoints * settings.activeSegment;
unsigned int segmentStopPoint = segmentStartPoint + npoints - 1;
if(segmentStopPoint >= settings.npoints) {
segmentStopPoint = settings.npoints - 1;
npoints = settings.npoints - segmentStartPoint;
}
auto seg_start = Util::Scale<double>(segmentStartPoint, 0, settings.npoints - 1, start, stop);
auto seg_stop = Util::Scale<double>(segmentStopPoint, 0, settings.npoints - 1, start, stop);
start = seg_start;
stop = seg_stop;
}
if(settings.sweepType == SweepType::Frequency) {
s.freqStart = start;
s.freqStop = stop;
s.points = npoints;
s.dBmStart = settings.Freq.excitation_power;
s.dBmStop = settings.Freq.excitation_power;
s.logSweep = settings.Freq.logSweep;
} else if(settings.sweepType == SweepType::Power) {
s.freqStart = settings.Power.frequency;
s.freqStop = settings.Power.frequency;
s.points = npoints;
s.dBmStart = start;
s.dBmStop = stop;
s.logSweep = false;
}
if(window->getDevice() && isActive) {
window->getDevice()->setVNA(s, [=](bool res){
// device received command, reset traces now
if (resetTraces) {
average.reset(settings.npoints);
traceModel.clearLiveData();
UpdateAverageCount();
UpdateCalWidget();
}
if(cb) {
cb(res);
}
changingSettings = false;
});
emit sweepStarted();
} else {
// no device, unable to start sweep
emit sweepStopped();
changingSettings = false;
}
} else {
if(window->getDevice()) {
changingSettings = true;
// single sweep finished
window->getDevice()->setIdle([=](bool){
emit sweepStopped();
changingSettings = false;
});
} else {
emit sweepStopped();
changingSettings = false;
}
}
configurationTimer.start(100);
}
void VNA::StartImpedanceMatching()
@ -1268,7 +1187,7 @@ void VNA::StartCalibrationMeasurements(std::set<CalibrationMeasurement::Base*> m
cal.clearMeasurements(calMeasurements);
});
// Trigger sweep to start from beginning
SettingsChanged(true, [=](bool){
ConfigureDevice(true, [=](bool){
// enable calibration measurement only in transmission callback (prevents accidental sampling of data which was still being processed)
calMeasuring = true;
});
@ -1693,20 +1612,111 @@ void VNA::SetSingleSweep(bool single)
emit singleSweepChanged(single);
}
if(single) {
SettingsChanged();
Run();
}
}
void VNA::Run()
{
running = true;
SettingsChanged();
ConfigureDevice();
}
void VNA::Stop()
{
running = false;
SettingsChanged();
ConfigureDevice(false);
}
void VNA::ConfigureDevice(bool resetTraces, std::function<void(bool)> cb)
{
if(running) {
if (resetTraces) {
settings.activeSegment = 0;
}
changingSettings = true;
// assemble VNA protocol settings
VirtualDevice::VNASettings s = {};
s.IFBW = settings.bandwidth;
if(Preferences::getInstance().Acquisition.alwaysExciteAllPorts) {
for(unsigned int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
s.excitedPorts.push_back(i);
}
} else {
for(unsigned int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
if(traceModel.PortExcitationRequired(i))
s.excitedPorts.push_back(i);
}
}
settings.excitedPorts = s.excitedPorts;
double start = settings.sweepType == SweepType::Frequency ? settings.Freq.start : settings.Power.start;
double stop = settings.sweepType == SweepType::Frequency ? settings.Freq.stop : settings.Power.stop;
int npoints = settings.npoints;
emit traceModel.SpanChanged(start, stop);
if (settings.segments > 1) {
// more than one segment, adjust start/stop
npoints = ceil((double) settings.npoints / settings.segments);
unsigned int segmentStartPoint = npoints * settings.activeSegment;
unsigned int segmentStopPoint = segmentStartPoint + npoints - 1;
if(segmentStopPoint >= settings.npoints) {
segmentStopPoint = settings.npoints - 1;
npoints = settings.npoints - segmentStartPoint;
}
auto seg_start = Util::Scale<double>(segmentStartPoint, 0, settings.npoints - 1, start, stop);
auto seg_stop = Util::Scale<double>(segmentStopPoint, 0, settings.npoints - 1, start, stop);
start = seg_start;
stop = seg_stop;
}
if(settings.sweepType == SweepType::Frequency) {
s.freqStart = start;
s.freqStop = stop;
s.points = npoints;
s.dBmStart = settings.Freq.excitation_power;
s.dBmStop = settings.Freq.excitation_power;
s.logSweep = settings.Freq.logSweep;
} else if(settings.sweepType == SweepType::Power) {
s.freqStart = settings.Power.frequency;
s.freqStop = settings.Power.frequency;
s.points = npoints;
s.dBmStart = start;
s.dBmStop = stop;
s.logSweep = false;
}
if(window->getDevice() && isActive) {
window->getDevice()->setVNA(s, [=](bool res){
// device received command, reset traces now
if (resetTraces) {
average.reset(settings.npoints);
traceModel.clearLiveData();
UpdateAverageCount();
UpdateCalWidget();
}
if(cb) {
cb(res);
}
changingSettings = false;
});
emit sweepStarted();
} else {
// no device, unable to start sweep
emit sweepStopped();
changingSettings = false;
}
} else {
if(window->getDevice()) {
changingSettings = true;
// single sweep finished
window->getDevice()->setIdle([=](bool){
emit sweepStopped();
changingSettings = false;
});
} else {
emit sweepStopped();
changingSettings = false;
}
}
}
bool VNA::LoadCalibration(QString filename)

View File

@ -116,7 +116,7 @@ private:
bool CalibrationMeasurementActive() { return calWaitFirst || calMeasuring; }
void SetupSCPI();
void UpdateAverageCount();
void SettingsChanged(bool resetTraces = true, std::function<void(bool)> cb = nullptr);
void SettingsChanged();
void ConstrainAndUpdateFrequencies();
void LoadSweepSettings();
void StoreSweepSettings();
@ -129,6 +129,7 @@ private slots:
void SetSingleSweep(bool single);
void Run();
void Stop();
void ConfigureDevice(bool resetTraces = true, std::function<void(bool)> cb = nullptr);
private:
Settings settings;
unsigned int averages;
@ -138,6 +139,7 @@ private:
Averaging average;
bool singleSweep;
bool running;
QTimer configurationTimer;
// Calibration
Calibration cal;

View File

@ -1140,6 +1140,14 @@ void AppWindow::LoadSetup(nlohmann::json j)
toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off")));
}
// Disconnect device prior to deleting and creating new modes. This prevents excessice and unnnecessary configuration of the device
QString serial = QString();
if(vdevice->getConnected()) {
serial = vdevice->serial();
delete vdevice;
vdevice = nullptr;
}
modeHandler->closeModes();
/* old style VNA/Generator/Spectrum Analyzer settings,
@ -1170,6 +1178,11 @@ void AppWindow::LoadSetup(nlohmann::json j)
}
}
// reconnect to device
if(!serial.isEmpty()) {
vdevice = new VirtualDevice(serial);
}
// activate the correct mode
QString modeName = QString::fromStdString(j.value("activeMode", ""));
for(auto m : modeHandler->getModes()) {

View File

@ -23,17 +23,17 @@ void ModeHandler::shutdown()
int ModeHandler::createMode(QString name, Mode::Type t)
{
auto mode = createNew(aw, name, t);
return createMode(mode);
return addMode(mode);
}
int ModeHandler::createMode(Mode *mode)
int ModeHandler::addMode(Mode *mode)
{
modes.push_back(mode);
currentModeIndex = int(modes.size()) - 1;
connect(mode, &Mode::statusbarMessage, this, &ModeHandler::setStatusBarMessageChanged);
auto m = getMode(currentModeIndex);
activate(m);
// auto m = getMode(currentModeIndex);
// activate(m);
emit ModeCreated(currentModeIndex);
return (currentModeIndex);

View File

@ -46,7 +46,7 @@ public slots:
private:
std::vector<Mode*> modes;
int currentModeIndex;
int createMode(Mode *mode);
int addMode(Mode *mode);
Mode *createNew(AppWindow *window, QString name, Mode::Type t);
AppWindow *aw;
Mode *activeMode;