Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(presence): derive the empty-room boundary from the reference quiet floor - #1917

Open
jingilibili wants to merge 1 commit into
ruvnet:mainfrom
jingilibili:fix/empty-room-boundary-upstream
Open

fix(presence): derive the empty-room boundary from the reference quiet floor#1917
jingilibili wants to merge 1 commit into
ruvnet:mainfrom
jingilibili:fix/empty-room-boundary-upstream

Conversation

@jingilibili

Copy link
Copy Markdown

Symptom

A three node ESP32-S3 rig (192 subcarriers, channel 11) reported zero
occupants for a whole still phase while a person sat motionless on the floor
,
so person_count stayed 0 and the publication gate, which requires exactly one
occupant, never opened. The vitals detectors kept producing estimates the whole
time; they were simply never allowed out.

Root cause

finalize_calibration stores p95(calibration window residuals) * 1.5 as the
empty-room boundary. Any disturbance during the ten minute hold - a person, an
animal, a door, an appliance, motion in an adjacent room - lands in that upper
tail, and the boundary then sits far above the settled empty level.

MEASURED on that rig:

quantity value
calibration 1 reference median 6.7, p95 15.86, stored boundary 23.79
settled empty room, minutes later 3.70 - 5.50
person sitting still on the floor 3.25 - 35.03 (median 14.4)

The occupant stayed inside the learned boundary for the entire still phase.
The same inflated boundary also feeds field_bridge::perturbation_occupancy, so
the count path and the empty-room match were wrong together.

Boundary sweep over the recorded labelled windows

Detection of the still occupant, with no false positive in the recorded empty
window (3.70-5.50, 70 s):

boundary detection (13:52-13:56) detection (14:23-14:24)
6.0 98% 100%
7.5 93% 100%
9.0 87% 97%
10.05 81% 82%
15.61 38% 26%
23.79 (stored) 3% 5%

Change

  • EmptyRoomReferenceStats derives p25/p50/p75/p95 and 1.4826 * MAD from the
    retained reference windows.
  • effective_empty_room_threshold() applies the tighter of the learned boundary
    and p25 * EMPTY_ROOM_RESIDUAL_MARGIN. The lower quartile estimates the quiet
    floor of the room and is not moved by a still occupant or by a transient
    during calibration. It can only tighten the learned suppression range, never
    widen it, so a quiet calibration keeps exactly the boundary it had.
  • field_bridge::perturbation_occupancy uses the same effective boundary as
    empty_room_match, so the occupancy count and the empty-room match cannot
    disagree.
  • empty_room_match now also reports the stored boundary, the reference p50 and
    robust scale, and a contamination flag, so a disturbed calibration is visible
    instead of being inferred from an invisible occupant.

Tests

cargo test -p wifi-densepose-signal --lib ruvsense::field_model
# 36 passed, including:
#   disturbed_calibration_reference_tightens_the_effective_boundary
#   quiet_calibration_reference_is_not_flagged_contaminated
cargo check -p wifi-densepose-sensing-server

Limits, stated plainly

  • The empty window used for the false-positive column is 70 s long, so "0%"
    means no crossing in that window, not a measured false-alarm rate over a long
    empty period. A longer verified-empty capture is still needed.
  • The room's residual floor is not perfectly stationary: calibration 1's own
    reference median (6.7) sat above the settled empty level measured minutes
    later (3.70-5.50). A boundary learned once is therefore a weak detector on
    this rig, and a tracked quiet floor is the next step.
  • Related context, not claimed as fixed here: 4x ESP32-S3 occupancy detection - what works, what doesn't, and questions on the intende d detection methods #1804 reports the mirror-image
    failure (a calibrated model still reporting presence in an empty home), which
    is the same boundary-versus-settled-floor question from the other side.

…t floor

Calibration finalization stores p95(calibration window residuals) x 1.5 as the
empty-room boundary. Any disturbance during the ten minute hold - a person, an
animal, a door, an appliance, motion in an adjacent room - lands in that upper
tail, and the boundary then sits far above the settled empty level.

MEASURED on a three node ESP32-S3 rig (192 subcarriers, channel 11):
  calibration 1   reference median 6.7, p95 15.86, stored boundary 23.79
  settled empty room minutes later                     3.70 -  5.50
  person sitting still on the floor                    3.25 - 35.03 (median 14.4)
The occupant stayed inside the learned boundary, person_count remained 0 for the
whole still phase, and the publication gate - which requires exactly one
occupant - could not open even though the detectors kept producing estimates.

Boundary sweep over the recorded labelled windows, with no false positive in the
recorded empty window (3.70-5.50, 70 s):
  6.0 -> 98%, 7.5 -> 93%, 9.0 -> 87%, 10.05 -> 81%, 15.61 -> 38%, 23.79 -> 3%

Changes:
- EmptyRoomReferenceStats derives p25/p50/p75/p95 and 1.4826 x MAD from the
  retained reference windows.
- effective_empty_room_threshold() applies the tighter of the learned boundary
  and p25 x EMPTY_ROOM_RESIDUAL_MARGIN. The lower quartile estimates the quiet
  floor of the room and is not moved by a still occupant or a transient during
  calibration. It can only tighten the learned suppression range, never widen it.
- field_bridge::perturbation_occupancy uses the same effective boundary as
  empty_room_match, so the occupancy count and the empty-room match cannot
  disagree.

Tests: cargo test -p wifi-densepose-signal --lib ruvsense::field_model (36 tests)
including disturbed_calibration_reference_tightens_the_effective_boundary and
quiet_calibration_reference_is_not_flagged_contaminated.
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