Skip to content

fix(calibration): bind the grid whose frames come from one population - #1919

Open
jingilibili wants to merge 1 commit into
ruvnet:mainfrom
jingilibili:fix/grid-population-homogeneity-upstream
Open

jingilibili wants to merge 1 commit into
ruvnet:mainfrom
jingilibili:fix/grid-population-homogeneity-upstream

Conversation

@jingilibili

Copy link
Copy Markdown

Why

A field model compares a runtime window mean against a calibration reference built
the same way, and it binds exactly one subcarrier grid. That comparison only
means something when both windows come from the same transmitter population.
select_calibration_grid ordered candidates by max gap, then rate, then width, so
a faster but mixed grid could win.

Measurement

Three ESP32-S3 nodes on one access point, 30 s capture per node, frames counted
straight off the UDP socket:

grid rate RSSI spread RSSI median
306 ~15 Hz 1-3 dB -23 to -27 dBm
192 ~13 Hz 15-43 dB -30 to -58 dBm
128 ~5-8 Hz 11-52 dB -28 to -63 dBm
64 0.2-0.7 Hz 19-58 dB -69 to -82 dBm

The 306 grid carries the array's own traffic: each node pings the gateway
(CONFIG_CSI_SELF_PING_HZ, documented as "a stable OFDM CSI source") and cannot
hear its own transmission, so what a node hears on that grid is the other
nodes. That population is strong and homogeneous.

With the mixed 192 grid bound, injecting 2000 pps from the host moved the field
model's residual median from 9.4 to 17.4 while the operator sat motionless -
a larger change than the occupant's own effect in the same session (empty room
median 10.4, seated median 11.9). The residual was following the frame population
instead of the room.

Related, and worth knowing when a report looks impossible: with two of the three
nodes powered down, node 3 saw 1.6 Hz on the 306 grid and 0.2 Hz on 192, both at
-58 dBm, and a 600 pps injection from the host raised neither (1.2 Hz and 0.9 Hz).
A one-node array has no steady population to calibrate against.

Change

  • RawGridObservation records the frame's reported RSSI.
  • CalibrationGridEvidence reports rssi_spread_db and rssi_median_dbm.
  • select_calibration_grid orders by RSSI spread first, then max gap, then rate,
    then width. The eligibility gates (10 s span, 2 Hz, 5 s gap) are unchanged, and
    a grid without RSSI evidence falls back to the previous ordering exactly.

Tests

cargo test -p wifi-densepose-sensing-server --bin sensing-server
# 323 passed, including the new
#   calibration_grid_selection_prefers_a_homogeneous_population

Limits

  • Measured on one rig (three ESP32-S3 nodes, one Tenda access point, 2.4 GHz
    channel 11) on one day. The spread is used for ordering only, never as a hard
    cutoff, so a rig whose grids all look homogeneous keeps its previous choice.
  • The occupant's own effect on the residual is small on this rig (median 10.4
    empty versus 11.9 seated), which is a separate problem: this change removes the
    traffic-driven part of the variance, it does not by itself make the residual a
    validated presence signal.

A field model compares a runtime window mean against a calibration reference
built the same way. That comparison only means something when both come from the
same transmitter population, and the field model binds exactly one subcarrier
grid. Selection ordered candidates by max gap, then rate, then width, so a faster
but mixed grid could win.

MEASURED on the room B rig, three ESP32-S3 nodes, 30 s capture per node:

    grid 306   ~15 Hz   RSSI spread  1-3 dB     (the array's own ping traffic)
    grid 192   ~13 Hz   RSSI spread 15-43 dB    (access point plus ambient clients)

With the mixed 192 grid bound, injecting 2000 pps from the host moved the
residual median from 9.4 to 17.4 while the operator sat motionless - a larger
change than the occupant's own effect (empty 10.4 versus seated 11.9), because
the residual was following the frame population and not the room.

Changes:
- RawGridObservation records the frame's reported RSSI.
- CalibrationGridEvidence reports rssi_spread_db and rssi_median_dbm.
- select_calibration_grid orders by grid width first, so selection agrees with
  `accept_grid`'s density lock, then by RSSI spread (population homogeneity),
  then max gap, then rate, then PPDU type. The eligibility gates (span, rate,
  gap) are unchanged.

Upstream landed the density ordering after this PR was opened, so that
expression was the single conflict when rebasing onto main: width stays the
primary key - a grid admission is about to discard must not win - and the RSSI
spread this PR introduces separates two candidate grids of the same width.
Upstream's own grid-selection test, added with that change, passes `None` for the
RSSI argument this PR introduces, which is what it wants: it asserts the density
key, and with no RSSI the homogeneity tie break has nothing to compare.

Also measured, and the reason a one-node array cannot work: a node cannot hear
its own transmissions, so the steady population on the 306 grid is the *other*
nodes' traffic. With two of three nodes powered down, node 3 saw 1.6 Hz on 306
and 0.2 Hz on 192, both at -58 dBm, and a 600 pps injection from the host did not
raise either (1.2 Hz and 0.9 Hz). The calibration needs at least two nodes.

Tests: cargo test -p wifi-densepose-sensing-server --bin sensing-server (323
passed), including calibration_grid_selection_prefers_a_homogeneous_population.
@matthewraynor448-mehdi
matthewraynor448-mehdi force-pushed the fix/grid-population-homogeneity-upstream branch from f594c11 to 63cf3a4 Compare September 18, 2026 11:00

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant