Skip to content

Keep spectrum visible during panadapter zoom#2246

Merged
ten9876 merged 1 commit intoten9876:mainfrom
rfoust:codex/panadapter-zoom-no-flash
May 1, 2026
Merged

Keep spectrum visible during panadapter zoom#2246
ten9876 merged 1 commit intoten9876:mainfrom
rfoust:codex/panadapter-zoom-no-flash

Conversation

@rfoust
Copy link
Copy Markdown
Contributor

@rfoust rfoust commented May 1, 2026

Summary

Fixes a panadapter display issue where the spectrum could flash or briefly blank while zooming in or out.

What changed

  • Reproject the existing FFT spectrum data across overlapping frequency ranges during zoom changes, matching the existing waterfall reprojection behavior.
  • Avoid clearing the spectrum buffers for zoom-related bandwidth changes when the old and new panadapter ranges overlap.
  • Preserve the existing clear behavior for non-overlapping jumps where old spectrum data no longer maps to the new range.

Testing

  • Built AetherSDR target successfully.
  • Ran configured CTest suite successfully.

Copilot AI review requested due to automatic review settings May 1, 2026 13:20
@rfoust rfoust requested review from jensenpat and ten9876 as code owners May 1, 2026 13:20
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the panadapter rendering path to keep the FFT spectrum trace visible during zoom operations by reprojection of existing spectrum bin data across overlapping frequency ranges (mirroring the existing waterfall reprojection behavior).

Changes:

  • Added reprojectSpectrum() to resample existing spectrum bins into the new frequency span when the old/new ranges overlap.
  • Updated zoom/frequency-range change paths to call spectrum reprojection to avoid transient blanking during zoom.
  • Preserved “clear on non-overlap” behavior for spectrum buffers in setFrequencyRange() when ranges do not overlap.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/gui/SpectrumWidget.h Declares the new reprojectSpectrum() helper used to preserve spectrum visibility across zoom changes.
src/gui/SpectrumWidget.cpp Implements spectrum reprojection and wires it into zoom and frequency-range update paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gui/SpectrumWidget.cpp Outdated
}

reprojectWaterfall(m_centerMhz, m_bandwidthMhz, newCenter, newBw);
reprojectSpectrum(m_centerMhz, m_bandwidthMhz, newCenter, newBw);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e85273d: direct zoom paths now check reprojectSpectrum() and clear m_bins/m_smoothed when the old and new ranges do not overlap, matching the intended clear-on-non-overlap behavior.

Comment thread src/gui/SpectrumWidget.cpp Outdated
return;
}

const QVector<float> oldBins = bins;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e85273d: reprojectSpectrum() now moves the source QVector into the temporary source buffer before assigning the reprojected result back, avoiding the extra full copy in the zoom path.

@aethersdr-agent
Copy link
Copy Markdown
Contributor

CI failure analysis

Hey @rfoust, thanks for the contribution! The CI failure here is not caused by your code — it's a CI infrastructure issue.

What failed

The "Cleanup artifacts" job failed at the "Delete artifacts" step (job log). This is a post-build housekeeping step that deletes temporary build artifacts and has nothing to do with compilation or tests.

The other jobs in the pipeline look fine:

  • Prepare — passed
  • Agent — passed
  • Upload results — passed
  • build — still in progress (not failed)
  • analyze (cpp) — still in progress (not failed)

What to do

Nothing on your end. This is likely a transient GitHub Actions permissions or API rate-limit issue with the artifact cleanup step. A maintainer can re-run the failed job, or it may resolve on the next push.

Copilot review notes (unrelated to CI, but worth noting)

Copilot left two suggestions on src/gui/SpectrumWidget.cpp that are worth considering as follow-ups (neither would cause a build failure):

  1. Line 248reprojectSpectrum(...) can return false when there's no frequency overlap, but the return value isn't checked in the zoom-button path. This could leave stale spectrum data visible while the waterfall clears. Consider handling the return value and clearing buffers when it returns false.

  2. Line 1028const QVector<float> oldBins = bins; copies the entire FFT bin array on every call to reprojectSpectrum(), including during continuous zoom gestures. A std::move could avoid the extra allocation on this hot path.

These are optional improvements and don't need to block this PR. Thanks for volunteering your time on this — the fix looks good! 🎙️

@rfoust rfoust force-pushed the codex/panadapter-zoom-no-flash branch from 208b29c to e85273d Compare May 1, 2026 13:35
Copy link
Copy Markdown
Contributor

@aethersdr-agent aethersdr-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, @rfoust — the approach is clean and well-scoped. Mirroring the existing reprojectWaterfall pattern for spectrum data is the right call, and the linear interpolation in reprojectBins should keep things smooth during continuous zoom gestures. CI is green.

A few observations:

m_wfWriteRow = 0 removal in setFrequencyRange (large-shift path)

The diff removes m_wfWriteRow = 0; alongside the m_bins/m_smoothed clearing at line 1056. This isn't mentioned in the PR description and is a waterfall behavioral change (not spectrum). The zoom-button and drag paths never reset m_wfWriteRow after reprojectWaterfall, so removing it here makes the large-shift path consistent — but worth confirming this was intentional rather than collateral from editing adjacent lines. If the ring buffer position was being reset to avoid visual glitches on non-overlapping band jumps, it might still be needed in the !keptSpectrum fallback path (i.e., alongside the buffer clears).

Copilot findings — both valid, both addressed

  • The stale-spectrum-on-no-overlap concern was real: reprojectSpectrum returns false without touching m_bins/m_smoothed, and all four call sites now clear them on false. Confirmed fixed in the diff.
  • The std::move optimization for the source vector is correct. const QVector<float> oldBins = std::move(bins) moves the buffer out, avoids the full copy, and bins = std::move(reprojected) puts the result back. No false positives from Copilot here.

Minor: reprojectSpectrum return value semantics

The function returns !m_bins.isEmpty() || !m_smoothed.isEmpty() — so it returns false when both buffers were already empty before the call (no FFT data received yet), even if the frequency ranges overlap. This is harmless (callers would clear already-empty vectors), but it means the return value conflates "no overlap" with "nothing to reproject." A comment clarifying this would help future readers, but not a blocker.

Everything else looks correct: changes are limited to the two stated files, no QSettings usage, no resource leaks, and the [&] capture on the reprojectBins lambda is fine since it doesn't outlive the enclosing scope. Thanks for the contribution!

@rfoust rfoust force-pushed the codex/panadapter-zoom-no-flash branch from e85273d to 8462fa1 Compare May 1, 2026 14:29
@rfoust
Copy link
Copy Markdown
Contributor Author

rfoust commented May 1, 2026

Addressed the waterfall write-row observation in 8462fa1 after local testing. The large-shift path now preserves the old reset behavior only when spectrum reprojection cannot keep data because the old/new ranges do not overlap:

  • overlapping zoom/range changes keep the existing waterfall ring position and reproject display data
  • non-overlapping large jumps clear the spectrum buffers and reset m_wfWriteRow back to 0, matching the previous fallback behavior

Verified with:

cmake --build /private/tmp/aethersdr-panadapter-zoom-build --target AetherSDR -j4
ctest --test-dir /private/tmp/aethersdr-panadapter-zoom-build --output-on-failure

@ten9876 ten9876 merged commit a01710a into ten9876:main May 1, 2026
5 checks passed
ten9876 added a commit that referenced this pull request May 2, 2026
Reliability sweep release.  Headline is jensenpat's DAX2 coexistence
policy refactor (#2271): platform-aware decision table, lazy dax_tx
stream creation, anti-stomp on incoming foreign DAX TX status, LAN
VITA UDP rebind on Flex's "Port/IP pair already in use" error, dead-
orphan DAX RX detection, and 24+ test assertions.

Substantial reliability fixes around disconnect teardown (#2247 —
sequenced stream remove with response wait, dropped self-disconnect,
dying-gasp byte), worker-thread shutdown (#2248 — no more killTimer
warnings), and panadapter zoom (#2246 — no spectrum flash).

Closes 12 issues via two paired triage-cleanup sweep PRs (#2270 +
#2272) covering small UI bugs, contrast, indicator routing, click-to-
tune behaviour, and visible regressions from recent feature work.

Also includes the #2273 follow-up to #2271: setDax() and DAX TX
stream creation are now both gated on platforms that can actually
feed DAX audio, so Linux non-PipeWire builds keep digital TX on the
physical mic input rather than going silent.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants