Skip to content

Dementia Signal Detection

A periodic worker (DementiaSignalWorker) runs every 60 s (configurable) and computes six signal kinds per tracked identity. Each signal is persisted via upsert with a deterministic UUID5 so the same detection window always maps to the same row.

Signal computation

All signals use robust z-scores (median + MAD) against per-person historical baselines fetched from the BehaviorBaselineRepository. A configurable hysteresis system prevents flicker:

  • Onset debounce: a trigger condition must hold for min_consecutive runs (default: 2) before first emission.
  • Cooldown: after emission, the same (identity, kind) is suppressed for cooldown_minutes (default: 60) unless severity escalates.
  • Severity monotonic: within an active episode, severity only increases; the episode closes when the trigger condition clears.

Incremental window computation (enabled by default) merges new trajectory/dwell data with rolling state from previous runs, avoiding re-fetching the full 24-hour window on each cycle.

Signal kinds

KindTriggerBaselineSeverity tiers
pacingRepeated room transitions in a 30 min window, normalized for observation density. Minimum 8 transitions and 2 unique rooms. Purpose-driven ambulation (kitchen, living room, bathroom) typically produces 5-6 transitions; 8+ in 30 min identifies repetitive, purposeless movement.30-day hourly activity transition ratesinfo (>0.15 rate), warning (>0.3 rate), emergency (rate-based)
sundowning_indexEvening (17:00-22:00 local) room transition rate vs 14-day evening baseline. Minimum 30 evening observation-minutes.14-day evening-window activityinfo (mod-z >= 2.5), warning (>= 3.0), emergency (>= 4.0)
bathroom_dwell_anomalyCurrent open bathroom dwell vs 30-day closed-dwell duration baseline. Nighttime (22:00-06:00) uses a relaxed z-threshold (4.0 vs 3.5). Cold start (before 5+ baseline samples): absolute 45 min threshold, severity capped at warning. Requires accurate single-PH resolution at the bathroom door: the cross-camera dedup pass ensures a hallway camera and an adjacent camera seeing the same senior at the door produce one PersonHypothesis, so the dwell timer starts correctly. The integration proof for this scenario lives in tests/integration/test_world_tracker_e2e.py::test_hallway_bathroom_one_person, replaying tests/fixtures/frame_replays/hallway_bathroom_door.bin.30-day dwell durationsinfo (z >= 3.5), warning (z >= 4.0), emergency (z >= 5.0)
nighttime_movementRoom transitions during 22:00-06:00 local time. Cold start: flat threshold of 3 transitions (one bathroom trip returns 2 transitions; 3+ indicates additional nocturnal movement).14-day hourly activityinfo, warning (z >= 3.0), emergency (z >= 4.0)
stillness_anomalySustained near-zero motion energy in a non-resting posture (lying in non-bedroom, or prolonged sitting/standing). Default threshold: 60 min. Desk work, reading, and TV watching routinely exceed 30 min without clinical concern; 60 min aligns with clinical guidelines for meaningful seated immobility. Resting rooms are configurable (default: "bed", "bedroom").30-day stillness episode durationsPosture-aware: lying starts at warning (escalates to emergency at 120 min); sitting/standing starts at info at threshold (upgrades to warning at 2× threshold)
absenceNo detection for > 60 min (configurable). Cameras do not cover every room; 30 min gaps are normal (cooking, porch, bathroom). Hourly context from 14-day baseline: if the person is historically frequently absent at this hour, severity is demoted.14-day hourly activityinfo (>60 min), warning (>120 min), emergency (>180 min); demoted by expected_absence_prior

Signal structure

Each DementiaSignal carries:

FieldDescription
signal_idDeterministic UUID5 from (identity, kind, window_start, window_end)
identity_idTracked person
signal_kindOne of the 6 kinds above
severityinfo, warning, or emergency
valueRaw metric value (rate, duration, transition count)
baselineHistorical median from the 30-day baseline
z_scoreModified z-score against the baseline
window_start / window_endDetection window (UTC)
algorithm_versionVersion stamp for signal evolution (currently 3)
contextStructured JSON payload with kind-specific details

Acknowledging a signal in the admin UI sets acknowledged_at, which the dementia_signal filter uses for cooldown.

Configuring signal thresholds

All signal thresholds are configurable via environment variables, with defaults set to clinically validated values. Override any threshold in the tracking orchestrator's config/settings.yaml or via environment variable:

yaml
# tracking-orchestrator/config/settings.yaml
signal:
  interval_s: "${SIGNAL_INTERVAL_S:-60}"
  stillness_threshold_minutes: "${SIGNAL_STILLNESS_THRESHOLD_MINUTES:-60}"
  stillness_emergency_minutes: "${SIGNAL_STILLNESS_EMERGENCY_MINUTES:-120}"
  stillness_motion_floor: "${SIGNAL_STILLNESS_MOTION_FLOOR:-0.02}"
  pacing_room_threshold: "${SIGNAL_PACING_ROOM_THRESHOLD:-8}"
  pacing_window_minutes: "${SIGNAL_PACING_WINDOW_MINUTES:-30}"
  nighttime_transition_threshold: "${SIGNAL_NIGHTTIME_TRANSITION_THRESHOLD:-3}"
  absence_threshold_minutes: "${SIGNAL_ABSENCE_THRESHOLD_MINUTES:-60}"
  bathroom_absolute_threshold_seconds: "${SIGNAL_BATHROOM_COLD_START_S:-2700}"
Environment variableDefaultDescription
SIGNAL_INTERVAL_S60How often the signal worker runs (seconds)
SIGNAL_STILLNESS_THRESHOLD_MINUTES60Minimum stillness duration before triggering stillness_anomaly at info severity
SIGNAL_STILLNESS_EMERGENCY_MINUTES120Stillness duration that escalates lying posture to emergency severity
SIGNAL_STILLNESS_MOTION_FLOOR0.02Motion energy below this value is treated as stillness. Normal physiological ambient motion (breathing, micro-adjustments) is approximately 0.01-0.02.
SIGNAL_PACING_ROOM_THRESHOLD8Minimum room transitions in the pacing window to trigger pacing
SIGNAL_PACING_WINDOW_MINUTES30Rolling window for pacing transition counting (minutes)
SIGNAL_NIGHTTIME_TRANSITION_THRESHOLD3Cold-start flat threshold for nighttime_movement (transitions per night)
SIGNAL_ABSENCE_THRESHOLD_MINUTES60Minimum undetected duration before triggering absence at info severity
SIGNAL_BATHROOM_COLD_START_S2700Cold-start absolute threshold for bathroom_dwell_anomaly (seconds; 2700 s = 45 min)

Released under the AGPL-3.0 License.