Implement zone-distrubution stats
This commit is contained in:
parent
15773cead0
commit
819629094e
|
|
@ -5,6 +5,5 @@
|
||||||
- FreeRide blocks
|
- FreeRide blocks
|
||||||
- Repeats (and nested repeats)
|
- Repeats (and nested repeats)
|
||||||
- Change # to @
|
- Change # to @
|
||||||
- Zone distribution stats
|
|
||||||
- Unsupported params: message duration & y-position
|
- Unsupported params: message duration & y-position
|
||||||
- More restricted syntax for text (with quotes)
|
- More restricted syntax for text (with quotes)
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@ import { normalizedIntensity } from "./normalizedIntensity";
|
||||||
import { totalDuration } from "./totalDuration";
|
import { totalDuration } from "./totalDuration";
|
||||||
import { tss } from "./tss";
|
import { tss } from "./tss";
|
||||||
import { tss2 } from "./tss2";
|
import { tss2 } from "./tss2";
|
||||||
|
import { zoneDistribution } from "./zoneDistribution";
|
||||||
|
|
||||||
// Generates statistics
|
// Generates statistics
|
||||||
export const stats = ({ intervals }: Workout): string => {
|
export const stats = ({ intervals }: Workout): string => {
|
||||||
const duration = totalDuration(intervals);
|
const duration = totalDuration(intervals);
|
||||||
const avgIntensity = averageIntensity(intervals);
|
const avgIntensity = averageIntensity(intervals);
|
||||||
const normIntensity = normalizedIntensity(intervals);
|
const normIntensity = normalizedIntensity(intervals);
|
||||||
|
const zones = zoneDistribution(intervals);
|
||||||
|
|
||||||
return `
|
return `
|
||||||
Total duration: ${(duration.seconds / 60).toFixed()} minutes
|
Total duration: ${(duration.seconds / 60).toFixed()} minutes
|
||||||
|
|
@ -19,5 +21,8 @@ Normalized intensity: ${(normIntensity.value * 100).toFixed()}%
|
||||||
|
|
||||||
TSS #1: ${tss(intervals).toFixed()}
|
TSS #1: ${tss(intervals).toFixed()}
|
||||||
TSS #2: ${tss2(duration, normIntensity).toFixed()}
|
TSS #2: ${tss2(duration, normIntensity).toFixed()}
|
||||||
|
|
||||||
|
Zone Distribution:
|
||||||
|
${zones.map(({ name, duration }) => `${(duration.seconds / 60).toFixed().padStart(3)} min - ${name}`).join("\n")}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Interval } from "../ast";
|
||||||
|
import { Duration } from "../Duration";
|
||||||
|
import { intervalsToIntensityNumbers } from "./intervalsToIntensityNumbers";
|
||||||
|
|
||||||
|
type Zone = {
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NumericZoneDuration = Zone & { duration: number };
|
||||||
|
type ZoneDuration = Zone & { duration: Duration };
|
||||||
|
|
||||||
|
// Intensity ranges based on https://zwiftinsider.com/power-zone-colors/
|
||||||
|
const emptyZones = (): NumericZoneDuration[] => [
|
||||||
|
{ from: 0.0, to: 0.6, name: "Z1: Recovery", duration: 0 },
|
||||||
|
{ from: 0.6, to: 0.75, name: "Z2: Endurance", duration: 0 },
|
||||||
|
{ from: 0.75, to: 0.9, name: "Z3: Tempo", duration: 0 },
|
||||||
|
{ from: 0.9, to: 1.05, name: "Z4: Threshold", duration: 0 },
|
||||||
|
{ from: 1.05, to: 1.18, name: "Z5: VO2 Max", duration: 0 },
|
||||||
|
{ from: 1.18, to: Infinity, name: "Z6: Anaerobic", duration: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const zoneDistribution = (intervals: Interval[]): ZoneDuration[] => {
|
||||||
|
const zones = emptyZones();
|
||||||
|
|
||||||
|
intervalsToIntensityNumbers(intervals).forEach((intensity) => {
|
||||||
|
const zone = zones.find((zone) => intensity >= zone.from && intensity < zone.to);
|
||||||
|
if (zone) {
|
||||||
|
zone.duration++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return zones.map(({ duration, ...rest }) => ({ duration: new Duration(duration), ...rest }));
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue