Skip to content

VDL2: gated noise estimator + burst-length sanity cap (16-17 → 19)#65

Merged
kevinelliott merged 1 commit into
masterfrom
vdl2-skew
Jun 11, 2026
Merged

VDL2: gated noise estimator + burst-length sanity cap (16-17 → 19)#65
kevinelliott merged 1 commit into
masterfrom
vdl2-skew

Conversation

@kevinelliott

@kevinelliott kevinelliott commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

The session's persistence pays: re-auditing the dumpvdl2 oracle showed 40/41 of its frames at 24-30 dB SNR — the missing frames were strong, not weak, overturning three investigations' framing. Instrumentation then found the real faults:

  1. False-lock monsters: bogus headers passing the 25-bit FEC with lengths up to 112,241 bits (3.4 s of "collection"). Capped at 16k bits.
  2. Noise-floor inflation: the energy gate's EMA learned from burst power during post-rewind rescans, shadowing rapid back-to-back bursts (XID/ack sequences — exactly the capture's pattern). Now a gated estimator: learns only below the gate, tiny up-creep for re-convergence.
rate before after
50 kS/s 16 19
100 kS/s 17 19
600 kS/s 16 18

…and the count is now flat across EF 8–20 / threshold 0.4–0.6 where the old estimator wobbled 17–20. Full suite green. Next step documented: time-aligned burst diff against the oracle for the remaining 19-vs-41.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved VDL2 demodulator noise floor estimation to prevent degradation from high-energy signals.
    • Added filtering for invalid transmission lengths during burst collection.
    • Added optional debug logging for demodulation troubleshooting.
  • Documentation

    • Added investigation notes documenting signal handling improvements and frame detection results.

The dumpvdl2 oracle audit overturned the weak-burst theory: 40 of its
41 frames are at 24-30 dB SNR. Instrumentation found two real faults:

- Bogus headers passing FEC with absurd lengths (up to 112k bits,
  3.4 s of collection) starved hunting and polluted the failure
  statistics. The demod now rejects transmission lengths over 16k bits.

- The energy gate's noise EMA learned from burst power during
  post-rewind rescans, inflating the floor ~0.1 s and shadowing rapid
  back-to-back transmissions (XID/ack sequences). The estimator is now
  gated (learns only below the gate, tiny up-creep for re-convergence).

Off-air capture: 19 frames at EVERY capture rate (50 kS/s 16 -> 19,
100 kS/s 17 -> 19, 600 kS/s 16 -> 18), and the count is flat across
ENERGY_FACTOR 8-20 / threshold 0.4-0.6 where the old estimator wobbled.
Full suite green; notes updated with the evidence chain and the next
instrumentation step (time-aligned burst diff vs the oracle).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79e8f626ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// passed FEC — collecting seconds of "burst" for it
// starves hunting and pollutes the failure statistics.
match header::decode(&hdr)
.filter(|&tl| tl <= 16_000)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Raise the TL cap to the protocol limit

For any standards-valid VDL2 burst whose decoded transmission length is above 16,000 bits, this new filter turns the burst into a header failure before collection/deinterleaving even though the local PHY code still defines the 17-bit header maximum as 131,071 bits (header::MAX_TL) and interleave::layout accepts lengths up to that value. That makes the demod silently drop larger AVLC/ATN transfers; if the goal is to reject false-lock monsters, the sanity check should not be below the protocol-supported range or should be based on a configurable/validated operational limit.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

The UW-hunting demodulator's noise-floor estimator was gated to prevent learning from high-energy burst samples. Header decoding now rejects transmission lengths above 16,000. Debug logging was added for RS decoding outcomes. Investigation documentation reports updated frame counts and root causes.

Changes

Noise-floor gating and false-lock prevention

Layer / File(s) Summary
Noise-floor estimator gating
crates/xng-mode-vdl2/src/demod.rs
ENERGY_FACTOR increased from 6.0 to 12.0; noise estimator only EWMA-updates when sample power is below the noise-derived threshold; otherwise performs a small up-creep to prevent inflation from burst energy.
Header transmission length validation
crates/xng-mode-vdl2/src/demod.rs
Decoded transmission lengths are filtered to reject values above 16,000, causing invalid headers to be treated as decode failures.
Debug logging for RS decoding
crates/xng-mode-vdl2/src/demod.rs
VDL2_DEBUG-gated logging reports RS success and failure outcomes with transmission-length bits, symbol count, and soft metric.
Investigation documentation
docs/notes/VDL2-DEMOD-V2.md
New section explains false-lock root causes (false-lock length handling and gated energy-EMA learning), reports revised frame counts (19 frames), and identifies next steps as timestamp-based burst alignment.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

In bursts so bright, the gates did fail,
Learning noise from the signal's tale,
We tuned the threshold, raised the bar,
And filtered false-locks near and far.
Now logs can peek behind the veil—
A cleaner demod, our debugging tale. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the two main changes: a gated noise estimator and a burst-length sanity cap, with measured frame count improvements (16-17 → 19).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch vdl2-skew

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kevinelliott
kevinelliott merged commit ccffb32 into master Jun 11, 2026
1 of 2 checks passed
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.

1 participant