My take on TSS calculation (apparently not correct)
This commit is contained in:
parent
8203e143e8
commit
e6a7cc6e6f
|
|
@ -0,0 +1,29 @@
|
||||||
|
Name: Darth Vader
|
||||||
|
Author: HumanPowerPerformance.com
|
||||||
|
Description:
|
||||||
|
Sign up for coaching with HumanPowerPerformance.com and get custom workouts and training plans
|
||||||
|
|
||||||
|
Warmup: 5:00 55%
|
||||||
|
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
Rest: 3:00 82%
|
||||||
|
Interval: 00:20 130%
|
||||||
|
|
||||||
|
Cooldown: 5:00 55%
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:ts": "tsc --noEmit",
|
"lint:ts": "tsc --noEmit",
|
||||||
"test": "ts-node src/index.ts examples/threshold-pushing.txt",
|
"test": "ts-node src/index.ts examples/threshold-pushing.txt",
|
||||||
|
"test:2": "ts-node src/index.ts examples/darth-vader.txt",
|
||||||
"format:js": "prettier --write src/"
|
"format:js": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
14
src/index.ts
14
src/index.ts
|
|
@ -1,6 +1,7 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { parse } from "./parser";
|
import { parse } from "./parser";
|
||||||
import { tokenize } from "./tokenizer";
|
import { tokenize } from "./tokenizer";
|
||||||
|
import { tss } from "./tss";
|
||||||
|
|
||||||
const filename = process.argv[2];
|
const filename = process.argv[2];
|
||||||
|
|
||||||
|
|
@ -10,4 +11,15 @@ const file = fs.readFileSync(filename, "utf8");
|
||||||
|
|
||||||
const workout = parse(tokenize(file));
|
const workout = parse(tokenize(file));
|
||||||
|
|
||||||
console.log(workout);
|
console.log(workout.intervals);
|
||||||
|
|
||||||
|
workout.intervals.forEach((interval, i) => {
|
||||||
|
console.log(`#${i} TSS: ${tss([interval])}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Total TSS: " + tss(workout.intervals));
|
||||||
|
|
||||||
|
const duration =
|
||||||
|
workout.intervals.map(({ duration }) => duration).reduce((a, b) => a + b, 0) /
|
||||||
|
60;
|
||||||
|
console.log(`Total duration: ${duration} minutes`);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Interval } from "./ast";
|
||||||
|
|
||||||
|
// Training Stress Score formula from Training and Racing with a Power Meter:
|
||||||
|
//
|
||||||
|
// TSS = (s * W * IF) / (FTP * 3600) * 100
|
||||||
|
//
|
||||||
|
// s - duration in seconds
|
||||||
|
// W - power in watts
|
||||||
|
// IF - intensity factor (power / FTP)
|
||||||
|
|
||||||
|
const steadyTss = (duration: number, power: number): number => {
|
||||||
|
const intensity = power / 100;
|
||||||
|
|
||||||
|
return ((duration * intensity * intensity) / 3600) * 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
const rangeTss = (duration: number, from: number, to: number): number => {
|
||||||
|
let score = 0;
|
||||||
|
const step = 1;
|
||||||
|
for (let i = 0; i < duration; i += step) {
|
||||||
|
let power = from + (to - from) * (i / duration);
|
||||||
|
score += steadyTss(step, power);
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
|
||||||
|
const intervalTss = ({ duration, power }: Interval): number => {
|
||||||
|
if (power.from === power.to) {
|
||||||
|
return steadyTss(duration, power.from);
|
||||||
|
} else {
|
||||||
|
return rangeTss(duration, power.from, power.to);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tss = (intervals: Interval[]): number => {
|
||||||
|
return intervals.map(intervalTss).reduce((a, b) => a + b, 0);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue