Counting Steps on a Smart Ring

2026/06/22

The problem

A smart ring streams tri-axial acceleration from the finger — one of the noisiest, most freely-rotating places on the body to mount a motion sensor. The ring tumbles as the hand swings, so no single axis is a reliable step signal, and rhythmic non-walking motion (typing, eating, brushing teeth) can look a lot like gait. The job: turn that raw stream into an accurate step count, while rejecting everything that isn’t walking.

One recording, end to end

The clearest way to see the pipeline is to push a single real recording through every stage and plot the actual signal at each step.

Step 1 — Raw tri-axial accelerometer

The ring streams ACC_X/Y/Z at 25 Hz (each CSV row holds 25 samples/axis), in units of g. Below is a 12 s window of steady walking. The three axes are all oscillating at the step rate, but their individual shapes depend on how the ring happens to sit and rotate on the finger — so no single axis is a reliable step signal.

Step 2 — Magnitude |a| (orientation invariance)

We collapse the three axes into their magnitude |a| = √(x²+y²+z²). This is orientation-invariant — it doesn’t matter which way the ring points — which matters because the data analysis showed the ring rotates continuously during motion. Each footfall now shows up as a clear hump riding on the ~1 g gravity baseline.

Step 3 — Band-pass 0.7–5 Hz

A 4th-order Butterworth band-pass (0.7–5 Hz) removes the gravity offset and slow drift (below 0.7 Hz) and high-frequency noise (above 5 Hz), leaving a clean zero-centred gait oscillation. Everything downstream runs on this signal. (The recording is also split into gap-free segments first, on any break in the 1 s timestamps — this example is a single segment.)

Step 4 — Activity gate (is this actually walking?)

Sliding windows are scored on three features, shown below over the whole recording:

  1. window RMS — band-limited motion energy (must clear a floor),
  2. spectral prominence — how sharp/dominant the cadence peak is,
  3. dominant cadence — must fall in the locomotion band (green).

Windows that pass are stitched into bouts (with hysteresis). A second sustained-gait fallback rescues real walking that the spectral test is too strict on. The shaded region (top panel) is what the gate accepts as walking — here, everything except the brief low-energy settling at the very start. This is the stage that rejects typing/eating and most non-gait motion.

Step 5 — Step counting (adaptive peak detection)

Inside the accepted region, steps are counted by adaptive peak detection on the band-passed signal: a prominence threshold that scales with the local amplitude, plus a refractory period (≥0.28 s, ~3.5 steps/s ceiling) so each footfall is counted once. Every red marker is one detected step.

Step 6 — Result

Summing the detected steps across all accepted bouts gives the final count. The cumulative-step curve climbs steadily with the walk and lands right on the ground truth.

301 vs 300 steps (+0.3%).

And this single example isn’t cherry-picked. Across the full evaluation — 62 labelled recordings, ~14.7 h of walking, jogging, stairs and free-living — the pipeline averages 4.0% absolute step error, beating the ring’s on-board firmware counter on every locomotion scenario (for example, 5.0% vs 25.4% on free-living commute data), while counting zero steps for typing and eating.

The full pipeline in one line

load (gap-aware segments) → |a| → band-pass 0.7–5 Hz
   → activity gate (energy + cadence prominence + sustained-gait fallback)
   → adaptive peak detection within accepted bouts → sum

Design notes

A few choices, all driven by the data analysis rather than guessed at: