Custom interval fields

Intervals.icu now supports custom fields for intervals. You can enter the values manually (e.g. from a test of some kind) or compute them using JavaScript code. Click “Fields” on the activity timeline page and then “Add Field” to create a new field or search for an existing field:

Note that the fields are specific to the athlete being edited. So if you are coaching people, create fields for yourself and then use the search button to add copies to your athletes.

You can click the values to edit:

Sample script for distance per stroke:

interval.average_stride * 2

The script has access to the following objects:

  • interval: the interval being updated
  • activity: the activity being analysed
  • athlete: for the activity
  • streams: the power, heart rate and so on traces for the activity
  • sportSettings: for the sport of the activity
  • wellness: for the day of the activity
  • field: the field being evaluated

The last expression in the script is the value stored for the field.

Variables are implicitly declared. Don’t use ‘let’ or ‘var’ etc… The script is invoked once for each interval using the same sandbox and this fails if it declares fields.

If you do need to declare things wrap the script in a block:

{
   activity.average_stride * 2
}

The JavaScript code runs in a sandbox on the server when the activity is analysed. If anyone figures out how to escape that sandbox I want to know first!

The data model is here:

The custom interval fields are also available as columns on the activity data page. You can edit the values on the grid:

8 Likes

This is awesome work!!! Thank you David!

1 Like

This is amazing :heart_eyes:

Having custom code is setting intervals.icu apart from the competition.

Potentially there could be a forum thread with a library of useful code.

7 Likes

Thank you, looks awesome !

Is “VAM” an available stream ?

2 Likes

No you would need to compute that from “fixed_altitude” (altitude with elevation correction applied if needed and gaps interpolated).

2 Likes

Hi @david,

Is it possible to add core_temperature as a field? If so, what script would I need to add to get this to work?

Thanks

Sure. I added a new public interval field “Average Core Temp” and added that to your interval fields. You should see it in the “Fields” list. The script looks like this:

temp = streams.get("core_temperature").data
tot = 0
c = 0
for (let i = interval.start_index; i < interval.end_index; i++) {
  let v = temp[i]
  if (v) {
    tot += v
    ++c
  }
}

c ? tot/c : null

I also added “Max Core Temp” if that is what you are after:

temp = streams.get("core_temperature").data
max = 0
for (let i = interval.start_index; i < interval.end_index; i++) {
  let v = temp[i]
  if (v > max) max = v
}

max > 0 ? max : null
3 Likes

Has anyone figured out if this can be used to get di2 gear info ?

Hi @david
I have created Interval Field for swimming: “Interval Swim Stroke” with select list. Is it possible to map fit file for this specific stroke type ? I can find it in file at the end of each inerval:

If so, what script should I add to get this to work?

That is on the length messages and there isn’t a way to get data out of those onto the intervals yet.

I have made custom fields called “Running time” and “Running time %”, similar to the run/walk detection in Garmin. Thought some of you might like it :slight_smile:

There are fields both for the activity as a whole, and for each interval.

Here’s what it looks like:

It defines running as anything over a 60 cadence, and walking as anything over a 10 cadence. It will also ignore any data during the warmup and cooldown periods defined for your running activity.

The running time calculated is usually a little lower than the one shown by Garmin - not sure why but its usually <1m of difference.

2 Likes

@david I’m trying to extract Stryd average Vertical Oscillation out of fit file data for my intervals and have been unsuccessful so far. Any advice?

You will be able to do that when I finally find time to complete support for mapping custom fields from records to activity traces. You will need to create a trace for it and then a custom activity/interval field to calculate the average.

Dear all,
I am trying to add an interval field which should be apparently pretty simple:
(Work above FTP/Total Work*100) > its simply the percentage of W>FTP to the Wtot for that interval.

I have found the “joules_above_ftp Integer” on the script page, but I must confess, my scripting-skills are pretty poor :worried:
Any help is much appreciated.

thanks
alfred

@david:
brief question to your “All Work >FTP” field:
it is described as “…This measure includes the below the line portion when operating at or above FTP.”

Does this mean that power AT FTP is also accounted for (i.e. FTP 250W > the script also calculates when working at 250W and not starts at 251W as the Work>FTP would do?).
And what means “…below the line portion…”? Does it also calculate 249 or 248, which is, by definition below FTP. Is there any trade-off in the script (e.g. if power is below FTP for xxx seconds > then calculate > else not).

Sorry for my simplified coding language, hope the question is clear enough.

best
alfred

There are 2 possibilities:

  • You only take the Work that has been done at or above FTP and only that portion
  • You take all Work done when intensity is equal or above FTP

The script does “if (w >= ftp) {” so yes work done at FTP counts. I think this script will do:

{
interval.joules_above_ftp * 100 / interval.joules
}

thank you David, script works as required, and also @MedTechCD for stepping in.

re to (w>=ftp): this makes a significant difference compared to (w>ftp), in the example below 35 vs 215kJ

image

Have to reconsider on whether 1Watt up or down can make such a difference. But then again over 3h…

cheers
alfred

hi again, sorry a little too late yesterday evening to think clear :sleeping:
Soon became clear afterwards that “All Work>FTP” calculate ALL power*t, whereas “W>FTP” use the typical Wbal calculation where W=(P-FTP)*t.
The former is obviously much higher.

cheers
alfred

That’s what I wanted to point out with this remark :wink: