fix(waterfall): remove 1 GHz ceiling in VITA-49 tile frequency decode#3457
Merged
Conversation
…hersdr#3449) The native waterfall went all-black for any transverter operating above 1 GHz (1296 MHz, 2.3/2.4 GHz) while the FFT trace stayed correct. Root cause: PanadapterStream::decodeWaterfallTile decoded FrameLowFreq / BinBandwidth by assuming VitaFrequency (Hz x 2^20), dividing, then rejecting any result > 1000.0 MHz and re-reading it as plain Hz. A real ~1296 MHz VitaFrequency value (raw ~1.359e15) tripped that ceiling, got divided by 1e6 instead of 2^20*1e6, and inflated by exactly 2^20 to ~1.359e9 MHz. Every waterfall bin then mapped outside the panadapter range, so SpectrumWidget::updateWaterfallRow left the scanline qRgb(0,0,0) -> entirely black. The ceiling has existed since the first native-waterfall commit (406dc10) and predates all the XVTR work. This is why the prior fixes never worked: PRs aethersdr#1845, aethersdr#2709 and aethersdr#2853 all edited the IF->RF remap layer (XvtrPolicy.cpp), which runs *after* the decode and was merely shifting an already-corrupted value. A support bundle on aethersdr#2835 (FLEX-6400, 1296 MHz, XVTA) shows it plainly: tile_mhz=1358902484..1359144312 pan_center_mhz=1296.065804 i.e. 1296 x 2^20. The XVTR was already valid=true, so the isValid debate was a red herring. Fix: extract the VitaFrequency-vs-plain-Hz disambiguation into a pure, unit-testable helper (src/core/VitaTileFrequency.h) that decides the encoding from the raw integer magnitude (>= 1e11 -> VitaFrequency, else plain Hz). There is a clean gap between the two encodings across the entire usable spectrum (~135 kHz to ~100 GHz), so this imposes no upper frequency limit while still supporting radios that send plain Hz. Verified on hardware (FLEX-6400, synthetic 1296 XVTR profile, XVTA): logs now show sane tile_mhz (~1296, zero garbage tiles) and the waterfall renders the noise floor instead of going black. Fixes aethersdr#3449 Fixes aethersdr#2835 Fixes aethersdr#1928 Fixes aethersdr#1843 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Codex <noreply@openai.com>
std::llabs requires <cstdlib>; with only <cmath> included it compiled on clang/libc++ (macOS) but failed on GCC/libstdc++ (Linux CI): error: 'llabs' is not a member of 'std' Switch to Qt's qAbs (already available via <QtGlobal>), which also drops the explicit cast, and remove the now-unused <cmath> include. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Codex <noreply@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The native waterfall goes all-black for any transverter operating above 1 GHz (1296 MHz, 2.3/2.4 GHz) while the FFT trace above it stays correct. This fixes the long-standing root cause behind #3449, #2835, #1928, and #1843 — none of which the previous attempts (#1845, #2709, #2853) could reach, because they were all editing the wrong layer.
Root cause
PanadapterStream::decodeWaterfallTiledecoded the VITA-49 tile'sFrameLowFreq/BinBandwidthby assuming VitaFrequency (Hz × 2²⁰), dividing, then rejecting any result> 1000.0 MHzand re-reading it as plain Hz:A real ~1296 MHz VitaFrequency value (raw ≈ 1.359e15) trips that ceiling, gets divided by
1e6instead of2²⁰·1e6, and is inflated by exactly 2²⁰ to ~1.359e9 MHz. Every waterfall bin then maps outside the panadapter range, soSpectrumWidget::updateWaterfallRowleaves the scanlineqRgb(0,0,0)→ entirely black. The FFT path has no frequency awareness, so it is unaffected. This ceiling has existed since the first native-waterfall commit (406dc100) and predates all of the XVTR work.Why the previous fixes never worked
PRs #1845, #2709, and #2853 all edited the IF→RF remap layer (
src/models/XvtrPolicy.cpp), which runs after the decode — it was merely shifting an already-corrupted value. A support bundle on #2835 (FLEX-6400, 1296 MHz, XVTA) shows it directly:i.e.
1296 × 2²⁰. The bundle also shows the XVTR entry asvalid=true rf=1296 if=28, so theisValiddebate (#2709 ↔ #2853) was a red herring — the value was destroyed six orders of magnitude upstream of any remap.Changes
src/core/VitaTileFrequency.h(new) — extracts the VitaFrequency-vs-plain-Hz disambiguation into a pure, unit-testable helper that decides the encoding from the raw integer magnitude (>= 1e11→ VitaFrequency, else plain Hz). There is a clean gap between the two encodings across the entire usable spectrum (~135 kHz to ~100 GHz), so this imposes no upper frequency limit while still supporting radios that send plain Hz.src/core/PanadapterStream.cpp— decoder now calls the helper.tests/vita_tile_frequency_test.cpp+ CMake target — regression coverage: HF, IF-domain, the 1000.015/1000.016 boundary from Waterfall breaks down on frequency higher than 1GHz #3449, 1296 / 2.3G / 2.4G, 2200 m, and plain-Hz radios.Validation
./build-ninja/vita_tile_frequency_test— all checks pass./build-ninja/xvtr_policy_test— still passes (remap layer untouched)cmake --build build-ninja --target AetherSDR --parallel 22— cleantile_mhz(~1296, zero garbage tiles), and the waterfall renders the noise floor (dark blue) instead of going black. Reversing the exact corrupted raw value from the In/out XVTA Transverter No signal in waterfall #2835 bundle through the fixed decoder recovers 1295.95 MHz.Known follow-up (out of scope)
A separate, pre-existing gap remains for transverters whose slice antenna is not named
XVT*and whose offset doesn't match a configured XVTR profile: such a tile is left in its own domain and would still not align with the pan. That is independent of this decode bug (which affected every >1 GHz tile regardless of antenna) and is better handled in the remap layer in a follow-up.Fixes #3449
Fixes #2835
Fixes #1928
Fixes #1843
💻 Generated with Claude Code (Opus 4.8) with architecture by @jensenpat