fix: BUG-22 smooth GPS-derived speeds in trip max (trailing window)
This commit is contained in:
+26
-1
@@ -7,6 +7,7 @@ GPS_MOTION_METERS = 8
|
|||||||
MIN_GPS_MOTION_SAMPLES = 3
|
MIN_GPS_MOTION_SAMPLES = 3
|
||||||
MAX_GPS_SAMPLE_GAP_SECONDS = 30
|
MAX_GPS_SAMPLE_GAP_SECONDS = 30
|
||||||
MAX_PLAUSIBLE_SPEED_KMH = 220
|
MAX_PLAUSIBLE_SPEED_KMH = 220
|
||||||
|
GPS_SPEED_WINDOW = 6 # ~30 s at 5 s logging — smooths GPS position jitter
|
||||||
EARTH_RADIUS_KM = 6371.0088
|
EARTH_RADIUS_KM = 6371.0088
|
||||||
|
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ def build_trip_summaries(raw_rows):
|
|||||||
distance_km = 0
|
distance_km = 0
|
||||||
segment_speeds = []
|
segment_speeds = []
|
||||||
obd_speeds = []
|
obd_speeds = []
|
||||||
|
gps_speeds = []
|
||||||
has_obd_motion = any(event["obd"] for event in events)
|
has_obd_motion = any(event["obd"] for event in events)
|
||||||
for previous, row in zip(trip_rows, trip_rows[1:]):
|
for previous, row in zip(trip_rows, trip_rows[1:]):
|
||||||
segment_km, segment_speed = _segment(row, previous)
|
segment_km, segment_speed = _segment(row, previous)
|
||||||
@@ -189,6 +191,29 @@ def build_trip_summaries(raw_rows):
|
|||||||
segment_speeds.append(segment_speed)
|
segment_speeds.append(segment_speed)
|
||||||
if row["speed"] > 0:
|
if row["speed"] > 0:
|
||||||
obd_speeds.append(row["speed"])
|
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]
|
start = trip_rows[0]
|
||||||
end = trip_rows[-1]
|
end = trip_rows[-1]
|
||||||
@@ -227,7 +252,7 @@ def build_trip_summaries(raw_rows):
|
|||||||
distance_km / duration_seconds * 3600, 1
|
distance_km / duration_seconds * 3600, 1
|
||||||
) if duration_seconds else 0,
|
) if duration_seconds else 0,
|
||||||
"max_speed_kmh": round(
|
"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),
|
"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),
|
"end_odometer": next((r["odometer"] for r in reversed(trip_rows) if r.get("odometer")), None),
|
||||||
|
|||||||
+10
-7
@@ -461,13 +461,16 @@ def compute_trips_for_device(device_id):
|
|||||||
speeds.append(s)
|
speeds.append(s)
|
||||||
max_speeds.append(s)
|
max_speeds.append(s)
|
||||||
else:
|
else:
|
||||||
# GPS-derived fallback for max (mirror the Pi): when OBD speed
|
# GPS-derived fallback for max (mirror the Pi, but smoothed over
|
||||||
# is missing, use the segment's GPS speed (>= 8 m, <= 220 km/h).
|
# a trailing ~30s window so GPS position jitter can't spike the max).
|
||||||
seconds = (seg_rows[i][0] - seg_rows[i - 1][0]).total_seconds()
|
j = max(0, i - 6)
|
||||||
if seconds > 0 and d * 1000 >= 8:
|
w_dt = (seg_rows[i][0] - seg_rows[j][0]).total_seconds()
|
||||||
seg_speed = d / seconds * 3600
|
w_d = haversine_km(seg_rows[j][1], seg_rows[j][2],
|
||||||
if seg_speed <= 220:
|
seg_rows[i][1], seg_rows[i][2])
|
||||||
max_speeds.append(seg_speed)
|
if w_dt > 0 and w_d * 1000 >= 8:
|
||||||
|
w_speed = w_d / w_dt * 3600
|
||||||
|
if w_speed <= 220:
|
||||||
|
max_speeds.append(w_speed)
|
||||||
|
|
||||||
duration_s = int((seg_rows[-1][0] - seg_rows[0][0]).total_seconds())
|
duration_s = int((seg_rows[-1][0] - seg_rows[0][0]).total_seconds())
|
||||||
if duration_s < 30 or distance < 0.05:
|
if duration_s < 30 or distance < 0.05:
|
||||||
|
|||||||
Reference in New Issue
Block a user