Status: Stage-2 sim result. Quantifies the cost of the firmware's blind (channel × SF)
grid scan and the latency win of the #65 guided-roam reframe (the coordinator announces a
neighbour-channel plan so a roaming client retunes directly instead of blind-sweeping).
Date: 2026-06-22.
Experiment: sim/experiments/discovery_latency.py
(cd sim && PYTHONPATH=. python3 -m experiments.discovery_latency).
Figure: docs/figures/discovery_latency.png.
Design source: frequency-agility-multisector-note.md (frequency = the fourth INFRA
authority; beacon carries the cell's freq, a grant can direct a client to another freq).
The firmware discovers a coordinator that may sit on a non-default frequency/SF by sweeping
a grid of G = N_channels × N_SFs cells, dwelling SCAN_DWELL_MS = 12 000 ms on each,
and adopting the PHY announced by the first beacon it hears. The bench-observed symptom that
motivated this work: a client took ~45 s to acquire a cell, catching the beacon on its
2nd dwell of the right channel — i.e. the grid was swept more than once before a
(channel, SF) cell that actually carried a beacon lined up with a dwell.
The #65 reframe: the coordinator's beacon announces a neighbour-channel plan (target
(ch, SF) and its beacon-phase offset), so a roaming client retunes directly — O(1)
acquisition — instead of blind-scanning the whole grid.
| Quantity | Value | Source |
|---|---|---|
| Beacon period B (one idle frame) | 2.117 s | BEACON 525 + GUARD 3 + 3·TELEM 280 + ADVERT 751 ms, FLEET SF9/BW125 (membership.py) |
| Dwell D | 12.0 s | firmware SCAN_DWELL_MS |
Arrivals per dwell D/B |
~5.67 | a dwell on the right cell almost always contains a beacon |
p_detect (per-arrival detect prob) |
0.95 (swept) | shadowing/SNR-margin knob; flagged for validation |
Because D ≫ B, the first dwell on the exact right (ch, SF) cell catches a beacon
with probability ≈ 1 (P(catch | right-cell dwell) = 1.00000 at p_detect = 0.95). The cost
is therefore not "miss the beacon on the right cell" — it is reaching the right cell
in a G-cell sweep, and the bench's "2nd dwell of the right channel" is the right channel
being revisited across its several SFs before the right (ch, SF) pair lined up.
Blind scan. The client sweeps G cells round-robin, D per cell; the coordinator's
cell is uniform-random in the sweep (the client has no prior — that is what "blind" means).
Mean cells visited before the right one is (G−1)/2. On the right cell it catches a beacon
with probability p_catch at conditional time e_t ≈ 1.17 s into the dwell; a miss (only
possible if fades knock out every arrival in the dwell) costs a full extra sweep G·D.
E[L_blind] = (G−1)/2 · D + ((1/p_catch) − 1) · G · D + e_t
≈ (G−1)/2 · D (since p_catch ≈ 1 for D ≫ B)
Guided roam. Retune to the named (ch, SF); acquire on the next detected beacon. With a
uniform start phase and per-arrival fades:
E[L_guided] = B/2 + ((1/p_detect) − 1) · B ≈ B/2 ≈ 1.06 s
The Monte-Carlo sim (40 000 trials/grid, full sweep-vs-beacon-phase geometry incl. fades) confirms the analytic mean to within MC error (e.g. 3×3: MC 49.20 s vs analytic 49.17 s; 4×6: MC 138.85 s vs analytic 139.17 s) and supplies the p95 tail the closed form does not.
p_detect = 0.95, D = 12 s, B = 2.117 s. Mean and p95 are acquisition latency (s).
| Grid (ch×SF) | G | Blind mean | Blind p95 | Guided mean | Guided p95 | Speed-up (mean) |
|---|---|---|---|---|---|---|
| 1×1 (fixed, no agility) | 1 | 1.2 s | 2.1 s | 1.2 s | 2.1 s | 1.0× |
| 2×1 | 2 | 7.2 s | 14.0 s | 1.2 s | 2.1 s | 6.2× |
| 2×2 | 4 | 19.2 s | 37.8 s | 1.2 s | 2.2 s | 16.3× |
| 3×3 | 9 | 49.2 s | 97.2 s | 1.2 s | 2.1 s | 42× |
| 3×4 | 12 | 67.1 s | 132.9 s | 1.2 s | 2.1 s | 57× |
| 4×6 (full ISM × SF7–12) | 24 | 138.9 s | 265.7 s | 1.2 s | 2.1 s | 118× |
Bench cross-check: the observed ~45 s acquisition sits between the model's 3×3 mean (49.2 s) and is well inside its p95 (97.2 s) — consistent with the "2nd dwell of the right channel" report at a ~3×3-class grid.
Blind grid scan: E[L] ≈ (G−1)/2 · D → LINEAR in G (≈ 6 s of latency per grid cell at D=12 s)
p95 ≈ (G−1) · D → full-sweep worst case
Guided roam: E[L] ≈ B/2 ≈ 1.06 s → CONSTANT in G (independent of grid size)
Blind scan pays D/2 ≈ 6 s of expected latency for every cell added to the grid; guided roam pays nothing. So the discovery cost is exactly what makes frequency/SF agility look expensive — and exactly what the beacon-announced plan removes. The speed-up grows with agility: ~6× at the smallest 2-cell grid, ~42× at 3×3, ~118× at the full 4×6.
| p_detect | Blind mean | P(catch/dwell) | Guided mean | Speed-up |
|---|---|---|---|---|
| 0.99 | 139.1 s | 1.000 | 1.08 s | 129× |
| 0.95 | 139.2 s | 1.000 | 1.17 s | 119× |
| 0.80 | 139.6 s | 1.000 | 1.59 s | 88× |
| 0.60 | 142.2 s | 0.994 | 2.47 s | 58× |
Blind scan is insensitive to p_detect (because D ≫ B so the right-cell dwell almost
always still catches a beacon even under heavy fading); the guided path degrades gently
(extra beacon periods to ride out fades) but stays one-to-two beacon periods. The blind
cost is dominated by sweep geometry, not link quality.
A camped client periodically hops away to look for a better cell. Each probe takes it off its home channel, so it misses its home telemetry/downlink windows for the probe duration.
(ch, SF), so it must
dwell the full D to confirm/deny → gap = D per candidate; surveying the grid probes
G−1 others.(ch, SF) and its
beacon-phase offset, so the client lands within ~1 beacon period of a known beacon,
confirms in ~B, and returns → gap ≈ B per candidate.Data gap, expressed as missed home frames (gap / B):
| Grid | candidates | Blind gap | Guided gap | Blind missed frames | Guided missed frames |
|---|---|---|---|---|---|
| 2×1 | 1 | 12.0 s | 2.1 s | 5.7 | 1.0 |
| 2×2 | 3 | 36.0 s | 6.4 s | 17.0 | 3.0 |
| 3×3 | 8 | 96.0 s | 16.9 s | 45.3 | 8.0 |
| 3×4 | 11 | 132.0 s | 23.3 s | 62.3 | 11.0 |
| 4×6 | 23 | 276.0 s | 48.7 s | 130.4 | 23.0 |
A blind scan-while-camped survey of a 3×3 grid blacks the client out of home service for
~45 frames (~96 s); the guided pre-tune costs ~8 frames (~17 s) — a D/B ≈ 5.7×
reduction per probed cell. This is the same D/B factor that drives the acquisition speed-up,
re-expressed as a hand-off cost: guided roaming replaces a full dwell with a single beacon
period at every cell touched.
D/2-per-cell blind law and the constant-B guided law are unchanged in form.D ≫ B (here 5.67×), so a right-cell dwell catches a beacon w.p. ≈ 1; the blind cost
is sweep geometry, not beacon-phase misses. If D were cut below B the model gains a
second per-cell miss term — not our regime, but the experiment's dwell_catch_stats
computes it exactly for that case.p_detect, swept above.O(1) and
still ~B mean; the phase just tightens the tail.(ch × SF) grid scan makes discovery latency linear in grid size: ≈ (G−1)/2·D,
i.e. ~6 s of expected acquisition per grid cell at the 12 s firmware dwell, reaching
~139 s mean / ~266 s p95 for the full 4×6 grid. This is the cost that makes
frequency/SF agility look expensive.≈ B/2 ≈
1.1 s regardless of grid size — a 42× win at 3×3 and 118× at 4×6 — and shrinks the
scan-while-camped roaming data gap by the same D/B ≈ 5.7× per probed cell.G-space; the plan
names it. Agility's discovery cost is therefore not intrinsic — it is the price of having
no map, and the beacon plan is the map. This argues for shipping the guided plan field
before turning on any multi-cell agility (DFS re-selection, dual-radio work channel,
multi-sector), so the agility never pays the blind-scan tax.Cross-references: frequency-agility-multisector-note.md (the beacon-freq / grant-freq
contract this builds on), jammer-freq-agility-result.md (the agility-escapes-jammer
companion), mode-and-handoff-note.md (hand-off hysteresis), data-window-latency /
membership.py (the frame-period B this reuses).