Skip to content
Alexander Refsum Jensenius edited this page Jul 29, 2026 · 4 revisions

Traps

Every item here is a mistake that was made in real analyses before the package existed.

Units

Linear acceleration from a phone is in m/s², not g. A data dictionary said g, the analysis multiplied by 9.80665, and every quantity of motion in a year-long study was that factor too large. It survived into two figure captions and a whole report directory after the correction was applied elsewhere. Pass unit= explicitly, or better, let the reader set it.

Sampling rates

Do not invert the median interval. Where timestamps are rounded to milliseconds, that returns exactly 250 Hz for a 256 Hz recording, and 636 Hz for one arriving at 106. Count samples over the elapsed span — mm.measured_rate.

A row rate is not a sensor rate. One phone logger writes a row whenever any sensor updates, repeating the previous accelerometer value in between: 100 Hz of rows, 16.7 Hz of actual accelerometer updates.

Never upsample. An analysis that upsampled 20 Hz data to 25 Hz produced multifractal widths up to 6.6 where the plausible range is about 1. Nothing failed. mm.to_rate raises instead.

Filters

Two conventions are in circulation and differ by 15.5 per cent. A 10 Hz low-pass keeps sub-0.3 Hz postural drift; the 0.3–10 Hz band-pass does not. Both are legitimate; quoting a number without saying which is not. An accelerometer can only use the band-pass.

A 10 Hz low-pass cannot be computed at 20 Hz — the cutoff is Nyquist there and no transition band remains.

Sentinels

Each of these is a plausible-looking number that is not a measurement, and each has been read as data:

  • an optical marker "at the origin" — a zero coordinate triplet is a gap code
  • a centre of pressure at exactly (0.5, 0.5) — that is the middle of a board with nobody on it
  • a respiration sample at 0 or 1023 — the converter's rails, not the waveform
  • exact-zero accelerometer rows at the start of a phone recording

The readers convert all of them to NaN.

Markers

Read by name, never by position. Six files in one collection break the documented 22-marker order. The README's positional quick-start mis-assigned markers in every one of them until it was rewritten.

Alignment

Never cross-correlate two drifting signals directly. Over 200 pairs of independent random walks, the best-lag correlation had a median of 0.47, exceeded 0.5 forty per cent of the time and reached 0.98. mm.xcorr_lag differences its inputs by default; the same pairs then never exceed 0.16.

A sharp correlation peak is not evidence. Two peak-sharpness measures were tried and both get it backwards — a drifting series correlates highly with itself at every nearby lag, so its true peak looks unremarkable, while white noise gives a flat curve whose maximum looks strikingly sharp.

Binning

Flag the partial final bin. Including it once inflated a deposited series three- to fourteenfold. QomResult.binned marks it partial, and marks the filter-contaminated ends filter_transient.

Comparisons that look fine and are not

Task instruction dominates everything. In one corpus: "stand as still as possible" gives 4.4 mm/s, "stand in a relaxed posture" 4.8, "you may sway" 39–42, and a performance including walking 13.8. No filtering makes those comparable.

Placement changes what the number is about. A head marker and a chest sensor correlate at 0.06, while two units on the same skull correlate at 0.93.

A body-worn accelerometer cannot separate leaning from moving. Measured against a gyroscope, tilt inflates the figure by 1.56×. mm.tilt_fraction quantifies it when a gyroscope is present.

Clone this wiki locally