Building workout using zone number instead of percentage range

Great update, thanks! :slight_smile:

I think there is a little bug introduced, it looks like it’s not counting Z1 anymore:
Screenshot 2022-04-14 105844

Until yesterday everything was ok.

EDIT: oh, I understand what is happening here. My “descriptions” (Z3, Z4,…) are now clashing with this new functionality, probably triggering this workout to be interpreted as power based.

Add Z1 before your Warmup line.
If I copy your workout, it shows Z1 once it is added.

  • Warmup Z1 10m 60-58% LTHR

3x
Z3 2m 83-94% LTHR

Edit: or get rid of the Z1/2 and only use

  • 10m 50-68-% LTHR

3x

  • 2m 83-94% LTHR


1 Like

Curious… this is a Bike Workout that’s HR Based? (Indoors on Turbo or outdoors?)

Yes, outdoors. It’s not ideal, but good enough for the start without powermeter :slight_smile:

1 Like

Drat … that is going to cause some problems with existing workouts. The default is power so if you have “Z2” in a step for an existing HR based workout you now also have power. Intervals.icu will pick power or HR for the workout depending on the settings of the athlete.

@david for Zone based workouts targets, I noticed in the JSON file it is marked as (for a Z2 workout)

“duration”:4800,“power”:{“value”:55,“units”:"%ftp"},“hr”:{“value”:2,“units”:“hr_zone”}}

Where would I be able to get the definition of the Zones? I hope that you have planned to add the zones definition somewhere in the JSON file downloads (similar to how you’re already adding LTHR and MAX_HR and the like into the JSON file)

Thanks

Which endpoint are you getting that from?

From this as it’s easier to download and do quick checks.

They will be different from a direct download vs getting it from the API?
let me check.

For a workout like this:

{“duration”:600,“steps”:[{“power”:{“value”:2,“units”:“power_zone”},“duration”:600}]
{“id”:“Z2”,“zone”:2,“name”:“Z2”,“color”:"#009e00",“max”:75,“minWatts”:111,“maxWatts”:150,“percentRange”:“56% - 75%”,“secs”:600}

So, it should be plausible to get the Power Zone Ranges from the id:Z2

Having a Power Zone range for indoor turbo training would be troublesome. Looks like intervals.icu just provides the middle of the zone 65.5 % ((56+75)/2) for MRC. Which is fine. ERG mode needs an actual target rather than a range. Edit: Supported now. BreakAway can now parse Power Zone Workouts using

  1. if not a ramp, will use the middle of the zone as Power Target
  2. if ramp, we will ramp from bottom of zone to top of zone (eg: from 56% to 75% of Power Z2)

For Z2 HR workout

This is what I get from the API Endpoint as well as the Download JSON.

[{“duration”:600,“hr”:{“value”:2,“units”:“hr_zone”}}]

API EndPoint - https://intervals.icu/api/v1/athlete/(athleteId)/events/(workoutId)/download.json"

Screenshot 2022-04-15 at 12.34.26 PM

Drats… I just got caught by this as well…
Changing it to Zone3 instead of Z3 worked.

using plain text is indeed going to be more challenging

I have update the “JSON” workout download to include the actual watts, bpm and mps values for power, hr and pace targets in steps. These are calculated using the zones etc for the athlete.

{
  "duration": 3600,
  "ftp": 290,
  "target": "POWER",
  "steps": [
    {
      "duration": 3600,
      "power": {
        "value": 2.0,
        "units": "power_zone"
      },
      "hidepower": false,
      "_power": {
        "value": 190.0,
        "start": 162.0,
        "end": 218.0
      }
    }
  ],
  "options": {}
}

The resolved values are in _power, _hr and _pace.

Absolute (not a range) power, pace and HR targets are converted into a range using a percentage of value (powerRange=2.5, paceRange=2.5, hrRange=1.5). You can specify these as query parameters to override.

If the workout has steps using power and/or HR and/or pace then the athletes preferences for the sport are used to choose how to execute the workout. This is in the “target” field. All targets are resolved in any case but maybe someone wants to use this.

So you don’t have to mess around with the zones to try calculate power etc…

1 Like

some observations and quick question.

  1. TARGET
    You mentioned that this is in the Athlete’s preference for the sport. Then this would not have any impact? (I tried on a workout that has both Power and HR, and used “HR” and it still shows “target: POWER”. Only when I removed all references of power, then the workout becomes “target=HR”. This is the intended behaviour? )

    This may become useful as I too am trying to differentiate between w HR Based workout (No Power Targets at all), a Power Based workout (no HR Targets at all) and a Hybrid Power + HR
    based workout.

    Hybrid power + hr workout = some parts user is using Power to control the trainer, some parts, user is asking for HR to control power targets. I may also expand this to using slope targets instead of wattage targets which would make HR Based training simpler (something like riding outdoors - and users get a > HR target beep or < hr target beep)

  2. What’s the usage of “hidepower”?

  3. Looks like you’ve removed all the (power)zoneTimes, maxHR, LTHR, FTP values…
    Would it be at all possible to re-instate the maxHR / LTHR / FTP . I currently store power based workouts as % of FTP as it easier to scale as user’s FTP changes. (The workouts don’t have to change. ) I’m doing the same thing for HR Based Training as well. Basically, this change broke everything I’m been testing/coding for past ~3weeks lolz.)

    If you could re-instate the maxHR/LTHR/FTP, then I can actually back-calculate the actual watts/bpm/mps into %. power_zone and hr_zone and it can be “best of both worlds” in terms of flexibility. :pray:

Edit: Stupid me… you’ve provided %FTP and %HR values as well as the corresponding actual watts/bpm… i think I can work w this… just need to refactor a bunch of stuffs… "dont’ change anything yet"

  1. I don’t quite understand the powerRange/hrRange parameters. How does the workout that uses this look like?

Oops I didn’t realise I got rid of those fields. They aren’t supposed to be there actually and sometimes would have been missing. The “ftp” one is good and is chosen from the athlete’s settings for indoor/outdoor workouts.

I have added “sportSettings” which gives you all of the athletes zones etc… I have also restored “zoneTimes”. Note that this has different format for power and HR/Pace workouts. The power one includes extra fields for legacy reasons. They will probably go away. Just use “id” and “secs”.

An athlete can configure how they would like to do workouts in /settings:

So for me if a workout has power and HR and it gets uploaded to my Garmin the power targets will be used. The “target” field is what was chosen after applying this setting and looking at the workout.

“hide power” is a flag for Zwift that disables the average power display during the workout. It can be set in the workout editor.

The powerRange etc. parameters are based on these settings for Suunto/Garmin:

Except that they are always applied regardless of indoor/outdoor.

Here is an HR example:

{
  "description": "Easy toddle around the block.",
  "duration": 3150,
  "sportSettings": {
    "id": 56086,
    "athlete_id": "2060784",
    "types": [
      "Run",
      "VirtualRun"
    ],
    "warmup_time": 1200,
    "cooldown_time": 600,
    "use_laps_for_power_intervals": false,
    "lthr": 178,
    "max_hr": 192,
    "hr_zones": [
      147,
      156,
      165,
      174,
      179,
      184,
      192
    ],
    "hr_zone_names": [
      "Recovery",
      "Aerobic",
      "Tempo",
      "SubThreshold",
      "SuperThreshold",
      "Aerobic Capacity",
      "Anaerobic"
    ],
    "hr_load_type": "HRSS",
    "threshold_pace": 2.7777777,
    "pace_units": "MINS_KM",
    "pace_zones": [
      77.5,
      87.7,
      94.3,
      100.0,
      103.4,
      111.5,
      999.0
    ],
    "pace_zone_names": [
      "Zone 1",
      "Zone 2",
      "Zone 3",
      "Zone 4",
      "Zone 5a",
      "Zone 5b",
      "Zone 5c"
    ],
    "pace_load_type": "RUN",
    "gap_model": "STRAVA_RUN",
    "elevation_correction": "AUTO",
    "use_gap_zone_times": true,
    "load_order": "POWER_PACE_HR",
    "tiz_order": "POWER_HR_PACE",
    "workout_order": "POWER_HR_PACE",
    "default_gear_id": "g152587",
    "other": false,
    "eFTPSupported": false,
    "use_distance_for_intervals": false
  },
  "target": "PACE",
  "steps": [
    {
      "duration": 3150,
      "distance": 7000.0,
      "pace": {
        "value": 80.0,
        "units": "%pace"
      },
      "_pace": {
        "value": 2.222222089767456,
        "start": 2.1666665375232697,
        "end": 2.2777776420116425
      }
    }
  ],
  "zoneTimes": [
    {
      "id": "Z1",
      "secs": 0
    },
    {
      "id": "Z2",
      "secs": 3150
    },
    {
      "id": "Z3",
      "secs": 0
    },
    {
      "id": "Z4",
      "secs": 0
    },
    {
      "id": "Z5",
      "secs": 0
    },
    {
      "id": "Z6",
      "secs": 0
    },
    {
      "id": "Z7",
      "secs": 0
    }
  ],
  "options": {}
}

Thanks for that. Finally managed to refactor all of it based on this new format. Hope it doesn’t change :-p

I’m taking maxHR and LTHR from SportSettings and using the FTP from the main block.

Noted for the “hide power” and “powerRange” parameters. Not using these.

Please help to verify if this is the intended behaviour of this workout and the resultant JSON.
Note that for ramp of 100-50% should have Start: 100% and End:50% (correct in power, but _power is flipped)

This is what I ended up with when I plot it.
Screenshot 2022-04-16 at 2.01.46 AM

  "target": "POWER",
  "steps": [
    {
      "duration": 300,
      "ramp": true,
      "power": {
        "start": 100,
        "end": 50,
        "units": "%ftp"
      },
      "_power": {
        "value": 150,
        "start": 100,
        "end": 200
      }
    },
    {
      "duration": 300,
      "ramp": true,
      "power": {
        "start": 50,
        "end": 100,
        "units": "%ftp"
      },
      "_power": {
        "value": 150,
        "start": 100,
        "end": 200
      }
    }
  ],

No thats a bug. Will fix!

1 Like

Thanks… I really need to sleep… 3am here :rofl:

@david The Zones don’t match using Zone Ranges

Same for HR Zones

i did a cursory check on the JSON downloaded from web-frontend and seems to also be mismatched.

yday i reported the mismatch in the ramp start and end for Power. Seems like it’s also affecting the JSON for HR as well. After parsing, the intervals looks like these

pwrInt:[[0.0, 50.0], [5.0, 100.0], [5.0, 50.0], [10.0, 100.0]]
hrInt :[[0.0, 116.0], [5.0, 232.0], [5.0, 116.0], [10.0, 232.0]]

Sorry about digging so much into this, been doing A LOT of different permutations to test my “parsing engine”. It was SO FUN :yum:

My next headache is how to parse HR only workouts

  1. due to the existent of HR ramps.
  2. Lack of Power Based Intervals that confuses the Indoor Turbo Trainer (and basically the entire architecture of the app)

Hi David,

How this zone range will translate to Garmin’s range settings?

Tks,

image

Intervals.icu resolves zones to actual watts/bpm/pace before sending to Garmin/Suunto etc…

So, if I understood correctly, in the exemple bellow, Intervals will send ROUND((136+123)/2) and the specified range on settings, is that it?

tks.

No it will send 123 to 136 because the zone already defines a range. The ranges in settings are used for fixed steps.

Hi,

I’ll give a new try on both steps bellow because back on June 2021 I couldn’t make the secondo to work ( FTP/MMP/eFTP how in calculates - #10 by Gato_Felix) on Garmin Fenix 5x.

Tks,

not to mention they ended up being slight different on the top end