GetRxQuality() — runtime RX link-quality feed + passive noise floor#201
Merged
Conversation
A Fluke-style adaptive-link controller measures its environment from the driver:
SNR/EVM, a noise-floor number (the self-jamming signal), and PA/LNA saturation.
devourer had the per-frame RSSI/SNR/EVM (only on the Packet callback) and the
LinkHealth classifier + windowing living demo-side — so a controller *linked
against the library* (fluke_gs) couldn't get them without scraping stdout, and
there was no noise-floor metric at all.
- src/RxQuality.h — RxQuality snapshot + a thread-safe RxQualityAccumulator
(the demo's RxAgg promoted, with a passive noise-floor term) + build_rx_quality
fusing the frame aggregate, GetRxEnergy, and classify_link_health once.
Noise floor is passive: nf_dbm = rssi_dbm - snr_db per OFDM/HT frame — the
effective floor the receiver sees. TX self-jam drops SNR while RSSI holds, so
it rises ("decrease txpower until NF returns to normal"). Works on all three
families incl. Jaguar3 (which has no background DIG, so its IGI can't track
the floor).
- IRtlDevice::GetRxQuality() — the runtime feed; subsumes GetRxEnergy (calls it
internally, consumes the FA/CCA delta). Each device owns an accumulator, feeds
it per decoded frame in the RX loop, and returns build_rx_quality(...).
- demo: DEVOURER_RXQUALITY=1 emits <devourer-rxquality> (dogfoods the API;
existing <devourer-energy>/<devourer-linkhealth> untouched).
Validation: RxQualitySelftest (ctest + mingw list) covers the aggregate math,
the NF formula against a synthesized saturation tuple, EVM/NF present-gates, and
delta-reset. On-air (tests/rx_noise_floor_onair.sh): the feed is valid across a
TX-power sweep and the noise floor is SELF-CONSISTENT on real frames
(worst |nf-(rssi-snr)| = 1.0 dB), with SATURATED firing at high power. NB the
bench can't produce a large controllable NF excursion — the wanted beacon is
~-50 dBm inches away and neither TX self-jam nor a co-located B210 AWGN at 78 dB
moves the 8822EU's SNR (its AGC absorbs it); the same near-field/front-end limit
the SDR-power + dis_cca work hit. The unit test covers the NF math directly.
Full all-chips build + J1-only subset + ctest (10/10) green.
Co-Authored-By: Claude Opus 4.8 <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.
Why
Seeded by Fluke (BlackFox's experimental alink replacement): it "measures its environment and builds its own optimal txprofile" from richer driver telemetry than alink's RSSI/SNR — SNR/EVM, a noise-floor number, and PA/LNA-oversaturation. Its sharpest insight is self-jamming (Paddy's 10-ft-indoors): benching at high TX power raises the receiver's noise floor → SNR collapses → the link jams itself; the manual fix is "decrease txpower until NF returns to normal", which needs the driver to report the floor.
devourer had the pieces but not the feed: per-frame RSSI/SNR/EVM only on the
Packetcallback, the windowing +LinkHealthverdict only indemo/main.cpp, and no noise-floor metric at all. A controller linked against the library (fluke_gs) had to scrape stdout.What
src/RxQuality.h—RxQualitysnapshot + a thread-safeRxQualityAccumulator(the demo'sRxAggpromoted, plus a passive noise-floor term) +build_rx_quality()fusing the frame aggregate,GetRxEnergy, andclassify_link_healthonce.nf_dbm = rssi_dbm − snr_dbper OFDM/HT frame — the effective floor the receiver sees. TX self-jam drops SNR while RSSI holds, so it rises. Works on all three families incl. Jaguar3 (no background DIG, so IGI can't track the floor).IRtlDevice::GetRxQuality()— the runtime feed; subsumesGetRxEnergy(calls it internally, consumes the FA/CCA delta). Each device owns an accumulator, feeds it per decoded frame in the RX loop, returnsbuild_rx_quality(...).DEVOURER_RXQUALITY=1emits<devourer-rxquality>(dogfoods the API; existing<devourer-energy>/<devourer-linkhealth>untouched).Validation
RxQualitySelftest, ctest + mingw list): aggregate math, the NF formula against a synthesized saturation tuple, EVM/NF present-gates, delta-reset.tests/rx_noise_floor_onair.sh): the feed is valid across a TX-power sweep and the noise floor is self-consistent on real frames — worst|nf−(rssi−snr)| = 1.0 dB— withSATURATEDfiring at high power.Bench caveat (measured, honest): the bench can't produce a large controllable NF excursion — the wanted beacon is ~−50 dBm inches away, and neither TX self-jam nor a co-located B210 AWGN at 78 dB moves the 8822EU's SNR (its AGC absorbs it) — the same near-field/front-end limit the SDR-power + dis_cca work hit. The unit test covers the NF math directly; a large controllable swing needs a real far-field link.
Full all-chips build + J1-only subset +
ctest(10/10) green. M2 (the frame-free active absolute noise floor, measure-first) builds on this struct next.🤖 Generated with Claude Code