trackerproject / trackeR

Infrastructure for Running, Cycling and Swimming Data from GPS-Enabled Tracking Devices
http://cran.r-project.org/package=trackeR
90 stars 7 forks source link

Add data column for stride / ground contact #21

Closed krissen closed 4 years ago

krissen commented 4 years ago

Would be great if there would be data columns for stride and ground contact time?

ikosmidis commented 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).

krissen commented 4 years ago

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.

krissen commented 4 years ago

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]
ikosmidis commented 4 years ago

This looks like a workout summary entry with derived quantities, is that right?. A few Qs:

  1. What are the stride and ground contact time above?
  2. How can I play with fitdump (never heard of that before)
krissen commented 4 years ago
  1. It's a script provided by python-fitparse.

  2. 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.

ikosmidis commented 4 years ago

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.

krissen commented 4 years ago

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:

Skärmavbild 2020-05-15 kl  21 40 16

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?

krissen commented 4 years ago

... 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.)

ikosmidis commented 4 years ago

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.

ikosmidis commented 4 years ago

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.

krissen commented 4 years ago
# 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.

ikosmidis commented 4 years ago
# 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.

ikosmidis commented 4 years ago

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.

krissen commented 4 years ago

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. 🤷‍♂️

krissen commented 4 years ago

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.

ikosmidis commented 4 years ago

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?

krissen commented 4 years ago

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.

Skärmklipp 2020-05-20 14 48 43 Skärmklipp 2020-05-20 14 47 41

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.

ikosmidis commented 4 years ago

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.