Data Field: AppBuilder

By user request, this app lets you define your own data field, based on a simple math formula like cadence / 2.

If you want to get fancy, there's conditional expressions (like IF in Excel), functions for data analysis (like MIN and AVG), and the data field can also display the text of your choice. The resulting data can be (optionally) written to the activity FIT file.

With AppBuilder, you can implement almost any field that involves math, such as: calculating normalized power and saving the data to the FIT activity file, showing the average pace for even-numbered laps, or recording the amount of time you sprinted.

Full documentation and examples here:
http://ciq-appbuilder.blogspot.com/

AppBuilder 5:
Now with new features! AppBuilder 5 is a completely new app, so please check it out in the store if you are interested in any of the new features.
https://apps.garmin.com/en-US/apps/fd690281-9c22-4fee-a81e-3b7f39aa67c5

- Store up to four formulas per app. Switch between formulas directly on the watch, without using a phone or PC. With four clone apps, you can store up to 16 formulas total
- User variables. Allows for powerful formulas where information can be stored at one point, like the start of a lap, and used later. e.g. Lap elevation change
- Improved timeavg() options. Allows for simpler, more flexible normalized power function
- More functions and variables

4 clones of AppBuilder are available in the store, so you can have 2 formulas in the same activity
  • Love This Data field averaging speed great idea i will try it tomorrow may be you can add color changing for fonts something like if speed more than something change color to red
  • Very nice app!
    Is there the possibility to write the custom data field to the fit file? or overwrite some of the existing fit data (power for example)?
  • Very nice app!
    Is there the possibility to write the custom data field to the fit file? or overwrite some of the existing fit data (power for example)?


    Custom data would definitely be possible. Don't think it's possible to overwrite native fields, though. I'll put it on the wishlist!
  • Love This Data field averaging speed great idea i will try it tomorrow may be you can add color changing for fonts something like if speed more than something change color to red


    Thanks! I hope it'll be useful in some way. It is still very much a work in progress, as I'm trying to figure what makes sense and what's useful.

    Unfortunately this is a "simple" data field, which means that I only get to control the value that is displayed and not much else. Given that I've already gone over the memory limits for older devices, I don't think it's possible to have all these features in a non-simple data field which lets you have complete control over its appearance.
  • Unfortunately for us developers, gradient calculation is not that simple: to calculate gradient in it's simplest form you need altitude difference divided by distance difference that's right, but this should be calculated over a distance difference around 100 meters for a value to have any practical meaning, averaging of previous second differences over a period of time will give you mathematically different result, I'm afraid.


    Thanks again! I went ahead and created functions PREVT(v, x) and PREVD(v, x) for retrieving the last sample from x seconds/metres ago.

    So this should be a decent elevation grade formula:
    (altitude_raw - PREVD(altitude_raw, 100)) / (distance_raw - PREVD(distance_raw, 100)) * 100

    The only gotcha is I don't store more than 10 or so samples at a time; hopefully it should be enough for most purposes.
  • That's a great idea! Thanks. I don't think there's a native value for elevation grade, but we can calculate it.

    I defined a function PREV(x) which returns the last sampled value of x (from 1 second ago).

    You can calculate the gradient as follows:
    (altitude_raw - PREV(altitude_raw)) / (distance_raw - PREV(distance_raw)) * 100

    The 30s average (for example) would be:
    TIMEAVG((altitude_raw - PREV(altitude_raw)) / (distance_raw - PREV(distance_raw)),30) * 100

    ---

    Edit:
    As easuvorov pointed out, the two formulas above don't provide the best results.

    I did implement a better way to calculate the gradient (over the last 100m), but I haven't tested it in real life (yet). You should be able to use this formula:

    (altitude_raw - PREVD(altitude_raw, 100)) / (distance_raw - PREVD(distance_raw, 100)) * 100

    (Thanks easuvorov!)

    Also, some watches have a native field for grade, but it isn't available to apps afaik.


    Thank you for adopting my opinion. :)
  • No worries! Thank you for the useful suggestion. When I started this app I wasn't sure if anything useful could be calculated which we can't do in our heads [Cadence / 2 lol] or which isn't available natively. Then I realized that max elevation isn't available on the Vivoactive HR or 735, for example.

    I did some more testing in the simulator (and thought about a little), and the PREVD(), PREVT() functions work pretty well, as long as you don't expect with the exact distance or time difference. Which is why you would use it twice, as in the example:
    (altitude_raw - PREVD(altitude_raw, 100)) / (distance_raw - PREVD(distance_raw, 100)) * 100

    PREVD(distance_raw, 100) will usually be a little over 100 metres, but never exactly 100.

    I've yet to to test that formula against the native grade. But I noticed that you seem to get a value for native grade immediately, without walking/running 100 metres. Whether that means they use a different algorithm for the first 100m I can't say. Similar to how lap pace is actually instant pace for the first little bit.

    With my formula above, you will have to move over 100m before you see anything.

    I also added a few new functions which I might even use myself:
    • LAPMIN[x], LAPMAX[x]: get min/max of x for current lap. e.g. Max HR for current lap = LAPMAX
    • AVG[x], LAPAVG[x]: get average of x for activity or current lap (ignoring zeros)
    • AVG0[x], LAPAVG0[x]: get average of x for activity or current lap (counting zeros)
    • lapCount: Number of laps completed so far (i.e. 0 during the first lap, 1 during the second lap, etc.)
    • lapDistance, lapTime

    I'm probably going to hit pause for a few days unless there are bug reports. But keep the suggestions coming!
  • Great Idea.

    Woukd it be possible, to have different fields with different formulas?
    I was thinking of one field showing me the distance and one showing me meters to climb to the next aid station.
  • Many thanks for building this!

    One of the uses I had in mind when I suggested this on the forum was to fix a bug in the Row app that Garmin stubbornly refuses to fix. The bug is that the distance per stroke gives twice the correct value. Having worked through the maths the formula turns out to be really simple and obvious.

    Rowing distance per stroke (DPS) = 500 / ( strokes per minute x rowing pace in minutes)

    Rowing pace in minutes is minutes per 500m

    Given that Cadence_raw = revs per minute and Speed_raw = metres per second, then

    Speed_raw * 60 = metres per minute
    1/(Speed_raw * 60) = minutes per metre
    500/(Speed_raw * 60) = minutes per 500m = Rowing pace

    DPS = 500 * (1/Cadence_raw) * (Speed_raw * 60/500)

    DPS = 60 * Speed_raw / Cadence_raw
    ... which should have been obvious!

    Phew. Now to put it in the app!

    PS: Not sure why Garmin find this formula so difficult to get right?? It is right in Garmin Connect, but wrong in the fenix 3.
  • My app didn't work :(

    Do I need to use a different field to get the stroke rate in the rowing? It is the same stroke rate as is used in the swim app.