fix the peak trace line running out of sync with the waterfall due to 793df68b

This commit is contained in:
2026-04-09 11:37:39 +02:00
parent bbdab305aa
commit d2ca7e745e
3 changed files with 50 additions and 30 deletions

View File

@@ -316,6 +316,10 @@ void Application::processAudio() {
// Push ALL new spectra to the waterfall so that the scroll rate // Push ALL new spectra to the waterfall so that the scroll rate
// is determined by the audio sample rate, not the display refresh. // is determined by the audio sample rate, not the display refresh.
int curCh = std::clamp(ui_.waterfallChannel, 0, nSpec - 1);
const auto& traceHist = audio_.getWaterfallHistory(curCh);
int traceHistSz = static_cast<int>(traceHist.size());
if (ui_.waterfallMultiCh && nSpec > 1) { if (ui_.waterfallMultiCh && nSpec > 1) {
// For multi-channel: replay the last spectraThisFrame entries // For multi-channel: replay the last spectraThisFrame entries
// from channel 0's history to get per-step data. Other // from channel 0's history to get per-step data. Other
@@ -353,16 +357,22 @@ void Application::processAudio() {
} }
} }
waterfall_.pushLineMulti(wfSpectra, wfInfo, ui_.minDB, ui_.maxDB); waterfall_.pushLineMulti(wfSpectra, wfInfo, ui_.minDB, ui_.maxDB);
// Push peak trace entry synchronized with each waterfall line.
int tIdx = std::max(0, traceHistSz - (histSz - si));
measurements_.pushPeakTrace(traceHist[tIdx],
settings.sampleRate, settings.isIQ, settings.fftSize);
} }
} else { } else {
int wfCh = std::clamp(ui_.waterfallChannel, 0, nSpec - 1); const auto& hist = audio_.getWaterfallHistory(curCh);
const auto& hist = audio_.getWaterfallHistory(wfCh);
int histSz = static_cast<int>(hist.size()); int histSz = static_cast<int>(hist.size());
int start = std::max(0, histSz - spectraThisFrame); int start = std::max(0, histSz - spectraThisFrame);
for (int si = start; si < histSz; ++si) for (int si = start; si < histSz; ++si) {
waterfall_.pushLine(hist[si], ui_.minDB, ui_.maxDB); waterfall_.pushLine(hist[si], ui_.minDB, ui_.maxDB);
measurements_.pushPeakTrace(hist[si],
settings.sampleRate, settings.isIQ, settings.fftSize);
}
} }
int curCh = std::clamp(ui_.waterfallChannel, 0, nSpec - 1);
cursors_.update(audio_.getSpectrum(curCh), cursors_.update(audio_.getSpectrum(curCh),
settings.sampleRate, settings.isIQ, settings.fftSize); settings.sampleRate, settings.isIQ, settings.fftSize);
measurements_.update(audio_.getSpectrum(curCh), measurements_.update(audio_.getSpectrum(curCh),

View File

@@ -61,24 +61,18 @@ void Measurements::findPeaks(const std::vector<float>& spectrumDB, int maxN,
} }
} }
void Measurements::update(const std::vector<float>& spectrumDB, void Measurements::pushPeakTrace(const std::vector<float>& spectrumDB,
double sampleRate, bool isIQ, int fftSize) { double sampleRate, bool isIQ, int fftSize) {
lastSampleRate_ = sampleRate; if (spectrumDB.empty()) return;
// Always track global peak (for the readout label).
if (!spectrumDB.empty()) {
auto it = std::max_element(spectrumDB.begin(), spectrumDB.end());
int bin = static_cast<int>(std::distance(spectrumDB.begin(), it));
globalPeak_.bin = bin;
globalPeak_.dB = *it;
globalPeak_.freq = binToFreq(bin, sampleRate, isIQ, fftSize);
// Push into peak history circular buffer (with optional freq range filter)
constexpr int kMaxHistory = 4096; constexpr int kMaxHistory = 4096;
if (static_cast<int>(peakHistBins_.size()) < kMaxHistory) if (static_cast<int>(peakHistBins_.size()) < kMaxHistory)
peakHistBins_.resize(kMaxHistory, -1); peakHistBins_.resize(kMaxHistory, -1);
// Find peak within the trace frequency range auto it = std::max_element(spectrumDB.begin(), spectrumDB.end());
int traceBin = bin; int traceBin = static_cast<int>(std::distance(spectrumDB.begin(), it));
// Optionally restrict to a frequency range.
int bins = static_cast<int>(spectrumDB.size()); int bins = static_cast<int>(spectrumDB.size());
if (traceMinFreq > 0.0f || traceMaxFreq > 0.0f) { if (traceMinFreq > 0.0f || traceMaxFreq > 0.0f) {
double fMin = isIQ ? -sampleRate / 2.0 : 0.0; double fMin = isIQ ? -sampleRate / 2.0 : 0.0;
@@ -97,6 +91,18 @@ void Measurements::update(const std::vector<float>& spectrumDB,
peakHistIdx_ = (peakHistIdx_ + 1) % kMaxHistory; peakHistIdx_ = (peakHistIdx_ + 1) % kMaxHistory;
peakHistBins_[peakHistIdx_] = traceBin; peakHistBins_[peakHistIdx_] = traceBin;
if (peakHistLen_ < kMaxHistory) ++peakHistLen_; if (peakHistLen_ < kMaxHistory) ++peakHistLen_;
}
void Measurements::update(const std::vector<float>& spectrumDB,
double sampleRate, bool isIQ, int fftSize) {
lastSampleRate_ = sampleRate;
// Always track global peak (for the readout label).
if (!spectrumDB.empty()) {
auto it = std::max_element(spectrumDB.begin(), spectrumDB.end());
int bin = static_cast<int>(std::distance(spectrumDB.begin(), it));
globalPeak_.bin = bin;
globalPeak_.dB = *it;
globalPeak_.freq = binToFreq(bin, sampleRate, isIQ, fftSize);
} }
if (!enabled) { peaks_.clear(); return; } if (!enabled) { peaks_.clear(); return; }

View File

@@ -18,6 +18,10 @@ public:
void update(const std::vector<float>& spectrumDB, void update(const std::vector<float>& spectrumDB,
double sampleRate, bool isIQ, int fftSize); double sampleRate, bool isIQ, int fftSize);
// Push a single peak trace entry for this spectrum (call once per waterfall line).
void pushPeakTrace(const std::vector<float>& spectrumDB,
double sampleRate, bool isIQ, int fftSize);
// Draw markers on the spectrum display area. // Draw markers on the spectrum display area.
void draw(const SpectrumDisplay& specDisplay, void draw(const SpectrumDisplay& specDisplay,
float posX, float posY, float sizeX, float sizeY, float posX, float posY, float sizeX, float sizeY,