fix high priority issues
This commit is contained in:
+26
-11
@@ -112,10 +112,11 @@ def compute_mmp(pts: list[DataPoint], started_at: datetime) -> Optional[list[lis
|
||||
[duration_s, avg_watts] pairs (integers), or None when the activity has no
|
||||
power data. Only durations shorter than the total activity are included.
|
||||
"""
|
||||
# 1 Hz downsample: at most one sample per second, skip sub-second duplicates.
|
||||
# Seconds without a recorded sample are omitted (not zero-filled) so that
|
||||
# paused-recording gaps don't silently lower power averages.
|
||||
power_1hz: list[int] = []
|
||||
# Build a dense 1 Hz power array with gaps zero-filled.
|
||||
# Zero-filling is the standard approach (matches GoldenCheetah / WKO):
|
||||
# a recording gap counts as 0 W so windows cannot silently span pauses
|
||||
# and inflate MMP values.
|
||||
sparse: dict[int, int] = {}
|
||||
last_t = -1
|
||||
for p in pts:
|
||||
t = int((p.timestamp - started_at).total_seconds())
|
||||
@@ -123,11 +124,15 @@ def compute_mmp(pts: list[DataPoint], started_at: datetime) -> Optional[list[lis
|
||||
continue
|
||||
last_t = t
|
||||
if p.power_w is not None:
|
||||
power_1hz.append(p.power_w)
|
||||
sparse[t] = p.power_w
|
||||
|
||||
if len(power_1hz) < 2:
|
||||
if len(sparse) < 2:
|
||||
return None
|
||||
|
||||
t_min = min(sparse)
|
||||
t_max = max(sparse)
|
||||
power_1hz: list[int] = [sparse.get(t, 0) for t in range(t_min, t_max + 1)]
|
||||
|
||||
n = len(power_1hz)
|
||||
results: list[list[int]] = []
|
||||
|
||||
@@ -166,17 +171,27 @@ def compute_best_efforts(
|
||||
"""
|
||||
targets = BEST_EFFORT_DISTANCES.get(sport, [])
|
||||
|
||||
# Build 1 Hz speed (km/h) and elevation (m) arrays — same downsampling as timeseries.py
|
||||
speed_1hz: list[float] = []
|
||||
ele_1hz: list[Optional[float]] = []
|
||||
# Build dense 1 Hz speed (km/h) and elevation (m) arrays with gap zero-filling.
|
||||
# Zero-filling speed gaps (0 km/h) prevents best-effort windows from spanning
|
||||
# recording pauses and producing artificially fast times.
|
||||
sparse_speed: dict[int, float] = {}
|
||||
sparse_ele: dict[int, Optional[float]] = {}
|
||||
last_t = -1
|
||||
for p in pts:
|
||||
t = int((p.timestamp - started_at).total_seconds())
|
||||
if t < 0 or t == last_t:
|
||||
continue
|
||||
last_t = t
|
||||
speed_1hz.append(p.speed_kmh if p.speed_kmh is not None else 0.0)
|
||||
ele_1hz.append(p.elevation_m)
|
||||
sparse_speed[t] = p.speed_kmh if p.speed_kmh is not None else 0.0
|
||||
sparse_ele[t] = p.elevation_m
|
||||
|
||||
if not sparse_speed:
|
||||
return None, None
|
||||
|
||||
t_min = min(sparse_speed)
|
||||
t_max = max(sparse_speed)
|
||||
speed_1hz: list[float] = [sparse_speed.get(t, 0.0) for t in range(t_min, t_max + 1)]
|
||||
ele_1hz: list[Optional[float]] = [sparse_ele.get(t) for t in range(t_min, t_max + 1)]
|
||||
|
||||
best_efforts: Optional[list[list[float]]] = None
|
||||
if targets and speed_1hz:
|
||||
|
||||
@@ -83,6 +83,13 @@ def write_activity(
|
||||
}
|
||||
|
||||
json_path = acts_dir / f"{activity_id}.json"
|
||||
# Collision guard: if a *different* activity already has this ID, append a
|
||||
# short hash suffix to disambiguate (same hash = idempotent re-extract).
|
||||
if json_path.exists():
|
||||
existing = json.loads(json_path.read_text(encoding="utf-8"))
|
||||
if existing.get("source_hash") != activity.source_hash:
|
||||
activity_id = f"{activity_id}-{activity.source_hash[-6:]}"
|
||||
json_path = acts_dir / f"{activity_id}.json"
|
||||
json_path.write_text(json.dumps(detail, indent=2, ensure_ascii=False))
|
||||
|
||||
# ── GeoJSON track ────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user