Average and normalized intensities
This commit is contained in:
parent
fed30e86b7
commit
046bce3f26
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { chain, pipe, sum } from "ramda";
|
||||||
|
import { Interval } from "./ast";
|
||||||
|
|
||||||
|
// Converts interval to array of intensity values for each second
|
||||||
|
const intervalToIntensities = ({ duration, intensity }: Interval): number[] => {
|
||||||
|
const seconds = [];
|
||||||
|
const { from, to } = intensity;
|
||||||
|
for (let i = 0; i < duration; i++) {
|
||||||
|
// Intensity in a single second
|
||||||
|
seconds.push(from + (to - from) * (i / duration));
|
||||||
|
}
|
||||||
|
return seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
const average = (arr: number[]) => sum(arr) / arr.length;
|
||||||
|
|
||||||
|
export const averageIntensity = (intervals: Interval[]): number => {
|
||||||
|
return pipe(chain(intervalToIntensities), average)(intervals);
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import { averageIntensity } from "./average-intensity";
|
||||||
|
import { normalizedIntensity } from "./normalized-intensity";
|
||||||
import { parse } from "./parser";
|
import { parse } from "./parser";
|
||||||
import { tokenize } from "./tokenizer";
|
import { tokenize } from "./tokenizer";
|
||||||
import { tss } from "./tss";
|
import { tss } from "./tss";
|
||||||
|
|
@ -23,3 +25,7 @@ const duration =
|
||||||
workout.intervals.map(({ duration }) => duration).reduce((a, b) => a + b, 0) /
|
workout.intervals.map(({ duration }) => duration).reduce((a, b) => a + b, 0) /
|
||||||
60;
|
60;
|
||||||
console.log(`Total duration: ${duration} minutes`);
|
console.log(`Total duration: ${duration} minutes`);
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
console.log(`Average intensity: ${averageIntensity(workout.intervals)}`);
|
||||||
|
console.log(`Normalized intensity: ${normalizedIntensity(workout.intervals)}`);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { chain, pipe, sum } from "ramda";
|
||||||
|
import { Interval } from "./ast";
|
||||||
|
|
||||||
|
// Converts interval to array of intensity values for each second
|
||||||
|
const intervalToIntensities = ({ duration, intensity }: Interval): number[] => {
|
||||||
|
const seconds = [];
|
||||||
|
const { from, to } = intensity;
|
||||||
|
for (let i = 0; i < duration; i++) {
|
||||||
|
// Intensity in a single second
|
||||||
|
seconds.push(from + (to - from) * (i / duration));
|
||||||
|
}
|
||||||
|
return seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Starting at the beginning of the data, calculate 30-second rolling average
|
||||||
|
const windowSize = 30;
|
||||||
|
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));
|
||||||
|
averages.push(rollingSum / windowSize);
|
||||||
|
for (let i = 0; i < intensities.length - windowSize; i++) {
|
||||||
|
rollingSum -= intensities[i];
|
||||||
|
rollingSum += intensities[i + windowSize];
|
||||||
|
averages.push(rollingSum / windowSize);
|
||||||
|
}
|
||||||
|
return averages;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fourthPower = (x: number) => Math.pow(x, 4);
|
||||||
|
|
||||||
|
const fourthRoot = (x: number) => Math.pow(x, 1 / 4);
|
||||||
|
|
||||||
|
const average = (arr: number[]) => sum(arr) / arr.length;
|
||||||
|
|
||||||
|
export const normalizedIntensity = (intervals: Interval[]): number => {
|
||||||
|
return pipe(
|
||||||
|
chain(intervalToIntensities),
|
||||||
|
rollingAverages,
|
||||||
|
(averages) => averages.map(fourthPower),
|
||||||
|
average,
|
||||||
|
fourthRoot
|
||||||
|
)(intervals);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue