Change to use Lin. TS for Drag calculation
Changing the drag and recovery slope calculation from OLS to Linear Theil-Sen
This commit is contained in:
parent
02fa5293f2
commit
b11a63a8fd
|
|
@ -23,6 +23,7 @@
|
||||||
import loglevel from 'loglevel'
|
import loglevel from 'loglevel'
|
||||||
import { createStreamFilter } from './utils/StreamFilter.js'
|
import { createStreamFilter } from './utils/StreamFilter.js'
|
||||||
import { createOLSLinearSeries } from './utils/OLSLinearSeries.js'
|
import { createOLSLinearSeries } from './utils/OLSLinearSeries.js'
|
||||||
|
import { createTSLinearSeries } from './utils/FullTSLinearSeries.js'
|
||||||
import { createTSQuadraticSeries } from './utils/FullTSQuadraticSeries.js'
|
import { createTSQuadraticSeries } from './utils/FullTSQuadraticSeries.js'
|
||||||
import { createWeighedSeries } from './utils/WeighedSeries.js'
|
import { createWeighedSeries } from './utils/WeighedSeries.js'
|
||||||
|
|
||||||
|
|
@ -35,13 +36,14 @@ function createFlywheel (rowerSettings) {
|
||||||
const minumumTorqueBeforeStroke = rowerSettings.minumumForceBeforeStroke * (rowerSettings.sprocketRadius / 100)
|
const minumumTorqueBeforeStroke = rowerSettings.minumumForceBeforeStroke * (rowerSettings.sprocketRadius / 100)
|
||||||
const currentDt = createStreamFilter(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses)
|
const currentDt = createStreamFilter(rowerSettings.smoothing, rowerSettings.maximumTimeBetweenImpulses)
|
||||||
const _deltaTime = createOLSLinearSeries(flankLength)
|
const _deltaTime = createOLSLinearSeries(flankLength)
|
||||||
|
// const _deltaTime = createTSLinearSeries(flankLength)
|
||||||
const _angularDistance = createTSQuadraticSeries(flankLength)
|
const _angularDistance = createTSQuadraticSeries(flankLength)
|
||||||
const _angularVelocityMatrix = []
|
const _angularVelocityMatrix = []
|
||||||
const _angularAccelerationMatrix = []
|
const _angularAccelerationMatrix = []
|
||||||
const drag = createStreamFilter(rowerSettings.dragFactorSmoothing, (rowerSettings.dragFactor / 1000000))
|
const drag = createWeighedSeries(rowerSettings.dragFactorSmoothing, (rowerSettings.dragFactor / 1000000))
|
||||||
const recoveryDeltaTime = createOLSLinearSeries()
|
const recoveryDeltaTime = createTSLinearSeries()
|
||||||
const strokedetectionMinimalGoodnessOfFit = rowerSettings.minimumStrokeQuality
|
const strokedetectionMinimalGoodnessOfFit = rowerSettings.minimumStrokeQuality
|
||||||
const minumumRecoverySlope = createStreamFilter(rowerSettings.dragFactorSmoothing, rowerSettings.minumumRecoverySlope)
|
const minumumRecoverySlope = createWeighedSeries(rowerSettings.dragFactorSmoothing, rowerSettings.minumumRecoverySlope)
|
||||||
let _deltaTimeBeforeFlank
|
let _deltaTimeBeforeFlank
|
||||||
let _angularVelocityAtBeginFlank
|
let _angularVelocityAtBeginFlank
|
||||||
let _angularVelocityBeforeFlank
|
let _angularVelocityBeforeFlank
|
||||||
|
|
@ -117,8 +119,8 @@ function createFlywheel (rowerSettings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's make room for a new set of values for angular velocity and acceleration
|
// Let's make room for a new set of values for angular velocity and acceleration
|
||||||
_angularVelocityMatrix[_angularVelocityMatrix.length] = createWeighedSeries()
|
_angularVelocityMatrix[_angularVelocityMatrix.length] = createWeighedSeries(flankLength, 0)
|
||||||
_angularAccelerationMatrix[_angularAccelerationMatrix.length] = createWeighedSeries()
|
_angularAccelerationMatrix[_angularAccelerationMatrix.length] = createWeighedSeries(flankLength, 0)
|
||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
const goodnessOfFit = _angularDistance.goodnessOfFit()
|
const goodnessOfFit = _angularDistance.goodnessOfFit()
|
||||||
|
|
@ -133,7 +135,7 @@ function createFlywheel (rowerSettings) {
|
||||||
_angularAccelerationAtBeginFlank = _angularAccelerationMatrix[0].weighedAverage()
|
_angularAccelerationAtBeginFlank = _angularAccelerationMatrix[0].weighedAverage()
|
||||||
|
|
||||||
// And finally calculate the torque
|
// And finally calculate the torque
|
||||||
_torqueAtBeginFlank = (rowerSettings.flywheelInertia * _angularAccelerationAtBeginFlank + drag.clean() * Math.pow(_angularVelocityAtBeginFlank, 2))
|
_torqueAtBeginFlank = (rowerSettings.flywheelInertia * _angularAccelerationAtBeginFlank + drag.weighedAverage() * Math.pow(_angularVelocityAtBeginFlank, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
function maintainStateOnly () {
|
function maintainStateOnly () {
|
||||||
|
|
@ -153,24 +155,28 @@ function createFlywheel (rowerSettings) {
|
||||||
// Completion of the recovery phase
|
// Completion of the recovery phase
|
||||||
inRecoveryPhase = false
|
inRecoveryPhase = false
|
||||||
|
|
||||||
|
// As goodnessOfFit is calculated in-situ (for 220 datapoints on a C2) and is CPU intensive, we only calculate it only once and reuse the cached value
|
||||||
|
const goodnessOfFit = recoveryDeltaTime.goodnessOfFit()
|
||||||
|
|
||||||
// Calculation of the drag-factor
|
// Calculation of the drag-factor
|
||||||
if (rowerSettings.autoAdjustDragFactor && recoveryDeltaTime.length() > minimumDragFactorSamples && recoveryDeltaTime.slope() > 0 && (!drag.reliable() || recoveryDeltaTime.goodnessOfFit() >= rowerSettings.minimumDragQuality)) {
|
if (rowerSettings.autoAdjustDragFactor && recoveryDeltaTime.length() > minimumDragFactorSamples && recoveryDeltaTime.slope() > 0 && (!drag.reliable() || goodnessOfFit >= rowerSettings.minimumDragQuality)) {
|
||||||
drag.push(slopeToDrag(recoveryDeltaTime.slope()))
|
drag.push(slopeToDrag(recoveryDeltaTime.slope()), goodnessOfFit)
|
||||||
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, no. samples: ${recoveryDeltaTime.length()}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`)
|
|
||||||
|
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, no. samples: ${recoveryDeltaTime.length()}, Goodness of Fit: ${goodnessOfFit.toFixed(4)}`)
|
||||||
if (rowerSettings.autoAdjustRecoverySlope) {
|
if (rowerSettings.autoAdjustRecoverySlope) {
|
||||||
// We are allowed to autoadjust stroke detection slope as well, so let's do that
|
// We are allowed to autoadjust stroke detection slope as well, so let's do that
|
||||||
minumumRecoverySlope.push((1 - rowerSettings.autoAdjustRecoverySlopeMargin) * recoveryDeltaTime.slope())
|
minumumRecoverySlope.push((1 - rowerSettings.autoAdjustRecoverySlopeMargin) * recoveryDeltaTime.slope(), goodnessOfFit)
|
||||||
log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`)
|
log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${goodnessOfFit.toFixed(4)}`)
|
||||||
} else {
|
} else {
|
||||||
// We aren't allowed to adjust the slope, let's report the slope to help help the user configure it
|
// We aren't allowed to adjust the slope, let's report the slope to help help the user configure it
|
||||||
log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}, not used as autoAdjustRecoverySlope isn't set to true`)
|
log.debug(`*** Calculated recovery slope: ${recoveryDeltaTime.slope().toFixed(6)}, Goodness of Fit: ${goodnessOfFit.toFixed(4)}, not used as autoAdjustRecoverySlope isn't set to true`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!rowerSettings.autoAdjustDragFactor) {
|
if (!rowerSettings.autoAdjustDragFactor) {
|
||||||
// autoAdjustDampingConstant = false, thus the update is skipped, but let's log the dragfactor anyway
|
// autoAdjustDampingConstant = false, thus the update is skipped, but let's log the dragfactor anyway
|
||||||
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, slope: ${recoveryDeltaTime.slope().toFixed(8)}, not used because autoAdjustDragFactor is not true`)
|
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, slope: ${recoveryDeltaTime.slope().toFixed(8)}, not used because autoAdjustDragFactor is not true`)
|
||||||
} else {
|
} else {
|
||||||
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, not used because reliability was too low. no. samples: ${recoveryDeltaTime.length()}, fit: ${recoveryDeltaTime.goodnessOfFit().toFixed(4)}`)
|
log.debug(`*** Calculated drag factor: ${(slopeToDrag(recoveryDeltaTime.slope()) * 1000000).toFixed(4)}, not used because reliability was too low. no. samples: ${recoveryDeltaTime.length()}, fit: ${goodnessOfFit.toFixed(4)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +223,7 @@ function createFlywheel (rowerSettings) {
|
||||||
|
|
||||||
function dragFactor () {
|
function dragFactor () {
|
||||||
// Ths function returns the current dragfactor of the flywheel
|
// Ths function returns the current dragfactor of the flywheel
|
||||||
return drag.clean()
|
return drag.weighedAverage()
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDwelling () {
|
function isDwelling () {
|
||||||
|
|
@ -243,9 +249,9 @@ function createFlywheel (rowerSettings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUnpowered () {
|
function isUnpowered () {
|
||||||
if (deltaTimeSlopeAbove(minumumRecoverySlope.clean()) && torqueAbsent() && _deltaTime.length() >= flankLength) {
|
if (deltaTimeSlopeAbove(minumumRecoverySlope.weighedAverage()) && torqueAbsent() && _deltaTime.length() >= flankLength) {
|
||||||
// We reached the minimum number of increasing currentDt values
|
// We reached the minimum number of increasing currentDt values
|
||||||
// log.info(`*** INFO: recovery detected based on due to slope exceeding recoveryslope = ${deltaTimeSlopeAbove(minumumRecoverySlope.clean())}, exceeding minumumForceBeforeStroke = ${torqueAbsent()}`)
|
// log.info(`*** INFO: recovery detected based on due to slope exceeding recoveryslope = ${deltaTimeSlopeAbove(minumumRecoverySlope.weighedAverage())}, exceeding minumumForceBeforeStroke = ${torqueAbsent()}`)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|
@ -253,7 +259,7 @@ function createFlywheel (rowerSettings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPowered () {
|
function isPowered () {
|
||||||
if ((deltaTimeSlopeBelow(minumumRecoverySlope.clean()) && torquePresent()) || _deltaTime.length() < flankLength) {
|
if ((deltaTimeSlopeBelow(minumumRecoverySlope.weighedAverage()) && torquePresent()) || _deltaTime.length() < flankLength) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue