Add matched training signals, daily recovery and performance analysis

This commit is contained in:
Peter Stockings
2026-10-03 13:22:32 +10:00
parent e6e2f22479
commit 418e03583a
37 changed files with 1380 additions and 47 deletions
+48
View File
@@ -0,0 +1,48 @@
"""Approximate same-start, same-direction full-course matching, without raw samples."""
import math
from itertools import pairwise
from .analytics import numeric
def distance(a, b):
lat1, lat2 = math.radians(a[0]), math.radians(b[0])
dlat, dlon = lat2 - lat1, math.radians(b[1] - a[1])
h = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
return 12742000 * math.asin(math.sqrt(min(1, h)))
def resample(segments):
# A recording break must not invent a connecting route.
if not isinstance(segments, list) or len(segments) != 1:
return None
points = segments[0]
if len(points) < 2 or any(not isinstance(p, list) or len(p) != 2 or
not all(numeric(v) for v in p) or
not -90 <= p[0] <= 90 or not -180 <= p[1] <= 180 for p in points):
return None
cumulative = [0.0]
for a, b in pairwise(points):
cumulative.append(cumulative[-1] + distance(a, b))
total = cumulative[-1]
if total < 500:
return None
result, cursor = [], 0
for i in range(33):
target = total * i / 32
while cursor < len(points) - 2 and cumulative[cursor + 1] < target:
cursor += 1
span = cumulative[cursor + 1] - cumulative[cursor]
fraction = (target - cumulative[cursor]) / span if span else 0
result.append([a + (b - a) * fraction for a, b in zip(points[cursor], points[cursor + 1], strict=True)])
return total, result
def similar(reference, candidate):
a, b = resample(reference), resample(candidate)
if not a or not b or abs(b[0] / a[0] - 1) > .1:
return False
differences = sorted(distance(x, y) for x, y in zip(a[1], b[1], strict=True))
return (distance(a[1][0], b[1][0]) <= 100 and distance(a[1][-1], b[1][-1]) <= 100
and sum(differences) / len(differences) <= 100 and differences[29] <= 200)