Closed krissen closed 4 years ago
We can definitely consider this for the next review of the data fields. Can you send over some data (a gpx or tcx file), units of measurement and details of the device these come from? Having data from a 2-3 workouts would be best to set up tests.
If you prefer no to disclose data publicly here but you still can share, please send them to my email address (see http://ikosmidis.com).
Well, the thing is that as far as I can tell there are no specific fields for it in gpx
or tcx
files downloaded from Garmin. There are such fields in csv
files downloaded from Garmin connect, but those are for summaries of several workouts and not for individual workouts.
Either there is such data in fit
-files or data for stride and ground contact time is something that is calculated from the data we have (just guessing here, but could difference between trackpoint time and distance be something?). Something that suggests such data would be in fit
-files is that Garmin Connect is also showing data for vertical movement, and I see no way how that could be calculated from the different fields of data in tcx
-files.
Ah yes, it is indeed stored in fit
-files.
fitdump
of the fit
file that corresponds to the tcx
-file mentioned in #22 gives the following (example of a 'record', analogous to a tcx
'trackpoint', I guess):
13. record
* activity_type: running
* altitude: 2685
* cadence: 85 [rpm]
* distance: 0.00767 [km]
* enhanced_altitude: 37.0 [m]
* enhanced_speed: 6.75 [km/h]
* fractional_cadence: 0.5 [rpm]
* heart_rate: 87 [bpm]
* position_lat: 59.377507930621505 [deg]
* position_long: 13.531123884022236 [deg]
* speed: 6750.0 [km/h]
* stance_time: 277.0 [ms]
* stance_time_percent: 40.0 [percent]
* timestamp: 2020-04-28 05:55:01
* vertical_oscillation: 86.7 [mm]
This looks like a workout summary entry with derived quantities, is that right?. A few Qs:
fitdump
(never heard of that before)It's a script provided by python-fitparse.
Hmm. Stride might be a derived quantity. Not sure about ground contact. Could that be stance_time
from the record data, above?
Besides a bunch of records
, fitdump also gives the following session
-data:
519. session
* avg_fractional_cadence: 0.59375 [rpm]
* avg_heart_rate: 143 [bpm]
* avg_running_cadence: 83 [strides/min]
* avg_speed: 11559.6 [km/h]
* avg_stance_time: 224.7 [ms]
* avg_stance_time_percent: 31.41 [percent]
* avg_vertical_oscillation: 104.9 [mm]
* enhanced_avg_speed: 11.5596 [km/h]
* enhanced_max_speed: 17.064 [km/h]
* event: lap
* event_group: None
* event_type: stop
* first_lap_index: 0
* max_fractional_cadence: 0.5 [rpm]
* max_heart_rate: 160 [bpm]
* max_running_cadence: 95 [strides/min]
* max_speed: 17064.0 [km/h]
* message_index: 0
* nec_lat: 59.39140831120312 [deg]
* nec_long: 13.547168858349323 [deg]
* num_laps: 8
* sport: running
* start_position_lat: 59.37746618874371 [deg]
* start_position_long: 13.531184401363134 [deg]
* start_time: 2020-04-28 05:54:59
* sub_sport: generic
* swc_lat: 59.375313045457006 [deg]
* swc_long: 13.505326816812158 [deg]
* timestamp: 2020-04-28 07:02:10
* total_ascent: 274 [m]
* total_calories: 487 [kcal]
* total_descent: 231 [m]
* total_distance: 7960.43 [m]
* total_elapsed_time: 3246.019 [s]
* total_fractional_cycles: None [cycles]
* total_strides: 3462 [strides]
* total_timer_time: 2478.976 [s]
* total_training_effect: 3.1
* trigger: activity_end
* unknown_81: 4
Here is the entire fitdump:ed file.
OK. Thanks. Stride seems to be a derived quantity. I cannot immediately understand what stance time and ground contact are though.
I'll close this issue but if you find any resources on their definition and units of measurement, please re-open and I'll take a look and see how can they be incorporated in trackeR.
As long as there is no fit
support, there is no use to reopen the issue, I guess. But I got curious and looked into it some more. Adding below both for the sake of sharing (what I think is) information and, if I may, to argue for the added benefit of adding fit
support.
Ground contact is stance_time
. See p. 449 in this article, stance, "time with feet in contact with the ground". stance_percent
is simply percent of time with feet in contact with the ground. Furthermore, avg_stance_time
as reported above is equal to "ground contact time" as reported for said activity at Garmin Connect.
Stride does indeed look to be a derived quantity, based on cadence and speed. Of note is that "For running, cadence is recorded as cycles per minute, as opposed to strides per minute, where one cycle is defined as a stride with the left foot plus a stride with the right foot. If your cadence is listed as 90, it means it is 90 cycles per minute, which equals 180 strides per minute." (source)
So if I use enchanced_speed: 6.75 [km/h]
(1.875 m/s = 112.5 m/min) and cadence: 85 [rpm]
(170 steps / min). Maybe stride would be something like 112.5 / 170 = 0.661764705882353 (for my first step, mind you! 😂).
Looking at Garmin Connect, it at least seems to agree with steps / min (listed as 171) for the first record:
But to get back to stride. Average stride, as reported by Garmin Connect for the activity, is 1.15 meters. If I look at the session data, and take enhanced_avg_speed: 11.5596 [km/h]
(3.211 m/s = 192.66 m/min) and avg_running_cadence: 83 [strides/min]
(166 steps / min). Then stride would be (192.66 / 166 =) 1.16 meters, which is close enough to make the point, I think?
... Or actually, since cadence is included in tcx-files --- as opposed to vertical movement and ground contact --- could I persuade you to add data column/row for stride? Or is derived data a no-go?
By the way, you wouldn't happen to have a chatroom of any kind, an email-list or some such? Trying to tinker with the package, but struggling to see --- no doubt because I'm still too unexperienced with R --- how I could, for instance, filter a trackeRdata object with +2500 sessions for workouts to get summaries per year, month, or whatever I'd be interested in at the moment. It's not feedback or bug reporting etc, so filing an issue isn't relevant. Rather looking for a forum to discuss usage? (Or where it has been discussed before, so I can learn from previous discussions.)
Thanks for the resources and the analysis!
We have a strict policy on what features are supported in trackeRdata objects. The current ones are common features across devices/formats, well-defined, and there is consensus on their units of measurements. See Section 3 of trackeR vignette for what features are currently included.
Stride as defined above is not as fundamental as speed, distance, temperature, etc, so I am putting a very low priority in its inclusion.
For now, I am taking note to provide a simple interface for users to compute composite metrics (like stride) themselves. trackeRdata objects are lists of multivariate zoo objects, so you can currently compute composite features using lapply
, e.g. continuing from your example above
my_run <- read_container(file, type = "tcx")
# Assuming meters per second for speed and steps per minute for cadence
strides <- lapply(my_run, function(x) (60 * x$speed) / (x$cadence_running))
plot(strides[[1]])
If you had a second session in my_run
, then just plot(strides[[2])
, etc. Not as friendly as the plot
method for trackeR objects but it does the job.
There is currently no mailing list about trackeR/trackeRapp (and, admittedly, github issues are not the right medium for support and discussion about usage). I suspect StackOverflow would be the right place nowadays (and I need to join that!), so feel free to start some discussion there. I'd recommend the tags r/trackeR and r/trackeRapp.
Having said that for session summaries just do s <- summary(my_run)
😉. The result is a data frame (try as.data.frame(s)
) with one row per session (just 1 for my_run
above), it has a plot method (see ?plot.trackeRdataSummary
), etc. The session starts and session ends are there for you to aggregate as you wish.
If you care about how trackeR works then a good place to start is the vignettes at trackeR's CRAN page.
# Assuming meters per second for speed and steps per minute for cadence strides <- lapply(my_run, function(x) (60 * x$speed) / (x$cadence_running))
In summary-data, using strideAvgMoving = (60 * avgSpeedMoving) / (avgCadenceRunningMoving * 2))
I get the same results as shown on Garmin Connect for average stride length. Note * 2
for cadence (see earlier post, above).
Thank you for the tips and pointers! Much appreciated.
# Assuming meters per second for speed and steps per minute for cadence strides <- lapply(my_run, function(x) (60 * x$speed) / (x$cadence_running))
In summary-data, using
strideAvgMoving = (60 * avgSpeedMoving) / (avgCadenceRunningMoving * 2))
I get the same results as shown on Garmin Connect for average stride length. Note* 2
for cadence (see earlier post, above).
OK. Thanks for checking in Garmin Connect. That's reassuring.
It seems that the code snippet does the right thing in computing strides if the assumption in the comment holds (# Assuming meters per second for speed and steps per minute for cadence
). But it does not for the tcx file you kindly provided, and the units get assigned wrongly to "steps/min" when importing to trackeR. So, I'd like to assess the need for adding a new unit for cadence.
Apparently cadence in the tcx file is measured in rpm. Do you know if that stands for "rounds per minute" or what it stands for if not, and what device it came from? Typically, garmin tcx files had cadence in steps per minute when I last checked.
This looks related: https://forums.garmin.com/apps-software/mobile-apps-web/f/garmin-connect-web/104684/cadence-in-exported-file-wrong
It seems that the tcx file exported from Garmin connect some times has 2 steps/min = 1 revolution/min
under cadence, while the dahsboard shows steps per minute.
Apparently cadence in the tcx file is measured in rpm. Do you know if that stands for "rounds per minute" or what it stands for if not, and what device it came from? Typically, garmin tcx files had cadence in steps per minute when I last checked.
Not sure about Garmin tcx -files in general, but all of my tcx-files seem to have cadence
recorded as half of steps per minutes, as shown on Garmin Connect. Yes, rpm
should be rounds per minute. (Note, that is the unit given in the fit
file, as per fitdump. Rpm isn't mentioned as a unit in any tcx-file I've seen.) Rounds or revolutions --- cycles in any case; left plus right (see earlier comment).
My fit files have been recorded with a Forerunner 620. Earlier I provided a locally converted tcx. Just to be sure, I downloaded the same workout from Garmin Connect as well; available here. Same numbers for cadence (although recorded as RunCadence
instead of just plain Cadence
).
Also, found another fit library, Garmin-Fit, written in Perl. It has a fitdump
-tool that is a bit more verbose than the previous one I mentioned, but the numbers (half of steps per minute) and units (rpm) were the same as previously mentioned.
Apparently, "the FIT documentation is included in the FIT SDK archive" (source). I have downloaded the zip, but so far I haven't found documentation which I can read. 🤷♂️
OK, I found something readable eventually. Go here; download FIT SDK 21.30.00
. It includes a file D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 2.4.pdf
which states (pp. 31, 32, 39) that the unit for cadence is rpm. Doesn't specify the meaning of it or any some such though. So nothing new, really.
Thanks, @krissen for digging this up! That's most helpful as you've given me some resources to look at. Next version of trackeR may get a new unit for cadence in running, and I am considering names for it.
Revolutions per minute, rounds per minute, cycles per minute sound too cycling-focused to me, and may cause confusion. Some resources measure running cadence in steps one foot takes per minute (e.g. here), which is accurate albeit long. Have you seen that before?
Revolutions per minute, rounds per minute, cycles per minute sound too cycling-focused to me, and may cause confusion. Some resources measure running cadence in steps one foot takes per minute (e.g. here), which is accurate albeit long. Have you seen that before?
Agreed, rounds per minute sounds cycling-focused. Although rpm
is the unit used internally in FIT-files, and Cadence
in TCX-files, Garmin connect mentions "Running cadence (spm)" in workout information.
No doubt, "spm" is short for steps per minute. Thus, spm
sounds like a reasonable unit. Whether it would be spelt out as "Steps per minute" or "Running cadence" is a matter of taste, I guess. "Running cadence" keeps it closer to the unit as recorded in the TCX and information from Garmin connect, whereas "Steps per minute" is, perhaps, more transparent.
The images above was from the example-workout I provided before, opened in Garmin connect. The following is using data from the same workout, acquired via trackeR:
> summaries$avgCadenceRunning[[2768]] * 2
[1] 166.6266
The headline for this section in Garmin connect is "Running dynamics", under which running cadence, stride length, vertical movement, and ground contact time is listed. To reiterate what we've discussed above, stride length is derived data. Currently I'm calculating it for my own uses with (60 * avgSpeedMoving) / (avgCadenceRunningMoving * 2)
. Vertical movement and ground contact time data is found in fit-files, unfortunately not in tcx-files.
> (summaries$avgSpeedMoving[[2768]] * 60) / (summaries$avgCadenceRunningMoving[[2768]] * 2)
[1] 1.155693
Of note is that if I calculate with avgSpeed
and avgCadenceRunning
instead of ...moving I get different results as compared to what Garmin Connect reports. If I use avgSpeedMoving
and avgCadenceRunningMoving
I get the same numbers from Garmin connect and trackeR alike. (Compare with the first image, above, "medelsteglängd", average step (or stride) length.) Not sure if the same is true for cadence as well, as the results for avgCadenceRunning
and avgCadenceRunningMoving
is pretty much the same.
Thanks. trackeR currently has steps/min for running cadence units. I think I will go for steps/min/foot for what garmin report as rpm.
On the difference between avgSpeedMoving and avgSpeed: trackeR detects periods where there is no movement and computes the average speed throughout the session (avgSpeed) and by excluding the periods of no movement (avgSpeedMoving). So, Garmin does the right thing to calculate stride length only on the periods that there is movement.
See ?summary.trackeRdata
for how trackeR determines periods that there is no movement. You can configure the thresholds that trackeR uses to detect movement explicitly through the moving_threshold
argument.
Would be great if there would be data columns for stride and ground contact time?