openrowingmonitor/app/engine/Rower.test.js

490 lines
23 KiB
JavaScript

'use strict'
/*
This test is a test of the Rower object, that tests wether this object fills all fields correctly, given one validated rower, (the
Concept2 RowErg) using a validated cycle of strokes. This thoroughly tests the raw physics of the translation of Angfular physics
to Linear physics. The combination with all possible known rowers is tested when testing the above function RowingStatistics, as
these statistics are dependent on these settings as well.
*/
import { test } from 'uvu'
import * as assert from 'uvu/assert'
import rowerProfiles from '../../config/rowerProfiles.js'
import { replayRowingSession } from '../tools/RowingRecorder.js'
import { deepMerge } from '../tools/Helper.js'
import { createRower } from './Rower.js'
const baseConfig = { // Based on Concept 2 settings, as this is the validation system
numOfImpulsesPerRevolution: 6,
sprocketRadius: 1.4,
maximumStrokeTimeBeforePause: 0.3, // Modification to standard settings to shorten test cases
dragFactor: 110,
autoAdjustDragFactor: true,
minimumDragQuality: 0.95,
dragFactorSmoothing: 3,
minimumTimeBetweenImpulses: 0.005,
maximumTimeBetweenImpulses: 0.017,
flankLength: 12,
smoothing: 1,
minimumStrokeQuality: 0.36,
minumumForceBeforeStroke: 20, // Modification to standard settings to shorten test cases
minumumRecoverySlope: 0.00070,
autoAdjustRecoverySlope: false, // Modification to standard settings to shorten test cases
autoAdjustRecoverySlopeMargin: 0.04,
minimumDriveTime: 0.04, // Modification to standard settings to shorten test cases
minimumRecoveryTime: 0.09, // Modification to standard settings to shorten test cases
flywheelInertia: 0.10138,
magicConstant: 2.8
}
// Test behaviour for no datapoints
test('Correct rower behaviour at initialisation', () => {
const rower = createRower(baseConfig)
testStrokeState(rower, 'WaitingForDrive')
testTotalMovingTimeSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testCycleDuration(rower, 0.13) // Default value
testCycleLinearDistance(rower, 0)
testCycleLinearVelocity(rower, 0)
testCyclePower(rower, 0)
testDriveDuration(rower, 0)
testDriveLinearDistance(rower, 0)
testDriveLength(rower, 0)
testDriveAverageHandleForce(rower, 0)
testDrivePeakHandleForce(rower, 0)
testRecoveryDuration(rower, 0)
testRecoveryDragFactor(rower, 110)
testInstantHandlePower(rower, 0)
})
// Test behaviour for one datapoint
// Test behaviour for three perfect identical strokes, including settingling behaviour of metrics
test('Test behaviour for three perfect identical strokes, including settingling behaviour of metrics', () => {
const rower = createRower(baseConfig)
testStrokeState(rower, 'WaitingForDrive')
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testCycleDuration(rower, 0.13) // Default value
testCycleLinearDistance(rower, 0)
testCycleLinearVelocity(rower, 0)
testCyclePower(rower, 0)
testDriveDuration(rower, 0)
testDriveLinearDistance(rower, 0)
testDriveLength(rower, 0)
testDriveAverageHandleForce(rower, 0)
testDrivePeakHandleForce(rower, 0)
testRecoveryDuration(rower, 0)
testRecoveryDragFactor(rower, 110)
testInstantHandlePower(rower, 0)
// Drive initial stroke starts here
rower.handleRotationImpulse(0.011221636)
rower.handleRotationImpulse(0.011175504)
rower.handleRotationImpulse(0.01116456)
rower.handleRotationImpulse(0.011130263)
rower.handleRotationImpulse(0.011082613)
rower.handleRotationImpulse(0.011081761)
rower.handleRotationImpulse(0.011062297)
rower.handleRotationImpulse(0.011051853)
rower.handleRotationImpulse(0.010973313)
rower.handleRotationImpulse(0.010919756)
rower.handleRotationImpulse(0.01086431)
rower.handleRotationImpulse(0.010800864)
rower.handleRotationImpulse(0.010956987)
rower.handleRotationImpulse(0.010653396)
rower.handleRotationImpulse(0.010648619)
rower.handleRotationImpulse(0.010536818)
rower.handleRotationImpulse(0.010526151)
rower.handleRotationImpulse(0.010511225)
rower.handleRotationImpulse(0.010386684)
testStrokeState(rower, 'Drive')
testTotalMovingTimeSinceStart(rower, 0.077918634)
testTotalLinearDistanceSinceStart(rower, 0.2491943602992768)
testTotalNumberOfStrokes(rower, 1)
testCycleDuration(rower, 0.13) // still default value
testCycleLinearDistance(rower, 0.2491943602992768) // Known issue: this shouldn't be filled at this time as the cycle isn't completed yet
testCycleLinearVelocity(rower, 0) // This isn't filled after the first drive, as we haven't survived a complete cycle yet
testCyclePower(rower, 0) // This isn't filled after the first drive, as we haven't survived a complete cycle yet
testDriveDuration(rower, 0) // Shouldn't this one be filled after the first drive?
testDriveLinearDistance(rower, 0.2491943602992768)
testDriveLength(rower, 0) // Shouldn't this one be filled after the first drive?
testDriveAverageHandleForce(rower, 1691.793078056684)
testDrivePeakHandleForce(rower, 10246.062011594136)
testRecoveryDuration(rower, 0)
testRecoveryDragFactor(rower, 110)
testInstantHandlePower(rower, 372.0199762100516)
// Recovery initial stroke starts here
rower.handleRotationImpulse(0.010769)
rower.handleRotationImpulse(0.010707554)
rower.handleRotationImpulse(0.010722165)
rower.handleRotationImpulse(0.01089567)
rower.handleRotationImpulse(0.010917504)
rower.handleRotationImpulse(0.010997969)
rower.handleRotationImpulse(0.011004655)
rower.handleRotationImpulse(0.011013618)
rower.handleRotationImpulse(0.011058193)
rower.handleRotationImpulse(0.010807149)
rower.handleRotationImpulse(0.0110626)
rower.handleRotationImpulse(0.011090787)
rower.handleRotationImpulse(0.011099509)
rower.handleRotationImpulse(0.011131862)
rower.handleRotationImpulse(0.011209919)
testStrokeState(rower, 'Recovery')
testTotalMovingTimeSinceStart(rower, 0.23894732900000007)
testTotalLinearDistanceSinceStart(rower, 0.7831822752262986)
testTotalNumberOfStrokes(rower, 1)
testCycleDuration(rower, 0.19636192600000005)
testCycleLinearDistance(rower, 0.7831822752262986)
testCycleLinearVelocity(rower, 3.2632879039515323)
testCyclePower(rower, 97.30254616461225)
testDriveDuration(rower, 0.19636192600000005)
testDriveLinearDistance(rower, 0.6407854979124261)
testDriveLength(rower, 0.2638937829015426)
testDriveAverageHandleForce(rower, 851.8820525641245) // This is the first stroke, which always leads to insane data like this
testDrivePeakHandleForce(rower, 10246.062011594136)
testRecoveryDuration(rower, 0)
testRecoveryDragFactor(rower, 110)
testInstantHandlePower(rower, 0)
// Drive seconds stroke starts here
rower.handleRotationImpulse(0.011221636)
rower.handleRotationImpulse(0.011175504)
rower.handleRotationImpulse(0.01116456)
rower.handleRotationImpulse(0.011130263)
rower.handleRotationImpulse(0.011082613)
rower.handleRotationImpulse(0.011081761)
rower.handleRotationImpulse(0.011062297)
rower.handleRotationImpulse(0.011051853)
rower.handleRotationImpulse(0.010973313)
rower.handleRotationImpulse(0.010919756)
rower.handleRotationImpulse(0.01086431)
rower.handleRotationImpulse(0.010800864)
rower.handleRotationImpulse(0.010956987)
rower.handleRotationImpulse(0.010653396)
rower.handleRotationImpulse(0.010648619)
rower.handleRotationImpulse(0.010536818)
rower.handleRotationImpulse(0.010526151)
rower.handleRotationImpulse(0.010511225)
rower.handleRotationImpulse(0.010386684)
testStrokeState(rower, 'Drive')
testTotalMovingTimeSinceStart(rower, 0.44915539800000004)
testTotalLinearDistanceSinceStart(rower, 1.5912564829320934)
testTotalNumberOfStrokes(rower, 2)
testCycleDuration(rower, 0.34889498300000005)
testCycleLinearDistance(rower, 0.9504709850196674)
testCycleLinearVelocity(rower, 3.2650920019419694)
testCyclePower(rower, 97.46401557792097)
testDriveDuration(rower, 0.19636192600000005)
testDriveLinearDistance(rower, 0.4520822644211139)
testDriveLength(rower, 0.2638937829015426)
testDriveAverageHandleForce(rower, 251.04336322997108)
testDrivePeakHandleForce(rower, 396.7011215867992)
testRecoveryDuration(rower, 0.152533057)
testRecoveryDragFactor(rower, 309.02744980039836)
testInstantHandlePower(rower, 526.5255378434941)
// Recovery second stroke starts here
rower.handleRotationImpulse(0.010769)
rower.handleRotationImpulse(0.010707554)
rower.handleRotationImpulse(0.010722165)
rower.handleRotationImpulse(0.01089567)
rower.handleRotationImpulse(0.010917504)
rower.handleRotationImpulse(0.010997969)
rower.handleRotationImpulse(0.011004655)
rower.handleRotationImpulse(0.011013618)
rower.handleRotationImpulse(0.011058193)
rower.handleRotationImpulse(0.010807149)
rower.handleRotationImpulse(0.0110626)
rower.handleRotationImpulse(0.011090787)
rower.handleRotationImpulse(0.011099509)
rower.handleRotationImpulse(0.011131862)
rower.handleRotationImpulse(0.011209919)
testStrokeState(rower, 'Recovery')
testTotalMovingTimeSinceStart(rower, 0.6101840930000001)
testTotalLinearDistanceSinceStart(rower, 2.3447269236339507)
testTotalNumberOfStrokes(rower, 2)
testCycleDuration(rower, 0.40310000200000007)
testCycleLinearDistance(rower, 1.2055527051229706)
testCycleLinearVelocity(rower, 4.6106683482425606)
testCyclePower(rower, 305.1751755713177)
testDriveDuration(rower, 0.25056694500000004)
testDriveLinearDistance(rower, 1.1969315172491561)
testDriveLength(rower, 0.3371976114853044)
testDriveAverageHandleForce(rower, 312.83830506634683)
testDrivePeakHandleForce(rower, 480.0144155860976)
testRecoveryDuration(rower, 0.152533057)
testRecoveryDragFactor(rower, 343.6343564104484) // As we decelerate the flywheel quite fast, this is expected
testInstantHandlePower(rower, 0)
// Drive third stroke starts here
rower.handleRotationImpulse(0.011221636)
rower.handleRotationImpulse(0.011175504)
rower.handleRotationImpulse(0.01116456)
rower.handleRotationImpulse(0.011130263)
rower.handleRotationImpulse(0.011082613)
rower.handleRotationImpulse(0.011081761)
rower.handleRotationImpulse(0.011062297)
rower.handleRotationImpulse(0.011051853)
rower.handleRotationImpulse(0.010973313)
rower.handleRotationImpulse(0.010919756)
rower.handleRotationImpulse(0.01086431)
rower.handleRotationImpulse(0.010800864)
rower.handleRotationImpulse(0.010956987)
rower.handleRotationImpulse(0.010653396)
rower.handleRotationImpulse(0.010648619)
rower.handleRotationImpulse(0.010536818)
rower.handleRotationImpulse(0.010526151)
rower.handleRotationImpulse(0.010511225)
rower.handleRotationImpulse(0.010386684)
testStrokeState(rower, 'Drive')
testTotalMovingTimeSinceStart(rower, 0.8203921620000004)
testTotalLinearDistanceSinceStart(rower, 3.3769157507594016)
testTotalNumberOfStrokes(rower, 3)
testCycleDuration(rower, 0.3490464680000002)
testCycleLinearDistance(rower, 1.0408100149992658)
testCycleLinearVelocity(rower, 4.7709866068572415)
testCyclePower(rower, 304.0763360087651)
testDriveDuration(rower, 0.25056694500000004)
testDriveLinearDistance(rower, 0.5724455082495962)
testDriveLength(rower, 0.3371976114853044)
testDriveAverageHandleForce(rower, 245.5974258934615)
testDrivePeakHandleForce(rower, 418.91839185069534)
testRecoveryDuration(rower, 0.09847952300000018)
testRecoveryDragFactor(rower, 343.6343564104484)
testInstantHandlePower(rower, 556.0136323776126)
// Recovery third stroke starts here
rower.handleRotationImpulse(0.010769)
rower.handleRotationImpulse(0.010707554)
rower.handleRotationImpulse(0.010722165)
rower.handleRotationImpulse(0.01089567)
rower.handleRotationImpulse(0.010917504)
rower.handleRotationImpulse(0.010997969)
rower.handleRotationImpulse(0.011004655)
rower.handleRotationImpulse(0.011013618)
rower.handleRotationImpulse(0.011058193)
rower.handleRotationImpulse(0.010807149)
rower.handleRotationImpulse(0.0110626)
rower.handleRotationImpulse(0.011090787)
rower.handleRotationImpulse(0.011099509)
rower.handleRotationImpulse(0.011131862)
rower.handleRotationImpulse(0.011209919)
testStrokeState(rower, 'Recovery')
testTotalMovingTimeSinceStart(rower, 0.9814208570000005)
testTotalLinearDistanceSinceStart(rower, 4.157523262008851)
testTotalNumberOfStrokes(rower, 3)
testCycleDuration(rower, 0.3712367640000004)
testCycleLinearDistance(rower, 1.353053019499046)
testCycleLinearVelocity(rower, 4.76616864783023)
testCyclePower(rower, 303.1560556797095)
testDriveDuration(rower, 0.2727572410000002)
testDriveLinearDistance(rower, 1.3010125187490824)
testDriveLength(rower, 0.36651914291880905)
testDriveAverageHandleForce(rower, 295.526758358351)
testDrivePeakHandleForce(rower, 480.01441558492223)
testRecoveryDuration(rower, 0.09847952300000018)
testRecoveryDragFactor(rower, 343.6343564104484)
testInstantHandlePower(rower, 0)
// Dwelling state starts here
rower.handleRotationImpulse(0.020769)
rower.handleRotationImpulse(0.020707554)
rower.handleRotationImpulse(0.020722165)
rower.handleRotationImpulse(0.02089567)
rower.handleRotationImpulse(0.020917504)
rower.handleRotationImpulse(0.020997969)
rower.handleRotationImpulse(0.021004655)
rower.handleRotationImpulse(0.021013618)
rower.handleRotationImpulse(0.021058193)
rower.handleRotationImpulse(0.020807149)
rower.handleRotationImpulse(0.0210626)
rower.handleRotationImpulse(0.021090787)
rower.handleRotationImpulse(0.021099509)
rower.handleRotationImpulse(0.021131862)
rower.handleRotationImpulse(0.021209919)
testStrokeState(rower, 'WaitingForDrive')
testTotalMovingTimeSinceStart(rower, 1.1137102920000004)
testTotalNumberOfStrokes(rower, 3)
testTotalLinearDistanceSinceStart(rower, 4.782009271008411)
testCycleDuration(rower, 0.4157688410000001)
testCycleLinearDistance(rower, 1.9775390284986059)
testCycleLinearVelocity(rower, 4.756342547801953)
testCyclePower(rower, 301.28492718029133)
testDriveDuration(rower, 0.2727572410000002)
testDriveLinearDistance(rower, 1.3010125187490824)
testDriveLength(rower, 0.36651914291880905)
testDriveAverageHandleForce(rower, 295.526758358351)
testDrivePeakHandleForce(rower, 480.01441558492223)
testRecoveryDuration(rower, 0.1430115999999999)
testRecoveryDragFactor(rower, 343.6343564104484)
testInstantHandlePower(rower, 0)
})
// Test behaviour for noisy upgoing flank
// Test behaviour for noisy downgoing flank
// Test behaviour for noisy stroke
// Test behaviour after reset
// Test behaviour for one datapoint
// Test behaviour for noisy stroke
// Test drag factor calculation
// Test Dynamic stroke detection
// Test behaviour after reset
// Test behaviour with real-life data
test('sample data for Sportstech WRX700 should produce plausible results', async () => {
const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700))
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor)
await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv', realtime: false, loop: false })
testTotalMovingTimeSinceStart(rower, 46.302522627)
testTotalLinearDistanceSinceStart(rower, 166.29596716416734)
testTotalNumberOfStrokes(rower, 16)
// As dragFactor is static, it should remain in place
testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor)
})
test('sample data for DKN R-320 should produce plausible results', async () => {
const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.DKN_R320))
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testRecoveryDragFactor(rower, rowerProfiles.DKN_R320.dragFactor)
await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/DKNR320.csv', realtime: false, loop: false })
testTotalMovingTimeSinceStart(rower, 21.701535821)
testTotalLinearDistanceSinceStart(rower, 70.11298001986664)
testTotalNumberOfStrokes(rower, 10)
// As dragFactor is static, it should remain in place
testRecoveryDragFactor(rower, rowerProfiles.DKN_R320.dragFactor)
})
test('sample data for NordicTrack RX800 should produce plausible results', async () => {
const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.NordicTrack_RX800))
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testRecoveryDragFactor(rower, rowerProfiles.NordicTrack_RX800.dragFactor)
await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/RX800.csv', realtime: false, loop: false })
testTotalMovingTimeSinceStart(rower, 17.389910236000024)
testTotalLinearDistanceSinceStart(rower, 62.49982252262572)
testTotalNumberOfStrokes(rower, 8)
// As dragFactor is dynamic, it should have changed
testRecoveryDragFactor(rower, 493.1277530352103)
})
test('A full session for SportsTech WRX700 should produce plausible results', async () => {
const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Sportstech_WRX700))
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor)
await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets_session.csv', realtime: false, loop: false })
testTotalMovingTimeSinceStart(rower, 2342.741183077012)
testTotalLinearDistanceSinceStart(rower, 8409.62244161274)
testTotalNumberOfStrokes(rower, 846)
// As dragFactor is static, it should remain in place
testRecoveryDragFactor(rower, rowerProfiles.Sportstech_WRX700.dragFactor)
})
test('A full session for a Concept2 RowErg should produce plausible results', async () => {
const rower = createRower(deepMerge(rowerProfiles.DEFAULT, rowerProfiles.Concept2_RowErg))
testTotalMovingTimeSinceStart(rower, 0)
testTotalLinearDistanceSinceStart(rower, 0)
testTotalNumberOfStrokes(rower, 0)
testRecoveryDragFactor(rower, rowerProfiles.Concept2_RowErg.dragFactor)
await replayRowingSession(rower.handleRotationImpulse, { filename: 'recordings/Concept2_RowErg_Session_2000meters.csv', realtime: false, loop: false })
testTotalMovingTimeSinceStart(rower, 590.111937)
testTotalLinearDistanceSinceStart(rower, 2029.6932502534587)
testTotalNumberOfStrokes(rower, 206)
// As dragFactor isn't static, it should have changed
testRecoveryDragFactor(rower, 80.79039510767821)
})
function testStrokeState (rower, expectedValue) {
assert.ok(rower.strokeState() === expectedValue, `strokeState should be ${expectedValue} at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.strokeState()}`)
}
function testTotalMovingTimeSinceStart (rower, expectedValue) {
assert.ok(rower.totalMovingTimeSinceStart() === expectedValue, `totalMovingTimeSinceStart should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalMovingTimeSinceStart()}`)
}
function testTotalNumberOfStrokes (rower, expectedValue) {
// Please note there is a stroke 0
assert.ok(rower.totalNumberOfStrokes() + 1 === expectedValue, `totalNumberOfStrokes should be ${expectedValue} at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalNumberOfStrokes() + 1}`)
}
function testTotalLinearDistanceSinceStart (rower, expectedValue) {
assert.ok(rower.totalLinearDistanceSinceStart() === expectedValue, `totalLinearDistanceSinceStart should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.totalLinearDistanceSinceStart()}`)
}
function testCycleDuration (rower, expectedValue) {
assert.ok(rower.cycleDuration() === expectedValue, `cycleDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleDuration()}`)
}
function testCycleLinearDistance (rower, expectedValue) {
assert.ok(rower.cycleLinearDistance() === expectedValue, `cycleLinearDistance should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleLinearDistance()}`)
}
function testCycleLinearVelocity (rower, expectedValue) {
assert.ok(rower.cycleLinearVelocity() === expectedValue, `cycleLinearVelocity should be ${expectedValue} m/s at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cycleLinearVelocity()}`)
}
function testCyclePower (rower, expectedValue) {
assert.ok(rower.cyclePower() === expectedValue, `cyclePower should be ${expectedValue} Watt at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.cyclePower()}`)
}
function testDriveDuration (rower, expectedValue) {
assert.ok(rower.driveDuration() === expectedValue, `driveDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveDuration()}`)
}
function testDriveLinearDistance (rower, expectedValue) {
assert.ok(rower.driveLinearDistance() === expectedValue, `driveLinearDistance should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveLinearDistance()}`)
}
function testDriveLength (rower, expectedValue) {
assert.ok(rower.driveLength() === expectedValue, `driveLength should be ${expectedValue} meters at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveLength()}`)
}
function testDriveAverageHandleForce (rower, expectedValue) {
assert.ok(rower.driveAverageHandleForce() === expectedValue, `driveAverageHandleForce should be ${expectedValue} N at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.driveAverageHandleForce()}`)
}
function testDrivePeakHandleForce (rower, expectedValue) {
assert.ok(rower.drivePeakHandleForce() === expectedValue, `drivePeakHandleForce should be ${expectedValue} N at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.drivePeakHandleForce()}`)
}
function testRecoveryDuration (rower, expectedValue) {
assert.ok(rower.recoveryDuration() === expectedValue, `recoveryDuration should be ${expectedValue} sec at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.recoveryDuration()}`)
}
function testRecoveryDragFactor (rower, expectedValue) {
assert.ok(rower.recoveryDragFactor() === expectedValue, `recoveryDragFactor should be ${expectedValue} N*m*s^2 at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.recoveryDragFactor()}`)
}
function testInstantHandlePower (rower, expectedValue) {
assert.ok(rower.instantHandlePower() === expectedValue, `instantHandlePower should be ${expectedValue} Watt at ${rower.totalMovingTimeSinceStart()} sec, is ${rower.instantHandlePower()}`)
}
function reportAll (rower) { // eslint-disable-line no-unused-vars
assert.ok(0, `time: ${rower.totalMovingTimeSinceStart()}, state ${rower.strokeState()}, No Strokes: ${rower.totalNumberOfStrokes() + 1}, Lin Distance: ${rower.totalLinearDistanceSinceStart()}, cycle dur: ${rower.cycleDuration()}, cycle Lin Dist: ${rower.cycleLinearDistance()}, Lin Velocity: ${rower.cycleLinearVelocity()}, Power: ${rower.cyclePower()}, Drive Dur: ${rower.driveDuration()}, Drive Lin. Dist. ${rower.driveLinearDistance()}, Drive Length: ${rower.driveLength()}, Av. Handle Force: ${rower.driveAverageHandleForce()}, Peak Handle Force: ${rower.drivePeakHandleForce()}, Rec. Dur: ${rower.recoveryDuration()}, Dragfactor: ${rower.recoveryDragFactor()}, Inst Handle Power: ${rower.instantHandlePower()}`)
}
test.run()