fix: BUG-22 smooth GPS-derived speeds in trip max (trailing window)

This commit is contained in:
Mathieu Moran
2026-08-14 23:00:53 -04:00
parent d9314969d8
commit a0be96dfaa
2 changed files with 36 additions and 8 deletions
+26 -1
View File
@@ -7,6 +7,7 @@ GPS_MOTION_METERS = 8
MIN_GPS_MOTION_SAMPLES = 3
MAX_GPS_SAMPLE_GAP_SECONDS = 30
MAX_PLAUSIBLE_SPEED_KMH = 220
GPS_SPEED_WINDOW = 6 # ~30 s at 5 s logging — smooths GPS position jitter
EARTH_RADIUS_KM = 6371.0088
@@ -180,6 +181,7 @@ def build_trip_summaries(raw_rows):
distance_km = 0
segment_speeds = []
obd_speeds = []
gps_speeds = []
has_obd_motion = any(event["obd"] for event in events)
for previous, row in zip(trip_rows, trip_rows[1:]):
segment_km, segment_speed = _segment(row, previous)
@@ -189,6 +191,29 @@ def build_trip_summaries(raw_rows):
segment_speeds.append(segment_speed)
if row["speed"] > 0:
obd_speeds.append(row["speed"])
# Smoothed GPS-derived speeds for the max — a trailing ~30s window
# averages out GPS position jitter (raw 5s segments can spike).
for index in range(1, len(trip_rows)):
if trip_rows[index]["speed"] > 0:
continue # OBD present here — already counted in obd_speeds
window_start = max(0, index - GPS_SPEED_WINDOW)
start_row = trip_rows[window_start]
end_row = trip_rows[index]
if (
start_row["latitude"] is not None
and end_row["latitude"] is not None
):
seconds = (
end_row["datetime"] - start_row["datetime"]
).total_seconds()
window_km = haversine_km(
(start_row["latitude"], start_row["longitude"]),
(end_row["latitude"], end_row["longitude"]),
)
if seconds > 0 and window_km * 1000 >= GPS_MOTION_METERS:
window_speed = window_km / seconds * 3600
if window_speed <= MAX_PLAUSIBLE_SPEED_KMH:
gps_speeds.append(window_speed)
start = trip_rows[0]
end = trip_rows[-1]
@@ -227,7 +252,7 @@ def build_trip_summaries(raw_rows):
distance_km / duration_seconds * 3600, 1
) if duration_seconds else 0,
"max_speed_kmh": round(
max((obd_speeds + segment_speeds) or [0]), 1
max((obd_speeds + gps_speeds) or [0]), 1
),
"start_odometer": next((r["odometer"] for r in trip_rows if r.get("odometer")), None),
"end_odometer": next((r["odometer"] for r in reversed(trip_rows) if r.get("odometer")), None),