Use 4.6-chirp minimum dwell for both radio profiles

This commit is contained in:
mikecarper committed 2026-09-14 18:06:59 -07:00
1 parent b5440c75c7
commit 239f6a84f5
14 files changed
+545 -70

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
# Automatic dwell policy: 4.6 chirps on both profiles
The shared `RadioProfiles` function uses a 4.6-symbol minimum for both logical
profiles of one physical transceiver, rounded upward to a whole microsecond.
The slower profile is selected by symbol duration, with primary winning ties.
The fast visit receives the remaining half-slow-preamble budget, subject to
the same 4.6-symbol minimum. The nominal allowances are 600 us per switch and
300 us per cycle, not added delays.
The scheduler, automatic preambles, configuration acceptance and diagnostic
calculator use the same minima. Preserve explicit preambles, safe-airtime
validation, too-short slow-preamble rejection, recommendation rounding to
multiples of eight (minimum 32), and the existing SF8/500 versus SF7/62.5
88-symbol recommendation floor. Measured switching overruns raise advisory
warnings without rewriting configured values. Single-profile RX still does
not perform a scan.
For SF7/62.5 plus SF8/500 with slow preamble 32, the allocation remains
9,421 us slow and 21,847 us fast, in either profile order. The fast visit
already exceeds 4.6 fast symbols. Raising the fast minimum matters when
less budget is available: equal SF7/500 profiles with slow preamble 30 no
longer fit, because only 1,162 us would remain versus the new 1,178 us floor.
Slow preamble 32 fits with a 1,418 us fast visit.
## Hardware context
The preceding V4 RX / fixed RAK4631 and T1000-E TX bench used explicit
32-symbol preambles on both profiles, 100 stationary controls per profile
and a complete 100/profile scan. Controls passed 100/100 each; scanning
received slow 97/100 and fast 100/100 (197/200 total). Switching averaged
582 us and peaked at 827 us. Successful-packet mean SNR was +12.27/+13.47 dB.
No RF retry or USB result replay was used. Radios were left idle.
That test used the same 9,421/21,847 us windows, so the higher fast floor
does not change this particular allocation. It does not establish lossless
performance or qualify other SF/BW combinations. Raw capture SHA-256:
`1c2e0eae3f304fcaeb6addfeef4f2f09a3c2bec8d78c60d3f151c952d0f6d5f5`.
No additional RF run is required to apply the user-requested policy change.
## Software verification
The portable C++ test sweeps 1,600 SF/BW pairs and checks both 4.6-symbol
minima, exact fast-window allocation, preamble/diagnostic consistency and
accepted return deadlines. It also covers reversed/equal symbol times,
explicit preambles, newly infeasible short settings, long requested visits,
invalid parameters and advisory-only switching overruns. CLI tests exercise
warnings, both timing aliases, saved/temporary configuration, persistence
and bounded replies. Native integration covers routing, retries and packet
ownership alongside the timing model.
Verification completed on 2026-09-14 (local date):
- Exact commit snapshot: 24/24 host production tests passed, including primary
CLI settings, shared timing, command dispatch, persistence and reply checks.
- Native radio/routing/retry integration: 63/63 passed.
- Existing HIL host regressions: 64/64 passed in the working checkout.
- Both firmware builds passed from the isolated commit snapshot, without the
unrelated local lab/Wi-Fi/extra modulation-cache edits: V4 repeater RAM
125,336 bytes / flash 1,597,497 bytes; USB companion RAM 62,452 bytes /
flash 828,257 bytes. Both passed runtime-RAM checks.
- Staged whitespace and documentation-link checks passed. No radios were
flashed for this function update.
+98 -16
View File
@@ -124,38 +124,119 @@ it automatically. Explicit values are used as entered, subject to the radio's
limits and safe airtime arithmetic.
Automatic dual-profile preambles round **up to a multiple of eight**, with a
32-symbol minimum. Each idle scan starts with **4.8 symbols on the slower
profile**, then spends the remaining safe time on the faster profile. Slower
32-symbol minimum. Each idle scan starts with **4.6 symbols on the slower
profile**, then spends the remaining budgeted time on the faster profile,
also with a **4.6-symbol floor**. Slower
means a longer LoRa symbol (`2^SF / bandwidth`), regardless of profile number.
The slower preamble sets the return deadline. The calculation allows two slow
visits within that preamble, reserving 6 ms per switch and 4 ms of main-loop
visits within that preamble, reserving 0.6 ms per switch and 0.3 ms of main-loop
margin. Fast-channel transmit preambles include sixteen acquisition symbols.
For a primary SF7 / 62.5 kHz profile:
| Secondary profile | Automatic secondary preamble | Tested explicit preamble | Primary preamble |
| Secondary profile | Automatic secondary preamble | Previously tested explicit preamble | Primary preamble |
| --- | ---: | ---: | ---: |
| SF9 / 500 kHz | 48 | 32 | 32 |
| SF9 / 500 kHz | 32 | 32 | 32 |
| SF8 / 500 kHz | 88 | 64 | 32 |
| SF7 / 500 kHz | 120 | 80 | 32 |
| SF7 / 500 kHz | 64 | 80 | 32 |
With preamble 32 on that slower profile, its visit is 9.831 ms and the faster
visit is 6.937 ms, plus the actual switching time. Increasing the slow preamble
With preamble 32 on that slower profile, its visit is 9.421 ms and the faster
visit is 21.847 ms, plus the actual switching time. Increasing the slow preamble
also increases the time available on the fast channel. If the symbols are equal
in length, the primary profile goes first. Detected packets hold the current
channel until reception finishes.
The SF8 / 500 kHz value also retains the measured 88-symbol floor from the
production V4/XIAO tests, where 72 and 80 each missed a packet.
The shorter explicit values come from the
The explicit values come from the
[production validation](radio_profiles_validation.md): the final fast-channel
attempts each received 50/50 packets at 4.8 slow symbols. Automatic values retain
the additional switching and loop-jitter margin.
attempts each received 50/50 packets at 4.8 slow symbols. Automatic values use
the switching and loop-jitter allowances below.
Those explicit-preamble tests used the older 4.8-symbol policy; they do not
validate the new 4.6-symbol slow dwell / 0.3 ms reserve. The
[4.6/0.3 ms two-profile bench](radio_dwell_policy_validation.md#hardware-context) received 197/200
at SF7/62.5 + SF8/500 with explicit 32-symbol preambles. The newer four-channel
5.1/6.1/7.7 tests also had misses, so this is a timing policy, not a claim of zero packet loss.
The automatic fast preamble covers the blind interval during the slow visit,
both switches and the acquisition margin. These settings do not guarantee
reception during overlapping packets or long pauses in the firmware loop.
**Transmitters on each channel also need a long enough preamble.** Changing the
receiver's setting does not lengthen packets sent by other nodes.
### Chirp calculator and warnings
`get radio2.timing` (alias `get radio.timing`) reports the active pair in
`radio,radio2` order: dwell in chirps, recommended preambles in symbols, and
the switching/loop allowances. For SF7/62.5 on `radio` and SF7/500 on `radio2`:
```text
> chirps=4.60,85.34; need=32,64; switch=600us; loop=300us (estimate); WARN recommended preamble: radio2=64
```
`WARN recommended preamble` identifies **each** profile whose recommendation
exceeds the standard 32 symbols or its explicitly selected value. For example,
with SF7/62.5 on the primary profile, `set radio2 910.5,500,7,5,rx,32` replies:
```text
OK - radio2 rx; preamble=32; WARN recommended preamble: radio2=64; short override: radio2
```
Successful `set radio ...` replies also include the recommended preamble for
each affected profile, calculated with the requested settings. A `short override`
note identifies an explicit value below the estimate; it is not silently
rewritten. Warnings are also included in profile settings/getters, scan info,
temporary settings and schedule acknowledgments. `off` disables the dual-profile
warning. A timing readout does not change settings or transmit a packet.
The shared `RadioProfiles::calculateChirpTiming()` function accepts both tuples,
optional visit times in microseconds, a per-switch allowance and loop margin.
Using microseconds throughout:
```text
T[i] = 2^SF[i] * 1000 / BW_kHz[i]
slow = profile with the longer T (radio wins ties)
L[slow] = max(requested_visit_us[slow], ceil(4.6 * T[slow]))
L[fast] = max(requested_visit_us[fast], ceil(4.6 * T[fast]))
O = 2 * switch_us + loop_margin_us
C = L[radio] + L[radio2] + O
P[slow] = round_up_to_8(max(32, 2 * C / T[slow]))
P[fast] = round_up_to_8(max(32, (L[slow] + O) / T[fast] + 16))
```
The previous SF8/500 versus SF7/62.5 measured 88-symbol floor remains in force.
Automatic selection uses the minimum visits to choose a preamble, then allocates
the fast visit from half the slow preamble's duration. Diagnostics feed the
actual allocated visits back into the same function, including longer visits
caused by an explicit slow preamble. Too-short slow preambles that cannot fit
both minimum visits remain rejected by the existing configuration validation.
The automatic scheduler uses these same role-specific minima and computes:
```text
slow_dwell = ceil(4.6 * T[slow])
fast_dwell = max(ceil(4.6 * T[fast]),
floor(P_configured[slow] * T[slow] / 2 - slow_dwell - O))
```
For the tested SF7/62.5 + SF8/500 pair with slow preamble 32, this yields
9,421 us slow and 21,847 us fast (42.67 fast chirps). Swapping `radio` and
`radio2` swaps the allocations automatically. The 0.3 ms reserve is not a sleep.
The calculator accepts board-specific allowances, but production scheduling
uses the requested **600 us per switch plus 300 us per cycle**. This is a
nominal fast-switch allowance, not a worst-case bound. Diagnostics use the
larger of 600 us and the observed maximum
switch time; an overrun increases the warning estimate without automatically
changing wire preambles or saved configuration. Recent V4 tests peaked at
836 us (827 us in the 4.6/0.3 ms run), and Indicator reached 8428 us:
both can exceed the nominal allowance.
The model preserves two slow-profile return opportunities and the existing
16-symbol fast-profile acquisition allowance. These are conservative policies,
not a fitted success curve, and neither packet overlap nor arbitrary application
stalls can be made safe by a finite preamble recommendation.
See the [implementation and validation notes](radio_dwell_policy_validation.md).
## Schedule the second profile
Use UTC Unix timestamps (seconds):
@@ -199,7 +280,7 @@ profile. Packets/retries bound to an expired or changed session are discarded.
Dual mode suspends RX power saving and MCU idle sleep so receive visits can run
promptly. The saved RX power-saving setting returns when profile 2 is off.
The scan uses **normal receive**, following the
[CAD/RX measurements](cad_scan_validation.md): 4.8 symbols on the slower
[CAD/RX measurements](cad_scan_validation.md), with the updated 4.6-symbol dwell on the slower
channel, followed by the remaining fast-channel visit. It does not use CAD for scanning.
The separate CAD check before an initial transmission still follows `cad`.
@@ -212,8 +293,8 @@ This does not disable the TCXO supply or its initial startup delay, and it is
not conditional on 500 kHz bandwidth. Keeping the oscillator on uses additional
power during the short standby intervals.
The 6 ms switch budget is still a default scheduling allowance, not a
forced delay, and has not been reduced for this change. The earlier standalone
The requested 0.6 ms switch budget is a nominal scheduling allowance, not a
forced settling delay or a measured worst-case bound. The earlier standalone
[keep-warm scan experiment](mixed_scan_validation.md) averaged about 1.19 ms
of overhead per hop (scan-cycle time minus both receive windows, divided by
two). That experiment used a leaner receive path; it is not a measurement or
@@ -247,8 +328,9 @@ Other variants do not opt in to faster SPI or the fast-RX state machine.
See [production and USB validation](radio_profile_switch_validation.md#production-integration-and-usb-recovery-v8)
for current measurements, lifecycle tests and limitations.
The Indicator result also shows that the
generic 6 ms allowance is not an upper bound for every board; its scheduling
and preambles need board-specific qualification, not a smaller common budget.
nominal 0.6 ms allowance is not an upper bound for every board; its scheduling
and preambles need board-specific qualification. Measured overruns raise the
recommended preambles shown by the CLI without rewriting configured values.
Single-channel noise-floor calibration and RSSI interference comparison are
suspended while scanning. Retries use the radio's preamble/header activity