implements better flank detection, adds spreadsheet for analysis

Added the flankdetector, to reliably detect an acceleration or deceleration of the flywheel
Added extra metrics for the creation of TCX-files
Added extra metrics (speed in m/s and cadence) to allow future export of this data to Garmin TCX files, which everybody seems to love.
I increased the priority of the GPIO-service, as I noticed that much of the measurement noise originates from delayed read-outs of the GPIO.
An Excel tool to "play" with the settings of a rower, to adjust the settings found in the rowerprofiles.js
Adds test and data for RX800 rower
Lightweight version of Excel file

Co-authored-by: Lars Berning <151194+laberning@users.noreply.github.com>
This commit is contained in:
JaapvanEkris 2021-04-30 22:03:47 +02:00 committed by GitHub
parent 1f947bd1d8
commit 2c6819ca02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1124 additions and 18 deletions

View File

@ -0,0 +1,68 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
This keeps an array, which we can test for an upgoing or downgoing flank
Please note: The array contains flankLenght + 1 measured currentDt's, thus flankLenght number of flanks between them
They are arranged that dataPoints[0] is the youngest, and dataPoints[flankLength] the youngest
*/
function createMovingFlankDetector (flankLength, initValue, numberOfErrorsAllowed) {
const dataPoints = new Array(flankLength + 1)
dataPoints.fill(initValue)
function pushValue (dataPoint) {
// add the new dataPoint to the array, we have to move datapoints starting at the oldst ones
let i = flankLength
while (i > 0) {
// older datapoints are moved toward the higher numbers
dataPoints[i] = dataPoints[i - 1]
i = i - 1
}
dataPoints[0] = dataPoint
}
function isDecelerating () {
let i = flankLength
let numberOfErrors = 0
while (i > 0) {
if (dataPoints[i] < dataPoints[i - 1]) {
// Oldest interval (dataPoints[i]) is shorter than the younger one (datapoint[i-1], as the distance is fixed, we are decelerating
} else {
numberOfErrors = numberOfErrors + 1
}
i = i - 1
}
if (numberOfErrors > numberOfErrorsAllowed) {
return false
} else {
return true
}
}
function isAccelerating () {
let i = flankLength
let numberOfErrors = 0
while (i > 0) {
if (dataPoints[i] > dataPoints[i - 1]) {
// Oldest interval (dataPoints[i]) is longer than the younger one (datapoint[i-1], as the distance is fixed, we are accelerating
} else {
numberOfErrors = numberOfErrors + 1
}
i = i - 1
}
if (numberOfErrors > numberOfErrorsAllowed) {
return false
} else {
return true
}
}
return {
pushValue,
isDecelerating,
isAccelerating
}
}
export { createMovingFlankDetector }

View File

@ -12,6 +12,7 @@
*/
import loglevel from 'loglevel'
import { createWeightedAverager } from './WeightedAverager.js'
import { createMovingFlankDetector } from './MovingFlankDetector.js'
import { createTimer } from './Timer.js'
const log = loglevel.getLogger('RowingEngine')
@ -55,6 +56,8 @@ function createRowingEngine (rowerSettings) {
let workoutHandler
const kDampEstimatorAverager = createWeightedAverager(3)
const flankDetector = createMovingFlankDetector(rowerSettings.numOfImpulsesPerRevolution, rowerSettings.maximumTimeBetweenMagnets, 0)
let prevDt = rowerSettings.maximumTimeBetweenMagnets
let kPower = 0.0
let jPower = 0.0
let kDampEstimator = 0.0
@ -84,6 +87,18 @@ function createRowingEngine (rowerSettings) {
return
}
// remember the state of drive phase from the previous impulse, we need it to detect state changes
wasInDrivePhase = isInDrivePhase
// STEP 1: reduce noise in the measurements by applying some sanity checks
// noise filter on the value of currentDt: it should be within sane levels and should not deviate too much from the previous reading
if (currentDt < rowerSettings.minimumTimeBetweenMagnets || currentDt > rowerSettings.maximumTimeBetweenMagnets || currentDt < (rowerSettings.maximumDownwardChange * prevDt) || currentDt > (rowerSettings.maximumUpwardChange * prevDt)) {
// impulses are outside plausible ranges, so we assume it is close to the previous one
currentDt = prevDt
log.debug(`noise filter corrected currentDt, ${currentDt} was dubious, changed to ${prevDt}`)
}
prevDt = currentDt
// each revolution of the flywheel adds distance of distancePerRevolution
strokeDistance += distancePerRevolution / numOfImpulsesPerRevolution
@ -109,8 +124,7 @@ function createRowingEngine (rowerSettings) {
// used to be 15
const accelerationIsPositive = omegaDotVector[0] > 0
wasInDrivePhase = isInDrivePhase
// STEP 2: detect where we are in the rowing phase (drive or recovery)
if (liquidFlywheel) {
// Identification of drive and recovery phase on water rowers is still Work in Progress
// ω does not seem to decay that linear on water rower in recovery phase, so this would not be
@ -121,11 +135,23 @@ function createRowingEngine (rowerSettings) {
// todo: do some measurements and find a better stable indicator for water rowers
isInDrivePhase = accelerationIsPositive
} else {
// ω decays linear on rowers with a solid flywheel, so we can use that to differentiate the phases
isInDrivePhase = accelerationIsChanging || (accelerationIsPositive && wasInDrivePhase)
flankDetector.pushValue(currentDt)
// Here we use a finite state machine that goes between "Drive" and "Recovery", provinding sufficient time has passed and there is a credible flank
// We analyse the current impulse, depending on where we are in the stroke
if (wasInDrivePhase) {
// during the previous impulse, we were in the "Drive" phase
const strokeElapsed = timer.getValue('drive')
// finish drive phase if we have been long enough in the Drive phase, and we see a clear deceleration
isInDrivePhase = !((strokeElapsed > rowerSettings.minimumDriveTime) && flankDetector.isDecelerating())
} else {
// during the previous impulse, we were in the "Recovery" phase
const recoveryElapsed = timer.getValue('stroke')
// if we are long enough in the Recovery phase, and we see a clear acceleration, we need to change to the Drive phase
isInDrivePhase = ((recoveryElapsed > rowerSettings.minimumRecoveryTime) && flankDetector.isAccelerating())
}
}
// handle the current impulse, depending on where we are in the stroke
// STEP 3: handle the current impulse, depending on where we are in the stroke
if (isInDrivePhase && !wasInDrivePhase) { startDrivePhase(currentDt) }
if (!isInDrivePhase && wasInDrivePhase) { startRecoveryPhase() }
if (isInDrivePhase && wasInDrivePhase) { updateDrivePhase(currentDt) }
@ -166,7 +192,9 @@ function createRowingEngine (rowerSettings) {
if (strokeElapsed !== 0 && workoutHandler) {
workoutHandler.handleStroke({
power: (jPower + kPower) / strokeElapsed,
// if the recoveryPhase is shorter than 0.2 seconds we set it to 2 seconds, this mitigates the problem
// that we do not have a recovery phase on the first stroke
power: (jPower + kPower) / (((strokeElapsed - driveElapsed) < 0.2) ? strokeElapsed + 2 : strokeElapsed),
duration: strokeElapsed,
durationDrivePhase: driveElapsed,
distance: strokeDistance,

View File

@ -48,9 +48,7 @@ test('sample data for WRX700 should produce plausible results with rower profile
rowingEngine.notify(workoutEvaluator)
await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/WRX700_2magnets.csv' })
assert.is(workoutEvaluator.getNumOfStrokes(), 16, 'number of strokes does not meet expectation')
// todo: maximum power of the first stroke is too high because it does not contain a recovery part
// should fix that in the RowingEngine and adjust the maximum power here to 220
assert.ok(workoutEvaluator.getMaxStrokePower() < 370, `maximum stroke power should be below 370w, but is ${workoutEvaluator.getMaxStrokePower()}w`)
assert.ok(workoutEvaluator.getMaxStrokePower() < 220, `maximum stroke power should be below 220w, but is ${workoutEvaluator.getMaxStrokePower()}w`)
assert.ok(workoutEvaluator.getMinStrokePower() > 50, `minimum stroke power should be above 50w, but is ${workoutEvaluator.getMinStrokePower()}w`)
})
@ -60,10 +58,18 @@ test('sample data for DKNR320 should produce plausible results with rower profil
rowingEngine.notify(workoutEvaluator)
await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/DKNR320.csv' })
assert.is(workoutEvaluator.getNumOfStrokes(), 10, 'number of strokes does not meet expectation')
// todo: maximum power of the first stroke is too high because it does not contain a recovery part
// should fix that in the RowingEngine and adjust the maximum power here to 200
assert.ok(workoutEvaluator.getMaxStrokePower() < 370, `maximum stroke power should be below 370w, but is ${workoutEvaluator.getMaxStrokePower()}w`)
assert.ok(workoutEvaluator.getMaxStrokePower() < 200, `maximum stroke power should be below 200w, but is ${workoutEvaluator.getMaxStrokePower()}w`)
assert.ok(workoutEvaluator.getMinStrokePower() > 75, `minimum stroke power should be above 75w, but is ${workoutEvaluator.getMinStrokePower()}w`)
})
test('sample data for RX800 should produce plausible results with rower profile', async () => {
const rowingEngine = createRowingEngine(rowerProfiles.RX800)
const workoutEvaluator = createWorkoutEvaluator()
rowingEngine.notify(workoutEvaluator)
await replayRowingSession(rowingEngine.handleRotationImpulse, { filename: 'recordings/RX800.csv' })
assert.is(workoutEvaluator.getNumOfStrokes(), 10, 'number of strokes does not meet expectation')
assert.ok(workoutEvaluator.getMaxStrokePower() < 260, `maximum stroke power should be below 260, but is ${workoutEvaluator.getMaxStrokePower()}w`)
assert.ok(workoutEvaluator.getMinStrokePower() > 160, `minimum stroke power should be above 160w, but is ${workoutEvaluator.getMinStrokePower()}w`)
})
test.run()

View File

@ -8,8 +8,21 @@
*/
import process from 'process'
import { Gpio } from 'onoff'
import os from 'os'
import config from '../tools/ConfigManager.js'
import log from 'loglevel'
log.setLevel(config.loglevel.default)
export function createGpioTimerService () {
// setting top (near-real-time) priority for the Gpio process, as we don't want to miss anything
log.debug('setting priority for the Gpio-service to maximum (-20)')
try {
// setting priority of current process
os.setPriority(-20)
} catch (err) {
log.error('error while setting priority of Gpio-Thread: ', err)
}
// mode can be rising, falling, both
const reedSensor = new Gpio(17, 'in', 'rising')
// use hrtime for time measurement to get a higher time precision

View File

@ -75,6 +75,21 @@ rowingStatistics.on('strokeFinished', (metrics) => {
`, split: ${metrics.splitFormatted}, ratio: ${metrics.powerRatio}, dist: ${metrics.distanceTotal}m` +
`, cal: ${metrics.caloriesTotal}kcal, SPM: ${metrics.strokesPerMinute}, speed: ${metrics.speed}km/h` +
`, cal/hour: ${metrics.caloriesPerHour}kcal, cal/minute: ${metrics.caloriesPerMinute}kcal`)
// Quick hack to generate tcx-trackpoints to get the basic concepts of TCX-export working
/*
const d = new Date()
const timestamp = d.toISOString()
fs.appendFile('exports/currentlog.tcx',
`<Trackpoint>\n <Time>${timestamp}</Time>\n` +
`<DistanceMeters>${metrics.distanceTotal}</DistanceMeters>\n` +
`<Cadence>${Math.round(metrics.strokesPerMinute)}</Cadence>\n` +
'<SensorState>Present</SensorState>\n' +
'<Extensions>\n <ns3:TPX>\n' +
`<ns3:Watts>${metrics.power}</ns3:Watts>\n` +
`<ns3:Speed>${(metrics.speed / 3.6).toFixed(2)}</ns3:Speed>\n` +
'</ns3:TPX>\n </Extensions>\n</Trackpoint>\n',
(err) => { if (err) log.error(err) })
*/
webServer.notifyClients(metrics)
peripheralManager.notifyMetrics('strokeFinished', metrics)
})

View File

@ -16,6 +16,18 @@ export default {
// i.e. the number of magnets if used with a reed sensor
numOfImpulsesPerRevolution: 1,
// Filter values for sanity checks
// First are the sane minimum and maximum times between magnets during active rows
minimumTimeBetweenMagnets: 0.014,
maximumTimeBetweenMagnets: 0.5,
// Procentual change between successive intervals
maximumDownwardChange: 0.2, // effectively the maximum deceleration
maximumUpwardChange: 1.75, // effectively the maximum acceleration
// Settings for the phase detection
minimumDriveTime: 0.300,
minimumRecoveryTime: 0.750,
// Needed to determine the damping constant of the rowing machine. This value can be measured in the recovery phase
// of the stroke (some ergometers do this constantly).
// However I still keep it constant here, as I still have to figure out the damping physics of a water rower (see below)
@ -50,10 +62,10 @@ export default {
// Sportstech WRX700
WRX700: {
numOfImpulsesPerRevolution: 2,
minimumTimeBetweenMagnets: 0.1,
maximumTimeBetweenMagnets: 0.4,
maximumDownwardChange: 0.40,
maximumUpwardChange: 1.50,
minimumTimeBetweenMagnets: 0.05,
maximumTimeBetweenMagnets: 1,
maximumDownwardChange: 0.25,
maximumUpwardChange: 2,
minimumDriveTime: 0.500,
minimumRecoveryTime: 0.800,
omegaDotDivOmegaSquare: 0.046,
@ -77,8 +89,8 @@ export default {
// NordicTrack RX800 Air Rower
RX800: {
liquidFlywheel: false,
numOfImpulsesPerRevolution: 4,
liquidFlywheel: false,
// Damper setting 10
minimumTimeBetweenMagnets: 0.018,

View File

@ -0,0 +1,30 @@
# Set Up of the Open Rowing Monitor settings for a specific rower
This guide helps you to adjust the rowing monitor specifically for your rower or even for you
## Why have setings
No rowingmachine is the same, and their physical construction is important for the Rowing Monitor to understand to be able to understand your rowing. Easiest way is to select your rower from owerProfiles.js and put its name in default.config.js instead of "rowerProfiles.DEFAULT".
If your rower isn't there, this guide will help you set it up (please send in the data and settings, so we can add it to the OpenRowingMonitor).
Settings important for Open Rowing Monitor:
* numOfImpulsesPerRevolution: tells Open Rowing Monitor how many impulses per rotation of the flywheel to expect. Although sometimes not easy to detect, you can sometimes find it in the manual under the parts-list
* liquidFlywheel: tells OpenRowingMonitor if you are using a waterrower (true) or a solid flywheel with magnetic or air-resistance (false)
* omegaDotDivOmegaSquare: tells OpenRowingMonitor how much damping and thus resistance your flywheel is offering. This is typically also dependent on your damper-setting (if present). To measure it for your rowing machine, comment in the logging at the end of "startDrivePhase" function. Then do some strokes on the rower and estimate a value based on the logging.
* jMoment: The inertia of the flywheel, which in practice influences your power values and distance. This typically is set by rowing and see what kind of power is displayed on the monitor. Typical ranges are weigth dependent (see [this explanation](https://www.rowingmachine-guide.com/tabata-rowing-workouts.html)).
* Noise reduction settings. You should only change these settings if you experience issues.
* minimumTimeBetweenImpulses
* maximumTimeBetweenImpulses
* maximumDownwardChange
* maximumUpwardChange
* Stroke detection settings.
* minimumDriveTime
* minimumRecoveryTime
For the noise reduction settings and stroke detection settings, you can use the Excel tool. When OpenRowingMonitor records a log (comment out the line in server.js), you can paste the values in the first column of the "Raw Data" tab (please observe that the Raspberry uses a point as seperator, and your version of Excel might expect a comma). From there, the Excel file simulates the calculations the OpenRowingMonitor makes, allowing you to play with these settings.
By changing the noise reduction settings, you can remove any obvious errors. You don't need to filter everything: it is just to remove obvious errors that might frustrate the stroke detection, but in the end you can't prevent every piece of noise out there. Begin with the noise filtering, when you are satisfied, you can adjust the stroke detection.
Please note that changing the noise filtering and stroke detection settings will affect your omegaDotDivOmegaSquare and jMoment. So it is best to start with rowing a few strokes to determine settings for noise filtering and stroke detection, and then move on to the other settings.

Binary file not shown.

View File

@ -25,7 +25,8 @@ print "This script will set up Open Rowing Monitor on a Raspberry Pi 3 / 4 with
print "You should only run this script on a SD Card that does not contain any important data."
print
if [[ "$(uname -n)" != "raspberrypi" ]]; then
OSID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"')
if [[ $OSID != "raspbian" ]]; then
cancel "This script currently only works on Raspberry Pi OS, you will have to do a manual installation."
fi
@ -35,6 +36,8 @@ if [[ $VERSION != "10 (buster)" ]]; then
print "You are running Raspberry Pi OS $VERSION, are you sure that you want to continue?"
fi
# todo: once we know what hardware we support we can check for that via /sys/firmware/devicetree/base/model
print
read -p "Press RETURN to continue or CTRL + C to abort"

931
recordings/RX800.csv Normal file
View File

@ -0,0 +1,931 @@
115.678730412
7.94730349
0.110655271
0.077529811
0.062992882
0.053962555
0.047993133
0.043563433
0.040500379
0.037841367
0.035730194
0.033988063
0.032694066
0.031287698
0.03023863
0.029224544
0.028584529
0.027804209
0.027228518
0.026601604
0.02622834
0.025706705
0.025334405
0.025007717
0.024811381
0.02453186
0.024368987
0.024340543
0.024487044
0.024602878
0.024564859
0.024720028
0.025279589
0.02465499
0.025149718
0.025149365
0.025259812
0.025432313
0.025509907
0.02563813
0.025838689
0.025927634
0.025995875
0.026110136
0.026352212
0.026413232
0.026417213
0.026604456
0.026904274
0.026781476
0.026986071
0.027189332
0.027265704
0.027384224
0.027518281
0.027624877
0.027859003
0.027958782
0.028054579
0.028164673
0.028417454
0.028516639
0.028558973
0.028746289
0.028958662
0.029114553
0.029130072
0.029342333
0.02957265
0.02962728
0.029873597
0.029832375
0.030176193
0.030259786
0.030379659
0.03055529
0.030806885
0.030893256
0.031081851
0.031216426
0.031459502
0.031524466
0.03170106
0.031872858
0.032085064
0.031965693
0.031717746
0.031340261
0.030476501
0.029614239
0.028671859
0.027737258
0.027034733
0.026210503
0.025537071
0.024957325
0.024545025
0.023962463
0.023533571
0.023152975
0.022930417
0.022550007
0.022305263
0.02208515
0.021964297
0.021756721
0.021738295
0.02186987
0.02129668
0.021308476
0.02200065
0.02156783
0.021978149
0.022081743
0.022036594
0.022198206
0.022369301
0.022337801
0.022457524
0.022883991
0.022335375
0.022751897
0.023201587
0.02251482
0.023127364
0.023257346
0.022998529
0.023309106
0.023810389
0.023168789
0.023598238
0.023773503
0.023775277
0.023906482
0.02399452
0.02407765
0.02429867
0.02432617
0.024424042
0.024526765
0.02470647
0.024749545
0.02486149
0.024947824
0.02514453
0.025196197
0.025300939
0.02539544
0.02559533
0.025752202
0.025703349
0.025826313
0.026817266
0.025348124
0.026221317
0.026347614
0.026551283
0.026602727
0.026710135
0.02684221
0.027094694
0.027109639
0.027203381
0.027410289
0.027474068
0.027628144
0.027736478
0.02788259
0.028100203
0.028185202
0.028227738
0.028413369
0.028648815
0.028713298
0.028844187
0.02902467
0.029164005
0.029129375
0.029028003
0.028715371
0.028230942
0.027403268
0.026514317
0.025669996
0.024969342
0.024160336
0.023867796
0.022693047
0.022650991
0.022198247
0.021833022
0.021517908
0.021319777
0.021019479
0.02080281
0.020632549
0.020567141
0.020413788
0.020344436
0.020309991
0.020409881
0.020586994
0.020312269
0.020637864
0.020928477
0.020416677
0.020740883
0.020987478
0.020907348
0.02105222
0.021295684
0.021022905
0.021335929
0.021515244
0.021309335
0.021518485
0.022034063
0.021357094
0.021787838
0.021993932
0.021921672
0.022061507
0.022377343
0.021966987
0.022375287
0.022552585
0.022377416
0.022565288
0.022832345
0.022696567
0.022873383
0.02302668
0.023156644
0.023027884
0.023247089
0.023342738
0.023537554
0.023543684
0.023658611
0.023728593
0.023912001
0.023941057
0.024042724
0.024150688
0.024311671
0.024365264
0.024458969
0.02459095
0.024706136
0.02478936
0.02489062
0.02503525
0.025131491
0.02523614
0.025332048
0.025463773
0.025590698
0.02568518
0.025785125
0.025866958
0.026099515
0.026158257
0.026251517
0.026376573
0.026573501
0.026637482
0.026751112
0.026859835
0.027081652
0.027135022
0.027240986
0.027369543
0.027756878
0.02733606
0.027475525
0.027725655
0.026831743
0.026708927
0.02611533
0.025523067
0.024970472
0.024312819
0.023734927
0.023239386
0.022890662
0.0224464
0.022083583
0.021769211
0.021553709
0.021266226
0.021045892
0.020831131
0.020753186
0.020596592
0.020478981
0.020447655
0.020518947
0.020718467
0.020377187
0.02065504
0.020983727
0.0206228
0.020881115
0.021115654
0.020988597
0.021144858
0.021619786
0.020896857
0.021452508
0.021660101
0.021355119
0.021634879
0.021936677
0.021694602
0.021868417
0.022137752
0.022055548
0.022093381
0.022786312
0.021745472
0.022486846
0.022588588
0.022551013
0.022682996
0.023087721
0.022701644
0.02297509
0.023565094
0.022699311
0.023277999
0.023439278
0.023387926
0.023629464
0.023870855
0.023559964
0.023847577
0.024125004
0.023969429
0.024162949
0.02427719
0.02443412
0.024506765
0.024580248
0.024685433
0.024856397
0.024947324
0.025012602
0.025120306
0.025315232
0.025371011
0.02546277
0.025564974
0.025774457
0.025814421
0.025928513
0.026035995
0.026229459
0.026297274
0.026674164
0.026244977
0.026738276
0.026812517
0.026804499
0.027016852
0.027338446
0.0271385
0.027401335
0.027507335
0.027737189
0.027782097
0.027756096
0.02761417
0.027369761
0.026738572
0.026071699
0.025357288
0.024756082
0.024050819
0.023470031
0.022975463
0.022622389
0.022212831
0.021848144
0.021575162
0.021398828
0.021141956
0.020915696
0.02076764
0.020709103
0.020557825
0.020475083
0.020441435
0.020516324
0.0208824
0.020203137
0.020692196
0.02093166
0.020601936
0.020884067
0.021384161
0.0209749
0.02081214
0.02122542
0.02151481
0.021201642
0.021485569
0.02173194
0.021428605
0.02175733
0.021974497
0.021782348
0.021889848
0.022251368
0.02207333
0.022183312
0.022623666
0.022233942
0.022455424
0.023861967
0.021408809
0.022842278
0.022991705
0.022864871
0.023062835
0.023389387
0.023109059
0.023356763
0.023604745
0.023485616
0.02361943
0.023870246
0.02372219
0.024017266
0.024178858
0.024056617
0.024241692
0.0244936
0.024421378
0.024563156
0.024694472
0.024843916
0.024890064
0.025007287
0.025220621
0.025245287
0.025292621
0.025450344
0.025550529
0.02584179
0.025754974
0.025907957
0.026291644
0.025872864
0.02625768
0.026443736
0.026446569
0.026693478
0.026781571
0.026840941
0.026994571
0.027214905
0.027294202
0.027376851
0.027500962
0.027689521
0.027693276
0.027614202
0.027347034
0.026932607
0.026196346
0.025462437
0.02478951
0.024261415
0.023633858
0.023142356
0.022748615
0.022468522
0.022088687
0.021797298
0.02154026
0.02138689
0.021137555
0.020965888
0.021211
0.020445998
0.020534424
0.020850128
0.020236257
0.020565758
0.020728795
0.020597035
0.020743072
0.021064647
0.020751036
0.020997666
0.021524094
0.020719554
0.021249
0.021410889
0.021312722
0.02156389
0.021988947
0.021290593
0.021679482
0.02222691
0.021593593
0.02198328
0.02211454
0.022137443
0.022277172
0.022386858
0.022454154
0.022589191
0.022630709
0.022718191
0.022811062
0.022959359
0.023008136
0.0230971
0.023185081
0.023357304
0.023393267
0.023487859
0.023575934
0.023742934
0.023786082
0.023881971
0.023974749
0.024267824
0.024098416
0.024273398
0.024496565
0.024459028
0.024605084
0.024733862
0.024814399
0.024967084
0.025036047
0.025147215
0.025273307
0.025447678
0.025470512
0.025604327
0.025772049
0.025838604
0.025945308
0.02606729
0.026149939
0.026373217
0.026454032
0.026514106
0.029372646
0.024299214
0.026766809
0.02724531
0.026901568
0.027349848
0.027429551
0.027561421
0.027643163
0.027711385
0.027513069
0.027226773
0.026645383
0.026096439
0.025404752
0.02491753
0.02416527
0.023825102
0.023376584
0.023004805
0.022632083
0.022424563
0.022105786
0.021883989
0.021674544
0.021585711
0.021380896
0.021255248
0.021153784
0.021188803
0.021369507
0.020650302
0.02102997
0.021639322
0.020711599
0.021290358
0.021449136
0.021460099
0.021547359
0.021632507
0.021699227
0.021858288
0.021883992
0.021968288
0.022047715
0.022206011
0.02223627
0.022318511
0.02240103
0.022560566
0.022594752
0.022694862
0.022755863
0.022924955
0.022977196
0.023081604
0.023109603
0.023290623
0.023350901
0.023434623
0.023632197
0.023634919
0.02369479
0.023831845
0.023930901
0.024107937
0.02416579
0.024232456
0.024347252
0.024517975
0.024571716
0.024661068
0.024767623
0.024945161
0.024998513
0.025097456
0.025206586
0.025402365
0.025430549
0.025545383
0.025717457
0.02578229
0.025925289
0.025969365
0.026119921
0.026331216
0.026384106
0.026482976
0.02660679
0.026809643
0.026838698
0.026979143
0.027098568
0.027311364
0.027379698
0.02750018
0.027600605
0.027821254
0.027885901
0.028153308
0.028103772
0.028140494
0.028043754
0.027678864
0.027128254
0.026512716
0.025741198
0.025076476
0.024474588
0.024034013
0.023519421
0.023091736
0.02275818
0.022489625
0.022155087
0.021895365
0.02167757
0.021563291
0.021364347
0.021239402
0.021144329
0.02111657
0.02099871
0.020966167
0.020930685
0.021043888
0.02142337
0.020759722
0.021209795
0.021955146
0.020781815
0.021602759
0.021749869
0.02132761
0.021719147
0.022234442
0.021459685
0.021988258
0.022147887
0.022077683
0.022227073
0.022466146
0.022376554
0.022639387
0.022535221
0.022700831
0.022835294
0.022798497
0.022958887
0.023137498
0.023184683
0.023257386
0.023339756
0.023519997
0.023562108
0.02372422
0.023726738
0.023924756
0.023944386
0.024020608
0.024135182
0.024329737
0.024366404
0.024470422
0.024548015
0.024751811
0.024793636
0.024921683
0.024996386
0.025196293
0.025206812
0.0253172
0.025433626
0.025633977
0.025681829
0.025790866
0.025897236
0.026101403
0.026144403
0.026283698
0.026368218
0.026574309
0.026627531
0.026738124
0.026992809
0.026950994
0.027134568
0.027158456
0.027364123
0.027576641
0.027657159
0.027778993
0.0278644
0.028082862
0.028053992
0.027852677
0.027509141
0.027151179
0.026383958
0.025696848
0.025127849
0.024619202
0.02399948
0.023564759
0.023171753
0.022900725
0.022543079
0.022238283
0.021994709
0.021873709
0.021626618
0.021497229
0.021381673
0.021356896
0.021232896
0.021182452
0.021129859
0.021221303
0.021639802
0.02084012
0.021332581
0.021859987
0.0211616
0.021616432
0.021803154
0.021856265
0.021751969
0.021956338
0.022520189
0.021661544
0.02219006
0.022312912
0.022391634
0.022559208
0.0226248
0.022659504
0.022757171
0.022910596
0.022977632
0.023024559
0.02313167
0.023295188
0.023340984
0.023412484
0.02351565
0.023694205
0.023731242
0.023812872
0.023918353
0.024087379
0.024130596
0.024223317
0.02434028
0.024493947
0.024544853
0.024653464
0.024725742
0.024928223
0.024975778
0.025079556
0.025208258
0.025392425
0.025399388
0.025553888
0.025549906
0.025823424
0.025998868
0.025865461
0.026131404
0.02625683
0.026343107
0.02645757
0.026576032
0.026783606
0.02683655
0.026965624
0.027074512
0.027281401
0.027333271
0.027407993
0.027577807
0.027798677
0.027872695
0.02796725
0.028118935
0.028317305
0.028374564
0.028373278
0.028223657
0.027903992
0.027208883
0.02650146
0.025809925
0.02528102
0.0246758
0.024167727
0.023704191
0.023414211
0.022959065
0.022660677
0.022364233
0.022168698
0.021985957
0.02162994
0.021570847
0.021424348
0.021360163
0.021154164
0.021102313
0.021189923
0.021629218
0.020866979
0.021217053
0.021707366
0.021245071
0.021565181
0.021939309
0.0214702
0.021823032
0.02204005
0.021857828
0.022149271
0.022573678
0.021833292
0.022337364
0.022574104
0.022462474
0.022607436
0.023096434
0.022456122
0.022914917
0.023221312
0.022849865
0.023207345
0.023634213
0.022982902
0.023455807
0.023694343
0.02362138
0.02376875
0.023959212
0.023906064
0.024067211
0.024217618
0.024209637
0.024437506
0.024557228
0.024516469
0.024703375
0.024877041
0.02496567
0.025000023
0.02504167
0.02529617
0.025353243
0.025516891
0.025564668
0.02575537
0.025809833
0.025912666
0.025995129
0.026223461
0.026277035
0.026386886
0.026501924
0.026742237
0.026711737
0.02687557
0.027060735
0.027143124
0.027273271
0.027341164
0.027508437
0.027724863
0.027823955
0.027899121
0.028032565
0.028283527
0.028205564
0.028228415
1 115.678730412
2 7.94730349
3 0.110655271
4 0.077529811
5 0.062992882
6 0.053962555
7 0.047993133
8 0.043563433
9 0.040500379
10 0.037841367
11 0.035730194
12 0.033988063
13 0.032694066
14 0.031287698
15 0.03023863
16 0.029224544
17 0.028584529
18 0.027804209
19 0.027228518
20 0.026601604
21 0.02622834
22 0.025706705
23 0.025334405
24 0.025007717
25 0.024811381
26 0.02453186
27 0.024368987
28 0.024340543
29 0.024487044
30 0.024602878
31 0.024564859
32 0.024720028
33 0.025279589
34 0.02465499
35 0.025149718
36 0.025149365
37 0.025259812
38 0.025432313
39 0.025509907
40 0.02563813
41 0.025838689
42 0.025927634
43 0.025995875
44 0.026110136
45 0.026352212
46 0.026413232
47 0.026417213
48 0.026604456
49 0.026904274
50 0.026781476
51 0.026986071
52 0.027189332
53 0.027265704
54 0.027384224
55 0.027518281
56 0.027624877
57 0.027859003
58 0.027958782
59 0.028054579
60 0.028164673
61 0.028417454
62 0.028516639
63 0.028558973
64 0.028746289
65 0.028958662
66 0.029114553
67 0.029130072
68 0.029342333
69 0.02957265
70 0.02962728
71 0.029873597
72 0.029832375
73 0.030176193
74 0.030259786
75 0.030379659
76 0.03055529
77 0.030806885
78 0.030893256
79 0.031081851
80 0.031216426
81 0.031459502
82 0.031524466
83 0.03170106
84 0.031872858
85 0.032085064
86 0.031965693
87 0.031717746
88 0.031340261
89 0.030476501
90 0.029614239
91 0.028671859
92 0.027737258
93 0.027034733
94 0.026210503
95 0.025537071
96 0.024957325
97 0.024545025
98 0.023962463
99 0.023533571
100 0.023152975
101 0.022930417
102 0.022550007
103 0.022305263
104 0.02208515
105 0.021964297
106 0.021756721
107 0.021738295
108 0.02186987
109 0.02129668
110 0.021308476
111 0.02200065
112 0.02156783
113 0.021978149
114 0.022081743
115 0.022036594
116 0.022198206
117 0.022369301
118 0.022337801
119 0.022457524
120 0.022883991
121 0.022335375
122 0.022751897
123 0.023201587
124 0.02251482
125 0.023127364
126 0.023257346
127 0.022998529
128 0.023309106
129 0.023810389
130 0.023168789
131 0.023598238
132 0.023773503
133 0.023775277
134 0.023906482
135 0.02399452
136 0.02407765
137 0.02429867
138 0.02432617
139 0.024424042
140 0.024526765
141 0.02470647
142 0.024749545
143 0.02486149
144 0.024947824
145 0.02514453
146 0.025196197
147 0.025300939
148 0.02539544
149 0.02559533
150 0.025752202
151 0.025703349
152 0.025826313
153 0.026817266
154 0.025348124
155 0.026221317
156 0.026347614
157 0.026551283
158 0.026602727
159 0.026710135
160 0.02684221
161 0.027094694
162 0.027109639
163 0.027203381
164 0.027410289
165 0.027474068
166 0.027628144
167 0.027736478
168 0.02788259
169 0.028100203
170 0.028185202
171 0.028227738
172 0.028413369
173 0.028648815
174 0.028713298
175 0.028844187
176 0.02902467
177 0.029164005
178 0.029129375
179 0.029028003
180 0.028715371
181 0.028230942
182 0.027403268
183 0.026514317
184 0.025669996
185 0.024969342
186 0.024160336
187 0.023867796
188 0.022693047
189 0.022650991
190 0.022198247
191 0.021833022
192 0.021517908
193 0.021319777
194 0.021019479
195 0.02080281
196 0.020632549
197 0.020567141
198 0.020413788
199 0.020344436
200 0.020309991
201 0.020409881
202 0.020586994
203 0.020312269
204 0.020637864
205 0.020928477
206 0.020416677
207 0.020740883
208 0.020987478
209 0.020907348
210 0.02105222
211 0.021295684
212 0.021022905
213 0.021335929
214 0.021515244
215 0.021309335
216 0.021518485
217 0.022034063
218 0.021357094
219 0.021787838
220 0.021993932
221 0.021921672
222 0.022061507
223 0.022377343
224 0.021966987
225 0.022375287
226 0.022552585
227 0.022377416
228 0.022565288
229 0.022832345
230 0.022696567
231 0.022873383
232 0.02302668
233 0.023156644
234 0.023027884
235 0.023247089
236 0.023342738
237 0.023537554
238 0.023543684
239 0.023658611
240 0.023728593
241 0.023912001
242 0.023941057
243 0.024042724
244 0.024150688
245 0.024311671
246 0.024365264
247 0.024458969
248 0.02459095
249 0.024706136
250 0.02478936
251 0.02489062
252 0.02503525
253 0.025131491
254 0.02523614
255 0.025332048
256 0.025463773
257 0.025590698
258 0.02568518
259 0.025785125
260 0.025866958
261 0.026099515
262 0.026158257
263 0.026251517
264 0.026376573
265 0.026573501
266 0.026637482
267 0.026751112
268 0.026859835
269 0.027081652
270 0.027135022
271 0.027240986
272 0.027369543
273 0.027756878
274 0.02733606
275 0.027475525
276 0.027725655
277 0.026831743
278 0.026708927
279 0.02611533
280 0.025523067
281 0.024970472
282 0.024312819
283 0.023734927
284 0.023239386
285 0.022890662
286 0.0224464
287 0.022083583
288 0.021769211
289 0.021553709
290 0.021266226
291 0.021045892
292 0.020831131
293 0.020753186
294 0.020596592
295 0.020478981
296 0.020447655
297 0.020518947
298 0.020718467
299 0.020377187
300 0.02065504
301 0.020983727
302 0.0206228
303 0.020881115
304 0.021115654
305 0.020988597
306 0.021144858
307 0.021619786
308 0.020896857
309 0.021452508
310 0.021660101
311 0.021355119
312 0.021634879
313 0.021936677
314 0.021694602
315 0.021868417
316 0.022137752
317 0.022055548
318 0.022093381
319 0.022786312
320 0.021745472
321 0.022486846
322 0.022588588
323 0.022551013
324 0.022682996
325 0.023087721
326 0.022701644
327 0.02297509
328 0.023565094
329 0.022699311
330 0.023277999
331 0.023439278
332 0.023387926
333 0.023629464
334 0.023870855
335 0.023559964
336 0.023847577
337 0.024125004
338 0.023969429
339 0.024162949
340 0.02427719
341 0.02443412
342 0.024506765
343 0.024580248
344 0.024685433
345 0.024856397
346 0.024947324
347 0.025012602
348 0.025120306
349 0.025315232
350 0.025371011
351 0.02546277
352 0.025564974
353 0.025774457
354 0.025814421
355 0.025928513
356 0.026035995
357 0.026229459
358 0.026297274
359 0.026674164
360 0.026244977
361 0.026738276
362 0.026812517
363 0.026804499
364 0.027016852
365 0.027338446
366 0.0271385
367 0.027401335
368 0.027507335
369 0.027737189
370 0.027782097
371 0.027756096
372 0.02761417
373 0.027369761
374 0.026738572
375 0.026071699
376 0.025357288
377 0.024756082
378 0.024050819
379 0.023470031
380 0.022975463
381 0.022622389
382 0.022212831
383 0.021848144
384 0.021575162
385 0.021398828
386 0.021141956
387 0.020915696
388 0.02076764
389 0.020709103
390 0.020557825
391 0.020475083
392 0.020441435
393 0.020516324
394 0.0208824
395 0.020203137
396 0.020692196
397 0.02093166
398 0.020601936
399 0.020884067
400 0.021384161
401 0.0209749
402 0.02081214
403 0.02122542
404 0.02151481
405 0.021201642
406 0.021485569
407 0.02173194
408 0.021428605
409 0.02175733
410 0.021974497
411 0.021782348
412 0.021889848
413 0.022251368
414 0.02207333
415 0.022183312
416 0.022623666
417 0.022233942
418 0.022455424
419 0.023861967
420 0.021408809
421 0.022842278
422 0.022991705
423 0.022864871
424 0.023062835
425 0.023389387
426 0.023109059
427 0.023356763
428 0.023604745
429 0.023485616
430 0.02361943
431 0.023870246
432 0.02372219
433 0.024017266
434 0.024178858
435 0.024056617
436 0.024241692
437 0.0244936
438 0.024421378
439 0.024563156
440 0.024694472
441 0.024843916
442 0.024890064
443 0.025007287
444 0.025220621
445 0.025245287
446 0.025292621
447 0.025450344
448 0.025550529
449 0.02584179
450 0.025754974
451 0.025907957
452 0.026291644
453 0.025872864
454 0.02625768
455 0.026443736
456 0.026446569
457 0.026693478
458 0.026781571
459 0.026840941
460 0.026994571
461 0.027214905
462 0.027294202
463 0.027376851
464 0.027500962
465 0.027689521
466 0.027693276
467 0.027614202
468 0.027347034
469 0.026932607
470 0.026196346
471 0.025462437
472 0.02478951
473 0.024261415
474 0.023633858
475 0.023142356
476 0.022748615
477 0.022468522
478 0.022088687
479 0.021797298
480 0.02154026
481 0.02138689
482 0.021137555
483 0.020965888
484 0.021211
485 0.020445998
486 0.020534424
487 0.020850128
488 0.020236257
489 0.020565758
490 0.020728795
491 0.020597035
492 0.020743072
493 0.021064647
494 0.020751036
495 0.020997666
496 0.021524094
497 0.020719554
498 0.021249
499 0.021410889
500 0.021312722
501 0.02156389
502 0.021988947
503 0.021290593
504 0.021679482
505 0.02222691
506 0.021593593
507 0.02198328
508 0.02211454
509 0.022137443
510 0.022277172
511 0.022386858
512 0.022454154
513 0.022589191
514 0.022630709
515 0.022718191
516 0.022811062
517 0.022959359
518 0.023008136
519 0.0230971
520 0.023185081
521 0.023357304
522 0.023393267
523 0.023487859
524 0.023575934
525 0.023742934
526 0.023786082
527 0.023881971
528 0.023974749
529 0.024267824
530 0.024098416
531 0.024273398
532 0.024496565
533 0.024459028
534 0.024605084
535 0.024733862
536 0.024814399
537 0.024967084
538 0.025036047
539 0.025147215
540 0.025273307
541 0.025447678
542 0.025470512
543 0.025604327
544 0.025772049
545 0.025838604
546 0.025945308
547 0.02606729
548 0.026149939
549 0.026373217
550 0.026454032
551 0.026514106
552 0.029372646
553 0.024299214
554 0.026766809
555 0.02724531
556 0.026901568
557 0.027349848
558 0.027429551
559 0.027561421
560 0.027643163
561 0.027711385
562 0.027513069
563 0.027226773
564 0.026645383
565 0.026096439
566 0.025404752
567 0.02491753
568 0.02416527
569 0.023825102
570 0.023376584
571 0.023004805
572 0.022632083
573 0.022424563
574 0.022105786
575 0.021883989
576 0.021674544
577 0.021585711
578 0.021380896
579 0.021255248
580 0.021153784
581 0.021188803
582 0.021369507
583 0.020650302
584 0.02102997
585 0.021639322
586 0.020711599
587 0.021290358
588 0.021449136
589 0.021460099
590 0.021547359
591 0.021632507
592 0.021699227
593 0.021858288
594 0.021883992
595 0.021968288
596 0.022047715
597 0.022206011
598 0.02223627
599 0.022318511
600 0.02240103
601 0.022560566
602 0.022594752
603 0.022694862
604 0.022755863
605 0.022924955
606 0.022977196
607 0.023081604
608 0.023109603
609 0.023290623
610 0.023350901
611 0.023434623
612 0.023632197
613 0.023634919
614 0.02369479
615 0.023831845
616 0.023930901
617 0.024107937
618 0.02416579
619 0.024232456
620 0.024347252
621 0.024517975
622 0.024571716
623 0.024661068
624 0.024767623
625 0.024945161
626 0.024998513
627 0.025097456
628 0.025206586
629 0.025402365
630 0.025430549
631 0.025545383
632 0.025717457
633 0.02578229
634 0.025925289
635 0.025969365
636 0.026119921
637 0.026331216
638 0.026384106
639 0.026482976
640 0.02660679
641 0.026809643
642 0.026838698
643 0.026979143
644 0.027098568
645 0.027311364
646 0.027379698
647 0.02750018
648 0.027600605
649 0.027821254
650 0.027885901
651 0.028153308
652 0.028103772
653 0.028140494
654 0.028043754
655 0.027678864
656 0.027128254
657 0.026512716
658 0.025741198
659 0.025076476
660 0.024474588
661 0.024034013
662 0.023519421
663 0.023091736
664 0.02275818
665 0.022489625
666 0.022155087
667 0.021895365
668 0.02167757
669 0.021563291
670 0.021364347
671 0.021239402
672 0.021144329
673 0.02111657
674 0.02099871
675 0.020966167
676 0.020930685
677 0.021043888
678 0.02142337
679 0.020759722
680 0.021209795
681 0.021955146
682 0.020781815
683 0.021602759
684 0.021749869
685 0.02132761
686 0.021719147
687 0.022234442
688 0.021459685
689 0.021988258
690 0.022147887
691 0.022077683
692 0.022227073
693 0.022466146
694 0.022376554
695 0.022639387
696 0.022535221
697 0.022700831
698 0.022835294
699 0.022798497
700 0.022958887
701 0.023137498
702 0.023184683
703 0.023257386
704 0.023339756
705 0.023519997
706 0.023562108
707 0.02372422
708 0.023726738
709 0.023924756
710 0.023944386
711 0.024020608
712 0.024135182
713 0.024329737
714 0.024366404
715 0.024470422
716 0.024548015
717 0.024751811
718 0.024793636
719 0.024921683
720 0.024996386
721 0.025196293
722 0.025206812
723 0.0253172
724 0.025433626
725 0.025633977
726 0.025681829
727 0.025790866
728 0.025897236
729 0.026101403
730 0.026144403
731 0.026283698
732 0.026368218
733 0.026574309
734 0.026627531
735 0.026738124
736 0.026992809
737 0.026950994
738 0.027134568
739 0.027158456
740 0.027364123
741 0.027576641
742 0.027657159
743 0.027778993
744 0.0278644
745 0.028082862
746 0.028053992
747 0.027852677
748 0.027509141
749 0.027151179
750 0.026383958
751 0.025696848
752 0.025127849
753 0.024619202
754 0.02399948
755 0.023564759
756 0.023171753
757 0.022900725
758 0.022543079
759 0.022238283
760 0.021994709
761 0.021873709
762 0.021626618
763 0.021497229
764 0.021381673
765 0.021356896
766 0.021232896
767 0.021182452
768 0.021129859
769 0.021221303
770 0.021639802
771 0.02084012
772 0.021332581
773 0.021859987
774 0.0211616
775 0.021616432
776 0.021803154
777 0.021856265
778 0.021751969
779 0.021956338
780 0.022520189
781 0.021661544
782 0.02219006
783 0.022312912
784 0.022391634
785 0.022559208
786 0.0226248
787 0.022659504
788 0.022757171
789 0.022910596
790 0.022977632
791 0.023024559
792 0.02313167
793 0.023295188
794 0.023340984
795 0.023412484
796 0.02351565
797 0.023694205
798 0.023731242
799 0.023812872
800 0.023918353
801 0.024087379
802 0.024130596
803 0.024223317
804 0.02434028
805 0.024493947
806 0.024544853
807 0.024653464
808 0.024725742
809 0.024928223
810 0.024975778
811 0.025079556
812 0.025208258
813 0.025392425
814 0.025399388
815 0.025553888
816 0.025549906
817 0.025823424
818 0.025998868
819 0.025865461
820 0.026131404
821 0.02625683
822 0.026343107
823 0.02645757
824 0.026576032
825 0.026783606
826 0.02683655
827 0.026965624
828 0.027074512
829 0.027281401
830 0.027333271
831 0.027407993
832 0.027577807
833 0.027798677
834 0.027872695
835 0.02796725
836 0.028118935
837 0.028317305
838 0.028374564
839 0.028373278
840 0.028223657
841 0.027903992
842 0.027208883
843 0.02650146
844 0.025809925
845 0.02528102
846 0.0246758
847 0.024167727
848 0.023704191
849 0.023414211
850 0.022959065
851 0.022660677
852 0.022364233
853 0.022168698
854 0.021985957
855 0.02162994
856 0.021570847
857 0.021424348
858 0.021360163
859 0.021154164
860 0.021102313
861 0.021189923
862 0.021629218
863 0.020866979
864 0.021217053
865 0.021707366
866 0.021245071
867 0.021565181
868 0.021939309
869 0.0214702
870 0.021823032
871 0.02204005
872 0.021857828
873 0.022149271
874 0.022573678
875 0.021833292
876 0.022337364
877 0.022574104
878 0.022462474
879 0.022607436
880 0.023096434
881 0.022456122
882 0.022914917
883 0.023221312
884 0.022849865
885 0.023207345
886 0.023634213
887 0.022982902
888 0.023455807
889 0.023694343
890 0.02362138
891 0.02376875
892 0.023959212
893 0.023906064
894 0.024067211
895 0.024217618
896 0.024209637
897 0.024437506
898 0.024557228
899 0.024516469
900 0.024703375
901 0.024877041
902 0.02496567
903 0.025000023
904 0.02504167
905 0.02529617
906 0.025353243
907 0.025516891
908 0.025564668
909 0.02575537
910 0.025809833
911 0.025912666
912 0.025995129
913 0.026223461
914 0.026277035
915 0.026386886
916 0.026501924
917 0.026742237
918 0.026711737
919 0.02687557
920 0.027060735
921 0.027143124
922 0.027273271
923 0.027341164
924 0.027508437
925 0.027724863
926 0.027823955
927 0.027899121
928 0.028032565
929 0.028283527
930 0.028205564
931 0.028228415