Add spectrum position lock#2643
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a spectrum position lock feature to the panadapter so the displayed spectrum/noise baseline can remain at a selected vertical position while range changes are automatically adjusted.
Changes:
- Adds lock state and baseline/target tracking fields to
SpectrumWidget. - Implements baseline estimation, lock target refresh/reset, smoothing, transient filtering, and dBm range command throttling.
- Adds a right-click context-menu action for toggling
Lock Spectrum Positionand disables existing noise-floor auto-adjust while active.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/gui/SpectrumWidget.h |
Declares spectrum lock helpers and state fields. |
src/gui/SpectrumWidget.cpp |
Implements lock behavior, integrates it with FFT updates, dBm dragging, zoom/range changes, and the context menu. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (on && m_measuredNoiseFloorDbm > -500.0f) { | ||
| m_spectrumLockBaselineDbm = m_measuredNoiseFloorDbm; | ||
| m_spectrumLockBaselineValid = true; | ||
| m_spectrumLockLastSampleMs = QDateTime::currentMSecsSinceEpoch(); | ||
| refreshSpectrumLocationLockTarget(); | ||
| } | ||
| } | ||
|
|
||
| void SpectrumWidget::refreshSpectrumLocationLockTarget() | ||
| { | ||
| if (m_spectrumLocationLockEnabled && !m_spectrumLockBaselineValid |
There was a problem hiding this comment.
Thanks for the well-documented PR, @rfoust — the extensive handling of zoom, manual drag, lightning-spike rejection, and smooth motion is nice work, and the refactor of the noise-floor estimator into estimateSpectrumBaselineDbm() is a clean side benefit.
A couple of suggestions:
1. Stale m_measuredNoiseFloorDbm on first enable (Copilot finding confirmed)
In setSpectrumLocationLockEnabled(true) (SpectrumWidget.cpp:813), the lock target is seeded from m_measuredNoiseFloorDbm. That EWMA (α=0.05, ~20 frames / ~0.8 s convergence) is updated continuously and is not reset on setFrequencyRange() or in the zoom paths — resetSpectrumLocationLockMeasurement() only runs when the lock is already enabled. If a user enables the lock shortly after changing bands or zoom, the seed baseline reflects the previous band and the target fraction will lock the spectrum to the wrong vertical position until the EWMA converges.
Suggested fix: on first enable, don't seed from m_measuredNoiseFloorDbm. Instead, set m_spectrumLockFreshFrameCount = 5 (the same mechanism resetSpectrumLocationLockMeasurement() already uses) and let updateSpectrumLocationLock(..., forceBaseline=true) establish baseline + target from the next fresh FFT frame.
2. Setting not persisted across sessions
Nearby panadapter context-menu toggles are persisted via AppSettings — see ExtendedFrequencyLine (SpectrumWidget.cpp:457), SingleClickTune (:455), ShowTuneGuides (:456). The new Lock Spectrum Position toggle resets every session. Consider adding a LockSpectrumPosition key to the same load/save block so it behaves like its menu neighbors.
Neither is a blocker; the rest of the implementation looks solid. 73
bc33793 to
63ea1c0
Compare
|
Updated the branch to address the stale first-enable baseline concern.
I intentionally left |
|
Hi @rfoust — thanks for the careful algorithm work on this PR. The smoothing + transient-rejection design is exactly what the existing Display → Floor: noise-floor auto-adjust needed. Closing this PR in favour of #2653, which cherry-picks your algorithm and applies it to the existing Floor: feature path instead of adding a second parallel right-click toggle. Two implementations of the same feature would have been confusing for users ("why are there two ways to lock the noise floor?") and a maintenance burden. Concretely, #2653 keeps:
And consolidates onto:
Your authorship is preserved via 73, Jeremy KK7GWY & Claude (AI dev partner) |
…ansient rejection + pan instead of zoom (#2653) Cherry-picks rfoust's algorithm work from PR #2643 (Lock Spectrum Position) and consolidates it into the existing Display → Floor: auto-adjust feature instead of adding a parallel right-click toggle. The old implementation used 20th-percentile / every-10-frames / zoom-the-span and had three visible problems: - Visible stepping as the range changed in 10-frame jumps - Span varied with the floor, making signal visual heights jump - Lightning crashes and key-up edge clicks pulled the lock immediately New algorithm (rfoust): - Per-frame baseline update with asymmetric smoothing — τ ≈ 0.08–0.12 s on drops (track noise reductions fast), τ ≈ 1.2–8 s on rises (don't chase upward transients). - Candidate-state transient filter — ≥4 dB upward shifts must persist 16 frames / 1.2 s before being adopted; downward 2 frames / 70 ms. - Pan instead of zoom: m_refLevel slides to keep the smoothed floor at the slider position; m_dynamicRange (span) stays fixed. Signals no longer change visual height when the floor drifts. - Smooth motion (τ ≈ 0.10–0.24 s) instead of 10-frame stepping. - Command throttling — ≥150 ms / ≥0.75 dB between dbmRangeChangeRequested emits. - Two-pass trimmed-mean noise-floor estimator extracted into a shared estimateNoiseFloorDbm() helper (was duplicated between the floor overlay line and the auto-adjust path). - Reset triggers in 5 zoom/band-change/dBm-drag paths so the baseline re-acquires after disruptions. Live-tested on FLEX-8600. Closes #2643 (rfoust's PR was closed in favour of this consolidation). Co-Authored-By: rfoust <rfoust@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds a right-click
Lock Spectrum Positionoption to the panadapter spectrum display.When enabled, the spectrum trace/noise floor keeps the same vertical screen position the user selected. Users can still drag the dBm scale normally; the lock records that new position and uses it as the target. As the measured spectrum baseline changes, the widget adjusts the dBm display range to bring the trace back to that target position.
The implementation also handles:
Test Plan
Built successfully with:
Manual checks to verify:
Lock Spectrum Positionfrom the spectrum context menu