updates documentation, fixes typos
This commit is contained in:
parent
8f064a0aab
commit
02359e819d
|
|
@ -2,20 +2,20 @@
|
|||
/*
|
||||
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
||||
|
||||
This keeps an array, which we can ask for an moving average
|
||||
This Averager can calculate the moving average of a continuous flow of data points
|
||||
|
||||
Please note: The array contains flankLength + 1 measured currentDt's, thus flankLength number of flanks between them
|
||||
They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the youngest
|
||||
They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the oldest
|
||||
*/
|
||||
function createMovingAverager (length, initValue) {
|
||||
let dataPoints
|
||||
reset()
|
||||
|
||||
function pushValue (dataPoint) {
|
||||
// add the new dataPoint to the array, we have to move datapoints starting at the oldst ones
|
||||
// add the new dataPoint to the array, we have to move data points starting at the oldest ones
|
||||
let i = length - 1
|
||||
while (i > 0) {
|
||||
// older datapoints are moved toward the higher numbers
|
||||
// older data points are moved towards the higher numbers
|
||||
dataPoints[i] = dataPoints[i - 1]
|
||||
i = i - 1
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ function createMovingAverager (length, initValue) {
|
|||
let i = length - 1
|
||||
let arrayTotal = 0.0
|
||||
while (i >= 0) {
|
||||
// summarise the value of the moving average
|
||||
// summarize the value of the moving average
|
||||
arrayTotal = arrayTotal + dataPoints[i]
|
||||
i = i - 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
||||
|
||||
This keeps an array, which we can test for an upgoing or downgoing flank
|
||||
A Detector used to test for up-going and down-going flanks
|
||||
|
||||
Please note: The array contains flankLength + 1 measured currentDt's, thus flankLength number of flanks between them
|
||||
They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the oldest
|
||||
|
|
@ -24,10 +24,10 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
const movingAverage = createMovingAverager(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses)
|
||||
|
||||
function pushValue (dataPoint) {
|
||||
// add the new dataPoint to the array, we have to move datapoints starting at the oldst ones
|
||||
// add the new dataPoint to the array, we have to move data points starting at the oldest ones
|
||||
let i = rowerSettings.flankLength
|
||||
while (i > 0) {
|
||||
// older datapoints are moved toward the higher numbers
|
||||
// older data points are moved toward the higher numbers
|
||||
dirtyDataPoints[i] = dirtyDataPoints[i - 1]
|
||||
cleanDataPoints[i] = cleanDataPoints[i - 1]
|
||||
angularVelocity[i] = angularVelocity[i - 1]
|
||||
|
|
@ -70,12 +70,14 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
function isFlywheelUnpowered () {
|
||||
let numberOfErrors = 0
|
||||
if (rowerSettings.naturalDeceleration < 0) {
|
||||
// A valid natural deceleration of the flywheel has been provided, this has to be maintained for a flanklength to count as an indication for an unpowered flywheel
|
||||
// Please note that angularAcceleration[] contains flank-information already, so we need to check from rowerSettings.flankLength -1 until 0 flanks
|
||||
// A valid natural deceleration of the flywheel has been provided, this has to be maintained for a flank length
|
||||
// to count as an indication for an unpowered flywheel
|
||||
// Please note that angularAcceleration[] contains flank-information already, so we need to check from
|
||||
// rowerSettings.flankLength -1 until 0 flanks
|
||||
let i = rowerSettings.flankLength - 1
|
||||
while (i >= 0) {
|
||||
if (angularAcceleration[i] > rowerSettings.naturalDeceleration) {
|
||||
// There seems to be some power present, so we detecten an error
|
||||
// There seems to be some power present, so we detected an error
|
||||
numberOfErrors = numberOfErrors + 1
|
||||
}
|
||||
i = i - 1
|
||||
|
|
@ -85,7 +87,8 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
let i = rowerSettings.flankLength
|
||||
while (i > 0) {
|
||||
if (cleanDataPoints[i] >= cleanDataPoints[i - 1]) {
|
||||
// Oldest interval (dataPoints[i]) is larger than the younger one (datapoint[i-1], as the distance is fixed, we are accelerating
|
||||
// Oldest interval (dataPoints[i]) is larger than the younger one (datapoint[i-1], as the distance is
|
||||
// fixed, we are accelerating
|
||||
numberOfErrors = numberOfErrors + 1
|
||||
}
|
||||
i = i - 1
|
||||
|
|
@ -101,8 +104,10 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
function isFlywheelPowered () {
|
||||
let numberOfErrors = 0
|
||||
if (rowerSettings.naturalDeceleration < 0) {
|
||||
// A valid natural deceleration of the flywheel has been provided, this has to be consistently be encountered for a flanklength to count as an indication of a powered flywheel
|
||||
// Please note that angularAcceleration[] contains flank-information already, so we need to check from rowerSettings.flankLength -1 until 0 flanks
|
||||
// A valid natural deceleration of the flywheel has been provided, this has to be consistently encountered
|
||||
// for a flank length to count as an indication of a powered flywheel
|
||||
// Please note that angularAcceleration[] contains flank-information already, so we need to check from
|
||||
// rowerSettings.flankLength -1 until 0 flanks
|
||||
let i = rowerSettings.flankLength - 1
|
||||
while (i >= 0) {
|
||||
if (angularAcceleration[i] < rowerSettings.naturalDeceleration) {
|
||||
|
|
@ -116,7 +121,8 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
let i = rowerSettings.flankLength
|
||||
while (i > 1) {
|
||||
if (cleanDataPoints[i] < cleanDataPoints[i - 1]) {
|
||||
// Oldest interval (dataPoints[i]) is shorter than the younger one (datapoint[i-1], as the distance is fixed, we discovered a deceleration
|
||||
// Oldest interval (dataPoints[i]) is shorter than the younger one (datapoint[i-1], as the distance is fixed, we
|
||||
// discovered a deceleration
|
||||
numberOfErrors = numberOfErrors + 1
|
||||
}
|
||||
i = i - 1
|
||||
|
|
@ -135,7 +141,7 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
}
|
||||
|
||||
function timeToBeginOfFlank () {
|
||||
// You expect the curve to bend between dirtyDataPoints[rowerSettings.flankLength] and dirtyDataPoints[rowerSettings.flankLength+1],
|
||||
// We expect the curve to bend between dirtyDataPoints[rowerSettings.flankLength] and dirtyDataPoints[rowerSettings.flankLength+1],
|
||||
// as acceleration FOLLOWS the start of the pulling the handle, we assume it must have started before that
|
||||
let i = rowerSettings.flankLength
|
||||
let total = 0.0
|
||||
|
|
@ -151,9 +157,10 @@ function createMovingFlankDetector (rowerSettings) {
|
|||
}
|
||||
|
||||
function impulseLengthAtBeginFlank () {
|
||||
// As this is fed into the speed calculation where small changes have big effects, and we typically use it when the curve is in a plateau,
|
||||
// we return the cleaned data and not the dirty data
|
||||
// Regardless of the way to determine the acceleration, cleanDataPoints[rowerSettings.flankLength] is always the impuls at the beginning of the flank being investigated
|
||||
// As this is fed into the speed calculation where small changes have big effects, and we typically use it when
|
||||
// the curve is in a plateau, we return the cleaned data and not the dirty data
|
||||
// Regardless of the way to determine the acceleration, cleanDataPoints[rowerSettings.flankLength] is always the
|
||||
// impulse at the beginning of the flank being investigated
|
||||
return cleanDataPoints[rowerSettings.flankLength]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
||||
|
||||
This averager calculates the average forcast for a moving inteval of a continuous flow
|
||||
This Averager calculates the average forecast for a moving interval of a continuous flow
|
||||
of data points for a certain (time) interval
|
||||
*/
|
||||
function createMovingIntervalAverager (movingDuration) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ const log = loglevel.getLogger('RowingEngine')
|
|||
function createRowingEngine (rowerSettings) {
|
||||
let workoutHandler
|
||||
const flankDetector = createMovingFlankDetector(rowerSettings)
|
||||
let movementAllowed = true
|
||||
let cyclePhase = 'Drive'
|
||||
let totalTime = 0.0
|
||||
let totalNumberOfImpulses = 0.0
|
||||
|
|
@ -43,8 +42,8 @@ function createRowingEngine (rowerSettings) {
|
|||
let currentDragFactor = rowerSettings.dragFactor / 1000000
|
||||
const movingDragAverage = createMovingAverager(5, currentDragFactor)
|
||||
let dragFactor = movingDragAverage.getMovingAverage()
|
||||
const minimumCycleLenght = rowerSettings.minimumDriveTime + rowerSettings.minimumRecoveryTime
|
||||
let cycleLenght = minimumCycleLenght
|
||||
const minimumCycleLength = rowerSettings.minimumDriveTime + rowerSettings.minimumRecoveryTime
|
||||
let cycleLength = minimumCycleLength
|
||||
let linearCycleVelocity = 0.0
|
||||
let totalLinearDistance = 0.0
|
||||
let averagedCyclePower = 0.0
|
||||
|
|
@ -54,12 +53,6 @@ function createRowingEngine (rowerSettings) {
|
|||
|
||||
// called if the sensor detected an impulse, currentDt is an interval in seconds
|
||||
function handleRotationImpulse (currentDt) {
|
||||
// First we check if the rower is allowed to move
|
||||
if (movementAllowed !== true) {
|
||||
// The rower isn't allowed to move
|
||||
return
|
||||
}
|
||||
|
||||
// impulses that take longer than maximumImpulseTimeBeforePause seconds are considered a pause
|
||||
if (currentDt > rowerSettings.maximumImpulseTimeBeforePause) {
|
||||
workoutHandler.handlePause(currentDt)
|
||||
|
|
@ -69,18 +62,19 @@ function createRowingEngine (rowerSettings) {
|
|||
totalTime += currentDt
|
||||
totalNumberOfImpulses++
|
||||
|
||||
// STEP 2: detect where we are in the rowing phase (drive or recovery)
|
||||
// detect where we are in the rowing phase (drive or recovery)
|
||||
flankDetector.pushValue(currentDt)
|
||||
|
||||
// Here we implement the finite state machine that goes between "Drive" and "Recovery" phases,
|
||||
// It will allow a phase-change provinding sufficient time has passed and there is a credible flank
|
||||
// we implement a finite state machine that goes between "Drive" and "Recovery" phases,
|
||||
// which allows a phase-change if sufficient time has passed and there is a plausible flank
|
||||
if (cyclePhase === 'Drive') {
|
||||
// We currently are in the "Drive" phase, lets determine what the next phase is
|
||||
if (flankDetector.isFlywheelUnpowered()) {
|
||||
// The flankdetector detects that the flywheel has no power excerted on it
|
||||
// The flank detector detects that the flywheel has no power exerted on it
|
||||
drivePhaseLength = (totalTime - flankDetector.timeToBeginOfFlank()) - drivePhaseStartTime
|
||||
if (drivePhaseLength >= rowerSettings.minimumDriveTime) {
|
||||
// We change into the Revocevery phase since we have been long enough in the Drive phase, and we see a clear lack of power excerted on the flywheel
|
||||
// We change into the "Recovery" phase since we have been long enough in the Drive phase, and we see a clear lack of power
|
||||
// exerted on the flywheel
|
||||
startRecoveryPhase(currentDt)
|
||||
cyclePhase = 'Recovery'
|
||||
} else {
|
||||
|
|
@ -95,32 +89,33 @@ function createRowingEngine (rowerSettings) {
|
|||
} else {
|
||||
// We currently are in the "Recovery" phase, lets determine what the next phase is
|
||||
if (flankDetector.isFlywheelPowered()) {
|
||||
// The flankdetector consistently detects some force on the flywheel
|
||||
// The flank detector consistently detects some force on the flywheel
|
||||
recoveryPhaseLength = (totalTime - flankDetector.timeToBeginOfFlank()) - recoveryPhaseStartTime
|
||||
if (recoveryPhaseLength >= rowerSettings.minimumRecoveryTime) {
|
||||
// We change into the Drive phase if we have been long enough in the Recovery phase, and we see a conistent force being excerted on the flywheel
|
||||
// We change into the "Drive" phase if we have been long enough in the "Recovery" phase, and we see a consistent force being
|
||||
// exerted on the flywheel
|
||||
startDrivePhase(currentDt)
|
||||
cyclePhase = 'Drive'
|
||||
} else {
|
||||
// We see a force, but the recovery phase has been too short, we stay in the recovery phase
|
||||
// We see a force, but the "Recovery" phase has been too short, we stay in the "Recovery" phase
|
||||
log.debug(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: flank suggests power (${flankDetector.accelerationAtBeginOfFlank().toFixed(1)} rad/s2), but waiting for recoveryPhaseLength (${recoveryPhaseLength.toFixed(4)} sec) to exceed minimumRecoveryTime (${rowerSettings.minimumRecoveryTime} sec)`)
|
||||
updateRecoveryPhase(currentDt)
|
||||
}
|
||||
} else {
|
||||
// No force on the flywheel, let's continue the drive phase
|
||||
// No force on the flywheel, let's continue the "Drive" phase
|
||||
updateRecoveryPhase(currentDt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDrivePhase (currentDt) {
|
||||
// First, we conclude the recovery phase
|
||||
// First, we conclude the "Recovery" phase
|
||||
log.debug('*** recovery phase completed')
|
||||
if (rowerSettings.minimumRecoveryTime <= recoveryPhaseLength && rowerSettings.minimumDriveTime <= drivePhaseLength) {
|
||||
// We have a credible cycletime
|
||||
cycleLenght = recoveryPhaseLength + drivePhaseLength
|
||||
// We have a plausible cycle time
|
||||
cycleLength = recoveryPhaseLength + drivePhaseLength
|
||||
} else {
|
||||
log.debug(`Cyclelenght isn't credible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s, maximumImpulseTimeBeforePause ${rowerSettings.maximumImpulseTimeBeforePause} s`)
|
||||
log.debug(`CycleLength isn't plausible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s, maximumImpulseTimeBeforePause ${rowerSettings.maximumImpulseTimeBeforePause} s`)
|
||||
}
|
||||
recoveryPhaseAngularDisplacement = (totalNumberOfImpulses - recoveryPhaseStartAngularDisplacement) * angularDisplacementPerImpulse
|
||||
|
||||
|
|
@ -132,12 +127,12 @@ function createRowingEngine (rowerSettings) {
|
|||
currentDragFactor = -1 * rowerSettings.flywheelInertia * ((1 / recoveryStartAngularVelocity) - (1 / recoveryEndAngularVelocity)) / recoveryPhaseLength
|
||||
if (rowerSettings.autoAdjustDragFactor) {
|
||||
if (currentDragFactor > (movingDragAverage.getMovingAverage() * 0.75) && currentDragFactor < (movingDragAverage.getMovingAverage() * 1.40)) {
|
||||
// If the calculated dragfactor is close to that we expect
|
||||
// If the calculated drag factor is close to what we expect
|
||||
movingDragAverage.pushValue(currentDragFactor)
|
||||
dragFactor = movingDragAverage.getMovingAverage()
|
||||
log.info(`*** Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}`)
|
||||
} else {
|
||||
// The calculated drag factor is outside the credible ranges
|
||||
// The calculated drag factor is outside the plausible range
|
||||
log.info(`Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}, which is too far off the currently used dragfactor of ${movingDragAverage.getMovingAverage() * 1000000}`)
|
||||
log.debug(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: recoveryStartAngularVelocity = ${recoveryStartAngularVelocity.toFixed(2)} rad/sec, recoveryEndAngularVelocity = ${recoveryEndAngularVelocity.toFixed(2)} rad/sec, recoveryPhaseLength = ${recoveryPhaseLength.toFixed(4)} sec`)
|
||||
}
|
||||
|
|
@ -159,15 +154,15 @@ function createRowingEngine (rowerSettings) {
|
|||
currentAngularVelocity = angularDisplacementPerImpulse / currentDt
|
||||
currentTorque = rowerSettings.flywheelInertia * ((currentAngularVelocity - previousAngularVelocity) / currentDt) + dragFactor * Math.pow(currentAngularVelocity, 2)
|
||||
}
|
||||
if (cycleLenght >= minimumCycleLenght) {
|
||||
// There is no division by zero and the data data is credible
|
||||
linearCycleVelocity = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * ((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLenght)
|
||||
averagedCyclePower = dragFactor * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLenght, 3.0)
|
||||
if (cycleLength >= minimumCycleLength) {
|
||||
// There is no division by zero and the data data is plausible
|
||||
linearCycleVelocity = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * ((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLength)
|
||||
averagedCyclePower = dragFactor * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLength, 3.0)
|
||||
} else {
|
||||
log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: cycle length was not credible, cycleLenght = ${cycleLenght} sec`)
|
||||
log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: cycle length was not plausible, CycleLength = ${cycleLength} sec`)
|
||||
}
|
||||
|
||||
// Next, we start the Drive Phase
|
||||
// Next, we start the "Drive" Phase
|
||||
log.debug(`*** DRIVE phase started at time: ${totalTime.toFixed(4)} sec, impuls number ${totalNumberOfImpulses}`)
|
||||
strokeNumber++
|
||||
drivePhaseStartTime = totalTime - flankDetector.timeToBeginOfFlank()
|
||||
|
|
@ -180,7 +175,7 @@ function createRowingEngine (rowerSettings) {
|
|||
timeSinceStart: totalTime,
|
||||
// currDragFactor : currentDragFactor,
|
||||
power: averagedCyclePower,
|
||||
duration: cycleLenght,
|
||||
duration: cycleLength,
|
||||
strokeDistance: driveLinearDistance + recoveryLinearDistance,
|
||||
durationDrivePhase: drivePhaseLength,
|
||||
speed: linearCycleVelocity,
|
||||
|
|
@ -211,13 +206,13 @@ function createRowingEngine (rowerSettings) {
|
|||
}
|
||||
|
||||
function startRecoveryPhase (currentDt) {
|
||||
// First, we conclude the Drive Phase
|
||||
// First, we conclude the "Drive" Phase
|
||||
log.debug('*** drive phase completed')
|
||||
if (rowerSettings.minimumRecoveryTime <= recoveryPhaseLength && rowerSettings.minimumDriveTime <= drivePhaseLength) {
|
||||
// We have a credible cycletime
|
||||
cycleLenght = recoveryPhaseLength + drivePhaseLength
|
||||
// We have a plausible cycle time
|
||||
cycleLength = recoveryPhaseLength + drivePhaseLength
|
||||
} else {
|
||||
log.debug(`Cycleleght wasn't credible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s`)
|
||||
log.debug(`CycleLength wasn't plausible: recoveryPhaseLength ${recoveryPhaseLength.toFixed(4)} sec, drivePhaseLength = ${drivePhaseLength.toFixed(4)} s`)
|
||||
}
|
||||
drivePhaseAngularDisplacement = ((totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()) - drivePhaseStartAngularDisplacement) * angularDisplacementPerImpulse
|
||||
// driveEndAngularVelocity = angularDisplacementPerImpulse / flankDetector.impulseLengthAtBeginFlank()
|
||||
|
|
@ -228,17 +223,17 @@ function createRowingEngine (rowerSettings) {
|
|||
currentAngularVelocity = angularDisplacementPerImpulse / currentDt
|
||||
currentTorque = rowerSettings.flywheelInertia * ((currentAngularVelocity - previousAngularVelocity) / currentDt) + dragFactor * Math.pow(currentAngularVelocity, 2)
|
||||
}
|
||||
// We display the AVERAGE speed in the display, NOT the topspeed of the stroke
|
||||
if (drivePhaseLength > rowerSettings.minimumDriveTime && cycleLenght > minimumCycleLenght) {
|
||||
// let's prevent division's by zero and make sure data is credible
|
||||
linearCycleVelocity = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * ((drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement) / cycleLenght)
|
||||
// We display the AVERAGE speed in the display, NOT the top speed of the stroke
|
||||
if (drivePhaseLength > rowerSettings.minimumDriveTime && cycleLength > minimumCycleLength) {
|
||||
// let's prevent division's by zero and make sure data is plausible
|
||||
linearCycleVelocity = Math.pow((dragFactor / rowerSettings.magicConstant), 1.0 / 3.0) * ((drivePhaseAngularDisplacement + recoveryPhaseAngularDisplacement) / cycleLength)
|
||||
// drivePhaseEnergyProduced = rowerSettings.flywheelInertia * ((driveEndAngularVelocity - driveStartAngularVelocity) / drivePhaseLength) * drivePhaseAngularDisplacement + dragFactor * Math.pow(driveEndAngularVelocity, 2) * drivePh$
|
||||
averagedCyclePower = dragFactor * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLenght, 3.0)
|
||||
averagedCyclePower = dragFactor * Math.pow((recoveryPhaseAngularDisplacement + drivePhaseAngularDisplacement) / cycleLength, 3.0)
|
||||
} else {
|
||||
log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: cycle length was not credible, drivePhaseLength = ${drivePhaseLength.toFixed(4)} sec, cycleLenght = ${cycleLenght.toFixed(4)} sec`)
|
||||
log.error(`Time: ${totalTime.toFixed(4)} sec, impuls ${totalNumberOfImpulses}: cycle length was not plausible, drivePhaseLength = ${drivePhaseLength.toFixed(4)} sec, cycleLength = ${cycleLength.toFixed(4)} sec`)
|
||||
}
|
||||
|
||||
// Next, we start the Recovery Phase
|
||||
// Next, we start the "Recovery" Phase
|
||||
log.debug(`*** RECOVERY phase started at time: ${totalTime.toFixed(4)} sec, impuls number ${totalNumberOfImpulses}`)
|
||||
recoveryPhaseStartTime = totalTime - flankDetector.timeToBeginOfFlank()
|
||||
recoveryPhaseStartAngularDisplacement = totalNumberOfImpulses - flankDetector.noImpulsesToBeginFlank()
|
||||
|
|
@ -253,7 +248,7 @@ function createRowingEngine (rowerSettings) {
|
|||
workoutHandler.handleStrokeEnd({
|
||||
timeSinceStart: totalTime,
|
||||
power: averagedCyclePower,
|
||||
duration: cycleLenght,
|
||||
duration: cycleLength,
|
||||
strokeDistance: driveLinearDistance + recoveryLinearDistance,
|
||||
durationDrivePhase: drivePhaseLength,
|
||||
speed: linearCycleVelocity,
|
||||
|
|
@ -282,14 +277,6 @@ function createRowingEngine (rowerSettings) {
|
|||
}
|
||||
}
|
||||
|
||||
function allowMovement () {
|
||||
movementAllowed = true
|
||||
}
|
||||
|
||||
function stopMoving () {
|
||||
movementAllowed = false
|
||||
}
|
||||
|
||||
function reset () {
|
||||
cyclePhase = 'Drive'
|
||||
totalTime = 0.0
|
||||
|
|
@ -313,7 +300,7 @@ function createRowingEngine (rowerSettings) {
|
|||
currentDragFactor = rowerSettings.dragFactor / 1000000
|
||||
movingDragAverage.reset()
|
||||
dragFactor = movingDragAverage.getMovingAverage()
|
||||
cycleLenght = 0.0
|
||||
cycleLength = 0.0
|
||||
linearCycleVelocity = 0.0
|
||||
totalLinearDistance = 0.0
|
||||
averagedCyclePower = 0.0
|
||||
|
|
@ -325,8 +312,6 @@ function createRowingEngine (rowerSettings) {
|
|||
|
||||
return {
|
||||
handleRotationImpulse,
|
||||
allowMovement,
|
||||
stopMoving,
|
||||
reset,
|
||||
notify
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ function createRowingStatistics (config) {
|
|||
function handleStrokeEnd (stroke) {
|
||||
if (!trainingRunning) startTraining()
|
||||
|
||||
// if we do not get a stroke for timeBetweenStrokesBeforePause miliseconds we treat this as a rowing pause
|
||||
// if we do not get a stroke for timeBetweenStrokesBeforePause milliseconds we treat this as a rowing pause
|
||||
if (rowingPausedTimer)clearInterval(rowingPausedTimer)
|
||||
rowingPausedTimer = setTimeout(() => pauseRowing(), timeBetweenStrokesBeforePause)
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ function createRowingStatistics (config) {
|
|||
powerAverager.pushValue(stroke.power)
|
||||
speedAverager.pushValue(stroke.speed)
|
||||
if (stroke.duration < timeBetweenStrokesBeforePause && stroke.duration > minimumStrokeTime) {
|
||||
// stroke duration has to be credible to be accepted
|
||||
// stroke duration has to be plausible to be accepted
|
||||
powerRatioAverager.pushValue(stroke.durationDrivePhase / stroke.duration)
|
||||
strokeAverager.pushValue(stroke.duration)
|
||||
caloriesAveragerMinute.pushValue(calories, stroke.duration)
|
||||
|
|
@ -92,13 +92,13 @@ function createRowingStatistics (config) {
|
|||
|
||||
// initiated when the stroke state changes
|
||||
function handleRecoveryEnd (stroke) {
|
||||
// todo: wee need a better mechanism to communicate strokeState updates
|
||||
// todo: we need a better mechanism to communicate strokeState updates
|
||||
// this is an initial hacky attempt to see if we can use it for the C2-pm5 protocol
|
||||
durationTotal = stroke.timeSinceStart
|
||||
powerAverager.pushValue(stroke.power)
|
||||
speedAverager.pushValue(stroke.speed)
|
||||
if (stroke.duration < timeBetweenStrokesBeforePause && stroke.duration > minimumStrokeTime) {
|
||||
// stroke duration has to be credible to be accepted
|
||||
// stroke duration has to be plausible to be accepted
|
||||
powerRatioAverager.pushValue(stroke.durationDrivePhase / stroke.duration)
|
||||
strokeAverager.pushValue(stroke.duration)
|
||||
} else {
|
||||
|
|
@ -120,9 +120,9 @@ function createRowingStatistics (config) {
|
|||
instantaneousTorque = stroke.instantaneousTorque
|
||||
}
|
||||
|
||||
// initiated when new heart rate value is received from heart rate sensor
|
||||
// initiated when a new heart rate value is received from heart rate sensor
|
||||
function handleHeartrateMeasurement (value) {
|
||||
// set the heart rate to zero, if we did not receive a value for some time
|
||||
// set the heart rate to zero if we did not receive a value for some time
|
||||
if (heartrateResetTimer)clearInterval(heartrateResetTimer)
|
||||
heartrateResetTimer = setTimeout(() => {
|
||||
heartrate = 0
|
||||
|
|
@ -194,7 +194,7 @@ function createRowingStatistics (config) {
|
|||
emitter.emit('rowingPaused')
|
||||
}
|
||||
|
||||
// converts a timeStamp in seconds to a human readable hh:mm:ss format
|
||||
// converts a timestamp in seconds to a human readable hh:mm:ss format
|
||||
function secondsToTimeString (secondsTimeStamp) {
|
||||
if (secondsTimeStamp === Infinity) return '∞'
|
||||
const hours = Math.floor(secondsTimeStamp / 60 / 60)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
||||
|
||||
The Averager calculates the weighted average of a continuous flow of data points
|
||||
This Averager can calculate the weighted average of a continuous flow of data points
|
||||
*/
|
||||
function createWeightedAverager (maxNumOfDataPoints) {
|
||||
let dataPoints = []
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export default {
|
|||
// A constant that is commonly used to convert flywheel revolutions to a rowed distance
|
||||
// see here: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section9
|
||||
// Concept2 seems to use 2.8, which they admit is an arbitrary number which came close
|
||||
// to their expectations. So for your rower, you have to find a credible distance for your effort.
|
||||
// to their expectations. So for your rower, you have to find a plausible distance for your effort.
|
||||
// Also note that the rowed distance also depends on flywheelInertia, so please calibrate that before changing this constant.
|
||||
// PLEASE NOTE: Increasing this number decreases your rowed meters
|
||||
magicConstant: 2.8
|
||||
|
|
|
|||
Loading…
Reference in New Issue