GPS drift elimination
Raw consumer GPS jitters by 5–15 m per fix at street level, much worse in cities and forests. Without any cleanup, your route on the map looks like a child's scribble — the line wanders 30 m to the left, snaps back, pops 50 m forward, then crosses itself twice. Drift elimination is what turns that into a real path.
The algorithm
The pipeline is a single-pass clustering filter. For each GPS point we keep a rolling centroid of nearby points; if the new point is within an adaptive threshold of the centroid, it's absorbed into the cluster (and only the cluster's running average position is kept). When the new point exceeds the threshold, the cluster closes and a fresh one starts.
Pseudo-code:
T_eff = max(T_config, gps.acc) # adaptive threshold
# — never tighter than the
# phone's stated accuracy
for each point p:
if cluster.empty:
cluster = [p]
continue
d = haversine(p, cluster.centroid)
if d <= T_eff:
cluster.append(p) # absorb into running avg
cluster.centroid = running_mean
cluster.weight += 1
else:
output(cluster.centroid, weight=cluster.weight)
cluster = [p]
Two key design choices:
- Adaptive threshold =
max(T_config, gps.acc). The per-point GPS accuracy reading from the phone is always honoured; configuration sets a floor, not a ceiling. So when accuracy degrades to 30 m in dense forest, the filter automatically loosens to match. - Running centroid is updated O(1) per absorbed point (running sum / count). For long stops with hundreds of absorbed points, this stays constant-time.
What gets through
- Any movement that exceeds the adaptive threshold for at least one point survives — fast walking, all running, all biking.
- Stops at viewpoints / cafés become a single cluster centred on the spot, with weight ~ N (= time spent there). The weight is later used by the heatmap density layer.
What gets filtered out
- Stationary jitter while you're standing still — collapsed to one point.
- Brief multi-meter jumps caused by satellite reacquisition.
- Burst-noise from urban canyons.
What it doesn't fix
- A genuinely wrong fix that's 200 m off but stays self- consistent for several seconds. The filter doesn't know your intended path; it can only collapse jitter, not correct systematic bias.
- Tunnels — those are GPS dead zones. See signal-independent tracking for how we handle long gaps and metro detection for the special-case underground rebuilder.
Per-point weight
Each output point carries a w (weight) field equal to the
number of raw points absorbed into it. Downstream stages use it:
- The heatmap layer uses weight as point density (heavy-stay spots burn brighter).
- The transport classifier sees weighted speed — a 10-second cluster doesn't get classified as "0 km/h driving"; the cluster is treated as a single fixed point that contributes zero to instantaneous speed but full duration to elapsed time.
Related
- Stop detection — runs after drift filtering, finds named clusters.
- Catmull-Rom route smoothing — visual smoothing on top of cleaned GPS.
- Altitude smoothing — Z-axis cleanup, runs in parallel.
Need help? Contact support · Where Is Tereza?