rowingdata 3.8.2__tar.gz → 3.8.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rowingdata-3.8.2/rowingdata.egg-info → rowingdata-3.8.3}/PKG-INFO +23 -21
- {rowingdata-3.8.2 → rowingdata-3.8.3}/README.rst +22 -20
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/data/fit_export_spec.json +8 -8
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fitwrite.py +25 -42
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fitwrite_spec.py +2 -2
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/otherparsers.py +24 -3
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowingdata.py +1 -1
- {rowingdata-3.8.2 → rowingdata-3.8.3/rowingdata.egg-info}/PKG-INFO +23 -21
- {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_instroke_export.py +1 -1
- {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_standard.py +49 -23
- {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_rowingdata.py +1 -1
- {rowingdata-3.8.2 → rowingdata-3.8.3}/LICENSE +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/MANIFEST.in +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/crewnerddata.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/crewnerddata.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/testdata.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/.buildinfo +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/2x20min.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/editrower.JPG +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/greghoc.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/image001.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/otwlogbook.JPG +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/otwscreenshot.JPG +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/screenshot.JPG +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/screenshotlogbook.JPG +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/woensdag.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/index.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/modules.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/rowingdata.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/ajax-loader.gif +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/alabaster.css +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/basic.css +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment-bright.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment-close.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/custom.css +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/doctools.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/down-pressed.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/down.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/file.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/jquery-1.11.1.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/jquery.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/minus.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/plus.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/pygments.css +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/searchtools.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/underscore-1.3.1.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/underscore.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/up-pressed.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/up.png +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/websupport.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/genindex.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/index.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/modules.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/objects.inv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/py-modindex.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/rowingdata.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/search.html +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/searchindex.js +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/__init__.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/__main__.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/boatedit.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/checkdatafiles.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/copystats.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/crewnerdplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/crewnerdplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/csvparsers.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdataplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdataplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdatatotcx.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergstickplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergstickplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergsticktotcx.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fit_garmin_bridge.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fit_transcode.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/gpxtools.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/gpxwrite.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/konkatenaadje.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/laptesting.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/obsolete.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_plot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_plottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_toc2.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledtoc2.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/roweredit.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowproplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowproplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachtoc2.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplot.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplot_nogeo.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplottime.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplottime_nogeo.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxtoc2.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxtools.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/trainingparser.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/utils.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/windcorrected.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/writetcx.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/SOURCES.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/dependency_links.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/not-zip-safe +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/requires.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/top_level.txt +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/setup.cfg +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/setup.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2016-03-25-0758.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2016-03-25-0758_data.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2x20min_o.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2x2km.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/3km_cd_o.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/3x250m.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/EUBoatCoach.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/EmpowerSpeedCoachForce.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NKEmporfromgreg.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NKLiNKv130.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NoHR.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/PainsledForce.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_interval.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_interval.csv_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_testdata.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpdCoach2_imp_inconsistent.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpdCoachAmbiguous.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach GPS Workout.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2Link_interval.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2Linkv1.27.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2v2.12.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/Speedcoach2example.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/aritmo.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc1.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc2.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc3.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach_fixed_distance.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach_otw.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/correctedpainsled.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/cottwich.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/coxmate.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerd_interval.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/cumvalues.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergdata_example.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergdata_example.csv_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick.csv_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick2.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick_o.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/example.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/example_data.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/faketcx.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/float.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/herodata.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/humon.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/impeller_empower.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/invalidchar.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/kinomap.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/mystery.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/nk_logbook.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_desktop_example.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_out_data.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_to_csv_20160221-105218_erg-400150318_760465m.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_left.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_new.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_right.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_seat.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/recover.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ritmointervals.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowingdata_eth.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowinginmotionexample.TCX +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowinginmotionexample.TCX_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowperfect.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowpro5.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowpro_carrick.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3_curve.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3intervals.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3intervals2.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp_out.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/smartrow.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/smartrow_intervals.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/spdcoach2noheader.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoach2test2.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoach3test3.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoachexample.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoachexample.csv_o.CSV +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/strava_export.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/summarytest.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata_part1.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata_part2.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdatasummary.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testlapidx.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcs_210614.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcx.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcx_210614.tcx +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/tim.csv +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata//345/210/222/350/210/271.csv" +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_transcode.py +0 -0
- {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/testparser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rowingdata
|
|
3
|
-
Version: 3.8.
|
|
3
|
+
Version: 3.8.3
|
|
4
4
|
Summary: The rowingdata library to create colorful plots from CrewNerd, Painsled and other rowing data tools
|
|
5
5
|
Home-page: https://github.com/sanderroosendaal/rowingdata
|
|
6
6
|
Author: Sander Roosendaal
|
|
@@ -555,7 +555,7 @@ The available data fields are
|
|
|
555
555
|
* 'cum_dist'
|
|
556
556
|
|
|
557
557
|
Oarlock parsers (NK Logbook) may add: ``catch``, ``finish``,
|
|
558
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
558
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
559
559
|
|
|
560
560
|
If imported from TCX, Rowpro, or other tools, some data fields may not contain
|
|
561
561
|
useful information.
|
|
@@ -567,7 +567,7 @@ rowingdata CSV Columns
|
|
|
567
567
|
This section describes the dataframe schema used by the ``rowingdata`` class.
|
|
568
568
|
It is this package's own column layout, not a vendor-neutral standard. For a
|
|
569
569
|
cross-vendor interchange format, see the Rowing Data Standard at
|
|
570
|
-
https://github.com/
|
|
570
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which rowingdata
|
|
571
571
|
targets when exporting FIT.
|
|
572
572
|
|
|
573
573
|
Any parser implementation feeding the ``rowingdata`` class should produce at
|
|
@@ -600,12 +600,12 @@ The standard field names are:
|
|
|
600
600
|
* ' ElapsedTime (sec)'
|
|
601
601
|
|
|
602
602
|
Optional (Oarlock/NK Logbook): ``catch``/``catchAngle``, ``finish``/``finishAngle``,
|
|
603
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
603
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
604
604
|
|
|
605
605
|
Planned for dual oarlock (port/starboard symmetry): ``catch_port``, ``catch_starboard``,
|
|
606
606
|
``finish_port``, ``finish_starboard``, ``slip_port``, ``slip_starboard``, ``wash_port``,
|
|
607
607
|
``wash_starboard``, ``peakforceangle_port``, ``peakforceangle_starboard``,
|
|
608
|
-
``
|
|
608
|
+
``effectiveArc_port``, ``effectiveArc_starboard``. See *Dual oarlock
|
|
609
609
|
(port/starboard)* below. **Note:** rowingdata does not yet implement parsing or
|
|
610
610
|
export for these per-side columns.
|
|
611
611
|
|
|
@@ -848,10 +848,9 @@ Oarlock scalars (OTW rigging)
|
|
|
848
848
|
-----------------------------
|
|
849
849
|
|
|
850
850
|
Field names: 'catch' / 'catchAngle', 'finish' / 'finishAngle', 'slip',
|
|
851
|
-
'wash', 'peakforceangle', '
|
|
851
|
+
'wash', 'peakforceangle', 'effectiveArc'
|
|
852
852
|
|
|
853
|
-
Units: degrees for angles
|
|
854
|
-
source: NK Logbook uses these columns).
|
|
853
|
+
Units: degrees for angles and for effectiveArc.
|
|
855
854
|
|
|
856
855
|
These fields come from NK Logbook (Oarlock) and similar OTW
|
|
857
856
|
measurement systems. They describe rigging geometry and blade angles:
|
|
@@ -864,12 +863,11 @@ measurement systems. They describe rigging geometry and blade angles:
|
|
|
864
863
|
* **slip** – blade slip angle.
|
|
865
864
|
* **wash** – wash/backwash angle.
|
|
866
865
|
* **peakforceangle** – oar angle at peak force (same 0° = perpendicular convention).
|
|
867
|
-
* **
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
they serve different purposes.
|
|
866
|
+
* **effectiveArc** – the part of the stroke arc that is effective: catch to
|
|
867
|
+
finish, less slip and wash (degrees). The Rowing Data Standard replaced the
|
|
868
|
+
earlier effective *length* (a lever length in mm) with this arc. Files written
|
|
869
|
+
against earlier drafts carry ``EffectiveLength``; it is read into the
|
|
870
|
+
``effectiveLength`` column (metres) and is not converted into an arc.
|
|
873
871
|
|
|
874
872
|
Dual oarlock (port/starboard)
|
|
875
873
|
..............................
|
|
@@ -973,12 +971,16 @@ Unreleased
|
|
|
973
971
|
----------
|
|
974
972
|
|
|
975
973
|
- **Breaking change to exported FIT file contents.** FIT export now follows the
|
|
976
|
-
Rowing Data Standard (https://github.com/
|
|
977
|
-
|
|
978
|
-
not: the developer application ID is now the standard UUID,
|
|
979
|
-
|
|
980
|
-
``AverageBoatSpeed`` uses scale
|
|
981
|
-
|
|
974
|
+
Rowing Data Standard (https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard,
|
|
975
|
+
current ``main``). The ``exporttofit`` API is unchanged, but the bytes it
|
|
976
|
+
writes are not: the developer application ID is now the standard UUID,
|
|
977
|
+
``DriveLength`` is encoded in millimetres rather than metres,
|
|
978
|
+
``AverageBoatSpeed`` uses scale 100, ``EffectiveLength`` is replaced by
|
|
979
|
+
``EffectiveArc`` in degrees (IDs 16, 210, 211; the ``effectiveLength*``
|
|
980
|
+
columns are no longer exported, use ``effectiveArc*``), the force fields are
|
|
981
|
+
named ``AverageDriveForce`` and ``PeakDriveForce``, stroke rate is written as
|
|
982
|
+
native ``cadence256``, stroke work uses field ID 19, and no value is written
|
|
983
|
+
as the FIT invalid value (255 / 65535 / 32767): measurements clip one below it. Consumers that hardcoded the previous rowingdata
|
|
982
984
|
application ID or the old metre-based scales must be updated. ``FITParser``
|
|
983
985
|
still reads files written by rowingdata 3.7.3 and earlier.
|
|
984
986
|
- In-stroke curve fields are emitted under a separate, private application ID,
|
|
@@ -986,7 +988,7 @@ Unreleased
|
|
|
986
988
|
carry no interoperable meaning.
|
|
987
989
|
- Removed ``docs/FIT_STANDARD.md`` and ``docs/FIT_STANDARD.pdf``. The standard is
|
|
988
990
|
maintained by a committee at
|
|
989
|
-
https://github.com/
|
|
991
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which is the single
|
|
990
992
|
source of truth; this repository no longer ships a copy.
|
|
991
993
|
|
|
992
994
|
0.97.x
|
|
@@ -521,7 +521,7 @@ The available data fields are
|
|
|
521
521
|
* 'cum_dist'
|
|
522
522
|
|
|
523
523
|
Oarlock parsers (NK Logbook) may add: ``catch``, ``finish``,
|
|
524
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
524
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
525
525
|
|
|
526
526
|
If imported from TCX, Rowpro, or other tools, some data fields may not contain
|
|
527
527
|
useful information.
|
|
@@ -533,7 +533,7 @@ rowingdata CSV Columns
|
|
|
533
533
|
This section describes the dataframe schema used by the ``rowingdata`` class.
|
|
534
534
|
It is this package's own column layout, not a vendor-neutral standard. For a
|
|
535
535
|
cross-vendor interchange format, see the Rowing Data Standard at
|
|
536
|
-
https://github.com/
|
|
536
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which rowingdata
|
|
537
537
|
targets when exporting FIT.
|
|
538
538
|
|
|
539
539
|
Any parser implementation feeding the ``rowingdata`` class should produce at
|
|
@@ -566,12 +566,12 @@ The standard field names are:
|
|
|
566
566
|
* ' ElapsedTime (sec)'
|
|
567
567
|
|
|
568
568
|
Optional (Oarlock/NK Logbook): ``catch``/``catchAngle``, ``finish``/``finishAngle``,
|
|
569
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
569
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
570
570
|
|
|
571
571
|
Planned for dual oarlock (port/starboard symmetry): ``catch_port``, ``catch_starboard``,
|
|
572
572
|
``finish_port``, ``finish_starboard``, ``slip_port``, ``slip_starboard``, ``wash_port``,
|
|
573
573
|
``wash_starboard``, ``peakforceangle_port``, ``peakforceangle_starboard``,
|
|
574
|
-
``
|
|
574
|
+
``effectiveArc_port``, ``effectiveArc_starboard``. See *Dual oarlock
|
|
575
575
|
(port/starboard)* below. **Note:** rowingdata does not yet implement parsing or
|
|
576
576
|
export for these per-side columns.
|
|
577
577
|
|
|
@@ -814,10 +814,9 @@ Oarlock scalars (OTW rigging)
|
|
|
814
814
|
-----------------------------
|
|
815
815
|
|
|
816
816
|
Field names: 'catch' / 'catchAngle', 'finish' / 'finishAngle', 'slip',
|
|
817
|
-
'wash', 'peakforceangle', '
|
|
817
|
+
'wash', 'peakforceangle', 'effectiveArc'
|
|
818
818
|
|
|
819
|
-
Units: degrees for angles
|
|
820
|
-
source: NK Logbook uses these columns).
|
|
819
|
+
Units: degrees for angles and for effectiveArc.
|
|
821
820
|
|
|
822
821
|
These fields come from NK Logbook (Oarlock) and similar OTW
|
|
823
822
|
measurement systems. They describe rigging geometry and blade angles:
|
|
@@ -830,12 +829,11 @@ measurement systems. They describe rigging geometry and blade angles:
|
|
|
830
829
|
* **slip** – blade slip angle.
|
|
831
830
|
* **wash** – wash/backwash angle.
|
|
832
831
|
* **peakforceangle** – oar angle at peak force (same 0° = perpendicular convention).
|
|
833
|
-
* **
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
they serve different purposes.
|
|
832
|
+
* **effectiveArc** – the part of the stroke arc that is effective: catch to
|
|
833
|
+
finish, less slip and wash (degrees). The Rowing Data Standard replaced the
|
|
834
|
+
earlier effective *length* (a lever length in mm) with this arc. Files written
|
|
835
|
+
against earlier drafts carry ``EffectiveLength``; it is read into the
|
|
836
|
+
``effectiveLength`` column (metres) and is not converted into an arc.
|
|
839
837
|
|
|
840
838
|
Dual oarlock (port/starboard)
|
|
841
839
|
..............................
|
|
@@ -939,12 +937,16 @@ Unreleased
|
|
|
939
937
|
----------
|
|
940
938
|
|
|
941
939
|
- **Breaking change to exported FIT file contents.** FIT export now follows the
|
|
942
|
-
Rowing Data Standard (https://github.com/
|
|
943
|
-
|
|
944
|
-
not: the developer application ID is now the standard UUID,
|
|
945
|
-
|
|
946
|
-
``AverageBoatSpeed`` uses scale
|
|
947
|
-
|
|
940
|
+
Rowing Data Standard (https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard,
|
|
941
|
+
current ``main``). The ``exporttofit`` API is unchanged, but the bytes it
|
|
942
|
+
writes are not: the developer application ID is now the standard UUID,
|
|
943
|
+
``DriveLength`` is encoded in millimetres rather than metres,
|
|
944
|
+
``AverageBoatSpeed`` uses scale 100, ``EffectiveLength`` is replaced by
|
|
945
|
+
``EffectiveArc`` in degrees (IDs 16, 210, 211; the ``effectiveLength*``
|
|
946
|
+
columns are no longer exported, use ``effectiveArc*``), the force fields are
|
|
947
|
+
named ``AverageDriveForce`` and ``PeakDriveForce``, stroke rate is written as
|
|
948
|
+
native ``cadence256``, stroke work uses field ID 19, and no value is written
|
|
949
|
+
as the FIT invalid value (255 / 65535 / 32767): measurements clip one below it. Consumers that hardcoded the previous rowingdata
|
|
948
950
|
application ID or the old metre-based scales must be updated. ``FITParser``
|
|
949
951
|
still reads files written by rowingdata 3.7.3 and earlier.
|
|
950
952
|
- In-stroke curve fields are emitted under a separate, private application ID,
|
|
@@ -952,7 +954,7 @@ Unreleased
|
|
|
952
954
|
carry no interoperable meaning.
|
|
953
955
|
- Removed ``docs/FIT_STANDARD.md`` and ``docs/FIT_STANDARD.pdf``. The standard is
|
|
954
956
|
maintained by a committee at
|
|
955
|
-
https://github.com/
|
|
957
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which is the single
|
|
956
958
|
source of truth; this repository no longer ships a copy.
|
|
957
959
|
|
|
958
960
|
0.97.x
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 4,
|
|
3
3
|
"protocol_version": 1,
|
|
4
4
|
"handle_force_curve_field_id": 60,
|
|
5
|
-
"_comment": "Authoritative FIT developer field definitions for rowingdata fitwrite. Field IDs, scales and units must match the Rowing Data Standard registry at https://github.com/
|
|
5
|
+
"_comment": "Authoritative FIT developer field definitions for rowingdata fitwrite. Field IDs, scales and units must match the Rowing Data Standard registry at https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard (registry/field-ids.md); that repository is the source of truth, this file is only rowingdata's machine-readable copy of the subset it emits. v2: mm precision for DriveLength/PeakForcePositionAbs (scale 1000); StrokeRate dev field (93); instroke curve Y-scale registry. v4: main of 2026-10-31: AverageBoatSpeed scale 100; EffectiveLength -> EffectiveArc (deg, scale 10; 16, 210, 211); force fields named without the N suffix. v3: standard draft 0.1: WorkoutState holds FIT intensity values; StrokeState (96); SlipThreshold/WashThreshold (94/95); HandleForceCurve fixed at 60; fields 4, 5 and 93 are not in the standard and are read-only (group legacy).",
|
|
6
6
|
"instroke_dynamic": {
|
|
7
7
|
"summary_start": 20,
|
|
8
8
|
"summary_id_padding": "ceil_to_10",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
{"field_id": 3, "group": "rowing", "fit_name": "StrokeRecoveryTime", "base_type": "UINT16", "size": 2, "scale": 1, "units": "ms", "df_columns": [" StrokeRecoveryTime (ms)"]},
|
|
53
53
|
{"field_id": 4, "group": "legacy", "fit_name": "AverageDriveForceLbs", "base_type": "UINT16", "size": 2, "scale": 10, "units": "lbs", "df_columns": [" AverageDriveForce (lbs)"]},
|
|
54
54
|
{"field_id": 5, "group": "legacy", "fit_name": "PeakDriveForceLbs", "base_type": "UINT16", "size": 2, "scale": 10, "units": "lbs", "df_columns": [" PeakDriveForce (lbs)"]},
|
|
55
|
-
{"field_id": 6, "group": "rowing", "fit_name": "
|
|
56
|
-
{"field_id": 7, "group": "rowing", "fit_name": "
|
|
57
|
-
{"field_id": 8, "group": "rowing", "fit_name": "AverageBoatSpeed", "base_type": "UINT16", "size": 2, "scale":
|
|
55
|
+
{"field_id": 6, "group": "rowing", "fit_name": "AverageDriveForce", "base_type": "UINT16", "size": 2, "scale": 10, "units": "N", "df_columns": [" AverageDriveForce (N)"]},
|
|
56
|
+
{"field_id": 7, "group": "rowing", "fit_name": "PeakDriveForce", "base_type": "UINT16", "size": 2, "scale": 10, "units": "N", "df_columns": [" PeakDriveForce (N)"]},
|
|
57
|
+
{"field_id": 8, "group": "rowing", "fit_name": "AverageBoatSpeed", "base_type": "UINT16", "size": 2, "scale": 100, "units": "m/s", "df_columns": [" AverageBoatSpeed (m/s)"]},
|
|
58
58
|
{"field_id": 9, "group": "rowing", "fit_name": "WorkoutState", "base_type": "UINT8", "size": 1, "scale": 1, "units": "", "df_columns": [" WorkoutState"]},
|
|
59
59
|
{"field_id": 10, "group": "metadata", "fit_name": "RecordingStrategy", "base_type": "UINT8", "size": 1, "scale": 1, "units": "", "df_columns": [], "message_type": "session"},
|
|
60
60
|
{"field_id": 94, "group": "metadata", "fit_name": "SlipThreshold", "base_type": "UINT16", "size": 2, "scale": 1, "units": "N", "df_columns": [], "message_type": "session"},
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
{"field_id": 13, "group": "oarlock", "fit_name": "Slip", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["slip", " slip"]},
|
|
69
69
|
{"field_id": 14, "group": "oarlock", "fit_name": "Wash", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["wash", " wash"]},
|
|
70
70
|
{"field_id": 15, "group": "oarlock", "fit_name": "PeakForceAngle", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["peakforceangle", " peakforceangle"]},
|
|
71
|
-
{"field_id": 16, "group": "oarlock", "fit_name": "
|
|
71
|
+
{"field_id": 16, "group": "oarlock", "fit_name": "EffectiveArc", "base_type": "UINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["effectiveArc", " effectiveArc", "effective arc"]},
|
|
72
72
|
|
|
73
73
|
{"field_id": 200, "group": "oarlock_dual", "dual_pair": "catch", "side": "port", "fit_name": "CatchPort", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["catch_port", "catchAngle_port"]},
|
|
74
74
|
{"field_id": 201, "group": "oarlock_dual", "dual_pair": "catch", "side": "starboard", "fit_name": "CatchStarboard", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["catch_starboard", "catchAngle_starboard"]},
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
{"field_id": 207, "group": "oarlock_dual", "dual_pair": "wash", "side": "starboard", "fit_name": "WashStarboard", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["wash_starboard"]},
|
|
81
81
|
{"field_id": 208, "group": "oarlock_dual", "dual_pair": "peakforceangle", "side": "port", "fit_name": "PeakForceAnglePort", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["peakforceangle_port"]},
|
|
82
82
|
{"field_id": 209, "group": "oarlock_dual", "dual_pair": "peakforceangle", "side": "starboard", "fit_name": "PeakForceAngleStarboard", "base_type": "SINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["peakforceangle_starboard"]},
|
|
83
|
-
{"field_id": 210, "group": "oarlock_dual", "dual_pair": "
|
|
84
|
-
{"field_id": 211, "group": "oarlock_dual", "dual_pair": "
|
|
83
|
+
{"field_id": 210, "group": "oarlock_dual", "dual_pair": "effectiveArc", "side": "port", "fit_name": "EffectiveArcPort", "base_type": "UINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["effectiveArc_port"]},
|
|
84
|
+
{"field_id": 211, "group": "oarlock_dual", "dual_pair": "effectiveArc", "side": "starboard", "fit_name": "EffectiveArcStarboard", "base_type": "UINT16", "size": 2, "scale": 10, "units": "deg", "df_columns": ["effectiveArc_starboard"]},
|
|
85
85
|
|
|
86
86
|
{"field_id": 17, "group": "peak_position", "fit_name": "PeakForcePositionNorm", "base_type": "UINT16", "size": 2, "scale": 1, "units": "", "df_columns": ["rel_peak_force_pos", "PeakForcePositionNorm", "% of Stroke Complete When Peak Force Is Reached"], "transformer": "peak_norm", "clip_uint16_max": 10000},
|
|
87
87
|
{"field_id": 18, "group": "peak_position", "fit_name": "PeakForcePositionAbs", "base_type": "UINT16", "size": 2, "scale": 1, "units": "mm", "df_columns": ["peak_force_pos", "PeakForcePositionAbs"], "transformer": "peak_abs"},
|
|
@@ -79,6 +79,12 @@ INTENSITY_RECOVERY = 4
|
|
|
79
79
|
INTENSITY_INTERVAL = 5
|
|
80
80
|
INTENSITY_OTHER = 6
|
|
81
81
|
|
|
82
|
+
# Largest value that is not the FIT invalid value of the base type (standard §6.5):
|
|
83
|
+
# 255 / 65535 / 32767 mean "no data" and are never written as a measurement.
|
|
84
|
+
UINT8_MAX_VALID = 254
|
|
85
|
+
UINT16_MAX_VALID = 65534
|
|
86
|
+
SINT16_MAX_VALID = 32766
|
|
87
|
+
|
|
82
88
|
# Developer fields that must be emitted even when value is 0 (semantic zero / unknown).
|
|
83
89
|
ALWAYS_EMIT_DEV_FIELD_IDS = frozenset(_FIT_EXPORT_RAW['always_emit_field_ids'])
|
|
84
90
|
|
|
@@ -248,7 +254,7 @@ def _series_to_peak_force_position_abs_m(values):
|
|
|
248
254
|
"""Map peak_force_pos (often RP3 cm) to millimeters for PeakForcePositionAbs (scale 1, units mm)."""
|
|
249
255
|
v = pd.to_numeric(values, errors='coerce').values
|
|
250
256
|
out = np.zeros(len(v), dtype=np.float64)
|
|
251
|
-
max_mm =
|
|
257
|
+
max_mm = float(UINT16_MAX_VALID)
|
|
252
258
|
for i, x in enumerate(v):
|
|
253
259
|
if not np.isfinite(x) or x <= 0:
|
|
254
260
|
continue
|
|
@@ -260,26 +266,18 @@ def _series_to_peak_force_position_abs_m(values):
|
|
|
260
266
|
return out
|
|
261
267
|
|
|
262
268
|
|
|
263
|
-
def _length_values_to_mm(arr):
|
|
264
|
-
"""Convert oarlock effective-length column values to millimeters."""
|
|
265
|
-
arr = np.asarray(arr, dtype=np.float64)
|
|
266
|
-
if np.nanmax(arr) <= 5.0:
|
|
267
|
-
return arr * 1000.0
|
|
268
|
-
return arr * 10.0
|
|
269
|
-
|
|
270
|
-
|
|
271
269
|
def _values_for_fit_field(arr, units, scale, base_type):
|
|
272
270
|
"""Map physical DataFrame values to FIT developer-field magnitudes before clipping."""
|
|
273
271
|
arr = np.nan_to_num(arr, nan=0.0, posinf=0.0, neginf=0.0)
|
|
274
272
|
if units == 'mm':
|
|
275
273
|
arr = arr * 1000.0
|
|
276
274
|
if base_type == BaseType.UINT8:
|
|
277
|
-
arr = np.clip(arr, 0,
|
|
275
|
+
arr = np.clip(arr, 0, UINT8_MAX_VALID)
|
|
278
276
|
elif base_type == BaseType.UINT16:
|
|
279
|
-
max_display =
|
|
277
|
+
max_display = UINT16_MAX_VALID / scale if scale else float(UINT16_MAX_VALID)
|
|
280
278
|
arr = np.clip(arr, 0, max_display)
|
|
281
279
|
elif base_type == BaseType.SINT16:
|
|
282
|
-
max_display =
|
|
280
|
+
max_display = SINT16_MAX_VALID / scale if scale else float(SINT16_MAX_VALID)
|
|
283
281
|
min_display = -32768.0 / scale if scale else -32768.0
|
|
284
282
|
arr = np.clip(arr, min_display, max_display)
|
|
285
283
|
return arr
|
|
@@ -301,7 +299,7 @@ def _split_cadence_arrays(df, nr_rows):
|
|
|
301
299
|
np.zeros(nr_rows, dtype=np.float64))
|
|
302
300
|
raw = np.where(raw > 0, raw, 0.0)
|
|
303
301
|
cadence_int = np.floor(raw + 0.5).astype(int)
|
|
304
|
-
cadence256 = np.clip(raw, 0.0,
|
|
302
|
+
cadence256 = np.clip(raw, 0.0, UINT16_MAX_VALID / 256.0)
|
|
305
303
|
return cadence_int, cadence256, raw
|
|
306
304
|
|
|
307
305
|
|
|
@@ -358,11 +356,11 @@ def _compute_instroke_axis_arrays(df, n_points, instroke_abscissa_type, instroke
|
|
|
358
356
|
)
|
|
359
357
|
# Millimeters between uniform samples along handle travel
|
|
360
358
|
interval = np.round(drive_m * 1000.0 / np.maximum(n_points - 1, 1))
|
|
361
|
-
interval = np.clip(interval, 0,
|
|
359
|
+
interval = np.clip(interval, 0, UINT16_MAX_VALID)
|
|
362
360
|
elif atype == INSTROKE_ABSCISSA_TIME_UNIFORM_MS and ' DriveTime (ms)' in df.columns:
|
|
363
361
|
drive_ms = np.nan_to_num(df[' DriveTime (ms)'].values, nan=0.0, posinf=0.0, neginf=0.0)
|
|
364
362
|
interval = np.round(drive_ms / np.maximum(n_points - 1, 1))
|
|
365
|
-
interval = np.clip(interval, 0,
|
|
363
|
+
interval = np.clip(interval, 0, UINT16_MAX_VALID)
|
|
366
364
|
else:
|
|
367
365
|
interval = np.zeros(nr)
|
|
368
366
|
pc = np.full(nr, float(min(int(n_points), 127)))
|
|
@@ -618,7 +616,7 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
618
616
|
Handle force in N above/below which the blade counts as entered/exited (Session
|
|
619
617
|
fields SlipThreshold 94 / WashThreshold 95, standard §5.4). Written when given
|
|
620
618
|
and use_developer_fields is True; the standard recommends writing them whenever
|
|
621
|
-
Slip, Wash or
|
|
619
|
+
Slip, Wash or EffectiveArc are written.
|
|
622
620
|
|
|
623
621
|
Returns
|
|
624
622
|
-------
|
|
@@ -704,13 +702,13 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
704
702
|
|
|
705
703
|
try:
|
|
706
704
|
heart_rate = df[' HRCur (bpm)'].values.astype(int)
|
|
707
|
-
heart_rate = np.clip(heart_rate, 0,
|
|
705
|
+
heart_rate = np.clip(heart_rate, 0, UINT8_MAX_VALID) # uint8
|
|
708
706
|
except KeyError:
|
|
709
707
|
heart_rate = np.zeros(nr_rows, dtype=int)
|
|
710
708
|
|
|
711
709
|
try:
|
|
712
710
|
power = df[' Power (watts)'].values.astype(int)
|
|
713
|
-
power = np.clip(power, 0,
|
|
711
|
+
power = np.clip(power, 0, UINT16_MAX_VALID) # uint16
|
|
714
712
|
except KeyError:
|
|
715
713
|
power = np.zeros(nr_rows, dtype=int)
|
|
716
714
|
|
|
@@ -795,21 +793,10 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
795
793
|
col = next((c for c in possible_cols if c in df.columns), None)
|
|
796
794
|
if col is not None:
|
|
797
795
|
arr = df[col].values
|
|
798
|
-
|
|
799
|
-
arr = _length_values_to_mm(arr)
|
|
800
|
-
arr = _values_for_fit_field(arr, '', scale, base_type)
|
|
801
|
-
elif base_type == BaseType.SINT16:
|
|
802
|
-
arr = _values_for_fit_field(arr, units, scale, base_type)
|
|
803
|
-
else:
|
|
804
|
-
arr = _values_for_fit_field(arr, units, scale, base_type)
|
|
796
|
+
arr = _values_for_fit_field(arr, units, scale, base_type)
|
|
805
797
|
dev_arrays[field_id] = arr
|
|
806
798
|
dev_specs.append((field_id, col, name, base_type, size, scale, units))
|
|
807
799
|
for _pair_key, port_fd, starboard_fd in OARLOCK_DUAL_PAIRS:
|
|
808
|
-
if _pair_key == 'effectiveLength':
|
|
809
|
-
# Draft defect: summary field 16 is mm while 210/211 are metres,
|
|
810
|
-
# and §5.3 calls 16 the average of the two. Unresolved upstream,
|
|
811
|
-
# so neither encoding is written.
|
|
812
|
-
continue
|
|
813
800
|
cols_p = port_fd[1]
|
|
814
801
|
cols_s = starboard_fd[1]
|
|
815
802
|
col_p = next((c for c in cols_p if c in df.columns), None)
|
|
@@ -819,11 +806,7 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
819
806
|
for fd, col in ((port_fd, col_p), (starboard_fd, col_s)):
|
|
820
807
|
field_id, possible_cols, name, base_type, size, scale, units = fd
|
|
821
808
|
arr = df[col].values
|
|
822
|
-
|
|
823
|
-
arr = _length_values_to_mm(arr)
|
|
824
|
-
arr = _values_for_fit_field(arr, '', scale, base_type)
|
|
825
|
-
else:
|
|
826
|
-
arr = _values_for_fit_field(arr, units, scale, base_type)
|
|
809
|
+
arr = _values_for_fit_field(arr, units, scale, base_type)
|
|
827
810
|
dev_arrays[field_id] = arr
|
|
828
811
|
dev_specs.append((field_id, col, name, base_type, size, scale, units))
|
|
829
812
|
for fd in PEAK_POSITION_DEV_FIELDS:
|
|
@@ -839,7 +822,7 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
839
822
|
continue
|
|
840
823
|
arr = np.nan_to_num(arr, nan=0.0, posinf=0.0, neginf=0.0)
|
|
841
824
|
if base_type == BaseType.UINT16:
|
|
842
|
-
max_display =
|
|
825
|
+
max_display = UINT16_MAX_VALID / scale if scale else float(UINT16_MAX_VALID)
|
|
843
826
|
arr = np.clip(arr, 0, max_display)
|
|
844
827
|
if clip_max is not None:
|
|
845
828
|
arr = np.clip(arr, 0, float(clip_max))
|
|
@@ -875,9 +858,9 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
875
858
|
field_id = base_id
|
|
876
859
|
name = '%s_%s' % (canonical, metric)
|
|
877
860
|
arr = np.nan_to_num(arr, nan=0.0, posinf=0.0, neginf=0.0)
|
|
878
|
-
# UINT16: encoded = value * scale, must be <=
|
|
861
|
+
# UINT16: encoded = value * scale, must be <= 65534. Scale 1 => max display 65534
|
|
879
862
|
scale = 1
|
|
880
|
-
arr = np.clip(arr, 0,
|
|
863
|
+
arr = np.clip(arr, 0, UINT16_MAX_VALID / max(scale, 1))
|
|
881
864
|
dev_arrays[field_id] = arr
|
|
882
865
|
dev_specs.append((field_id, col, name, BaseType.UINT16, 2, scale, ''))
|
|
883
866
|
instroke_private_field_ids.add(field_id)
|
|
@@ -935,9 +918,9 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
935
918
|
fid, name, bt, size, scale, units = axis_row
|
|
936
919
|
arr = np.nan_to_num(arr, nan=0.0, posinf=0.0, neginf=0.0)
|
|
937
920
|
if bt == BaseType.UINT8:
|
|
938
|
-
arr = np.clip(arr, 0,
|
|
921
|
+
arr = np.clip(arr, 0, UINT8_MAX_VALID)
|
|
939
922
|
elif bt == BaseType.UINT16:
|
|
940
|
-
arr = np.clip(arr, 0,
|
|
923
|
+
arr = np.clip(arr, 0, UINT16_MAX_VALID)
|
|
941
924
|
dev_arrays[fid] = arr
|
|
942
925
|
dev_specs.append((fid, '_instroke_axis', name, bt, size, scale, units))
|
|
943
926
|
|
|
@@ -1124,7 +1107,7 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
1124
1107
|
if is_array_field and arr.ndim == 2:
|
|
1125
1108
|
row = arr[i]
|
|
1126
1109
|
vals = np.nan_to_num(row, nan=0.0, posinf=0.0, neginf=0.0)
|
|
1127
|
-
max_phys =
|
|
1110
|
+
max_phys = UINT16_MAX_VALID / max(scale, 1)
|
|
1128
1111
|
vals = np.clip(vals, 0, max_phys)
|
|
1129
1112
|
has_data = np.any(vals != 0)
|
|
1130
1113
|
if has_data:
|
|
@@ -1144,7 +1127,7 @@ def write_fit(file_name, df, row_date="2016-01-01", notes="Exported by Rowingdat
|
|
|
1144
1127
|
else:
|
|
1145
1128
|
val = float(arr[i])
|
|
1146
1129
|
if base_type == BaseType.UINT8:
|
|
1147
|
-
val = int(np.clip(round(val), 0,
|
|
1130
|
+
val = int(np.clip(round(val), 0, UINT8_MAX_VALID))
|
|
1148
1131
|
if val != 0 or field_id in ALWAYS_EMIT_DEV_FIELD_IDS:
|
|
1149
1132
|
dev = DeveloperField(
|
|
1150
1133
|
developer_data_index=_dev_index_for(field_id),
|
|
@@ -78,9 +78,9 @@ def load_fit_spec_raw():
|
|
|
78
78
|
|
|
79
79
|
def _validate_spec(raw):
|
|
80
80
|
version = raw.get('version', 0)
|
|
81
|
-
if version not in (1, 2, 3):
|
|
81
|
+
if version not in (1, 2, 3, 4):
|
|
82
82
|
warnings.warn(
|
|
83
|
-
'fit_export_spec.json version %s may be unsupported (expected 1, 2 or
|
|
83
|
+
'fit_export_spec.json version %s may be unsupported (expected 1, 2, 3 or 4)' % version,
|
|
84
84
|
UserWarning,
|
|
85
85
|
stacklevel=2,
|
|
86
86
|
)
|
|
@@ -44,6 +44,10 @@ def _standard_app_ids():
|
|
|
44
44
|
return ROWINGDATA_APP_ID, INSTROKE_APP_ID
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
# FIT invalid ("no data") value per base type (standard §6.5): read as missing.
|
|
48
|
+
_FIT_INVALID_VALUES = {'UINT8': 255, 'UINT16': 65535, 'SINT16': 32767}
|
|
49
|
+
|
|
50
|
+
|
|
47
51
|
def _load_developer_field_spec():
|
|
48
52
|
"""Reverse map of the export spec: lowercase FIT field name -> definition.
|
|
49
53
|
|
|
@@ -64,6 +68,22 @@ def _load_developer_field_spec():
|
|
|
64
68
|
'column': columns[0],
|
|
65
69
|
'units': entry.get('units') or '',
|
|
66
70
|
'scale': entry.get('scale') or 1,
|
|
71
|
+
'invalid': _FIT_INVALID_VALUES.get(entry.get('base_type')),
|
|
72
|
+
}
|
|
73
|
+
# Names the standard has since renamed. Files written against earlier drafts
|
|
74
|
+
# still carry them, so they are read, but never written.
|
|
75
|
+
renamed = (
|
|
76
|
+
('AverageDriveForceN', 'AverageDriveForce'),
|
|
77
|
+
('PeakDriveForceN', 'PeakDriveForce'),
|
|
78
|
+
)
|
|
79
|
+
for old, new in renamed:
|
|
80
|
+
mapping[old.lower()] = dict(mapping[new.lower()])
|
|
81
|
+
# EffectiveLength (mm) became EffectiveArc (deg); the two are not convertible
|
|
82
|
+
# into each other, so an old file's length keeps its own column, in metres.
|
|
83
|
+
for suffix in ('', 'Port', 'Starboard'):
|
|
84
|
+
column = 'effectiveLength' + ('_' + suffix.lower() if suffix else '')
|
|
85
|
+
mapping['effectivelength' + suffix.lower()] = {
|
|
86
|
+
'column': column, 'units': 'mm', 'scale': 1, 'invalid': 65535,
|
|
67
87
|
}
|
|
68
88
|
return mapping
|
|
69
89
|
|
|
@@ -865,9 +885,8 @@ class FITParser(object):
|
|
|
865
885
|
"""Rename standard developer fields to rowingdata CSV columns.
|
|
866
886
|
|
|
867
887
|
fitparse does not apply developer-field scales, so the raw integers are
|
|
868
|
-
divided here. The scale in the file wins when present;
|
|
869
|
-
|
|
870
|
-
cannot survive in a field_description.
|
|
888
|
+
divided here. The scale in the file wins when present; the spec scale is
|
|
889
|
+
the fallback for files that do not carry one.
|
|
871
890
|
"""
|
|
872
891
|
spec = _developer_field_spec()
|
|
873
892
|
if not spec: # pragma: no cover
|
|
@@ -887,6 +906,8 @@ class FITParser(object):
|
|
|
887
906
|
file_scale = standard.get(key) if is_standard else legacy.get(key)
|
|
888
907
|
scale = file_scale if file_scale else definition['scale']
|
|
889
908
|
values = pd.to_numeric(self.df[source], errors='coerce')
|
|
909
|
+
if definition.get('invalid') is not None:
|
|
910
|
+
values = values.mask(values == definition['invalid'])
|
|
890
911
|
if scale and scale != 1:
|
|
891
912
|
values = values / float(scale)
|
|
892
913
|
# Pre-UUID files carried lengths in metres already.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rowingdata
|
|
3
|
-
Version: 3.8.
|
|
3
|
+
Version: 3.8.3
|
|
4
4
|
Summary: The rowingdata library to create colorful plots from CrewNerd, Painsled and other rowing data tools
|
|
5
5
|
Home-page: https://github.com/sanderroosendaal/rowingdata
|
|
6
6
|
Author: Sander Roosendaal
|
|
@@ -555,7 +555,7 @@ The available data fields are
|
|
|
555
555
|
* 'cum_dist'
|
|
556
556
|
|
|
557
557
|
Oarlock parsers (NK Logbook) may add: ``catch``, ``finish``,
|
|
558
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
558
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
559
559
|
|
|
560
560
|
If imported from TCX, Rowpro, or other tools, some data fields may not contain
|
|
561
561
|
useful information.
|
|
@@ -567,7 +567,7 @@ rowingdata CSV Columns
|
|
|
567
567
|
This section describes the dataframe schema used by the ``rowingdata`` class.
|
|
568
568
|
It is this package's own column layout, not a vendor-neutral standard. For a
|
|
569
569
|
cross-vendor interchange format, see the Rowing Data Standard at
|
|
570
|
-
https://github.com/
|
|
570
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which rowingdata
|
|
571
571
|
targets when exporting FIT.
|
|
572
572
|
|
|
573
573
|
Any parser implementation feeding the ``rowingdata`` class should produce at
|
|
@@ -600,12 +600,12 @@ The standard field names are:
|
|
|
600
600
|
* ' ElapsedTime (sec)'
|
|
601
601
|
|
|
602
602
|
Optional (Oarlock/NK Logbook): ``catch``/``catchAngle``, ``finish``/``finishAngle``,
|
|
603
|
-
``slip``, ``wash``, ``peakforceangle``, ``
|
|
603
|
+
``slip``, ``wash``, ``peakforceangle``, ``effectiveArc``.
|
|
604
604
|
|
|
605
605
|
Planned for dual oarlock (port/starboard symmetry): ``catch_port``, ``catch_starboard``,
|
|
606
606
|
``finish_port``, ``finish_starboard``, ``slip_port``, ``slip_starboard``, ``wash_port``,
|
|
607
607
|
``wash_starboard``, ``peakforceangle_port``, ``peakforceangle_starboard``,
|
|
608
|
-
``
|
|
608
|
+
``effectiveArc_port``, ``effectiveArc_starboard``. See *Dual oarlock
|
|
609
609
|
(port/starboard)* below. **Note:** rowingdata does not yet implement parsing or
|
|
610
610
|
export for these per-side columns.
|
|
611
611
|
|
|
@@ -848,10 +848,9 @@ Oarlock scalars (OTW rigging)
|
|
|
848
848
|
-----------------------------
|
|
849
849
|
|
|
850
850
|
Field names: 'catch' / 'catchAngle', 'finish' / 'finishAngle', 'slip',
|
|
851
|
-
'wash', 'peakforceangle', '
|
|
851
|
+
'wash', 'peakforceangle', 'effectiveArc'
|
|
852
852
|
|
|
853
|
-
Units: degrees for angles
|
|
854
|
-
source: NK Logbook uses these columns).
|
|
853
|
+
Units: degrees for angles and for effectiveArc.
|
|
855
854
|
|
|
856
855
|
These fields come from NK Logbook (Oarlock) and similar OTW
|
|
857
856
|
measurement systems. They describe rigging geometry and blade angles:
|
|
@@ -864,12 +863,11 @@ measurement systems. They describe rigging geometry and blade angles:
|
|
|
864
863
|
* **slip** – blade slip angle.
|
|
865
864
|
* **wash** – wash/backwash angle.
|
|
866
865
|
* **peakforceangle** – oar angle at peak force (same 0° = perpendicular convention).
|
|
867
|
-
* **
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
they serve different purposes.
|
|
866
|
+
* **effectiveArc** – the part of the stroke arc that is effective: catch to
|
|
867
|
+
finish, less slip and wash (degrees). The Rowing Data Standard replaced the
|
|
868
|
+
earlier effective *length* (a lever length in mm) with this arc. Files written
|
|
869
|
+
against earlier drafts carry ``EffectiveLength``; it is read into the
|
|
870
|
+
``effectiveLength`` column (metres) and is not converted into an arc.
|
|
873
871
|
|
|
874
872
|
Dual oarlock (port/starboard)
|
|
875
873
|
..............................
|
|
@@ -973,12 +971,16 @@ Unreleased
|
|
|
973
971
|
----------
|
|
974
972
|
|
|
975
973
|
- **Breaking change to exported FIT file contents.** FIT export now follows the
|
|
976
|
-
Rowing Data Standard (https://github.com/
|
|
977
|
-
|
|
978
|
-
not: the developer application ID is now the standard UUID,
|
|
979
|
-
|
|
980
|
-
``AverageBoatSpeed`` uses scale
|
|
981
|
-
|
|
974
|
+
Rowing Data Standard (https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard,
|
|
975
|
+
current ``main``). The ``exporttofit`` API is unchanged, but the bytes it
|
|
976
|
+
writes are not: the developer application ID is now the standard UUID,
|
|
977
|
+
``DriveLength`` is encoded in millimetres rather than metres,
|
|
978
|
+
``AverageBoatSpeed`` uses scale 100, ``EffectiveLength`` is replaced by
|
|
979
|
+
``EffectiveArc`` in degrees (IDs 16, 210, 211; the ``effectiveLength*``
|
|
980
|
+
columns are no longer exported, use ``effectiveArc*``), the force fields are
|
|
981
|
+
named ``AverageDriveForce`` and ``PeakDriveForce``, stroke rate is written as
|
|
982
|
+
native ``cadence256``, stroke work uses field ID 19, and no value is written
|
|
983
|
+
as the FIT invalid value (255 / 65535 / 32767): measurements clip one below it. Consumers that hardcoded the previous rowingdata
|
|
982
984
|
application ID or the old metre-based scales must be updated. ``FITParser``
|
|
983
985
|
still reads files written by rowingdata 3.7.3 and earlier.
|
|
984
986
|
- In-stroke curve fields are emitted under a separate, private application ID,
|
|
@@ -986,7 +988,7 @@ Unreleased
|
|
|
986
988
|
carry no interoperable meaning.
|
|
987
989
|
- Removed ``docs/FIT_STANDARD.md`` and ``docs/FIT_STANDARD.pdf``. The standard is
|
|
988
990
|
maintained by a committee at
|
|
989
|
-
https://github.com/
|
|
991
|
+
https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard, which is the single
|
|
990
992
|
source of truth; this repository no longer ships a copy.
|
|
991
993
|
|
|
992
994
|
0.97.x
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""Thorough tests for FIT in-stroke curve export.
|
|
3
3
|
|
|
4
4
|
In-stroke curve field IDs are unallocated in the Rowing Data Standard registry
|
|
5
|
-
(https://github.com/
|
|
5
|
+
(https://github.com/Rowing-Industry-Trade-Association/rowing-data-standard), so they are emitted
|
|
6
6
|
under rowingdata's private application ID; see fitwrite.INSTROKE_APP_ID.
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import absolute_import
|