Zerospan mode for spectrum analyzer mode

This commit is contained in:
Jan Käberich 2022-06-26 22:53:12 +02:00
parent 6adac7ebb4
commit 8492b38936
9 changed files with 96 additions and 16 deletions

View File

@ -573,6 +573,9 @@ These commands change or query spectrum analyzer settings. Although most of them
\subsubsection{SA:FREQuency:FULL} \subsubsection{SA:FREQuency:FULL}
\event{Sets the device to the maximum span possible}{SA:FREQuency:FULL}{None} \event{Sets the device to the maximum span possible}{SA:FREQuency:FULL}{None}
\subsubsection{SA:FREQuency:ZERO}
\event{Sets the device to zero span mode}{SA:FREQuency:ZERO}{None}
\subsubsection{SA:ACQuisition:RBW} \subsubsection{SA:ACQuisition:RBW}
\event{Sets the resolution bandwidth}{SA:ACQuisition:IFBW}{<resolution bandwidth>, in Hz} \event{Sets the resolution bandwidth}{SA:ACQuisition:IFBW}{<resolution bandwidth>, in Hz}
\query{Queries the currently selected resolution bandwidth}{SA:ACQuisition:IFBW?}{None}{resolution bandwidth in Hz} \query{Queries the currently selected resolution bandwidth}{SA:ACQuisition:IFBW?}{None}{resolution bandwidth in Hz}

View File

@ -135,6 +135,13 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
connect(bZoomOut, &QPushButton::clicked, this, &SpectrumAnalyzer::SpanZoomOut); connect(bZoomOut, &QPushButton::clicked, this, &SpectrumAnalyzer::SpanZoomOut);
tb_sweep->addWidget(bZoomOut); tb_sweep->addWidget(bZoomOut);
auto bZero = new QPushButton("0");
bZero->setToolTip("Zero span");
bZero->setMaximumWidth(28);
bZero->setMaximumHeight(24);
connect(bZero, &QPushButton::clicked, this, &SpectrumAnalyzer::SetZeroSpan);
tb_sweep->addWidget(bZero);
window->addToolBar(tb_sweep); window->addToolBar(tb_sweep);
toolbars.insert(tb_sweep); toolbars.insert(tb_sweep);
@ -450,6 +457,16 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
d = average.process(d); d = average.process(d);
if(settings.f_start == settings.f_stop) {
// keep track of first point time
if(d.pointNum == 0) {
firstPointTime = d.us;
d.us = 0;
} else {
d.us -= firstPointTime;
}
}
if(normalize.measuring) { if(normalize.measuring) {
if(average.currentSweep() == averages) { if(average.currentSweep() == averages) {
// this is the last averaging sweep, use values for normalization // this is the last averaging sweep, use values for normalization
@ -464,7 +481,7 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
normalize.f_stop = settings.f_stop; normalize.f_stop = settings.f_stop;
normalize.points = settings.pointNum; normalize.points = settings.pointNum;
EnableNormalization(true); EnableNormalization(true);
qDebug() << "Normalization measuremen complete"; qDebug() << "Normalization measurement complete";
} }
} }
} }
@ -496,7 +513,7 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
void SpectrumAnalyzer::SettingsChanged() void SpectrumAnalyzer::SettingsChanged()
{ {
changingSettings = true; changingSettings = true;
if(settings.f_stop - settings.f_start >= 1000) { if(settings.f_stop - settings.f_start >= 1000 || settings.f_stop - settings.f_start <= 0) {
settings.pointNum = 1001; settings.pointNum = 1001;
} else { } else {
settings.pointNum = settings.f_stop - settings.f_start + 1; settings.pointNum = settings.f_stop - settings.f_start + 1;
@ -505,10 +522,16 @@ void SpectrumAnalyzer::SettingsChanged()
settings.applySourceCorrection = 1; settings.applySourceCorrection = 1;
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
if(!settings.trackingGenerator && pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) { if(settings.f_stop > settings.f_start) {
// Enable DFT if below RBW threshold and TG is not enabled // non-zerospan, check usability of DFT
settings.UseDFT = 1; if(!settings.trackingGenerator && pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) {
// Enable DFT if below RBW threshold and TG is not enabled
settings.UseDFT = 1;
} else {
settings.UseDFT = 0;
}
} else { } else {
// zerospan, DFT not usable
settings.UseDFT = 0; settings.UseDFT = 0;
} }
@ -620,6 +643,13 @@ void SpectrumAnalyzer::SetFullSpan()
ConstrainAndUpdateFrequencies(); ConstrainAndUpdateFrequencies();
} }
void SpectrumAnalyzer::SetZeroSpan()
{
auto center = (settings.f_start + settings.f_stop) / 2;
SetStartFreq(center);
SetStopFreq(center);
}
void SpectrumAnalyzer::SpanZoomIn() void SpectrumAnalyzer::SpanZoomIn()
{ {
auto center = (settings.f_start + settings.f_stop) / 2; auto center = (settings.f_start + settings.f_stop) / 2;
@ -853,6 +883,11 @@ void SpectrumAnalyzer::SetupSCPI()
SetFullSpan(); SetFullSpan();
return ""; return "";
}, nullptr)); }, nullptr));
scpi_freq->add(new SCPICommand("ZERO", [=](QStringList params) -> QString {
Q_UNUSED(params)
SetZeroSpan();
return "";
}, nullptr));
auto scpi_acq = new SCPINode("ACQuisition"); auto scpi_acq = new SCPINode("ACQuisition");
SCPINode::add(scpi_acq); SCPINode::add(scpi_acq);
scpi_acq->add(new SCPICommand("RBW", [=](QStringList params) -> QString { scpi_acq->add(new SCPICommand("RBW", [=](QStringList params) -> QString {

View File

@ -61,6 +61,7 @@ private slots:
void SetCenterFreq(double freq); void SetCenterFreq(double freq);
void SetSpan(double span); void SetSpan(double span);
void SetFullSpan(); void SetFullSpan();
void SetZeroSpan();
void SpanZoomIn(); void SpanZoomIn();
void SpanZoomOut(); void SpanZoomOut();
void SetSingleSweep(bool single); void SetSingleSweep(bool single);
@ -92,6 +93,7 @@ private:
bool changingSettings; bool changingSettings;
unsigned int averages; unsigned int averages;
bool singleSweep; bool singleSweep;
double firstPointTime; // timestamp of the first point in the sweep, only use when zerospan is used
TraceModel traceModel; TraceModel traceModel;
TraceWidget *traceWidget; TraceWidget *traceWidget;
MarkerModel *markerModel; MarkerModel *markerModel;

View File

@ -120,11 +120,16 @@ void Trace::addData(const Trace::Data& d, DataType domain, double reference_impe
emit outputSamplesChanged(index, index + 1); emit outputSamplesChanged(index, index + 1);
} }
void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettings &s) void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettings &s, int index)
{ {
settings.SA = s; settings.SA = s;
settings.valid = true; settings.valid = true;
addData(d, DataType::Frequency); auto domain = DataType::Frequency;
if (s.f_start == s.f_stop) {
// in zerospan mode
domain = DataType::TimeZeroSpan;
}
addData(d, domain, 50.0, index);
} }
void Trace::setName(QString name) { void Trace::setName(QString name) {

View File

@ -46,15 +46,15 @@ public:
void clear(); void clear();
void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1); void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1);
void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s); void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s, int index = -1);
void setName(QString name); void setName(QString name);
void setVelocityFactor(double v); void setVelocityFactor(double v);
void fillFromTouchstone(Touchstone &t, unsigned int parameter); void fillFromTouchstone(Touchstone &t, unsigned int parameter);
QString fillFromCSV(CSV &csv, unsigned int parameter); // returns the suggested trace name (not yet set in member data) QString fillFromCSV(CSV &csv, unsigned int parameter); // returns the suggested trace name (not yet set in member data)
static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data); static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data);
void fromLivedata(LivedataType type, LiveParameter param); void fromLivedata(LivedataType type, LiveParameter param);
QString name() { return _name; }; QString name() { return _name; }
QColor color() { return _color; }; QColor color() { return _color; }
bool isVisible(); bool isVisible();
void pause(); void pause();
void resume(); void resume();
@ -65,7 +65,7 @@ public:
bool isReflection(); bool isReflection();
LiveParameter liveParameter() { return _liveParam; } LiveParameter liveParameter() { return _liveParam; }
LivedataType liveType() { return _liveType; } LivedataType liveType() { return _liveType; }
TraceMath::DataType outputType() const { return lastMath->getDataType(); }; TraceMath::DataType outputType() const { return lastMath->getDataType(); }
unsigned int size() const; unsigned int size() const;
double minX(); double minX();
double maxX(); double maxX();
@ -123,7 +123,7 @@ public:
virtual nlohmann::json toJSON() override; virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override; virtual void fromJSON(nlohmann::json j) override;
Type getType() override {return Type::Last;}; // can return invalid type, this will never be called Type getType() override {return Type::Last;} // can return invalid type, this will never be called
// Traces are referenced by pointers throughout this project (e.g. when added to a graph) // Traces are referenced by pointers throughout this project (e.g. when added to a graph)
// When saving the current graph configuration, the pointer is not useful. Instead a trace // When saving the current graph configuration, the pointer is not useful. Instead a trace

View File

@ -248,8 +248,15 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
source = DataSource::SA; source = DataSource::SA;
for(auto t : traces) { for(auto t : traces) {
if (t->isLive() && !t->isPaused()) { if (t->isLive() && !t->isPaused()) {
int index = -1;
Trace::Data td; Trace::Data td;
td.x = d.frequency; if(settings.f_start == settings.f_stop) {
// in zerospan mode, insert data by index
index = d.pointNum;
td.x = (double) d.us / 1000000.0;
} else {
td.x = d.frequency;
}
switch(t->liveParameter()) { switch(t->liveParameter()) {
case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 0); break; case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 0); break;
case Trace::LiveParameter::Port2: td.y = complex<double>(d.port2, 0); break; case Trace::LiveParameter::Port2: td.y = complex<double>(d.port2, 0); break;
@ -257,7 +264,7 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
// not a SA trace, skip // not a SA trace, skip
continue; continue;
} }
t->addData(td, settings); t->addData(td, settings, index);
} }
} }
} }

View File

@ -152,7 +152,16 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
float port1; float port1;
float port2; float port2;
uint64_t frequency; union {
struct {
// for non-zero span
uint64_t frequency;
};
struct {
// for zero span
uint64_t us; // time in us since first datapoint
};
};
uint16_t pointNum; uint16_t pointNum;
}; };

View File

@ -36,6 +36,10 @@ static uint8_t attenuator;
static int64_t trackingFreq; static int64_t trackingFreq;
static bool trackingLowband; static bool trackingLowband;
static uint64_t firstPointTime;
static bool firstPoint;
static bool zerospan;
static void StartNextSample() { static void StartNextSample() {
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1); uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
freq = Cal::FrequencyCorrectionToDevice(freq); freq = Cal::FrequencyCorrectionToDevice(freq);
@ -205,6 +209,8 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
points += s.pointNum - points % s.pointNum; points += s.pointNum - points % s.pointNum;
binSize = points / s.pointNum; binSize = points / s.pointNum;
LOG_DEBUG("%u displayed points, resulting in %lu points and bins of size %u", s.pointNum, points, binSize); LOG_DEBUG("%u displayed points, resulting in %lu points and bins of size %u", s.pointNum, points, binSize);
zerospan = (s.f_start == s.f_stop);
// set initial state // set initial state
pointCnt = 0; pointCnt = 0;
// enable the required hardware resources // enable the required hardware resources
@ -256,6 +262,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
} }
lastLO2 = 0; lastLO2 = 0;
firstPoint = true;
active = true; active = true;
StartNextSample(); StartNextSample();
} }
@ -375,7 +382,19 @@ void SA::Work() {
// Send result to application // Send result to application
p.type = Protocol::PacketType::SpectrumAnalyzerResult; p.type = Protocol::PacketType::SpectrumAnalyzerResult;
// measurements are already up to date, fill remaining fields // measurements are already up to date, fill remaining fields
p.spectrumResult.frequency = s.f_start + (s.f_stop - s.f_start) * binIndex / (s.pointNum - 1); if(zerospan) {
uint64_t timestamp = HW::getLastISRTimestamp();
if(firstPoint) {
p.spectrumResult.us = 0;
firstPointTime = timestamp;
firstPoint = false;
} else {
p.spectrumResult.us = timestamp - firstPointTime;
}
} else {
// non-zero span, set frequency
p.spectrumResult.frequency = s.f_start + (s.f_stop - s.f_start) * binIndex / (s.pointNum - 1);
}
// scale approximately (constant determined empirically) // scale approximately (constant determined empirically)
p.spectrumResult.port1 /= 253000000.0; p.spectrumResult.port1 /= 253000000.0;
p.spectrumResult.port2 /= 253000000.0; p.spectrumResult.port2 /= 253000000.0;