BehaviorConfig.enableMotionLite = true, the SDK runs a small classifier on accelerometer features to predict the user’s gross motion state. This page is the model card.
Identity
| Attribute | Value |
|---|---|
| Family | Linear Support Vector Classifier (One-vs-Rest) |
| Format | ONNX |
| Asset path | assets/models/linear_svc_model.onnx (Android) / bundled equivalents on iOS and Dart |
| Runtime | ONNX Runtime (ai.onnxruntime on Android, native onnxruntime framework on iOS) |
| Class count | 4 |
| Latency target | < 5 ms per inference on a modern mid-range device |
| Distribution | Bundled in the SDK; no network calls; no over-the-air updates |
Classes
Inputs
The classifier consumes a fixed-order feature vector derived from a windowed accelerometer buffer:- 3-axis acceleration in m/s² (gravity included).
- Sampling rate: native motion collector at the platform’s max — typically 50 Hz.
- Window: a rolling buffer the SDK aggregates into derived features.
MotionFeatureExtractor — refer to source for the authoritative list.
Outputs
majorStatePct comes from the model’s calibration head (a softmax-style normalisation since the underlying SVC produces decision scores rather than probabilities). Treat it as a heuristic, not a calibrated posterior.
Training context
- The model file is shipped as ONNX, exported from
scikit-learn(Linear SVC with one-vs-rest). - Training data, train/test splits, fairness metrics, and demographic coverage are not documented in the SDK source. Treat the classifier as a fast best-effort component, not a clinical sensor.
emitRawMotionSamples = true and forwarding samples to the Synheart runtime via pushAccel.
Runtime considerations
| Concern | Behavior |
|---|---|
| Thread | Inference runs on a background dispatcher. Results delivered back on the main isolate / main queue. |
| Battery | Continuous 50 Hz collection is the primary cost — much higher than the inference itself. Disable when not needed. |
| Memory | Model bytes loaded once on loadModel(); ORT session retained for the SDK’s lifetime. |
| Cold start | First inference includes ORT environment + session init; subsequent inferences are pure compute. |
| Failure modes | If the model fails to load (asset missing, ORT init error), the SDK logs and motionState is permanently null for the session. |
When the model is and is not loaded
| Condition | Loaded? |
|---|---|
BehaviorConfig.enableMotionLite = false (default) | No — collectors don’t run, no inference. |
enableMotionLite = true | Loaded lazily on initialize(). |
emitRawMotionSamples = true && enableMotionLite = false | Not loaded — the SDK only forwards raw samples to the host. |
Both true | Loaded; the SDK’s classifier and the host-side runtime classifier run side-by-side. |
Known limits
- No gait variants. “MOVING” is a single class; the SDK does not distinguish walking, running, cycling, or vehicle motion.
- Posture vs activity. “SITTING” vs “STANDING” relies on gravity decomposition, which is sensitive to phone orientation. A phone flat on a desk reads differently from one in a pocket.
- No biometric calibration. The classifier does not adapt per user.
- No location or transport context. Inputs are accelerometer-only; “MOVING” inside a vehicle is detected the same as walking.
- Charging stationary cases. A phone left charging on a flat surface typically classifies as “LAYING”.
- No confidence threshold. The SDK returns whichever class has the highest score; downstream consumers should apply their own threshold using
majorStatePctif they want to drop low-confidence predictions.
Migration path
The runtime’sMotionStateHead is the long-term replacement. Apps consuming synheart-core should already prefer:
- Set
BehaviorConfig.emitRawMotionSamples = true. - Set
BehaviorConfig.enableMotionLite = false. - Read motion state from the runtime’s HSI emit.
Related
- Behavior Overview —
enableMotionLiteandemitRawMotionSamplesconfig. - Metric Definitions — the other 12 metrics, separate from motion state.