Summary
reference/airtime_model_check.py — our reference port of SX126x::calculateTimeOnAir(), and the
project's stated authority for airtime — silently maps coding rate 4/7 to 4/8. Every ToA computed
at CR 4/7 is overstated by a factor 8/7 (~14%).
Host-side analysis script, kept in the project folder rather than in this repo; filed here because
this is the project tracker (cf. #5).
Location
reference/airtime_model_check.py:55
cr = cr_wire + 4 if cr_wire < 5 else (cr_wire + 1 if cr_wire == 7 else cr_wire)
The cr_wire == 7 branch adds 1. For cr_wire in {5, 6, 8} the value passes through unchanged, so
the special case is asymmetric and unexplained by the surrounding comment, which states that "a
stored 5..8 is used as-is".
Evidence it is wrong
RadioLib applies the coding-rate denominator directly, with no special case:
.pio/libdeps/Heltec_v3_repeater/RadioLib/src/modules/SX126x/SX126x.cpp:767
uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
The symptom is visible directly in the model's own output — the CR7 column is byte-identical to CR8:
bytes CR5 CR6 CR7 CR8
64 529.4 599.0 738.3 738.3
184 1143.8 1336.3 1721.3 1721.3
Correct values (SF8 / BW 62.5 kHz / preamble 32 / CRC on):
| bytes |
4/5 |
4/7 (correct) |
4/7 (current, wrong) |
| 16 |
283.6 ms |
324.6 ms |
345.1 ms |
| 64 |
529.4 ms |
668.7 ms |
738.3 ms |
| 184 |
1143.8 ms |
1528.8 ms |
1721.3 ms |
Why the selftest did not catch it
--selftest passes 15/15 because every vector uses CR 5. A selftest pinned to a single coding
rate cannot detect a per-CR mapping error by construction. Any fix should add vectors at 4/6, 4/7
and 4/8.
Impact
Low until now, because everything measured so far assumed the AT/EU-narrow preset (CR 4/5), which is
unaffected. It became relevant on 2026-08-22: get radio showed AT-PL-Hofstetten01 running CR 4/7
while KK and the bench companion run 4/5, and the first airtime comparison for that node used the
inflated figures. This is the second CR-related defect in this file after the coefficient fix of
2026-08-17, so the area deserves the extra vectors rather than another point fix.
Suggested fix
Drop the special case, use the denominator as stored, and extend --selftest to cover 4/6, 4/7, 4/8
with hand-computed reference points.
Summary
reference/airtime_model_check.py— our reference port ofSX126x::calculateTimeOnAir(), and theproject's stated authority for airtime — silently maps coding rate 4/7 to 4/8. Every ToA computed
at CR 4/7 is overstated by a factor 8/7 (~14%).
Host-side analysis script, kept in the project folder rather than in this repo; filed here because
this is the project tracker (cf. #5).
Location
reference/airtime_model_check.py:55The
cr_wire == 7branch adds 1. Forcr_wirein {5, 6, 8} the value passes through unchanged, sothe special case is asymmetric and unexplained by the surrounding comment, which states that "a
stored 5..8 is used as-is".
Evidence it is wrong
RadioLib applies the coding-rate denominator directly, with no special case:
.pio/libdeps/Heltec_v3_repeater/RadioLib/src/modules/SX126x/SX126x.cpp:767The symptom is visible directly in the model's own output — the CR7 column is byte-identical to CR8:
Correct values (SF8 / BW 62.5 kHz / preamble 32 / CRC on):
Why the selftest did not catch it
--selftestpasses 15/15 because every vector uses CR 5. A selftest pinned to a single codingrate cannot detect a per-CR mapping error by construction. Any fix should add vectors at 4/6, 4/7
and 4/8.
Impact
Low until now, because everything measured so far assumed the AT/EU-narrow preset (CR 4/5), which is
unaffected. It became relevant on 2026-08-22:
get radioshowed AT-PL-Hofstetten01 running CR 4/7while KK and the bench companion run 4/5, and the first airtime comparison for that node used the
inflated figures. This is the second CR-related defect in this file after the coefficient fix of
2026-08-17, so the area deserves the extra vectors rather than another point fix.
Suggested fix
Drop the special case, use the denominator as stored, and extend
--selftestto cover 4/6, 4/7, 4/8with hand-computed reference points.