peak trace: initial work
This commit is contained in:
@@ -994,7 +994,7 @@ void Application::renderWaterfallPanel() {
|
||||
|
||||
measurements_.drawWaterfall(specDisplay_, wfPosX_, wfPosY_, wfSizeX_, wfSizeY_,
|
||||
settings_.sampleRate, settings_.isIQ, freqScale_,
|
||||
viewLo_, viewHi_);
|
||||
viewLo_, viewHi_, screenRows, analyzer_.spectrumSize());
|
||||
|
||||
// ── Mouse interaction: zoom, pan & hover on waterfall ──
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
@@ -70,6 +70,14 @@ void Measurements::update(const std::vector<float>& spectrumDB,
|
||||
globalPeak_.bin = bin;
|
||||
globalPeak_.dB = *it;
|
||||
globalPeak_.freq = binToFreq(bin, sampleRate, isIQ, fftSize);
|
||||
|
||||
// Push into peak history circular buffer
|
||||
constexpr int kMaxHistory = 4096;
|
||||
if (static_cast<int>(peakHistBins_.size()) < kMaxHistory)
|
||||
peakHistBins_.resize(kMaxHistory, -1);
|
||||
peakHistIdx_ = (peakHistIdx_ + 1) % kMaxHistory;
|
||||
peakHistBins_[peakHistIdx_] = bin;
|
||||
if (peakHistLen_ < kMaxHistory) ++peakHistLen_;
|
||||
}
|
||||
|
||||
if (!enabled) { peaks_.clear(); return; }
|
||||
@@ -154,11 +162,47 @@ void Measurements::draw(const SpectrumDisplay& specDisplay,
|
||||
void Measurements::drawWaterfall(const SpectrumDisplay& specDisplay,
|
||||
float posX, float posY, float sizeX, float sizeY,
|
||||
double sampleRate, bool isIQ, FreqScale freqScale,
|
||||
float viewLo, float viewHi) const {
|
||||
if (!enabled || !showOnWaterfall || peaks_.empty()) return;
|
||||
|
||||
float viewLo, float viewHi,
|
||||
int screenRows, int spectrumSize) const {
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
|
||||
// Peak trace: red squiggly line showing peak frequency history
|
||||
if (showPeakTrace && peakHistLen_ > 1 && screenRows > 1 && spectrumSize > 0) {
|
||||
int histSize = static_cast<int>(peakHistBins_.size());
|
||||
int count = std::min(screenRows, peakHistLen_);
|
||||
ImU32 traceCol = IM_COL32(255, 30, 30, 200);
|
||||
|
||||
// Convert bin index to screen X via normalized frequency fraction
|
||||
auto binToX = [&](int bin) -> float {
|
||||
float frac = (static_cast<float>(bin) + 0.5f) / spectrumSize;
|
||||
// Map through view range
|
||||
float viewFrac = (frac - viewLo) / (viewHi - viewLo);
|
||||
return posX + viewFrac * sizeX;
|
||||
};
|
||||
|
||||
// Walk from newest (bottom) to oldest (top)
|
||||
float prevX = 0, prevY = 0;
|
||||
bool havePrev = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
int idx = (peakHistIdx_ - i + histSize) % histSize;
|
||||
int bin = peakHistBins_[idx];
|
||||
if (bin < 0) break;
|
||||
|
||||
// Y: i=0 is newest (bottom), i=count-1 is oldest (top)
|
||||
float y = posY + sizeY - (static_cast<float>(i) + 0.5f) / screenRows * sizeY;
|
||||
float x = binToX(bin);
|
||||
|
||||
if (havePrev) {
|
||||
dl->AddLine({prevX, prevY}, {x, y}, traceCol, 3.0f);
|
||||
}
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
havePrev = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical markers at current peak positions
|
||||
if (enabled && showOnWaterfall && !peaks_.empty()) {
|
||||
auto peakColor = [](int idx) -> ImU32 {
|
||||
if (idx == 0) return IM_COL32(255, 80, 80, 120);
|
||||
return IM_COL32(255, 140, 60, 80);
|
||||
@@ -174,8 +218,10 @@ void Measurements::drawWaterfall(const SpectrumDisplay& specDisplay,
|
||||
dl->AddLine({x, posY}, {x, posY + sizeY}, col, thickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Measurements::drawPanel() {
|
||||
ImGui::Checkbox("Peak trace", &showPeakTrace);
|
||||
if (!enabled) return;
|
||||
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
|
||||
@@ -25,11 +25,12 @@ public:
|
||||
float minDB, float maxDB,
|
||||
float viewLo, float viewHi) const;
|
||||
|
||||
// Draw vertical markers on the waterfall panel.
|
||||
// Draw vertical markers and peak trace on the waterfall panel.
|
||||
void drawWaterfall(const SpectrumDisplay& specDisplay,
|
||||
float posX, float posY, float sizeX, float sizeY,
|
||||
double sampleRate, bool isIQ, FreqScale freqScale,
|
||||
float viewLo, float viewHi) const;
|
||||
float viewLo, float viewHi,
|
||||
int screenRows, int spectrumSize) const;
|
||||
|
||||
// Draw sidebar panel (ImGui widgets).
|
||||
void drawPanel();
|
||||
@@ -44,11 +45,17 @@ public:
|
||||
float peakThreshold = -120.0f; // ignore peaks below this dB
|
||||
bool showOnSpectrum = true; // draw markers on spectrum
|
||||
bool showOnWaterfall = false; // draw vertical lines on waterfall
|
||||
bool showPeakTrace = false; // draw peak history curve on waterfall
|
||||
|
||||
private:
|
||||
PeakInfo globalPeak_; // always-tracked highest peak
|
||||
std::vector<PeakInfo> peaks_;
|
||||
|
||||
// Peak history for waterfall trace (circular buffer, newest at peakHistIdx_)
|
||||
std::vector<int> peakHistBins_; // bin index per waterfall line
|
||||
int peakHistIdx_ = 0;
|
||||
int peakHistLen_ = 0; // how many entries are valid
|
||||
|
||||
// Find top-N peaks with minimum bin separation.
|
||||
void findPeaks(const std::vector<float>& spectrumDB, int maxN,
|
||||
int minDist, float threshold);
|
||||
|
||||
Reference in New Issue
Block a user