CPM Pipeline
Scope
This document defines the runtime CPM pipeline from accelerometer samples to prediction consumption.
Canonical Flow
App.tsxstartsstartActivityService()on mount and callsstopActivityService()on cleanup.activityServicestartsexpo-sensorsaccelerometer streaming at ~30 Hz.- Sensor samples are buffered in memory (
src/sensors/accelerometer.ts), converted fromgtom/s^2, timestamped from the native sensor event, and pruned to the last ~75 seconds. activityServicetreats a CPM window as ready only when it spans nearly 60 seconds, allowing one configured sensor interval of tolerance.- Every 60 seconds,
activityServicereads the most recent ready window and callscomputeCpmFrom60s(...)insrc/model/inferenceActivity.ts, which consumes the collected 30 Hz window directly. - When CPM computation succeeds, one row is written to
cpm_historyin SQLite throughsrc/db/cpmDb.ts. - Callers such as
predictionHeatRiskandPredictionCoreTempCardconsumegetActivityCpm40Average()fromactivityService.
Readiness Contract (getActivityCpm40Average)
- Window: last 40 minutes.
- Minimum history: at least 35 rows.
- Freshness: latest row must be <= 2 minutes old.
- Return: average CPM when ready, otherwise
null.
Supporting References
- Schema: schemas/cpm-history.md
- Diagram: ../diagrams/activity-cpm-pipeline.mmd
Invariants
- Model behavior lives in
src/model/inferenceActivity.ts; orchestration should stay inactivityService. - The model consumes the collected 30 Hz window directly; there is no separate 60 Hz downsampling stage.
- Each successful minute tick produces at most one persisted CPM row.
- Storage shape, retention, and query ordering live in the schema doc.