mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-05 06:25:16 +00:00
proof-of-concept spectrum analyzer mode
This commit is contained in:
parent
76875c2316
commit
38e73365df
33 changed files with 942 additions and 82 deletions
Binary file not shown.
|
|
@ -15,6 +15,7 @@ HEADERS += \
|
|||
Device/manualcontroldialog.h \
|
||||
Generator/generator.h \
|
||||
Generator/signalgenwidget.h \
|
||||
SpectrumAnalyzer/spectrumanalyzer.h \
|
||||
Tools/eseries.h \
|
||||
Tools/impedancematchdialog.h \
|
||||
Traces/bodeplotaxisdialog.h \
|
||||
|
|
@ -57,6 +58,7 @@ SOURCES += \
|
|||
Device/manualcontroldialog.cpp \
|
||||
Generator/generator.cpp \
|
||||
Generator/signalgenwidget.cpp \
|
||||
SpectrumAnalyzer/spectrumanalyzer.cpp \
|
||||
Tools/eseries.cpp \
|
||||
Tools/impedancematchdialog.cpp \
|
||||
Traces/bodeplotaxisdialog.cpp \
|
||||
|
|
|
|||
|
|
@ -203,6 +203,14 @@ bool Device::Configure(Protocol::SweepSettings settings)
|
|||
return SendPacket(p);
|
||||
}
|
||||
|
||||
bool Device::Configure(Protocol::SpectrumAnalyzerSettings settings)
|
||||
{
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::SpectrumAnalyzerSettings;
|
||||
p.spectrumSettings = settings;
|
||||
return SendPacket(p);
|
||||
}
|
||||
|
||||
bool Device::SetManual(Protocol::ManualControl manual)
|
||||
{
|
||||
Protocol::PacketInfo p;
|
||||
|
|
@ -364,6 +372,9 @@ void Device::ReceivedData()
|
|||
case Protocol::PacketType::Status:
|
||||
emit ManualStatusReceived(packet.status);
|
||||
break;
|
||||
case Protocol::PacketType::SpectrumAnalyzerResult:
|
||||
emit SpectrumResultReceived(packet.spectrumResult);
|
||||
break;
|
||||
case Protocol::PacketType::DeviceInfo:
|
||||
lastInfo = packet.info;
|
||||
lastInfoValid = true;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
Q_DECLARE_METATYPE(Protocol::Datapoint);
|
||||
Q_DECLARE_METATYPE(Protocol::ManualStatus);
|
||||
Q_DECLARE_METATYPE(Protocol::DeviceInfo);
|
||||
Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult);
|
||||
|
||||
class USBInBuffer : public QObject {
|
||||
Q_OBJECT;
|
||||
|
|
@ -57,6 +58,7 @@ public:
|
|||
~Device();
|
||||
bool SendPacket(Protocol::PacketInfo packet, std::function<void(TransmissionResult)> cb = nullptr, unsigned int timeout = 10);
|
||||
bool Configure(Protocol::SweepSettings settings);
|
||||
bool Configure(Protocol::SpectrumAnalyzerSettings settings);
|
||||
bool SetManual(Protocol::ManualControl manual);
|
||||
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
|
||||
bool SendCommandWithoutPayload(Protocol::PacketType type);
|
||||
|
|
@ -69,6 +71,7 @@ public:
|
|||
signals:
|
||||
void DatapointReceived(Protocol::Datapoint);
|
||||
void ManualStatusReceived(Protocol::ManualStatus);
|
||||
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
|
||||
void DeviceInfoUpdated();
|
||||
void ConnectionLost();
|
||||
void AckReceived();
|
||||
|
|
|
|||
371
Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp
Normal file
371
Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
#include "spectrumanalyzer.h"
|
||||
#include <QGridLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <math.h>
|
||||
#include <QToolBar>
|
||||
#include <QMenu>
|
||||
#include <QToolButton>
|
||||
#include <QActionGroup>
|
||||
#include <QSpinBox>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QSettings>
|
||||
#include <algorithm>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFile>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <QDateTime>
|
||||
#include "unit.h"
|
||||
#include "CustomWidgets/toggleswitch.h"
|
||||
#include "Device/manualcontroldialog.h"
|
||||
#include "Traces/tracemodel.h"
|
||||
#include "Traces/tracewidget.h"
|
||||
#include "Traces/tracesmithchart.h"
|
||||
#include "Traces/tracebodeplot.h"
|
||||
#include "Traces/traceimportdialog.h"
|
||||
#include "CustomWidgets/tilewidget.h"
|
||||
#include "CustomWidgets/siunitedit.h"
|
||||
#include <QDockWidget>
|
||||
#include "Traces/markerwidget.h"
|
||||
#include "Tools/impedancematchdialog.h"
|
||||
#include "Calibration/calibrationtracedialog.h"
|
||||
#include "ui_main.h"
|
||||
#include "Device/firmwareupdatedialog.h"
|
||||
#include "preferences.h"
|
||||
#include "Generator/signalgenwidget.h"
|
||||
#include <QDesktopWidget>
|
||||
#include <QApplication>
|
||||
#include <QActionGroup>
|
||||
|
||||
SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
||||
: Mode(window, "Spectrum Analyzer"),
|
||||
pref(window->getPreferenceRef()),
|
||||
central(new TileWidget(traceModel))
|
||||
{
|
||||
averages = 1;
|
||||
|
||||
// Create default traces
|
||||
auto tPort1 = new Trace("Port1", Qt::yellow);
|
||||
tPort1->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port1);
|
||||
traceModel.addTrace(tPort1);
|
||||
auto tPort2 = new Trace("Port2", Qt::blue);
|
||||
tPort2->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port2);
|
||||
traceModel.addTrace(tPort2);
|
||||
|
||||
auto tracebode = new TraceBodePlot(traceModel);
|
||||
tracebode->enableTrace(tPort1, true);
|
||||
tracebode->enableTrace(tPort2, true);
|
||||
tracebode->setYAxis(0, TraceBodePlot::YAxisType::Magnitude, false, false, -120,0,10);
|
||||
tracebode->setYAxis(1, TraceBodePlot::YAxisType::Disabled, false, true, 0,0,1);
|
||||
|
||||
central->setPlot(tracebode);
|
||||
|
||||
// Create menu entries and connections
|
||||
// Sweep toolbar
|
||||
auto tb_sweep = new QToolBar("Sweep");
|
||||
auto eStart = new SIUnitEdit("Hz", " kMG", 6);
|
||||
eStart->setFixedWidth(100);
|
||||
eStart->setToolTip("Start frequency");
|
||||
connect(eStart, &SIUnitEdit::valueChanged, this, &SpectrumAnalyzer::SetStartFreq);
|
||||
connect(this, &SpectrumAnalyzer::startFreqChanged, eStart, &SIUnitEdit::setValueQuiet);
|
||||
tb_sweep->addWidget(new QLabel("Start:"));
|
||||
tb_sweep->addWidget(eStart);
|
||||
|
||||
auto eCenter = new SIUnitEdit("Hz", " kMG", 6);
|
||||
eCenter->setFixedWidth(100);
|
||||
eCenter->setToolTip("Center frequency");
|
||||
connect(eCenter, &SIUnitEdit::valueChanged, this, &SpectrumAnalyzer::SetCenterFreq);
|
||||
connect(this, &SpectrumAnalyzer::centerFreqChanged, eCenter, &SIUnitEdit::setValueQuiet);
|
||||
tb_sweep->addWidget(new QLabel("Center:"));
|
||||
tb_sweep->addWidget(eCenter);
|
||||
|
||||
auto eStop = new SIUnitEdit("Hz", " kMG", 6);
|
||||
eStop->setFixedWidth(100);
|
||||
eStop->setToolTip("Stop frequency");
|
||||
connect(eStop, &SIUnitEdit::valueChanged, this, &SpectrumAnalyzer::SetStopFreq);
|
||||
connect(this, &SpectrumAnalyzer::stopFreqChanged, eStop, &SIUnitEdit::setValueQuiet);
|
||||
tb_sweep->addWidget(new QLabel("Stop:"));
|
||||
tb_sweep->addWidget(eStop);
|
||||
|
||||
auto eSpan = new SIUnitEdit("Hz", " kMG", 6);
|
||||
eSpan->setFixedWidth(100);
|
||||
eSpan->setToolTip("Span");
|
||||
connect(eSpan, &SIUnitEdit::valueChanged, this, &SpectrumAnalyzer::SetSpan);
|
||||
connect(this, &SpectrumAnalyzer::spanChanged, eSpan, &SIUnitEdit::setValueQuiet);
|
||||
tb_sweep->addWidget(new QLabel("Span:"));
|
||||
tb_sweep->addWidget(eSpan);
|
||||
|
||||
auto bFull = new QPushButton(QIcon::fromTheme("zoom-fit-best"), "");
|
||||
bFull->setToolTip("Full span");
|
||||
connect(bFull, &QPushButton::clicked, this, &SpectrumAnalyzer::SetFullSpan);
|
||||
tb_sweep->addWidget(bFull);
|
||||
|
||||
auto bZoomIn = new QPushButton(QIcon::fromTheme("zoom-in"), "");
|
||||
bZoomIn->setToolTip("Zoom in");
|
||||
connect(bZoomIn, &QPushButton::clicked, this, &SpectrumAnalyzer::SpanZoomIn);
|
||||
tb_sweep->addWidget(bZoomIn);
|
||||
|
||||
auto bZoomOut = new QPushButton(QIcon::fromTheme("zoom-out"), "");
|
||||
bZoomOut->setToolTip("Zoom out");
|
||||
connect(bZoomOut, &QPushButton::clicked, this, &SpectrumAnalyzer::SpanZoomOut);
|
||||
tb_sweep->addWidget(bZoomOut);
|
||||
|
||||
window->addToolBar(tb_sweep);
|
||||
toolbars.insert(tb_sweep);
|
||||
|
||||
// Acquisition toolbar
|
||||
auto tb_acq = new QToolBar("Acquisition");
|
||||
|
||||
auto eBandwidth = new SIUnitEdit("Hz", " k", 3);
|
||||
eBandwidth->setValueQuiet(settings.RBW);
|
||||
eBandwidth->setFixedWidth(70);
|
||||
eBandwidth->setToolTip("RBW");
|
||||
connect(eBandwidth, &SIUnitEdit::valueChanged, this, &SpectrumAnalyzer::SetRBW);
|
||||
connect(this, &SpectrumAnalyzer::RBWChanged, eBandwidth, &SIUnitEdit::setValueQuiet);
|
||||
tb_acq->addWidget(new QLabel("RBW:"));
|
||||
tb_acq->addWidget(eBandwidth);
|
||||
|
||||
tb_acq->addWidget(new QLabel("Window:"));
|
||||
auto cbWindowType = new QComboBox();
|
||||
cbWindowType->addItem("None");
|
||||
cbWindowType->addItem("Kaiser");
|
||||
cbWindowType->addItem("Hann");
|
||||
cbWindowType->addItem("Flat Top");
|
||||
cbWindowType->setCurrentIndex(1);
|
||||
connect(cbWindowType, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||
settings.WindowType = index;
|
||||
SettingsChanged();
|
||||
});
|
||||
tb_acq->addWidget(cbWindowType);
|
||||
|
||||
tb_acq->addWidget(new QLabel("Detector:"));
|
||||
auto cbDetector = new QComboBox();
|
||||
cbDetector->addItem("+Peak");
|
||||
cbDetector->addItem("-Peak");
|
||||
cbDetector->addItem("Sample");
|
||||
cbDetector->addItem("Normal");
|
||||
cbDetector->addItem("Average");
|
||||
cbDetector->setCurrentIndex(0);
|
||||
connect(cbDetector, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||
settings.Detector = index;
|
||||
SettingsChanged();
|
||||
});
|
||||
tb_acq->addWidget(cbDetector);
|
||||
|
||||
auto cbSignalID = new QCheckBox("Signal ID");
|
||||
connect(cbSignalID, &QCheckBox::toggled, [=](bool enabled) {
|
||||
settings.SignalID = enabled;
|
||||
SettingsChanged();
|
||||
});
|
||||
tb_acq->addWidget(cbSignalID);
|
||||
|
||||
window->addToolBar(tb_acq);
|
||||
toolbars.insert(tb_acq);
|
||||
|
||||
|
||||
markerModel = new TraceMarkerModel(traceModel);
|
||||
|
||||
auto tracesDock = new QDockWidget("Traces");
|
||||
tracesDock->setWidget(new TraceWidget(traceModel, this, true));
|
||||
window->addDockWidget(Qt::LeftDockWidgetArea, tracesDock);
|
||||
docks.insert(tracesDock);
|
||||
|
||||
|
||||
auto markerWidget = new MarkerWidget(*markerModel);
|
||||
|
||||
auto markerDock = new QDockWidget("Marker");
|
||||
markerDock->setWidget(markerWidget);
|
||||
window->addDockWidget(Qt::BottomDockWidgetArea, markerDock);
|
||||
docks.insert(markerDock);
|
||||
|
||||
qRegisterMetaType<Protocol::SpectrumAnalyzerResult>("SpectrumResult");
|
||||
|
||||
// Set initial sweep settings
|
||||
// TODO
|
||||
// if(pref.Startup.RememberSweepSettings) {
|
||||
// LoadSweepSettings();
|
||||
// } else {
|
||||
settings.f_start = pref.Startup.DefaultSweep.start;
|
||||
settings.f_stop = pref.Startup.DefaultSweep.stop;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
SetRBW(10000);
|
||||
settings.WindowType = 1;
|
||||
settings.Detector = 0;
|
||||
settings.pointNum = 1001;
|
||||
settings.SignalID = 0;
|
||||
// }
|
||||
|
||||
finalize(central);
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::deactivate()
|
||||
{
|
||||
StoreSweepSettings();
|
||||
Mode::deactivate();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::initializeDevice()
|
||||
{
|
||||
connect(window->getDevice(), &Device::SpectrumResultReceived, this, &SpectrumAnalyzer::NewDatapoint, Qt::UniqueConnection);
|
||||
|
||||
// Configure initial state of device
|
||||
window->getDevice()->Configure(settings);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
|
||||
{
|
||||
// TODO level adjustment in device
|
||||
d.port1 /= pow(10.0, 7.5);
|
||||
d.port2 /= pow(10.0, 7.5);
|
||||
d = average.process(d);
|
||||
traceModel.addSAData(d);
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SettingsChanged()
|
||||
{
|
||||
if(window->getDevice()) {
|
||||
window->getDevice()->Configure(settings);
|
||||
}
|
||||
average.reset();
|
||||
traceModel.clearVNAData();
|
||||
TracePlot::UpdateSpan(settings.f_start, settings.f_stop);
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::StartImpedanceMatching()
|
||||
{
|
||||
auto dialog = new ImpedanceMatchDialog(*markerModel);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetStartFreq(double freq)
|
||||
{
|
||||
settings.f_start = freq;
|
||||
if(settings.f_stop < freq) {
|
||||
settings.f_stop = freq;
|
||||
}
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetStopFreq(double freq)
|
||||
{
|
||||
settings.f_stop = freq;
|
||||
if(settings.f_start > freq) {
|
||||
settings.f_start = freq;
|
||||
}
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetCenterFreq(double freq)
|
||||
{
|
||||
auto old_span = settings.f_stop - settings.f_start;
|
||||
if (freq > old_span / 2) {
|
||||
settings.f_start = freq - old_span / 2;
|
||||
settings.f_stop = freq + old_span / 2;
|
||||
} else {
|
||||
settings.f_start = 0;
|
||||
settings.f_stop = 2 * freq;
|
||||
}
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetSpan(double span)
|
||||
{
|
||||
auto old_center = (settings.f_start + settings.f_stop) / 2;
|
||||
if(old_center > span / 2) {
|
||||
settings.f_start = old_center - span / 2;
|
||||
} else {
|
||||
settings.f_start = 0;
|
||||
}
|
||||
settings.f_stop = old_center + span / 2;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetFullSpan()
|
||||
{
|
||||
settings.f_start = 0;
|
||||
settings.f_stop = 6000000000;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SpanZoomIn()
|
||||
{
|
||||
auto center = (settings.f_start + settings.f_stop) / 2;
|
||||
auto old_span = settings.f_stop - settings.f_start;
|
||||
settings.f_start = center - old_span / 4;
|
||||
settings.f_stop = center + old_span / 4;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SpanZoomOut()
|
||||
{
|
||||
auto center = (settings.f_start + settings.f_stop) / 2;
|
||||
auto old_span = settings.f_stop - settings.f_start;
|
||||
if(center > old_span) {
|
||||
settings.f_start = center - old_span;
|
||||
} else {
|
||||
settings.f_start = 0;
|
||||
}
|
||||
settings.f_stop = center + old_span;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetRBW(double bandwidth)
|
||||
{
|
||||
settings.RBW = bandwidth;
|
||||
emit RBWChanged(settings.RBW);
|
||||
SettingsChanged();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetAveraging(unsigned int averages)
|
||||
{
|
||||
this->averages = averages;
|
||||
average.setAverages(averages);
|
||||
emit averagingChanged(averages);
|
||||
SettingsChanged();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::ConstrainAndUpdateFrequencies()
|
||||
{
|
||||
// TODO central hardware limits
|
||||
if(settings.f_stop > 6000000000) {
|
||||
settings.f_stop = 6000000000;
|
||||
}
|
||||
if(settings.f_start > settings.f_stop) {
|
||||
settings.f_start = settings.f_stop;
|
||||
}
|
||||
emit startFreqChanged(settings.f_start);
|
||||
emit stopFreqChanged(settings.f_stop);
|
||||
emit spanChanged(settings.f_stop - settings.f_start);
|
||||
emit centerFreqChanged((settings.f_stop + settings.f_start)/2);
|
||||
SettingsChanged();
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::LoadSweepSettings()
|
||||
{
|
||||
// TODO
|
||||
// QSettings s;
|
||||
// settings.f_start = s.value("SweepStart", pref.Startup.DefaultSweep.start).toULongLong();
|
||||
// settings.f_stop = s.value("SweepStop", pref.Startup.DefaultSweep.stop).toULongLong();
|
||||
// ConstrainAndUpdateFrequencies();
|
||||
// SetIFBandwidth(s.value("SweepBandwidth", pref.Startup.DefaultSweep.bandwidth).toUInt());
|
||||
// SetPoints(s.value("SweepPoints", pref.Startup.DefaultSweep.points).toInt());
|
||||
// SetSourceLevel(s.value("SweepLevel", pref.Startup.DefaultSweep.excitation).toDouble());
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::StoreSweepSettings()
|
||||
{
|
||||
// TODO
|
||||
// QSettings s;
|
||||
// s.setValue("SweepStart", static_cast<unsigned long long>(settings.f_start));
|
||||
// s.setValue("SweepStop", static_cast<unsigned long long>(settings.f_stop));
|
||||
// s.setValue("SweepBandwidth", settings.if_bandwidth);
|
||||
// s.setValue("SweepPoints", settings.points);
|
||||
// s.setValue("SweepLevel", (double) settings.cdbm_excitation / 100.0);
|
||||
}
|
||||
63
Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h
Normal file
63
Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef SPECTRUMANALYZER_H
|
||||
#define SPECTRUMANALYZER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include "appwindow.h"
|
||||
#include "mode.h"
|
||||
#include "CustomWidgets/tilewidget.h"
|
||||
|
||||
class SpectrumAnalyzer : public Mode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpectrumAnalyzer(AppWindow *window);
|
||||
|
||||
void deactivate() override;
|
||||
void initializeDevice() override;
|
||||
private slots:
|
||||
void NewDatapoint(Protocol::SpectrumAnalyzerResult d);
|
||||
void StartImpedanceMatching();
|
||||
// Sweep control
|
||||
void SetStartFreq(double freq);
|
||||
void SetStopFreq(double freq);
|
||||
void SetCenterFreq(double freq);
|
||||
void SetSpan(double span);
|
||||
void SetFullSpan();
|
||||
void SpanZoomIn();
|
||||
void SpanZoomOut();
|
||||
// Acquisition control
|
||||
void SetRBW(double bandwidth);
|
||||
void SetAveraging(unsigned int averages);
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
void UpdateStatusPanel();
|
||||
void SettingsChanged();
|
||||
void ConstrainAndUpdateFrequencies();
|
||||
void LoadSweepSettings();
|
||||
void StoreSweepSettings();
|
||||
|
||||
Preferences &pref;
|
||||
|
||||
Protocol::SpectrumAnalyzerSettings settings;
|
||||
unsigned int averages;
|
||||
TraceModel traceModel;
|
||||
TraceMarkerModel *markerModel;
|
||||
Averaging average;
|
||||
|
||||
TileWidget *central;
|
||||
|
||||
signals:
|
||||
void dataChanged();
|
||||
void startFreqChanged(double freq);
|
||||
void stopFreqChanged(double freq);
|
||||
void centerFreqChanged(double freq);
|
||||
void spanChanged(double span);
|
||||
void RBWChanged(double RBW);
|
||||
|
||||
void averagingChanged(unsigned int averages);
|
||||
};
|
||||
|
||||
#endif // VNA_H
|
||||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
Trace::Trace(QString name, QColor color)
|
||||
Trace::Trace(QString name, QColor color, LiveParameter live)
|
||||
: _name(name),
|
||||
_color(color),
|
||||
_liveType(LivedataType::Overwrite),
|
||||
_liveParam(live),
|
||||
reflection(true),
|
||||
visible(true),
|
||||
paused(false),
|
||||
|
|
|
|||
|
|
@ -21,7 +21,16 @@ public:
|
|||
std::complex<double> S;
|
||||
};
|
||||
|
||||
Trace(QString name = QString(), QColor color = Qt::darkYellow);
|
||||
enum class LiveParameter {
|
||||
S11,
|
||||
S12,
|
||||
S21,
|
||||
S22,
|
||||
Port1,
|
||||
Port2,
|
||||
};
|
||||
|
||||
Trace(QString name = QString(), QColor color = Qt::darkYellow, LiveParameter live = LiveParameter::S11);
|
||||
~Trace();
|
||||
|
||||
enum class LivedataType {
|
||||
|
|
@ -29,12 +38,7 @@ public:
|
|||
MaxHold,
|
||||
MinHold,
|
||||
};
|
||||
enum class LiveParameter {
|
||||
S11,
|
||||
S12,
|
||||
S21,
|
||||
S22,
|
||||
};
|
||||
|
||||
|
||||
void clear();
|
||||
void addData(Data d);
|
||||
|
|
|
|||
|
|
@ -58,11 +58,32 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
|
|||
case Trace::LivedataType::MinHold: ui->CLiveType->setCurrentIndex(2); break;
|
||||
}
|
||||
|
||||
switch(t.liveParameter()) {
|
||||
case Trace::LiveParameter::S11:
|
||||
case Trace::LiveParameter::S12:
|
||||
case Trace::LiveParameter::S21:
|
||||
case Trace::LiveParameter::S22:
|
||||
VNAtrace = true;
|
||||
ui->CLiveParam->addItem("S11");
|
||||
ui->CLiveParam->addItem("S12");
|
||||
ui->CLiveParam->addItem("S21");
|
||||
ui->CLiveParam->addItem("S22");
|
||||
break;
|
||||
case Trace::LiveParameter::Port1:
|
||||
case Trace::LiveParameter::Port2:
|
||||
ui->CLiveParam->addItem("Port 1");
|
||||
ui->CLiveParam->addItem("Port 2");
|
||||
VNAtrace = false;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(t.liveParameter()) {
|
||||
case Trace::LiveParameter::S11: ui->CLiveParam->setCurrentIndex(0); break;
|
||||
case Trace::LiveParameter::S12: ui->CLiveParam->setCurrentIndex(1); break;
|
||||
case Trace::LiveParameter::S21: ui->CLiveParam->setCurrentIndex(2); break;
|
||||
case Trace::LiveParameter::S22: ui->CLiveParam->setCurrentIndex(3); break;
|
||||
case Trace::LiveParameter::Port1: ui->CLiveParam->setCurrentIndex(0); break;
|
||||
case Trace::LiveParameter::Port2: ui->CLiveParam->setCurrentIndex(1); break;
|
||||
}
|
||||
|
||||
connect(ui->GSource, qOverload<int>(&QButtonGroup::buttonClicked), updateFileStatus);
|
||||
|
|
@ -100,11 +121,18 @@ void TraceEditDialog::on_buttonBox_accepted()
|
|||
case 1: type = Trace::LivedataType::MaxHold; break;
|
||||
case 2: type = Trace::LivedataType::MinHold; break;
|
||||
}
|
||||
switch(ui->CLiveParam->currentIndex()) {
|
||||
case 0: param = Trace::LiveParameter::S11; break;
|
||||
case 1: param = Trace::LiveParameter::S12; break;
|
||||
case 2: param = Trace::LiveParameter::S21; break;
|
||||
case 3: param = Trace::LiveParameter::S22; break;
|
||||
if(VNAtrace) {
|
||||
switch(ui->CLiveParam->currentIndex()) {
|
||||
case 0: param = Trace::LiveParameter::S11; break;
|
||||
case 1: param = Trace::LiveParameter::S12; break;
|
||||
case 2: param = Trace::LiveParameter::S21; break;
|
||||
case 3: param = Trace::LiveParameter::S22; break;
|
||||
}
|
||||
} else {
|
||||
switch(ui->CLiveParam->currentIndex()) {
|
||||
case 0: param = Trace::LiveParameter::Port1; break;
|
||||
case 1: param = Trace::LiveParameter::Port2; break;
|
||||
}
|
||||
}
|
||||
trace.fromLivedata(type, param);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ private:
|
|||
void setColor(QColor c);
|
||||
Ui::TraceEditDialog *ui;
|
||||
Trace &trace;
|
||||
bool VNAtrace;
|
||||
};
|
||||
|
||||
#endif // TRACEEDITDIALOG_H
|
||||
|
|
|
|||
|
|
@ -119,28 +119,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="CLiveParam">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>S11</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>S12</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>S21</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>S22</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="CLiveParam"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -148,6 +148,27 @@ void TraceModel::addVNAData(Protocol::Datapoint d)
|
|||
case Trace::LiveParameter::S12: td.S = complex<double>(d.real_S12, d.imag_S12); break;
|
||||
case Trace::LiveParameter::S21: td.S = complex<double>(d.real_S21, d.imag_S21); break;
|
||||
case Trace::LiveParameter::S22: td.S = complex<double>(d.real_S22, d.imag_S22); break;
|
||||
default:
|
||||
// not a VNA trace, skip
|
||||
continue;
|
||||
}
|
||||
t->addData(td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceModel::addSAData(Protocol::SpectrumAnalyzerResult d)
|
||||
{
|
||||
for(auto t : traces) {
|
||||
if (t->isLive()) {
|
||||
Trace::Data td;
|
||||
td.frequency = d.frequency;
|
||||
switch(t->liveParameter()) {
|
||||
case Trace::LiveParameter::Port1: td.S = complex<double>(d.port1, 0); break;
|
||||
case Trace::LiveParameter::Port2: td.S = complex<double>(d.port2, 0); break;
|
||||
default:
|
||||
// not a SA trace, skip
|
||||
continue;
|
||||
}
|
||||
t->addData(td);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ signals:
|
|||
public slots:
|
||||
void clearVNAData();
|
||||
void addVNAData(Protocol::Datapoint d);
|
||||
void addSAData(Protocol::SpectrumAnalyzerResult d);
|
||||
|
||||
private:
|
||||
std::vector<Trace*> traces;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
#include "traceexportdialog.h"
|
||||
#include <QFileDialog>
|
||||
|
||||
TraceWidget::TraceWidget(TraceModel &model, QWidget *parent) :
|
||||
TraceWidget::TraceWidget(TraceModel &model, QWidget *parent, bool SA) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::TraceWidget),
|
||||
model(model)
|
||||
model(model),
|
||||
SA(SA)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->view->setModel(&model);
|
||||
|
|
@ -27,7 +28,8 @@ TraceWidget::~TraceWidget()
|
|||
void TraceWidget::on_add_clicked()
|
||||
{
|
||||
createCount++;
|
||||
auto t = new Trace("Trace #"+QString::number(createCount));
|
||||
auto liveParam = SA ? Trace::LiveParameter::Port1 : Trace::LiveParameter::S11;
|
||||
auto t = new Trace("Trace #"+QString::number(createCount), Qt::darkYellow, liveParam);
|
||||
t->setColor(QColor::fromHsl((createCount * 50) % 360, 250, 128));
|
||||
model.addTrace(t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class TraceWidget : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TraceWidget(TraceModel &model, QWidget *parent = nullptr);
|
||||
explicit TraceWidget(TraceModel &model, QWidget *parent = nullptr, bool SA = false);
|
||||
~TraceWidget();
|
||||
|
||||
public slots:
|
||||
|
|
@ -36,6 +36,7 @@ private:
|
|||
Ui::TraceWidget *ui;
|
||||
TraceModel &model;
|
||||
int createCount;
|
||||
bool SA;
|
||||
};
|
||||
|
||||
#endif // TRACEWIDGET_H
|
||||
|
|
|
|||
|
|
@ -85,9 +85,6 @@ VNA::VNA(AppWindow *window)
|
|||
central->Child2()->Child1()->setPlot(tracebode2);
|
||||
central->Child2()->Child2()->setPlot(tracesmith2);
|
||||
|
||||
// central widget is constructed, mode can be finalized
|
||||
finalize(central);
|
||||
|
||||
// Create menu entries and connections
|
||||
auto calMenu = new QMenu("Calibration");
|
||||
window->menuBar()->insertMenu(window->getUi()->menuWindow->menuAction(), calMenu);
|
||||
|
|
@ -437,6 +434,16 @@ VNA::VNA(AppWindow *window)
|
|||
SetIFBandwidth(pref.Startup.DefaultSweep.bandwidth);
|
||||
SetPoints(pref.Startup.DefaultSweep.points);
|
||||
}
|
||||
|
||||
// Set ObjectName for toolbars and docks
|
||||
for(auto d : findChildren<QDockWidget*>()) {
|
||||
d->setObjectName(d->windowTitle());
|
||||
}
|
||||
for(auto t : findChildren<QToolBar*>()) {
|
||||
t->setObjectName(t->windowTitle());
|
||||
}
|
||||
|
||||
finalize(central);
|
||||
}
|
||||
|
||||
void VNA::deactivate()
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <mode.h>
|
||||
#include "VNA/vna.h"
|
||||
#include "Generator/generator.h"
|
||||
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -71,6 +72,7 @@ AppWindow::AppWindow(QWidget *parent)
|
|||
CreateToolbars();
|
||||
auto logDock = new QDockWidget("Device Log");
|
||||
logDock->setWidget(&deviceLog);
|
||||
logDock->setObjectName("Log Dock");
|
||||
addDockWidget(Qt::BottomDockWidgetArea, logDock);
|
||||
|
||||
// fill toolbar/dock menu
|
||||
|
|
@ -88,6 +90,7 @@ AppWindow::AppWindow(QWidget *parent)
|
|||
setCentralWidget(central);
|
||||
auto vna = new VNA(this);
|
||||
new Generator(this);
|
||||
new SpectrumAnalyzer(this);
|
||||
// auto signalGenWidget = new Signalgenerator;
|
||||
// modeSGen = new GUIMode(this, "Signal Generator", signalGenWidget);
|
||||
|
||||
|
|
@ -122,14 +125,6 @@ AppWindow::AppWindow(QWidget *parent)
|
|||
restoreGeometry(settings.value("geometry").toByteArray());
|
||||
}
|
||||
|
||||
// Set ObjectName for toolbars and docks
|
||||
for(auto d : findChildren<QDockWidget*>()) {
|
||||
d->setObjectName(d->windowTitle());
|
||||
}
|
||||
for(auto t : findChildren<QToolBar*>()) {
|
||||
t->setObjectName(t->windowTitle());
|
||||
}
|
||||
|
||||
// Set default mode
|
||||
vna->activate();
|
||||
|
||||
|
|
@ -248,6 +243,7 @@ void AppWindow::CreateToolbars()
|
|||
connect(toolbars.reference.outputEnabled, &QCheckBox::clicked, this, &AppWindow::UpdateReference);
|
||||
|
||||
addToolBar(tb_reference);
|
||||
tb_reference->setObjectName("Reference Toolbar");
|
||||
}
|
||||
|
||||
Preferences &AppWindow::getPreferenceRef()
|
||||
|
|
|
|||
|
|
@ -68,6 +68,40 @@ Protocol::Datapoint Averaging::process(Protocol::Datapoint d)
|
|||
return d;
|
||||
}
|
||||
|
||||
Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerResult d)
|
||||
{
|
||||
if (d.pointNum == avg.size()) {
|
||||
// add moving average entry
|
||||
deque<array<complex<double>, 4>> deque;
|
||||
avg.push_back(deque);
|
||||
}
|
||||
|
||||
if (d.pointNum < avg.size()) {
|
||||
// can compute average
|
||||
// get correct queue
|
||||
auto deque = &avg[d.pointNum];
|
||||
// add newest sample to queue
|
||||
array<complex<double>, 4> sample = {d.port1, d.port2, 0, 0};
|
||||
deque->push_back(sample);
|
||||
if(deque->size() > averages) {
|
||||
deque->pop_front();
|
||||
}
|
||||
|
||||
// calculate average
|
||||
complex<double> sum[4];
|
||||
for(auto s : *deque) {
|
||||
sum[0] += s[0];
|
||||
sum[1] += s[1];
|
||||
sum[2] += s[2];
|
||||
sum[3] += s[3];
|
||||
}
|
||||
d.port1 = abs(sum[0] / (double) (deque->size()));
|
||||
d.port2 = abs(sum[1] / (double) (deque->size()));
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
unsigned int Averaging::getLevel()
|
||||
{
|
||||
if(avg.size() > 0) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ public:
|
|||
void reset();
|
||||
void setAverages(unsigned int a);
|
||||
Protocol::Datapoint process(Protocol::Datapoint d);
|
||||
Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult d);
|
||||
unsigned int getLevel();
|
||||
private:
|
||||
std::vector<std::deque<std::array<std::complex<double>, 4>>> avg;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ void Mode::activate()
|
|||
|
||||
// restore visibility of toolbars and docks
|
||||
// window->getUi()->menuDocks->clear();
|
||||
for(auto d : window->findChildren<QDockWidget*>()) {
|
||||
for(auto d : docks) {
|
||||
// window->getUi()->menuDocks->addAction(d->toggleViewAction());
|
||||
bool hidden = settings.value("dock_"+name+"_"+d->windowTitle(), d->isHidden()).toBool();
|
||||
if(hidden) {
|
||||
|
|
@ -78,7 +78,7 @@ void Mode::activate()
|
|||
}
|
||||
}
|
||||
// window->getUi()->menuToolbars->clear();
|
||||
for(auto t : window->findChildren<QToolBar*>()) {
|
||||
for(auto t : toolbars) {
|
||||
// window->getUi()->menuToolbars->addAction(t->toggleViewAction());
|
||||
bool hidden = settings.value("toolbar_"+name+"_"+t->windowTitle(), t->isHidden()).toBool();
|
||||
if(hidden) {
|
||||
|
|
@ -99,10 +99,10 @@ void Mode::deactivate()
|
|||
{
|
||||
QSettings settings;
|
||||
// save dock/toolbar visibility
|
||||
for(auto d : window->findChildren<QDockWidget*>()) {
|
||||
for(auto d : docks) {
|
||||
settings.setValue("dock_"+name+"_"+d->windowTitle(), d->isHidden());
|
||||
}
|
||||
for(auto t : window->findChildren<QToolBar*>()) {
|
||||
for(auto t : toolbars) {
|
||||
settings.setValue("toolbar_"+name+"_"+t->windowTitle(), t->isHidden());
|
||||
}
|
||||
// settings.setValue("geometry_"+name, window->saveGeometry());
|
||||
|
|
@ -133,6 +133,13 @@ void Mode::finalize(QWidget *centralWidget)
|
|||
{
|
||||
central = centralWidget;
|
||||
window->getCentral()->addWidget(central);
|
||||
// Set ObjectName for toolbars and docks
|
||||
for(auto d : docks) {
|
||||
d->setObjectName(d->windowTitle()+name);
|
||||
}
|
||||
for(auto t : toolbars) {
|
||||
t->setObjectName(t->windowTitle()+name);
|
||||
}
|
||||
// hide all mode specific GUI elements
|
||||
for(auto t : toolbars) {
|
||||
t->hide();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue