Fix/noise floor ratchet, adapt noise to the real floor with recovery in both directions#2933
Open
usrflo wants to merge 3 commits into
Open
Fix/noise floor ratchet, adapt noise to the real floor with recovery in both directions#2933usrflo wants to merge 3 commits into
usrflo wants to merge 3 commits into
Conversation
The noise-floor calibration sampled only RSSI values below the current floor + threshold, a one-way ratchet: it accepted ever-lower samples but never recovered upward, so _noise_floor drifted to the -120 clamp and stayed there. That left the RSSI-margin LBT (isChannelActive with interference_threshold, plus isResendChannelActive / isChannelNoisy on the feature branches that consume _noise_floor) permanently over-sensitive — resends and dwell-gated TX deferred even on a quiet channel. Replace the ratcheted block mean with the median of the 64-sample block: - accepts every idle (!isReceivingPacket) sample — no downward bias; - median rejects transient interference spikes (high and low outliers) and recovers in BOTH directions; - _noise_floor is written only after a full block, so the previous value stays valid while the next block is sampled — no reset-to-0 and thus no permissive LBT window (margin = RSSI - 0) during reconvergence. resetAGC no longer forces _noise_floor = 0 (the stuck-ratchet workaround); it only discards the in-progress block so a fresh one is measured after the analog frontend reset. Verified: Heltec_v3_repeater firmware build (compiles RadioLibWrappers.cpp against real RadioLib). Co-Authored-By: Claude <noreply@anthropic.com>
Documents the ratchet-to-median fix on fix/noise-floor-ratchet: symptom, root cause (one-way ratchet drift to -120), the median-of-64 replacement, files touched, build verification note (sim does not compile RadioLibWrappers.cpp; verified via Heltec_v3_repeater), and merge intent. Co-Authored-By: Claude <noreply@anthropic.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.
Symptom
On long-running nodes (I saw it with an ufo integration branch, which combines
feature/repeated-sending-2+feature/quiet-dwell), direct-packet resends and dwell-gated TX get deferred or suppressed even on a quiet channel.The radio's reported
noise_floordrifts to the-120clamp and never recovers, so the RSSI-margin LBT checks (isResendChannelActive,isChannelNoisy,isChannelActivewithinterference_threshold) stay permanently over-sensitive — every send looks like it collides with noise.Root cause
RadioLibWrapper::loop()calibrated_noise_floorfrom a 64-sample block, but only accepted samples that satisfiedThat filter is a one-way ratchet: it admits ever-lower samples but rejects anything above the current floor, so the block mean can only move down. Over time it walks to the
-120lower clamp and sticks there. The only thing that reset it wasresetAGCsetting_noise_floor = 0— butresetAGCis gated onagc_reset_interval, which defaults to0(off), and forcing0would anyway open a brief permissive LBT window (margin = RSSI − 0) until the next block completes.The fix
Replace the ratcheted block mean with the median of the 64-sample block:
!isReceivingPacket()) — no downward bias._noise_flooronly after a full block is collected. The previous value stays valid while the next block is sampled — no reset-to-0, hence no permissive LBT window during reconvergence.-120(lower bound of the radio's RSSI range).resetAGC()no longer touches_noise_floor; it only discards the in-progress block (the analog frontend was just reset, so queued samples are stale)._noise_flooritself is left in place because the median estimator no longer needs the hard reset that the ratchet did.SAMPLING_THRESHOLDis removed (it only fed the ratchet filter).NUM_NOISE_FLOOR_SAMPLES(64) moves to the header so the sample buffer can be a member array.