Skip to content

Sampling rates

Two rules, both learned by getting them wrong.

Measure the rate, do not read it

mm.measured_rate(timestamps)      # samples over elapsed span

Deliberately not the reciprocal of the median interval. Where timestamps are rounded to whole milliseconds the intervals become a mixture of adjacent integers whose median is a quantisation artefact:

Truth Median-interval estimate
256 Hz 250 Hz
106 Hz 636 Hz

Nominal rates in headers and documentation were wrong by up to 4.4 per cent in one corpus, and by a factor of 37 in one record.

Beware also of the difference between a row rate and a sensor rate. One phone logger writes a row whenever any sensor updates and repeats the previous accelerometer value in between: the rows arrive at 100 Hz while the accelerometer updates at 16.7 Hz.

mm.rate_quality(timestamps)
# jitter, largest gap, duplicate and backward timestamps, coverage

Downsample, never upsample

mm.to_rate(x, fs_in, 20.0)     # raises if this would upsample

Upsampling invents structure between samples, and every method that reads across scales — multifractal analysis, recurrence quantification, anything with an embedding — treats the invention as real. One 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; the numbers were simply wrong.

If a series cannot reach the target rate it does not belong in a comparison built at that rate. Excluding it is correct; interpolating it in corrupts the comparison silently.

The common rate

mm.COMMON_RATE is 20 Hz. It is the Nyquist rate of the 0.2–10 Hz band, so nothing the band keeps is lost, and it is low enough that the slowest collections need no upsampling.

It costs about 2 per cent against the native-rate value on 200 Hz optical data. Report both if it matters.

Irregular sampling

grid, y = mm.regularize(t, x, fs_out=20.0, max_gap_s=2.0)

Sorts, drops duplicate and backward timestamps, interpolates, and returns NaN inside gaps longer than max_gap_s rather than bridging them — so that a 132-second hole cannot be mistaken for 132 seconds of stillness.