diff --git a/src/stats/normalizedIntensity.test.ts b/src/stats/normalizedIntensity.test.ts new file mode 100644 index 0000000..7b99ad3 --- /dev/null +++ b/src/stats/normalizedIntensity.test.ts @@ -0,0 +1,75 @@ +import { Interval } from "../ast"; +import { Duration } from "../Duration"; +import { ConstantIntensity, RangeIntensity } from "../Intensity"; +import { normalizedIntensity } from "./normalizedIntensity"; + +const round = (intensity: ConstantIntensity) => Math.round(intensity.value * 100) / 100; + +describe("normalizedIntensity()", () => { + it("when no intervals, returns 0 for all zones", () => { + expect(round(normalizedIntensity([]))).toEqual(0); + }); + + it("returns plain average for < 30-seconds workout", () => { + expect( + round( + normalizedIntensity([ + { + type: "Interval", + duration: new Duration(10), + intensity: new ConstantIntensity(0.5), + comments: [], + }, + { + type: "Interval", + duration: new Duration(10), + intensity: new ConstantIntensity(0.7), + comments: [], + }, + ]), + ), + ).toEqual(0.6); + }); + + it("is the intensity of an interval for single-interval workout", () => { + const intervals: Interval[] = [ + { + type: "Interval", + duration: new Duration(20 * 60), + intensity: new ConstantIntensity(0.75), + comments: [], + }, + ]; + expect(round(normalizedIntensity(intervals))).toEqual(0.75); + }); + + it("leans towards higher intensity for two-interval workout", () => { + const intervals: Interval[] = [ + { + type: "Interval", + duration: new Duration(10 * 60), + intensity: new ConstantIntensity(0.5), + comments: [], + }, + { + type: "Interval", + duration: new Duration(10 * 60), + intensity: new ConstantIntensity(1.0), + comments: [], + }, + ]; + expect(round(normalizedIntensity(intervals))).toEqual(0.85); + }); + + it("handles range-intensities", () => { + const intervals: Interval[] = [ + { + type: "Warmup", + duration: new Duration(20 * 60), + intensity: new RangeIntensity(0.5, 1.0), + comments: [], + }, + ]; + expect(round(normalizedIntensity(intervals))).toEqual(0.79); + }); +}); diff --git a/src/stats/normalizedIntensity.ts b/src/stats/normalizedIntensity.ts index 656082e..c2346f5 100644 --- a/src/stats/normalizedIntensity.ts +++ b/src/stats/normalizedIntensity.ts @@ -7,11 +7,16 @@ import { intervalsToIntensityNumbers } from "./intervalsToIntensityNumbers"; // Starting at the beginning of the data, calculate 30-second rolling average const windowSize = 30; // equals to nr of seconds, but also to nr of entries in intensities array const rollingAverages = (intensities: number[]): number[] => { - if (intensities.length < windowSize) { - throw new Error(`Workout must be at least ${windowSize} seconds long`); - } - const averages: number[] = []; let rollingSum: number = sum(intensities.slice(0, windowSize)); + + if (intensities.length === 0) { + return [0]; + } + if (intensities.length < windowSize) { + return [rollingSum / intensities.length]; + } + + const averages: number[] = []; averages.push(rollingSum / windowSize); for (let i = 0; i < intensities.length - windowSize; i++) { rollingSum -= intensities[i];