Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate TRIMP score for running? #48

Open
misev opened this issue Sep 2, 2020 · 7 comments
Open

Calculate TRIMP score for running? #48

misev opened this issue Sep 2, 2020 · 7 comments

Comments

@misev
Copy link

misev commented Sep 2, 2020

Is this something that could be calculated and shown in a column for running activities with heart rate data?

I have a small python script that can calculate it given a FIT file, would be nice if it could be integrated into ActivityLog2 though.

from fitparse import FitFile

def compute_frac_trimp(seconds, hr, minhr, maxhr, gender):
  minutes = seconds / 60.0
  hrr = (float(hr) - minhr)/(maxhr - minhr)
  ret = minutes * hrr * 0.64 * math.pow(2.71828, gender * hrr)
  return ret

def compute_trimp(file_name, minhr, maxhr, gender):
  ret = 0
  hr = None
  ts = None
  old_ts = None

  fitfile = FitFile(file_name)
  for record in fitfile.get_messages('lap'):
    sport = record.get_value('sport')
    if sport != SPORT:
      return 0

  for record in fitfile.get_messages('record'):
    for record_data in record:
      if record_data.name == 'heart_rate':
        hr = record_data.value
      elif record_data.name == 'timestamp':
        old_ts = ts
        ts = time.mktime(datetime.datetime.strptime(str(record_data.value), "%Y-%m-%d %H:%M:%S").timetuple())
        if old_ts and hr:
          trimp = compute_frac_trimp(ts - old_ts, hr, minhr, maxhr, gender)
          ret += trimp

  return ret
@alex-hhh
Copy link
Owner

alex-hhh commented Sep 2, 2020

Calculating the TRIMP score requires changes to the source code of the application.

While calculating the TRIMP value is easy enough, there are several options for displaying it, ranging from showing it in the session inspector only (easy), storing it in the database and showing it in the activity list + some reports (medium) and all the way of implementing a custom metric definition and storage mechanism -- this would be a lot of work, but would be the most flexible solution.

However, I am unable to implement any of these things in the short to medium term, as I have little time to work on ActivityLog2 and what time I have other things planned. I will leave this issue open, for possible future implementation.

@misev
Copy link
Author

misev commented Sep 2, 2020

I'm not really familiar with Racket, but I might have a look at the code in free time for the easy solution at least as a first step.

@alex-hhh
Copy link
Owner

alex-hhh commented Sep 2, 2020

If you decide to try that, here are some things to get you started. This function below will calculate TRIMP, and it is similar to the Python one. You can place the code in a file in the "etc" folder of the source code. The "al-interactive.rkt" library will give you access to the same database that ActivityLog2 is using, so to test it out, find the session id for the session you want (use the "Activities / Copy Session Id To Clipboard..." in the application), than use the call:

(compute-trimp (sid->df SESSION-ID) 60 190 #t)

Once you got that working and are happy with it, you will need to place the function in an appropriate file (or create a new one) inside the application (the "rkt" folder), as the "etc" folder and "al-interactive" are only for testing things out. You can than hook this function to the session inspector to display the value by adding an entry here:

(badge-field-def "Aerobic Decoupling: "

There is a lot more work to get this "production ready", such as getting the min / max heart rate from the sport zones and caching values to avoid recalculating it every time, but for your own use, it might be sufficient.

#lang racket
(require "al-interactive.rkt")

(define (is-running? sport)
  (equal? (vector-ref sport 0) 1))

(define (compute-trimp df min-hr max-hr is-male?)
  ;; NOTE use the "elapsed" series if you want to compute TRIMP over periods
  ;; where recording was stopped.  See docs/sesion-df.md for available data
  ;; series.
  (define previous-timestamp #f)
  (define gender-factor (if is-male? 1.92 1.67))
  (if (and (df-contains? df "timer" "hr")
           (is-running? (df-get-property df 'sport)))
      (df-fold
       df
       '("timer" "hr")
       0                           ; initial TRIMP
       (lambda (curent-trimp current-entry)
         (match-let ([(list timestamp hr) current-entry])
           ;; make sure we have a previous-timestamp (not the first call) and
           ;; this is a good sample (good HR).
           (begin0
               (if (and previous-timestamp hr)
                   (let ([dt (/ (- timestamp previous-timestamp) 60.0)]
                         [hrr (/ (- hr min-hr) (- max-hr min-hr))])
                     (+ curent-trimp (* dt hrr 0.64 (exp gender-factor))))
                   curent-trimp)
             (set! previous-timestamp timestamp)))))
      ;; Return false if TRIMP cannot be computed
      #f))

@misev
Copy link
Author

misev commented Sep 3, 2020

That's really helpful, thank you!

Not sure if I should open a separate issue btw, after pulling the latest commits building fails with this error:

$ racket build.rkt
standard-module-name-resolver: collection not found
  for module path: the-application
  collection: "the-application"
  in collection directories:
   /home/dimitar/.racket/7.8/collects
   /home/dimitar/apps/racket/share/racket/collects
   ... [161 additional linked and package directories]
  context...:
   show-collection-err
   standard-module-name-resolver
   module-path-index-resolve
   perform-require!
   for-loop
   finish
   [repeats 11 more times]
   pass-1-and-2-loop
   module-begin-k
   expand-module
   expand-capturing-lifts
   temp98_0
   temp71_0
   compile
   temp65_0
   standard-module-name-resolver
   ...

Reverting back to commit 562cf2b fixes the issue.

@alex-hhh
Copy link
Owner

alex-hhh commented Sep 3, 2020

I would recommend you follow the instructions for building the application here

I think you may have installed some extra packages, I suggest you remove them first. If you don't remember what packages you installed, you can run the command:

raco pkg show --scope user --all

You can than remove the packages using raco pkg remove PACKAGE-NAME. If you follow the instructions from the readme file, these packages will be installed from the git submodules and will track the versions required by the currently checked out version.

Also, given that you are about to work on the application, It might be simpler to just run compile the application, than run it directly (build.rkt is for when you want to build a standalone distribution). This is also explained in the readme file I linked above.

Finally, the readme file is not perfect, if you have any suggestions on how to improve it, let me know.

@misev
Copy link
Author

misev commented Sep 4, 2020

I had installed the dependencies with raco before. It's my fault, the README is fine as is, it warns that this could cause issues. It's just the error message was pretty cryptic to and there was nothing I could find online that would help understand it. After removing the packages and following the instructions for setting up the local catalog it now works fine.

@misev
Copy link
Author

misev commented Nov 21, 2020

I made some attempts to get the TRIMP calculation working but didn't get far unfortunately. Meanwhile I've gotten a Stryd pod and TRIMP is no longer very relevant for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants