Skip to content

occupancy classification does not change across gross occupancy change (single deployment, needs second-site confirmation) #1758

Description

@proffesor-for-testing

Summary

On one hardware deployment, the top-level occupancy classification never changed value. Across
90 samples spanning deliberately extreme stimulus — including the operator leaving the room
entirely — presence had exactly one distinct value (true), estimated_persons was always
1, and confidence was always 0.4.

Stated limitation up front: this is one room, one server build, one node topology. It has
not been reproduced on a second installation. Filing so it can be checked elsewhere; if other
installs do not show it, something specific to this one is responsible and the issue should be
closed.

Measurements

Three ESP32-S3 nodes on v0.8.4, ~127 frames/s aggregate, with a completed empty-room baseline
active (fresh, bound, 85,731 frames, receipt issued).

Perturbation sequence, 90 samples at 1 Hz:

phase n presence persons confidence variance (median)
sit still 18 18/18 true 1 0.4 427.8
walk through node↔AP line of sight 18 18/18 true 1 0.4 468.3
wave both arms ~50 cm from a node 18 18/18 true 1 0.4 452.7
operator out of the room 18 18/18 true 1 0.4 408.0
return and sit 18 18/18 true 1 0.4 443.9
across all 90 samples:  distinct presence values   = {true}
                        distinct confidence values = [0.4]

Separate empty-vs-occupied A/B (10 samples each) — classification bit-identical. Per-feature
discrimination (AUC; 0.5 = chance):

breathing_band_power  0.38     spectral_power    0.40
dominant_freq_hz      0.53     change_points     0.53
mean_rssi             0.60     motion_band_power 0.60
variance              0.69

The DSP underneath is alive — features vary sample to sample. variance carries weak signal
(AUC 0.69). It does not reach the classification.

breathing_band_power at AUC 0.38 is below chance: it read slightly lower with a person in
the room.

Notes on interpretation

The three constant fields are not three independent results, and should not be read as
three confirmations:

  • confidence is 0.4 + signal_quality * 0.3 + motion_score * 0.3 (main.rs:2670), so 0.4 is
    its floor.
  • estimated_persons is gated behind if classification.presence (main.rs:8090).

So this is one stuck classification echoed through dependent fields.

One inconsistency worth a look independently: the emitted confidence is 0.3999999999999996
while the live signal_quality_score was 0.4928733422189253. By the expression above that
should be at least 0.4 + 0.4929*0.3 = 0.5479, so the emitted value does not appear to come
from that expression.

Environment caveats (disclosed, not dismissed)

  • The three nodes sit within roughly 1 m of one another — poor multistatic geometry.
  • Masonry/stone room with a structural pillar and metal radiators — heavy multipath.

Both would weaken spatial discrimination. Neither explains a constant: node spacing cannot
make presence unable to differ between an occupied and an empty room, and the arms-at-50 cm
phase is about the largest perturbation available in the space.

Done when

Either the classification responds to gross occupancy change on this class of deployment, or
it is established that this configuration is out of scope and the system says so rather than
emitting a confident constant.

Work items

  • Confirm or refute on a second installation — the blocking question.
  • Trace why classification.presence never leaves true when frames continue and the
    environment changes drastically.
  • Check the confidence expression against signal_quality_score (above).
  • Consider whether an undiscriminating classifier should report low confidence rather than
    a constant 0.4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions