diff --git a/app/engine/RowingEngine.js b/app/engine/RowingEngine.js index 0de00a3..d0f7a9e 100644 --- a/app/engine/RowingEngine.js +++ b/app/engine/RowingEngine.js @@ -40,8 +40,10 @@ function createRowingEngine (rowerSettings) { let recoveryEndAngularVelocity = angularDisplacementPerImpulse / rowerSettings.maximumTimeBetweenImpulses let recoveryLinearDistance = 0.0 let currentDragFactor = rowerSettings.dragFactor / 1000000 - const movingDragAverage = createMovingAverager(5, currentDragFactor) + const movingDragAverage = createMovingAverager(rowerSettings.dampingConstantSmoothing, currentDragFactor) let dragFactor = movingDragAverage.getAverage() + const dragFactorMaxUpwardChange = 1 + rowerSettings.dampingConstantMaxChange + const dragFactorMaxDownwardChange = 1 - rowerSettings.dampingConstantMaxChange const minimumCycleLength = rowerSettings.minimumDriveTime + rowerSettings.minimumRecoveryTime let cycleLength = minimumCycleLength let linearCycleVelocity = 0.0 @@ -126,7 +128,7 @@ function createRowingEngine (rowerSettings) { // Prevent division by zero and keep useless data out of our calculations currentDragFactor = -1 * rowerSettings.flywheelInertia * ((1 / recoveryStartAngularVelocity) - (1 / recoveryEndAngularVelocity)) / recoveryPhaseLength if (rowerSettings.autoAdjustDragFactor) { - if (currentDragFactor > (movingDragAverage.getAverage() * 0.75) && currentDragFactor < (movingDragAverage.getAverage() * 1.40)) { + if (currentDragFactor > (movingDragAverage.getAverage() * dragFactorMaxDownwardChange) && currentDragFactor < (movingDragAverage.getAverage() * dragFactorMaxUpwardChange)) { // If the calculated drag factor is close to what we expect movingDragAverage.pushValue(currentDragFactor) dragFactor = movingDragAverage.getAverage() @@ -135,6 +137,15 @@ function createRowingEngine (rowerSettings) { // 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.getAverage() * 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`) + if (currentDragFactor < (movingDragAverage.getAverage() * dragFactorMaxDownwardChange)) { + // The current calculated dragfactor makes an abrupt downward change, let's follow the direction, but limit it to the maximum allowed change + movingDragAverage.pushValue(movingDragAverage.getAverage() * dragFactorMaxDownwardChange) + } else { + // The current calculated dragfactor makes an abrupt upward change, let's follow the direction, but limit it to the maximum allowed change + movingDragAverage.pushValue(movingDragAverage.getAverage() * dragFactorMaxUpwardChange) + } + dragFactor = movingDragAverage.getAverage() + log.debug(`*** Applied drag factor: ${dragFactor * 1000000}`) } } else { log.info(`*** Calculated drag factor: ${(currentDragFactor * 1000000).toFixed(2)}`) diff --git a/config/rowerProfiles.js b/config/rowerProfiles.js index 72ab5dc..64ab5cf 100644 --- a/config/rowerProfiles.js +++ b/config/rowerProfiles.js @@ -58,18 +58,30 @@ export default { // autoAdjustDragFactor to true (see below). dragFactor: 1500, - // The moment of inertia of the flywheel kg*m^2 - // A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia" - // You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for - // plausibility. Note that the power also depends on the drag factor (see above). - flywheelInertia: 0.5, - // Set this to true, if you want to automatically update the drag factor based on the measured // values in the stroke recovery phase. If your rower produces stable damping values, then this could be a good // option to dynamically adjust your measurements to the damper setting of your rower. // When your machine's power and speed readings are too volatile it is wise to turn it off autoAdjustDragFactor: false, + // The moment of inertia of the flywheel kg*m^2, which is ONLY relevant when autoAdjustDragFactor is set to true or when you + // use Force Curves. Otherwise this value isn't relevant to your rower + // A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia" + // You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for + // plausibility. Note that the power also depends on the drag factor (see above). + flywheelInertia: 0.5, + + // If autoAdjustDragFactor is set to true, it will calculate the drag each recovery phase and update it accordingly to calculate speed, + // distance, etc.. As this calculation that is prone to noise in the measuremnts, it is wise to apply smoothing to prevent this noise + // from throwing off your key metrics. The default value is a running average of the drag factor of 5 strokes + dampingConstantSmoothing: 5, + + // Another setting for when autoAdjustDragFactor is set to true: the maximum allowed change from the current value. Spikes usually imply + // measurement errors, so this setting determines the maximum change with respect to the current dragfactor. Please note that this filter + // will prevent large changes, but will still move the dragfactor upward/downward to prevent it from being stuck. The value is in maximum + // allowed change. The default value of 0.10 implies that the maximum upward/downward change is an increase of the drag with 10%. + dampingConstantMaxChange: 0.10, + // 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 diff --git a/docs/rower_settings.md b/docs/rower_settings.md index 9020e03..cad80ad 100644 --- a/docs/rower_settings.md +++ b/docs/rower_settings.md @@ -71,4 +71,6 @@ Some people want it all, and we're happy to give to you when your rower and your * **magicConstant** is a constant that is commonly used to convert flywheel revolutions to a rowed distance and speed (see [the physics of ergometers](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 of a competetion boat. As this setting only affects speed/distance, this setting typically is used to change the power needed to row a certain distance or reach a certain speed. So changing this can make your rower's metrics act as sluggish as an oil tanker (much power needed for little speed), or more like a smooth eight (less power needed for more speed). So for your rower, you could set your own plausible distance for the effort you put in. Please note that the rowed distance also depends on **flywheelInertia**, so please calibrate that before changing this constant. Another note: increasing this number decreases your rowed meters, but not in a linear fashion. * **screenUpdateInterval**: normally set at 1000 milliseconds, but for a more smoother experience on your monitor you can go as low as 100 ms. This makes the transition of the distance and time quite smooth, but at the price of some more CPU-load. * **numOfPhasesForAveragingScreenData**: we average the data from several stroke phases to prevent the monitor and Bluetooth devices to become fidgety. Typically, we set this value to 6, which means 3 strokes (there are two phases in each stroke). However, some Bluetooth devices do their own calculations. And sometimes you really want the feedback on your individual strokes without any punches hold back. Setting this to 1 will result in a very volatile, but direct feedback mechanism on your stroke. +* **dampingConstantSmoothing** determines the smoothing of the dragfactor across strokes (if autoAdjustDragFactor is set to true). Normally set at 5 strokes, which prevents wild values to throw off all your measurements. If you have rower that produces very little noise in the data, then it could be an option to reduce. If your machine produces noisy data, this is the one to increase before anything else. +* **dampingConstantMaxChange** determines the maximum change between a currently determined dragfactor and the current average of the previous dampingConstantSmoothing strokes (if autoAdjustDragFactor is set to true). This filter reduces spikes in the calculation and thus makes the dragfactor less responsive to changes. The default value of 0.10 implies that the maximum upward/downward change is an increase of the drag with 10%. Please note that this filter still allows changes, it just limits their impact to this percentage. Most rower's dragfactor is relatively constant, however certain hyrid rower's dragfactor changes when the speed changes. To allow for bigger changes within a stroke, increase this setting. When the expected changes are small, set this setting small. When your rower is a hybrid or when you have one configuration for all your damper settings, this should be a bit wider. * **recordRawData**: This is as raw as it gets, as setting this to `true` makes Open Rowing Monitor dump the raw impulse-lengths to a file (see [how we interpret this data](physics_openrowingmonitor.md)).