4 Commits

Author SHA1 Message Date
20abda421a Fix CFO estimation and timing for loopback tests
Two fixes for the frame sync timing bug reported by uart-agent:

1. CFO Overwritten by Timing Refinement
   - The _refine_symbol_boundary() returns a bin that reflects timing
     offset, not CFO. For aligned loopback signals, any timing shift k
     produces bin=k, incorrectly interpreted as CFO.
   - Fix: Keep CFO from state machine instead of overwriting.

2. SFD Correlation Noise Issues
   - For perfectly aligned signals, skip SFD correlation and use known
     frame structure offset (preamble_count + 4.25 symbols).
   - For real captures, use SFD correlation with adjusted search start.

Also updates SFD search start from (preamble_count + 1) to
(preamble_count + 3) for real captures to match existing decoder.

Loopback test: 50/50 seeds pass (100%)
Real SDR capture: All 10 bins match existing decoder
2026-02-07 04:28:39 -07:00
ec0dfedc50 Add sub-symbol timing recovery to FrameSync
Implement precision timing recovery functions:
- _refine_symbol_boundary(): Scans at 1/32-symbol resolution to find
  exact chirp boundary by maximizing dechirped SNR
- _find_sfd_boundary(): FFT-based correlation with downchirp template
  to find exact data start position

Bug fixes:
- Fix _is_downchirp() false positives by comparing both correlations
- Fix _estimate_cfo() to return values in [0, N) range

The improved sync_from_samples() now produces bins identical to the
reference lora_decode_gpu decoder.
2026-02-05 14:25:20 -07:00
3660f139ec Add channelizer and fix FrameSync for real SDR captures
- Add Channelizer class for wideband capture processing (2 MHz → 125 kHz)
  - FIR low-pass filter with scipy.firwin (or fallback windowed-sinc)
  - Proper decimation for anti-aliasing
- Fix FrameSync preamble detection to accept any CFO
  - Real captures have significant carrier frequency offset
  - Preamble bins appear at arbitrary values, not just near 0
  - Now accepts any strong signal as first preamble, validates consistency
- Add decode_capture.py example script for processing raw BladeRF captures
- PHYDecode verified to match existing lora_phy decoder output
2026-02-05 14:00:17 -07:00
c839d225a8 Initial release: complete LoRa TX/RX for RYLR998 modems
GNU Radio Out-of-Tree module providing:
- Complete TX chain: PHYEncode → FrameGen → CSSMod
- Complete RX chain: CSSDemod → FrameSync → PHYDecode
- NETWORKID extraction/encoding (0-255 range)
- All SF (7-12) and CR (4/5-4/8) combinations
- Loopback tested with 24/24 configurations passing

Key features:
- Fractional SFD (2.25 downchirp) handling
- Gray encode/decode with proper inverse operations
- gr-lora_sdr compatible decode modes
- GRC block definitions and example flowgraphs
- Comprehensive documentation

Discovered RYLR998 sync word mapping:
  sync_bin_1 = (NETWORKID >> 4) * 8
  sync_bin_2 = (NETWORKID & 0x0F) * 8
2026-02-05 13:38:07 -07:00