Reproduces the validation of the ActiMotus human activity recognition algorithm against annotated ground truth, on seven public accelerometry datasets covering children, adults and older adults, including the three walking paces that ActiMotus reports from version 2.4.0.
Three commands regenerate every table and confusion matrix in the study. No data is
redistributed here: it is fetched from HuggingFace at pinned revisions and the
algorithm comes from PyPI, so the package supplies only the pipeline between them.
The generated tables and figures are committed under results/ so they can be read
without running anything; re-running overwrites them.
uv sync
uv run python scripts/01_features.py # several GB on the first run, tens of minutes
uv run python scripts/02_activities.py # about ten minutes
uv run python scripts/03_analysis.py # secondsResults land in results/ as .xlsx tables and .png confusion matrices.
Add --dataset <name> to restrict stages 1–2 to one dataset, --limit N for a quick
smoke run, --only <stem> to rebuild a single stage 3 output.
Each stage stamps its output with the ActiMotus version and dataset revisions it used, and refuses to consume a cache built from different inputs — a stale cache is an error, not a source of plausible wrong numbers.
| Dataset | Population | Sensors | HuggingFace | License |
|---|---|---|---|---|
| Lendt Adults | 35 adults | lateral thigh, SENS 12.5 Hz | josefheidler/har_adults_2024-lendt |
CC-BY-4.0 |
| NTNU Children | 46 typically-developing children | thigh + back, AX3 50 Hz | josefheidler/har_children_2024-harth |
CC0-1.0 |
| NTNU Adults | 31 adults | thigh + back, AX3 50 Hz | josefheidler/har_adults_2021-harth |
MIT |
| NTNU Older Adults | 18 adults aged 70–95 | thigh + back, AX3 50 Hz | josefheidler/har_older-adults_2023-harth |
CC-BY-4.0 |
| NTNU Walking Speeds | 24 adults | thigh + back, AX3 50 Hz | josefheidler/har_ws_adults_2025-harth |
CC-BY-4.0 |
| Lendt Energy Expenditure | 69 adults | lateral thigh, AX6 100 Hz | josefheidler/har_ee_adults_2024-lendt |
CC-BY-4.0 |
| Lendt Gait | 21 adults | lateral thigh, AX6 100 Hz | josefheidler/har_gait_adults_2023-lendt |
CC-BY-4.0 |
Revisions are pinned in datasets.toml. Lendt Energy Expenditure is pinned to v1.3.0,
which removes the labels of protocol stages that were logged but never performed (the
participant had stopped and the sensor was off the leg); see that dataset card. This package redistributes no data; the
dataset licenses bind you at download, and CC-BY-4.0 requires attribution to the
source study listed on each dataset card.
From version 2.4.0, ActiMotus splits walking into three paces on its step rate:
slow-walk below 100 steps a minute, walk from 100 to 115, and fast-walk above.
Walking is scored split wherever the protocol measured a speed, and pooled as
walk wherever it did not: free-living video cannot establish a pace. The ground
truth follows the speed bands of the datasets, anchored on the 2024 Adult Compendium
of Physical Activities: below 4.0 km/h is slow-walk (light), 4.0 to 5.5 km/h is
walk, and 5.5 to 7.2 km/h is fast-walk. A walk with no measured speed is never
scored for its pace.
| Walking scored | Datasets |
|---|---|
| split | Lendt laboratory, Lendt Energy Expenditure, NTNU Walking Speeds, Lendt Gait |
pooled as walk |
Lendt free-living, NTNU Children, NTNU Adults, NTNU Older Adults |
The step-rate cut-points were tuned on Lendt laboratory, Lendt Energy Expenditure and
NTNU Walking Speeds, so those three scores are not independent of the tuning. Lendt
Gait was not used to tune them and is the held-out check. Only NTNU Walking Speeds
reaches fast-walk, and its paces are approximate: its speeds are cohort means for
each tier rather than each participant's own, and its fastest tier is open-ended
upstream, so fast-walk there is a judgement rather than a measured band.
F1 per activity against the ground truth, ActiMotus 2.4.0 with its built-in
DEFAULT thresholds, thigh sensor only. Accuracy and Cohen's kappa describe the whole
recording; where walking is split, a pace read as the next pace counts as an error.
| Dataset | Lie | Sit | Stand | Shuffle | Slow-walk | Walk | Fast-walk | Stairs | Run | Cycle | Acc. | κ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Lendt, laboratory | 1.00 | 1.00 | 0.99 | — | 0.93 | 0.82 | — | — | 1.00 | 1.00 | 0.98 | 0.97 |
| Lendt, free-living | 0.08 | 0.90 | 0.77 | 0.43 | — | 0.89 | — | 0.40 | 0.97 | 0.97 | 0.88 | 0.83 |
| Lendt Energy Expenditure | — | 0.75 | 0.97 | — | 0.92 | 0.74 | — | — | 0.99 | 1.00 | 0.95 | 0.93 |
| NTNU Children | 0.79 | 0.83 | 0.81 | 0.33 | — | 0.89 | — | 0.46 | 0.83 | 0.88 | 0.83 | 0.78 |
| NTNU Adults | 0.08 | 0.79 | 0.79 | 0.38 | — | 0.84 | — | 0.63 | 0.93 | 0.89 | 0.81 | 0.70 |
| NTNU Older Adults | 0.05 | 0.82 | 0.83 | 0.29 | — | 0.91 | — | 0.16 | — | — | 0.80 | 0.71 |
| NTNU Walking Speeds | — | — | — | — | 0.86 | 0.65 | 0.73 | — | 0.98 | — | 0.81 | 0.75 |
| Lendt Gait | — | — | — | — | 0.91 | 0.86 | — | — | — | — | 0.86 | 0.75 |
The common pace error in the three treadmill datasets is normal walking read as slow, at 14 to 16% of normal walking. In NTNU Walking Speeds, normal walking is read as fast instead (26%). Few walking seconds leave walking altogether: at most 3%, except slow walking in Lendt Gait, which is read as shuffling 6% of the time.
Rows are normalised over the true class. The remaining figures — fused classes, the
thigh + trunk configuration, energy expenditure, walking speeds and gait — are in results/, alongside the
.xlsx tables and a provenance.json recording the ActiMotus version and dataset
revisions that produced them.
Adding the lower-back sensor changes only lying and sitting; every other activity is unchanged to two decimals, since the trunk feeds only that discrimination:
| Dataset | Lie, thigh | Lie, +trunk | Sit, thigh | Sit, +trunk |
|---|---|---|---|---|
| NTNU Children | 0.79 | 0.90 | 0.83 | 0.93 |
| NTNU Adults | 0.08 | 0.90 | 0.79 | 0.91 |
| NTNU Older Adults | 0.05 | 0.77 | 0.82 | 0.87 |
Collapsing to five behaviour classes — sedentary (lying + sitting), standing (standing + shuffling), walking (all three paces + stairs), running and cycling — gives F1, thigh sensor only:
| Dataset | Sedentary | Standing | Walking | Running | Cycling |
|---|---|---|---|---|---|
| Lendt, laboratory | 1.00 | 0.99 | 0.99 | 1.00 | 1.00 |
| Lendt, free-living | 0.99 | 0.82 | 0.90 | 0.97 | 0.97 |
| Lendt Energy Expenditure | 1.00 | 0.96 | 0.99 | 0.99 | 1.00 |
| NTNU Children | 0.97 | 0.85 | 0.89 | 0.83 | 0.88 |
| NTNU Adults | 0.95 | 0.83 | 0.85 | 0.93 | 0.89 |
| NTNU Older Adults | 0.99 | 0.84 | 0.92 | — | — |
The lower-back sensor makes no difference here — every fused F1 is unchanged to two decimals with or without it. Its whole contribution is separating lying from sitting, and both collapse into sedentary.
Precision, recall and F1 with 95% confidence intervals, computed per participant and
then averaged across participants, are written to the .xlsx tables in results/,
alongside confusion matrices as .png, for both the eight-activity and fused
vocabularies.
- ActiMotus 2.4.0 (was 2.3.3): three walking paces on a repaired step rate, no walk-to-run cadence rule, and a corrected stairs reference. Stairs → walk in Lendt Energy Expenditure accounts for most of its rise.
- Walking is scored split where a speed was measured and pooled elsewhere (see Walking paces). The separate fast-walk handling of 1.0 is replaced by this rule.
- Two datasets added: Lendt Energy Expenditure, added after 1.0.1 and released here for the first time, and Lendt Gait (pace only, held out from the tuning).
- Newer dataset revisions: Lendt Adults v1.0.3, NTNU Walking Speeds v1.1.0 (a truncated recording repaired) and Lendt Energy Expenditure v1.3.0 (unperformed stages unlabelled). The other three are unchanged.
- Figures that pair two vocabularies give each matrix its own row axis.
The published datasets use a hub frame with x up along the limb, y right and
z forward. The two sensors need opposite treatment, so data.sensor_frame takes a
required to_acti_frame argument rather than guessing:
- Thigh — rotated 180° about its long axis (
yandznegated). ActiMotus expects the thighzposterior. Without this, Lendt falls from 0.952 to 0.665. - Back — left as published. ActiMotus expects the trunk
zanterior, which the hub frame already provides.
Automatic flip detection stays enabled, but only as a guard against genuinely
mis-worn sensors — never as a substitute for the conversion. With the frames correct
it changes nothing on any of the 244 thigh recordings, and both orientation=True and
orientation=False give identical predictions, an invariant enforced by
tests/test_integration.py.
- Thresholds are ActiMotus's built-in
DEFAULTconfiguration, tuned by Bayesian optimization outside this package. Re-deriving them is out of scope. - Lying detection from the thigh alone fails for adults and older adults (recall 0.08 and 0.06); the back sensor resolves it (0.88 and 0.82). Children are the exception, reaching 0.96 from the thigh alone.
- The walking-pace cut-points were tuned on three of the four split datasets; only Lendt Gait is independent of them.
Please cite the validation study, not this repository. The article is under review; its DOI will be added here on publication.
If you need to reference the code specifically — for example to pin the exact version that produced a result — this package also has a DOI, 10.5281/zenodo.21955041, which always resolves to the latest release.
The datasets are cited separately. Each HuggingFace card names the study to attribute; CC-BY-4.0 requires it.
BSD 3-Clause, matching ActiMotus. See
LICENSE.

