Skip to content

Channel Sounding — what is settled, and what still needs measuring

Status: CS works. Board V1 (nRF54LM20A) and an nRF54L15-DK range against each other and produce distance, and ifft is accurate to ±0.20 m after a single constant calibration. The premise the whole hardware pivot rests on is no longer an assumption. What follows is the list of things still unmeasured, in the order they block product decisions.

Rig and raw data: ~/Impulse/ImpulseFirmware/nrf_cs_test/ (RESULTS.md has the full analysis and the CSVs). Firmware side: nrf_firmware/src/proximity/.


⚠️ TOP PRIORITY — a proper BM20C ↔ BM20C calibration sweep (added 2026-09-10)

Two Board V1s now range against each other, which supersedes every number on this page that was measured against a dev kit. Offsets in CS are dominated by antenna delay, so a DK-derived constant does not transfer to a BM20C pair — and the direction of the error matters.

What was measured (2026-09-10): a SINGLE point, boards ~2 ft (61 cm) apart, line-of-sight, 150+ samples:

estimator median sd
ifft 1.32–1.36 m 0.02–0.04 m
phase_slope 1.66–1.80 m 0.08 m
rtt 0.15 m 0.49 m, and 38/113 samples exactly 0.00

What was changed on that basis: IMPULSE_CS_IFFT_OFFSET_CM 97 → 72. The old value came from the DK pair and errs in the UNSAFE direction — it reports the watch ~25 cm CLOSER than it is, so a stayNear commitment reads as satisfied slightly too far out.

What is still owed, and why one point is not enough:

  1. A multi-station sweep to separate slope from offset. One point cannot. The slope in the firmware (0.993) is still the DK's. Stations at roughly 0.5 / 1 / 2 / 4 / 7 m LOS, ./cs_sample.sh 25 "<distance>" at each, then fit. Expect the far stations to need longer captures — sampling drops from ~10 Hz at contact to under 2 Hz past 5 m.
  2. Re-derive the divergence floor. phase_slope − ifft is +0.30 to +0.48 m on a clean line-of-sight bench with no occlusion at all. The whole design treats divergence as the occlusion/multipath quality signal, so a baseline this large means CS_QUALITY_MIN cannot keep its DK-derived value. Measure the LOS baseline across distance FIRST, then re-measure occluded.
  3. Precision looks materially better than the DK pair — ifft sd of 0.02–0.04 m versus 0.20 m rmse. If that holds across distance, the burst size (N=10) and possibly the 1.5 m NEAR/AWAY band are more generous than needed, and a burst could be shorter — which is an energy saving, not just tidiness.
  4. Nothing here is orientation- or body-controlled. The board was static on a bench. Repeat with rotation and with a body in the path.

Settled — do not re-litigate without new data

Question Answer Evidence
Does CS work on this silicon? Yes, ~10 Hz Board V1 ↔ nRF54L15-DK, HCI 6.3
Which estimator is primary? ifft best noise, least occlusion-sensitive, and the only one whose slope is 1.0
Is ifft correctly scaled? Yes — 0.993 LOS sweep, 11 stations, R² 0.9881
Calibration shape constant offset, +0.97 m not a scale error
Accuracy after calibration 0.20 m sd, 0.39 m worst 0.9–7.0 m, board rotating
Samples needed per verdict 10 resampled: N=10 → 0.19–0.57 m error
Are NEAR/AWAY = 200/350 cm sane? Yes a ±0.2 m instrument separates them easily

P0 — blocks correctness, not just tuning

1. Anchor targeting

The backend ranges against whatever advertises the Ranging Service, not against event.anchorId. With two anchors in a house it measures the wrong one. This is a correctness bug and no amount of threshold tuning helps. Not a measurement — an implementation task.

2. Two BLE roles at once

CS holds a central connection while the app needs the watch to be a peripheral. Concurrent roles is exactly what broke the ESP32 build (firmware_spec_v2.md §10.1: ble_hs_timer_exp panic, reproduced on both IDF 4.4.7 and 5.5.5). Zephyr's host has its own version of the hazard. Test this early — if it fails, the enforcement design changes shape, not just its constants.

3. Does the engine work inside the product firmware?

Proven standalone; never run beside the enforcement loop. Build with cs.conf, flash Board V1, put a reflector on the DK, and confirm a real burst drives a real verdict — cond_met flipping and the motor firing as the reflector crosses the threshold. That single test is the whole product.


P1 — the numbers that set the remaining §11 constants

4. BM20C ↔ BM20C

Every number so far is Board V1 against a DK, which has a different antenna, ground plane and enclosure. Offsets are antenna-delay dominated, so the +0.97 m constant is specific to this pair and will move. Needs a second Board V1. Until then treat the calibration as provisional.

5. Orientation

The sweep rotated the board continuously, so its ±0.20 m already includes rotation — a good sign. What is not known is whether specific orientations are systematically biased (a wrist rolls into repeatable positions). Test: fixed 2 m, eight orientations, 30 s each, look for bias rather than spread.

6. On a body

The watch will sit on a wrist with a person between it and half the room. The walk captures included body occlusion but with no ground truth. Test: fixed distances with the board worn, facing toward and away from the anchor.

7. Through walls, and in a second room

Decides whether the 150 cm hysteresis band is wide enough. Expect it to need widening, not narrowing (v3 §11).

8. Failure rate at the edge — sets CS_ABSTAIN_MAX_CONSECUTIVE (5)

The sample rate collapses with distance: ~10/s at contact, 5.7/s at 2 m, 2.5/s at 3.4 m, 0.2/s at 6.4 m. So a burst takes longer the further away the anchor is. Needed: how often CS legitimately fails at 3–5 m over a long run, because too low a cap trips the fail-safe in normal use and too high makes jamming free.

9. Energy per procedure — feeds the 8 h floor (§6.3)

The engine currently free-runs at ~9 Hz once connected, which is certainly wrong for a wrist. Measure per-procedure cost, then decide the duty cycle. This is the one open item that can fail the runtime requirement.


P2 — refinements with a known shape

10. Recalibrate rtt and use it for what it is

rtt's slope is also ≈1.0 (1.030) with a +3.79 m offset — uncalibrated antenna/group delay, as predicted. Offset it and it becomes a usable speed-of-light bound. Its job is not accuracy; it is the only thing that can catch a relay attack, which PBR cannot see at all (v3 §4.6). Keep the tolerance generous — its own noise is 0.37 m — and remember a false positive there costs an abstention, which is not free.

11. Turn estimator divergence into the quality floor

In line of sight phase_slope ≈ 0.92·ifft + 1.97; under occlusion the walk captures gave ≈ 1.45·ifft. That difference is the mechanism: reflections lengthen phase_slope while ifft can still resolve the direct path, so divergence is a physically-motivated blocked-path detector. Currently a fixed 250 cm threshold. Wants tuning against labelled occluded/clear data — which means recording what the test actually was, the one thing the walk captures lacked.

12. Decide what a dropout means

In LOS, dropout correlates strongly with distance. Under occlusion the walks showed dropouts at close range. So "no signal" means far or blocked, and must stay an abstention rather than becoming a positive AWAY — a positive AWAY would let shielding fabricate compliance for getAway. The criterion-dependent fail-safe (§4.5) already resolves this correctly; the point is not to "improve" it into a distance claim.

13. Re-derive a third poll tier

v2's 600 s STILL tier was deleted with the motion channel. Once per-procedure energy is known, a third tier may be worth reintroducing on a different justification (§4.3).


Method notes, learned the hard way

  • Record what each capture is. The three walk files mixed body, cushion and house occlusion with no labels, which made every per-file conclusion provisional. One line of context per run is the difference between data and anecdote.
  • Whole-file SD is not noise — it is mostly the tester walking. Use a short rolling window, or stationary segments.
  • Averaging helps less than it looks. The noise is time-correlated multipath drift: 40 samples cut it by 46% where white noise would give 84%. Prefer a median over ~10 samples to a long mean.
  • Ground truth or it is precision, not accuracy. Everything before the LOS sweep could only speak to repeatability.