Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt

Use this file to discover all available pages before exploring further.

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

AttributeValue
FamilyLinear Support Vector Classifier (One-vs-Rest)
FormatONNX
Asset pathassets/models/linear_svc_model.onnx (Android) / bundled equivalents on iOS and Dart
RuntimeONNX Runtime (ai.onnxruntime on Android, native onnxruntime framework on iOS)
Class count4
Latency target< 5 ms per inference on a modern mid-range device
DistributionBundled in the SDK; no network calls; no over-the-air updates

Classes

["LAYING", "MOVING", "SITTING", "STANDING"]
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

class MotionState {
  final String majorState;                  // one of the four labels
  final double majorStatePct;               // probability mass on major state
  final Map<String, double> perStateConfidence; // class probabilities
}
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

ConcernBehavior
ThreadInference runs on a background dispatcher. Results delivered back on the main isolate / main queue.
BatteryContinuous 50 Hz collection is the primary cost — much higher than the inference itself. Disable when not needed.
MemoryModel bytes loaded once on loadModel(); ORT session retained for the SDK’s lifetime.
Cold startFirst inference includes ORT environment + session init; subsequent inferences are pure compute.
Failure modesIf 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

ConditionLoaded?
BehaviorConfig.enableMotionLite = false (default)No — collectors don’t run, no inference.
enableMotionLite = trueLoaded lazily on initialize().
emitRawMotionSamples = true && enableMotionLite = falseNot loaded — the SDK only forwards raw samples to the host.
Both trueLoaded; 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 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.