import * as _ from "lodash" ; import { InconsistentParametersException } from "@elevate/shared/exceptions" ; export class RunningPowerEstimator { param athleteWeight param distanceArray param timeArray param altitudeArray returns { Array < number > } public static createRunningPowerEstimationStream ( athleteWeight , distanceArray , timeArray , altitudeArray ) { if ( ! _ . isNumber ( athleteWeight ) ) { throw new InconsistentParametersException ( "athleteWeight required as number" ) ; } if ( ! _ . isArray ( distanceArray ) ) { throw new InconsistentParametersException ( "distanceArray required as array" ) ; } if ( ! _ . isArray ( timeArray ) ) { throw new InconsistentParametersException ( "timeArray required as array" ) ; } const powerStream = [ ] ; for ( let i = 0 ; i < timeArray . length ; i ++ ) { let power = 0 ; if ( i > 0 ) { const time = timeArray [ i ] - timeArray [ i - 1 ] ; const distanceAdjusted = distanceArray [ i ] - distanceArray [ i - 1 ] ; const elevationGain = ( altitudeArray ) ? altitudeArray [ i ] - altitudeArray [ i - 1 ] : 0 ; power = this . estimateRunningPower ( athleteWeight , distanceAdjusted , time , elevationGain ) ; } powerStream . push ( power ) ; } return powerStream ; } param { number } weightKg param { number } meters param { number } seconds param elevationGain returns { number } public static estimateRunningPower ( weightKg , meters , seconds , elevationGain ) { if ( ! _ . isNumber ( seconds ) || seconds === 0 ) { return 0 ; } const runningEcoVolumeO2PerKm = 210 ; const cyclingEcoWattsPerVolumeO2 = 75 ; const minutes = seconds / 60 ; const km = meters / 1000 ; const minPerKmPace = minutes / km ; const RelativeVO2 = runningEcoVolumeO2PerKm / minPerKmPace ; const AbsoluteVO2 = RelativeVO2 * weightKg ; const horizontalWatts = cyclingEcoWattsPerVolumeO2 * AbsoluteVO2 / 1000 ; const verticalWatts = ( weightKg * 9.81 * elevationGain ) / seconds ; const power = Math . round ( horizontalWatts + verticalWatts ) ; return ( power > 0 ) ? power : 0 ; } }