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.
Files changed (204) hide show
  1. {rowingdata-3.8.2/rowingdata.egg-info → rowingdata-3.8.3}/PKG-INFO +23 -21
  2. {rowingdata-3.8.2 → rowingdata-3.8.3}/README.rst +22 -20
  3. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/data/fit_export_spec.json +8 -8
  4. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fitwrite.py +25 -42
  5. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fitwrite_spec.py +2 -2
  6. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/otherparsers.py +24 -3
  7. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowingdata.py +1 -1
  8. {rowingdata-3.8.2 → rowingdata-3.8.3/rowingdata.egg-info}/PKG-INFO +23 -21
  9. {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_instroke_export.py +1 -1
  10. {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_standard.py +49 -23
  11. {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_rowingdata.py +1 -1
  12. {rowingdata-3.8.2 → rowingdata-3.8.3}/LICENSE +0 -0
  13. {rowingdata-3.8.2 → rowingdata-3.8.3}/MANIFEST.in +0 -0
  14. {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/crewnerddata.csv +0 -0
  15. {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/crewnerddata.tcx +0 -0
  16. {rowingdata-3.8.2 → rowingdata-3.8.3}/bin/testdata.csv +0 -0
  17. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/.buildinfo +0 -0
  18. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/2x20min.png +0 -0
  19. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/editrower.JPG +0 -0
  20. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/greghoc.png +0 -0
  21. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/image001.png +0 -0
  22. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/otwlogbook.JPG +0 -0
  23. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/otwscreenshot.JPG +0 -0
  24. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/screenshot.JPG +0 -0
  25. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/screenshotlogbook.JPG +0 -0
  26. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_images/woensdag.png +0 -0
  27. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/index.txt +0 -0
  28. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/modules.txt +0 -0
  29. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_sources/rowingdata.txt +0 -0
  30. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/ajax-loader.gif +0 -0
  31. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/alabaster.css +0 -0
  32. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/basic.css +0 -0
  33. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment-bright.png +0 -0
  34. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment-close.png +0 -0
  35. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/comment.png +0 -0
  36. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/custom.css +0 -0
  37. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/doctools.js +0 -0
  38. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/down-pressed.png +0 -0
  39. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/down.png +0 -0
  40. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/file.png +0 -0
  41. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/jquery-1.11.1.js +0 -0
  42. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/jquery.js +0 -0
  43. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/minus.png +0 -0
  44. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/plus.png +0 -0
  45. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/pygments.css +0 -0
  46. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/searchtools.js +0 -0
  47. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/underscore-1.3.1.js +0 -0
  48. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/underscore.js +0 -0
  49. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/up-pressed.png +0 -0
  50. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/up.png +0 -0
  51. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/_static/websupport.js +0 -0
  52. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/genindex.html +0 -0
  53. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/index.html +0 -0
  54. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/modules.html +0 -0
  55. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/objects.inv +0 -0
  56. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/py-modindex.html +0 -0
  57. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/rowingdata.html +0 -0
  58. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/search.html +0 -0
  59. {rowingdata-3.8.2 → rowingdata-3.8.3}/docs/_build/html/searchindex.js +0 -0
  60. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/__init__.py +0 -0
  61. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/__main__.py +0 -0
  62. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/boatedit.py +0 -0
  63. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/checkdatafiles.py +0 -0
  64. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/copystats.py +0 -0
  65. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/crewnerdplot.py +0 -0
  66. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/crewnerdplottime.py +0 -0
  67. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/csvparsers.py +0 -0
  68. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdataplot.py +0 -0
  69. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdataplottime.py +0 -0
  70. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergdatatotcx.py +0 -0
  71. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergstickplot.py +0 -0
  72. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergstickplottime.py +0 -0
  73. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/ergsticktotcx.py +0 -0
  74. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fit_garmin_bridge.py +0 -0
  75. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/fit_transcode.py +0 -0
  76. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/gpxtools.py +0 -0
  77. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/gpxwrite.py +0 -0
  78. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/konkatenaadje.py +0 -0
  79. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/laptesting.py +0 -0
  80. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/obsolete.py +0 -0
  81. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_plot.py +0 -0
  82. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_plottime.py +0 -0
  83. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsled_desktop_toc2.py +0 -0
  84. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledplot.py +0 -0
  85. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledplottime.py +0 -0
  86. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/painsledtoc2.py +0 -0
  87. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/roweredit.py +0 -0
  88. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowproplot.py +0 -0
  89. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/rowproplottime.py +0 -0
  90. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachplot.py +0 -0
  91. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachplottime.py +0 -0
  92. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/speedcoachtoc2.py +0 -0
  93. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplot.py +0 -0
  94. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplot_nogeo.py +0 -0
  95. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplottime.py +0 -0
  96. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxplottime_nogeo.py +0 -0
  97. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxtoc2.py +0 -0
  98. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/tcxtools.py +0 -0
  99. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/trainingparser.py +0 -0
  100. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/utils.py +0 -0
  101. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/windcorrected.py +0 -0
  102. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata/writetcx.py +0 -0
  103. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/SOURCES.txt +0 -0
  104. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/dependency_links.txt +0 -0
  105. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/not-zip-safe +0 -0
  106. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/requires.txt +0 -0
  107. {rowingdata-3.8.2 → rowingdata-3.8.3}/rowingdata.egg-info/top_level.txt +0 -0
  108. {rowingdata-3.8.2 → rowingdata-3.8.3}/setup.cfg +0 -0
  109. {rowingdata-3.8.2 → rowingdata-3.8.3}/setup.py +0 -0
  110. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2016-03-25-0758.CSV +0 -0
  111. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2016-03-25-0758_data.CSV +0 -0
  112. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2x20min_o.csv +0 -0
  113. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/2x2km.tcx +0 -0
  114. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/3km_cd_o.csv +0 -0
  115. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/3x250m.tcx +0 -0
  116. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/EUBoatCoach.csv +0 -0
  117. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/EmpowerSpeedCoachForce.csv +0 -0
  118. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NKEmporfromgreg.csv +0 -0
  119. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NKLiNKv130.csv +0 -0
  120. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/NoHR.tcx +0 -0
  121. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/PainsledForce.csv +0 -0
  122. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_interval.csv +0 -0
  123. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_interval.csv_o.CSV +0 -0
  124. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/RP_testdata.csv +0 -0
  125. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpdCoach2_imp_inconsistent.csv +0 -0
  126. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpdCoachAmbiguous.csv +0 -0
  127. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach GPS Workout.csv +0 -0
  128. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2Link_interval.csv +0 -0
  129. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2Linkv1.27.csv +0 -0
  130. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/SpeedCoach2v2.12.csv +0 -0
  131. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/Speedcoach2example.csv +0 -0
  132. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/aritmo.csv +0 -0
  133. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc1.csv +0 -0
  134. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc2.csv +0 -0
  135. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/bc3.csv +0 -0
  136. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach.csv +0 -0
  137. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach_fixed_distance.csv +0 -0
  138. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/boatcoach_otw.csv +0 -0
  139. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/correctedpainsled.csv +0 -0
  140. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/cottwich.csv +0 -0
  141. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/coxmate.csv +0 -0
  142. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerd_interval.csv +0 -0
  143. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata.CSV +0 -0
  144. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata.tcx +0 -0
  145. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/crewnerddata_o.CSV +0 -0
  146. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/cumvalues.csv +0 -0
  147. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergdata_example.csv +0 -0
  148. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergdata_example.csv_o.CSV +0 -0
  149. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick.csv +0 -0
  150. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick.csv_o.CSV +0 -0
  151. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick2.csv +0 -0
  152. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ergstick_o.csv +0 -0
  153. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/example.csv +0 -0
  154. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/example_data.csv +0 -0
  155. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/faketcx.tcx +0 -0
  156. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/float.csv +0 -0
  157. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/herodata.csv +0 -0
  158. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/humon.csv +0 -0
  159. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/impeller_empower.csv +0 -0
  160. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/invalidchar.tcx +0 -0
  161. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/kinomap.csv +0 -0
  162. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/mystery.csv +0 -0
  163. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/nk_logbook.csv +0 -0
  164. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled.tcx +0 -0
  165. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_desktop_example.csv +0 -0
  166. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_out_data.csv +0 -0
  167. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/painsled_to_csv_20160221-105218_erg-400150318_760465m.csv +0 -0
  168. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_left.csv +0 -0
  169. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_new.csv +0 -0
  170. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_right.csv +0 -0
  171. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/quiske_per_stroke_seat.csv +0 -0
  172. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/recover.tcx +0 -0
  173. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/ritmointervals.csv +0 -0
  174. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowingdata_eth.csv +0 -0
  175. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowinginmotionexample.TCX +0 -0
  176. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowinginmotionexample.TCX_o.CSV +0 -0
  177. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowperfect.csv +0 -0
  178. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowpro5.csv +0 -0
  179. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rowpro_carrick.csv +0 -0
  180. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3_curve.csv +0 -0
  181. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3intervals.csv +0 -0
  182. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp3intervals2.csv +0 -0
  183. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/rp_out.csv +0 -0
  184. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/smartrow.csv +0 -0
  185. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/smartrow_intervals.csv +0 -0
  186. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/spdcoach2noheader.csv +0 -0
  187. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoach2test2.csv +0 -0
  188. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoach3test3.csv +0 -0
  189. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoachexample.csv +0 -0
  190. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/speedcoachexample.csv_o.CSV +0 -0
  191. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/strava_export.tcx +0 -0
  192. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/summarytest.csv +0 -0
  193. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata.csv +0 -0
  194. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata_part1.csv +0 -0
  195. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdata_part2.csv +0 -0
  196. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testdatasummary.csv +0 -0
  197. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testlapidx.csv +0 -0
  198. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcs_210614.tcx +0 -0
  199. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcx.tcx +0 -0
  200. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/testtcx_210614.tcx +0 -0
  201. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata/tim.csv +0 -0
  202. {rowingdata-3.8.2 → rowingdata-3.8.3}/testdata//345/210/222/350/210/271.csv" +0 -0
  203. {rowingdata-3.8.2 → rowingdata-3.8.3}/tests/test_fit_transcode.py +0 -0
  204. {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.2
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``, ``effectiveLength``.
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/MoveLab-Studio/rowing-data-standard, which rowingdata
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``, ``effectiveLength``.
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
- ``effectiveLength_port``, ``effectiveLength_starboard``. See *Dual oarlock
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', 'effectiveLength'
851
+ 'wash', 'peakforceangle', 'effectiveArc'
852
852
 
853
- Units: degrees for angles; meter for effectiveLength (scale may vary by
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
- * **effectiveLength** – effective lever length (rigging geometry). *Not*
868
- the same as Drive Length: Effective Length is the horizontal component
869
- from pin to handle (a rigging/setup measure, often in cm), whereas
870
- Drive Length is the *actual distance the handle traveled* during the
871
- stroke (typically 1.2–1.5 m). Both may appear in the same dataset;
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/MoveLab-Studio/rowing-data-standard,
977
- Draft v0.1). The ``exporttofit`` API is unchanged, but the bytes it writes are
978
- not: the developer application ID is now the standard UUID, ``DriveLength``
979
- and ``EffectiveLength`` are encoded in millimetres rather than metres,
980
- ``AverageBoatSpeed`` uses scale 255, stroke rate moves to field ID 93, and
981
- stroke work to field ID 19. Consumers that hardcoded the previous rowingdata
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/MoveLab-Studio/rowing-data-standard, which is the single
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``, ``effectiveLength``.
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/MoveLab-Studio/rowing-data-standard, which rowingdata
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``, ``effectiveLength``.
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
- ``effectiveLength_port``, ``effectiveLength_starboard``. See *Dual oarlock
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', 'effectiveLength'
817
+ 'wash', 'peakforceangle', 'effectiveArc'
818
818
 
819
- Units: degrees for angles; meter for effectiveLength (scale may vary by
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
- * **effectiveLength** – effective lever length (rigging geometry). *Not*
834
- the same as Drive Length: Effective Length is the horizontal component
835
- from pin to handle (a rigging/setup measure, often in cm), whereas
836
- Drive Length is the *actual distance the handle traveled* during the
837
- stroke (typically 1.2–1.5 m). Both may appear in the same dataset;
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/MoveLab-Studio/rowing-data-standard,
943
- Draft v0.1). The ``exporttofit`` API is unchanged, but the bytes it writes are
944
- not: the developer application ID is now the standard UUID, ``DriveLength``
945
- and ``EffectiveLength`` are encoded in millimetres rather than metres,
946
- ``AverageBoatSpeed`` uses scale 255, stroke rate moves to field ID 93, and
947
- stroke work to field ID 19. Consumers that hardcoded the previous rowingdata
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/MoveLab-Studio/rowing-data-standard, which is the single
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": 3,
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/MoveLab-Studio/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. 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).",
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": "AverageDriveForceN", "base_type": "UINT16", "size": 2, "scale": 10, "units": "N", "df_columns": [" AverageDriveForce (N)"]},
56
- {"field_id": 7, "group": "rowing", "fit_name": "PeakDriveForceN", "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": 255, "units": "m/s", "df_columns": [" AverageBoatSpeed (m/s)"]},
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": "EffectiveLength", "base_type": "UINT16", "size": 2, "scale": 1, "units": "mm", "df_columns": ["effectiveLength", " effectiveLength", "effective length"]},
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": "effectiveLength", "side": "port", "fit_name": "EffectiveLengthPort", "base_type": "UINT16", "size": 2, "scale": 1, "units": "mm", "df_columns": ["effectiveLength_port"]},
84
- {"field_id": 211, "group": "oarlock_dual", "dual_pair": "effectiveLength", "side": "starboard", "fit_name": "EffectiveLengthStarboard", "base_type": "UINT16", "size": 2, "scale": 1, "units": "mm", "df_columns": ["effectiveLength_starboard"]},
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 = 65535.0
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, 255)
275
+ arr = np.clip(arr, 0, UINT8_MAX_VALID)
278
276
  elif base_type == BaseType.UINT16:
279
- max_display = 65535.0 / scale if scale else 65535.0
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 = 32767.0 / scale if scale else 32767.0
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, 65535.0 / 256.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, 65535)
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, 65535)
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 EffectiveLength are written.
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, 255) # uint8
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, 65535) # uint16
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
- if units == 'mm' and 'EffectiveLength' in name:
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
- if units == 'mm' and 'EffectiveLength' in name:
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 = 65535.0 / scale if scale else 65535.0
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 <= 65535. Scale 1 => max display 65535
861
+ # UINT16: encoded = value * scale, must be <= 65534. Scale 1 => max display 65534
879
862
  scale = 1
880
- arr = np.clip(arr, 0, 65535.0 / max(scale, 1))
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, 255)
921
+ arr = np.clip(arr, 0, UINT8_MAX_VALID)
939
922
  elif bt == BaseType.UINT16:
940
- arr = np.clip(arr, 0, 65535)
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 = 65535.0 / max(scale, 1)
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, 255))
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 3)' % version,
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; ``AverageBoatSpeed``
869
- needs the spec fallback because scale 255 is the uint8 invalid value and
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.
@@ -6,7 +6,7 @@ from __future__ import print_function
6
6
  from six.moves import range
7
7
  from six.moves import input
8
8
 
9
- __version__ = "3.8.2"
9
+ __version__ = "3.8.3"
10
10
 
11
11
  from collections import Counter
12
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rowingdata
3
- Version: 3.8.2
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``, ``effectiveLength``.
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/MoveLab-Studio/rowing-data-standard, which rowingdata
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``, ``effectiveLength``.
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
- ``effectiveLength_port``, ``effectiveLength_starboard``. See *Dual oarlock
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', 'effectiveLength'
851
+ 'wash', 'peakforceangle', 'effectiveArc'
852
852
 
853
- Units: degrees for angles; meter for effectiveLength (scale may vary by
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
- * **effectiveLength** – effective lever length (rigging geometry). *Not*
868
- the same as Drive Length: Effective Length is the horizontal component
869
- from pin to handle (a rigging/setup measure, often in cm), whereas
870
- Drive Length is the *actual distance the handle traveled* during the
871
- stroke (typically 1.2–1.5 m). Both may appear in the same dataset;
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/MoveLab-Studio/rowing-data-standard,
977
- Draft v0.1). The ``exporttofit`` API is unchanged, but the bytes it writes are
978
- not: the developer application ID is now the standard UUID, ``DriveLength``
979
- and ``EffectiveLength`` are encoded in millimetres rather than metres,
980
- ``AverageBoatSpeed`` uses scale 255, stroke rate moves to field ID 93, and
981
- stroke work to field ID 19. Consumers that hardcoded the previous rowingdata
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/MoveLab-Studio/rowing-data-standard, which is the single
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/MoveLab-Studio/rowing-data-standard), so they are emitted
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