-
Notifications
You must be signed in to change notification settings - Fork 0
Traps
Every item here is a mistake that was made in real analyses before the package existed.
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.
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.
Two conventions are in circulation and differ by about 15 per cent. A 10 Hz low-pass keeps the slow postural drift; the 0.2–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.
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.
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.
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.
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.
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.
Do not test a group stilling statistic against 0.5. People standing still are not a coin
flip: movement decays after any excursion, so at a randomly chosen moment rather more than half
of a group is already slowing down. Testing against a half finds an effect in any recording.
Use sliding_null, which computes the same statistic at every moment of the same recording.
Do not average pairwise correlations to answer "did they move together". That loses the
timing, which is usually the question. coincidence_test keeps it.
Do not shuffle samples to build a group null. That destroys each person's own rhythm along with the alignment, so it tests a hypothesis nobody holds. Shift each person by an independent bounded offset instead: individual structure survives, only alignment breaks.
Do not optimise a band edge on one statistic and then report another. Sweeping the lower edge on medians gives an optimum at 0.2 Hz, where the between-dataset spread is 2.1 per cent and the mean's is 4.6. At 0.3 Hz it is the reverse. Whichever you tune on is the one to report.
A lower band edge needs a longer recording. The filter transient scales with it: 27 seconds
at each end at 0.3 Hz, 40 at 0.2. Below about two minutes at 0.2 Hz there is no clean interior
at all, and QomResult.binned will flag every bin.
Check a lower edge against integration drift before adopting it. That is what the edge is for. The mean-to-median speed ratio is a cheap proxy: it climbs when drift leaks through. It sits at 2.00 at 0.3 Hz and 2.07 at 0.2, which is flat enough to be safe.