Skip to content

Performance

The perf/ directory contains AWGN SNR-sweep scripts that measure the receiver end-to-end and produce PER (packet-error-rate) curves. All of them generate a clean LoRa packet with the gr-lora_sdr GNU Radio TX chain, then decode the same noisy draws with the receiver, so the only thing being measured is the sync + decode path.

awgn_testbench_xhonneux.py — SF 7–12 PER sweep

The main testbench:10,000 point Monte Carlo simulation over AWGN channel to measure PER across SF 7 to 12.

Setup

  • BW=125 kHz, fs=250 kHz, CR=1 (4/5, uncoded), CRC on, explicit header, 19-byte payload, 8-upchirp preamble, sync word 0x12, up to 10000 packets per SNR point.
  • PER is the fraction of trials whose decoded payload bytes differ from the transmitted payload. Covering sync failure, header failure, wrong length and payload bit errors. p_detect separates sync failures from post-sync decode errors.
| | |:---:| | *Combined PER panels from `perf/plot_xhonneux.py` — one sub-plot per spreading factor; each SF step gains roughly 4 dB.* |
| | |:---:| | *All SF curves overlaid: the SF7–12 waterfall in one figure.* |

awgn_compare_sf7.py — receiver vs GNU Radio vs theory

An uncoded SF7 comparison (no Hamming FEC, implicit header, no CRC, 20-byte payload) that decodes the same noisy draws with both sync algorithms:

  • xhonneux — the Xhonneux et al. paper sync (default)
  • gr-lora-sdr — the gr-lora_sdr frame_sync port

and reports SER (payload-symbol errors vs the TX ground truth) and PER, compared against the theoretical AWGN limit for perfect sync (the non-coherent M-ary orthogonal symbol error probability).

| | |:---:| | *Uncoded SF7 SER/PER: the two sync front-ends vs the theoretical AWGN limit for perfect sync.* |

awgn_chase_vs_hard.py — Chase coding gain

Runs an AWGN PER sweep for the Chase soft-decision decoder (DecoderSettings(decode_mode='chase')) on the same config of hard-decoder, and compares the two PER curves point-for-point on the stored SNR grid. Reports the SNR needed for PER = 1e-2 and 1e-1 for both decoders and the Chase coding gain in dB.

python3 perf/awgn_chase_vs_hard.py                       # uses stored hard data
python3 perf/awgn_chase_vs_hard.py --paired --snr=-13,-12,-11,-10,-9
  • --paired re-runs the hard decoder on the same noisy draws as Chase (a per-trial "Chase recovered N packets hard missed" count).
  • Chase is roughly 6× slower than hard decoding (~0.1 s/pkt at SF7/250 kHz), so narrow the run with --snr / --packets.
  • Results → perf/data/awgn_chase_sf7_results.json, plot → perf/plots/awgn_chase_vs_hard_sf7.png.
| | |:---:| | *Chase vs hard-decision PER at SF7 — the horizontal gap between the two curves is the Chase coding gain.* |

Interpreting the curves

  • PER — where the curve climbs is the sensitivity floor; each SF step adds roughly 4 dB of processing gain (SF10 floors around −18 dB).
  • SER / PER vs theory — validates the sync against the ideal AWGN limit.
  • Chase vs hard — the horizontal gap between the two PER curves is the Chase coding gain at marginal SNR.

Synthetic packets

The test suite ships tests/tx_helpers.py, a pure-Python LoRa TX encoder (whiten, Hamming encode, interleave, Gray-code, chirp modulation) used to build known packets for round-trip tests at any spreading factor.