Wearable inference pipeline that approaches Shake or Tremor Sensing using detection of motion samples on Apple Devices - Watch and iPhone. Ingredients include capure of Inertial Measurement Unit (IMU) samples for accleration, rotattion and gravity using CoreMotion capture. Samples are passed both to on-board CoreML inference lightweight 1D CN plus to a backend inference pipeline - a Python substrate for orchestration and model training.
iPhone capture
Apple Watch
Watch Controls
Motion waveform
Landing
Shake inference plot
Quattro is a system for detecting shake and tremor from Apple Watch and iPhone sensor data. It captures motion readings from the device's accelerometer and gyroscope, sends them to a backend for analysis, and returns a single result: shake detected — yes or no — with a confidence score (0.0 to 1.0).
The clinical motivation is detecting motion patterns associated with neurological conditions such as Parkinson's Disease and Essential Tremors. An Apple Watch worn on the wrist is a natural source for continuous, unobtrusive monitoring.
The iOS and watchOS applications use Apple's CoreMotion framework to capture
motion samples — acceleration, rotation, and gravity vectors — at approximately 100 Hz.
Each sample is packaged as a MotionDataSample with a timestamp and device
identifier, batched for backend transmission.
On-device inference is also supported: a CoreML model package runs locally on
the phone or watch for real-time classification without a network round trip. The CoreML model
is exported from the same PyTorch model used in the backend, ensuring weight parity.
Waveform display was adapted from EKG signal work in the Signals project — generic enough to support the 9 IMU channels with minor adjustments. Two display modes are available: bundle-internal raw sample sets, and loaded files from the export/upload feature.
A Python service built around a REST receiver, data storage, workflow orchestration, inference, and CoreML export.
| Component | Role |
|---|---|
| Receiver | FastAPI REST endpoint accepting motion data batches from devices |
| Data Storage | Samples persisted as JSON for downstream processing |
| Orchestrator | Workflow coordination and data processing — Prefect and Dagster |
| Inference | 1D CNN classifier (PyTorch) — shake vs. no-shake |
| Converter | Exports trained model to CoreML for on-device deployment |
Reference below for an illustration for the key steps in the capture and inference pipeline data flow.
| Connection | Carries | Transport |
|---|---|---|
| Core Motion → Motion Detector | Inertial Measurement Unit (IMU) data sample: [acceleration,rotation,gravity] | call |
| Motion Detector → Data Buffer | IMU data sample (N=1) | memory |
| Motion Detector → Classifier | IMU data samples (N=128) | memory |
| Classifier → Provider | shake prediction with confidence score | call |
| Provider → Receiver | batch of IMU data samples | JSON REST API [FastAPI] |
| Receiver → Data Storage | IMU data sample batch | filesystem |
| Orchestrator → Inference | IMU data sample set, batch selection | Data Storage |
| Inference → Orchestrator | shake prediction with confidence score | call |
| Orchestrator → User Interface | IMU data sample batch, shake prediction with confidence score | user data navigation |
A lightweight 1D convolutional neural network ShakeTremorClassifier designed for fast inference on edge devices.
First deployment targets Apple Watch and Apple iPhone; architecture is also suitable for
NVIDIA Jetson Orin Nano.
| Property | Value |
|---|---|
| Parameters | ~161K |
| Model size | ~630 KB |
| Inference time | 1–15 ms (CPU) |
| Input window | 1.28 seconds at 100 Hz (128 samples) |
| Input channels | 9 — acceleration x/y/z · rotation x/y/z · gravity x/y/z |
| Output | SHAKE yes/no + confidence score 0.0–1.0 |
Three convolutional blocks with decreasing kernel sizes (7 → 5 → 3) capture motion patterns at different time scales — from broad shake gestures down to fine tremor oscillations. A classification head outputs probabilities for shake vs. no-shake.
Raw sensor data passes through three stages before the classifier:
| Stage | Detail |
|---|---|
| 1. Normalization | z-score scaling per sensor type — acceleration, rotation, and gravity each have different ranges |
| 2. Fixed-length formatting | Sequences padded or truncated to exactly 128 timesteps |
| 3. Channel reordering | Data reshaped to (N, 9, 128) for the convolutional layers |
While the classifier operates on raw IMU data without hand-crafted features, classical feature extraction remains useful upstream as a signal quality gate. The Euclidean norm of the acceleration vector provides a low-cost switch to wake or sleep the inference pipeline:
|a| = √(ax² + ay² + az²) Near zero → static / quiet state → no need to run inference Non-zero → dynamic state → candidate for classification
Initial weights were determined using the
Parkinson's Disease Tremor Dataset
— pre-windowed X.npy (N, 128, 3) + Y.npy labels, binarized with
Y > 0 (tremor vs. none). The IMU-Wild sub-dataset adds gyroscope (6 channels).
input_channels=3.
Fix: X.transpose(0, 2, 1) → (N, 3, 128), then pad to (N, 9, 128).
Active workbench project. Confidence scores are flowing end-to-end — from sensor capture on device, through the backend inference pipeline, back to the app UI.
Current focus areas:
| Area | Notes |
|---|---|
| Model architecture evaluation | Comparing approaches from recent HAR literature |
| Training data pipeline | Expanding dataset coverage and augmentation |
| Preprocessing refinement | Feature extraction and normalization tuning |
| Attention mechanisms | Frequency-domain features under exploration as enhancements |