Skip to main content
When 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

Classes

These are the only labels the SDK emits today. The class list is loaded from the model’s label asset on init; mismatches against the model’s output dimension cause init to fail loudly.

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.
The exact set of derived features (statistical moments, jerk magnitudes, axis correlations, gravity-removed components, etc.) is owned by the SDK’s 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.
When you need stronger guarantees, switch to the runtime’s on-device motion classifier by setting emitRawMotionSamples = true and forwarding samples to the Synheart runtime via pushAccel.

Runtime considerations

When the model is and is not loaded

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 majorStatePct if they want to drop low-confidence predictions.

Migration path

The runtime’s MotionStateHead is the long-term replacement. Apps consuming synheart-core should already prefer:
  1. Set BehaviorConfig.emitRawMotionSamples = true.
  2. Set BehaviorConfig.enableMotionLite = false.
  3. Read motion state from the runtime’s HSI emit.
The SDK’s Linear SVC remains for direct consumers and for the migration window.