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}
\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}
\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}

View File

@ -135,6 +135,13 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
connect(bZoomOut, &QPushButton::clicked, this, &SpectrumAnalyzer::SpanZoomOut);
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);
toolbars.insert(tb_sweep);
@ -450,6 +457,16 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult 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(average.currentSweep() == averages) {
// 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.points = settings.pointNum;
EnableNormalization(true);
qDebug() << "Normalization measuremen complete";
qDebug() << "Normalization measurement complete";
}
}
}
@ -496,7 +513,7 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
void SpectrumAnalyzer::SettingsChanged()
{
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;
} else {
settings.pointNum = settings.f_stop - settings.f_start + 1;
@ -505,10 +522,16 @@ void SpectrumAnalyzer::SettingsChanged()
settings.applySourceCorrection = 1;
auto pref = Preferences::getInstance();
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;
if(settings.f_stop > settings.f_start) {
// non-zerospan, check usability of DFT
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 {
// zerospan, DFT not usable
settings.UseDFT = 0;
}
@ -620,6 +643,13 @@ void SpectrumAnalyzer::SetFullSpan()
ConstrainAndUpdateFrequencies();
}
void SpectrumAnalyzer::SetZeroSpan()
{
auto center = (settings.f_start + settings.f_stop) / 2;
SetStartFreq(center);
SetStopFreq(center);
}
void SpectrumAnalyzer::SpanZoomIn()
{
auto center = (settings.f_start + settings.f_stop) / 2;
@ -853,6 +883,11 @@ void SpectrumAnalyzer::SetupSCPI()
SetFullSpan();
return "";
}, nullptr));
scpi_freq->add(new SCPICommand("ZERO", [=](QStringList params) -> QString {
Q_UNUSED(params)
SetZeroSpan();
return "";
}, nullptr));
auto scpi_acq = new SCPINode("ACQuisition");
SCPINode::add(scpi_acq);
scpi_acq->add(new SCPICommand("RBW", [=](QStringList params) -> QString {

View File

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

View File

@ -46,15 +46,15 @@ public:
void clear();
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 setVelocityFactor(double v);
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)
static void fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, const std::vector<VNAData> &data);
void fromLivedata(LivedataType type, LiveParameter param);
QString name() { return _name; };
QColor color() { return _color; };
QString name() { return _name; }
QColor color() { return _color; }
bool isVisible();
void pause();
void resume();
@ -65,7 +65,7 @@ public:
bool isReflection();
LiveParameter liveParameter() { return _liveParam; }
LivedataType liveType() { return _liveType; }
TraceMath::DataType outputType() const { return lastMath->getDataType(); };
TraceMath::DataType outputType() const { return lastMath->getDataType(); }
unsigned int size() const;
double minX();
double maxX();
@ -123,7 +123,7 @@ public:
virtual nlohmann::json toJSON() 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)
// 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;
for(auto t : traces) {
if (t->isLive() && !t->isPaused()) {
int index = -1;
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()) {
case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 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
continue;
}
t->addData(td, settings);
t->addData(td, settings, index);
}
}
}

View File

@ -152,7 +152,16 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
float port1;
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;
};

View File

@ -36,6 +36,10 @@ static uint8_t attenuator;
static int64_t trackingFreq;
static bool trackingLowband;
static uint64_t firstPointTime;
static bool firstPoint;
static bool zerospan;
static void StartNextSample() {
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
freq = Cal::FrequencyCorrectionToDevice(freq);
@ -205,6 +209,8 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
points += s.pointNum - 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);
zerospan = (s.f_start == s.f_stop);
// set initial state
pointCnt = 0;
// enable the required hardware resources
@ -256,6 +262,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
}
lastLO2 = 0;
firstPoint = true;
active = true;
StartNextSample();
}
@ -375,7 +382,19 @@ void SA::Work() {
// Send result to application
p.type = Protocol::PacketType::SpectrumAnalyzerResult;
// 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)
p.spectrumResult.port1 /= 253000000.0;
p.spectrumResult.port2 /= 253000000.0;