Files
Stride/app/training_metrics.py
T

48 lines
2.8 KiB
Python

"""Explicit units for recording, performance and daily recovery observations."""
METRICS = {}
UNITS = {}
def metric(key, label, unit, definition, conversions=None):
METRICS[key] = (label, unit, definition)
UNITS[key] = conversions or {unit: 1}
for key, label in (("elapsed", "Elapsed recording offset"),
("moving_offset", "Moving-time offset"),
("matched_minutes", "Matched moving minutes")):
metric(key, label, "min", "Minutes since recording start, or usable matched moving time.",
{"min": 1, "s": 1 / 60, "h": 60})
for key, label in (("grade", "Smoothed grade"), ("grade_variability", "Grade variation"),
("terrain_coverage", "Terrain coverage"),
("joint_coverage", "Joint HR and terrain coverage"),
("hr_artifact_percent", "Suspect HR time"),
("long_run_share", "Largest run share of 7-day volume")):
metric(key, label, "%", "Recording-derived percentage; missing observations stay missing.")
metric("matched_windows", "Matched windows", "windows", "Usable continuous recording windows.")
metric("sessions", "Sessions", "runs", "Number of recorded running sessions on this local day.")
metric("days_since_run", "Days since running", "days", "Local days since the latest recorded run.")
metric("days_since_long_run", "Days since long run", "days",
"Local days since a recorded run meeting the query's long-run distance threshold.")
metric("effort_time", "Best effort time", "time", "Elapsed recorded best-effort window, in seconds.",
{"s": 1, "min": 60})
for km in (1, 2, 5, 10):
metric(f"best_{km}km", f"Best {km} km", "time",
"Fastest elapsed window within this run, not a standardized race result.",
{"s": 1, "min": 60})
for key, label, unit in (("resting_hr", "Resting HR", "bpm"),
("hrv", "Overnight HRV", "ms"),
("sleep_hours", "Sleep", "h"),
("stress", "Daily stress", "score"),
("perceived_effort", "Perceived effort", "score"),
("fatigue", "Reported fatigue", "score")):
metric(key, label, unit, "Private recorded daily observation or owner-entered session context; no diagnosis.")
for sensor, unit in (("cadence", "spm"), ("power", "W"), ("ground_contact", "ms"),
("stride_length", "m"), ("vertical_oscillation", "cm")):
metric(sensor + "_coverage", sensor.replace("_", " ").title() + " coverage", "%",
"Percent of this continuous moving window with a usable positive sensor measurement.")
for band in ("lower", "middle", "upper"):
metric(band + "_hr_minutes", band.title() + " HR minutes", "min",
"Time in individually configured HR bands; unavailable until thresholds are set.")