user defined expressions
The user defined expression system added with version 2.3.9 is really a fairly fully functional programming system. If you are not happy with programing concepts then best to leave it alone. You are being given great power but you can make the app very battery heavey and unresponsive if you mess up. you can also make the database grow excesivly large so be cautious utill you are sure you have it right.
To access the system long press an item to edit it and choose change item (or add type options) and you get the item chooser list with a sub list specifically for user defined expressions and can use an item here as a standard display item. The item chooser dialog also has a Mange user defined items button. This brings up a separate list where long presses will give you a menu with delete and copy options. Selecting an expression gives you the User expression editor view. If you have an item on the screen with a user expression you can long press the item and select User expression to go directly to the editor view for the expression. The app ships with a number of example expressions.
The user expression editor lets you name the expression which is how it will be listed in the item chooser. You can set the label for the item and how the value will be displayed in an item. If the result of the expression is something IpBike understands units wise you can set this and then have the full units customization available for the item. If it's not sensible to use any standard units you can select None - user and then set the text for the units label explicitly. You can specify the maximum number of characters for the result and the default result value for sizeing the item slot when not active.
Item slots on screen have the concept of potentially having multiple instances. You can set the maximum number of instances for a user defined item. If this is more than one then an item slot with the user defined item set as the item will have a long press What details -> Select which instance which will allows you to set the instance number for that slot. You can use instance in the experssion to get this value.
At the bottom of the page there is a hints view with some basic instructions. This can change if the expression is in error then you may get for instance a list of close match items if your using $item_name. Or possibly a list of functions available. If in error there is a single line summary of the error and the specific bit in error is highlighted in red in the expression editor this normally gives you a good clue about the error but can be miss-leading so treat it with care.
The expression can have arbitrary spacing and new lines. I try and format things so it's clearer what is going on. It really is just an expression but the ',' operator allows you to join together sub expressions which if they have side effects like assigning to a variable means you really have a fully functional programming system. All the standard sorts of operators are available and follow the standard precedents rules but if in any double add brackets '(' ')' to make it clear what you want.
By default the expression is only evaluated if it is on screen or some other expression on screen references it. There is a check box Run always that can be used to force it to run all the time which is what you want for something like a moving average filter that you may bring onto the screen some time later and want to be correct straight away. When being run either with the run always option or because the result is needed the expression is evaluated at most once a second. This matches the update rate of the standard IpBike items and allows you to write things like a moving average filter fairly simply.
Everything is basically a double. For the logical operators 0.0 defined as false anything else is true. The comparison operators will set 0.0 for false and 1.0 for true but like I say anything not 0.0 is considered true. You may need to take care with exact comparisons if your calculation may lead to fractional values.
Unary operators.
+ - Standard mathematical positive and negative operators.
! Logical negation.
Binary operators.
+ - * / The standard mathematical binary operators.
% Standard modulo division remainder operator.
^ The raise to a power operator. e.g. ^2 to square and ^3 for cube but you can also do ^ 3.54.
& | Logical and and logical or operators. The logical operators will short circuit. So the second part of the | want be evaluated if the first part evaluates to true. The second part of a & want be evaluated if the first part is false. Be aware of this if you have side effects in these bits of code.
< <= == != >= > The 6 standard comparison operators.
, Compound expression operator. Lets you concatenate expressions. The result is the second value so normally the first value will have some side effects like assigning to a variable to be of any use. This is the key to more complex program like expressions.
Other operators.
expr1 ? expr2 : expr3 This is the main selection operator. Read it as if expr1 then expr2 else expr3. use it to selct one thing or another. expr2 and expr3 can both be compound expressions using the , operator with side effects. Only one of expr2 or expr3 will be executed.
for ( init_expr ; condition_expr ; increment_expr ) do_expr ; The standard C or Java style for syntax is the only looping construct.
sqrt sin cos tan asin acos atan floor int abs ceil exp log log10 round Standard set of maths functions.$item_name reference an IpBike display item. The item name is not case sensitive. The items generally follow the English names with _ for spaces. As you type in a name the hints section should start showing you a list of items that match allowing you to narrow down to to get the item you want. You will get the value of the item in standard SI units so speeds are in meters per second. Distances in meters, time in seconds. Cadences and heart rate are per minute. Angles are in degrees.
Getting the value of an item can be relatively inefficient as for the vast majority of items it is coming via the string representation you see when you display the item. This limits the precision as well as being slow to evaluate. If you use a value multiple times assign it to a variable the once first. I have a system in place to remove this inefficiently but with 350 items it will take me time to add the code to each one to improve this. I will work on the more obvious items you may use first.
#variable_name defines a variable. Variable name is case sensitive and can contain _ it must start with a character. You need the # to define the variable the first time. Once defined you can just use variable_name. This enables the hints display to help you keep a track of the variables you have defined. If you reference a variable that has not been assigned yet you will get 0.0. I often have code like this with a variable di short for done_init
#di ?
(di=1, more initialization code, and more) :
(The main body of the expression after initialization has happened)
# variable_name [ int_expr ] defines an array variable. int_expr is any expression but it is cast to int to generate the array entry. Arrays are sparse so do not worry about the size but clearly don't go mad as memory usage will go up.
variable_name = expr assign the value of expr to variable_name
variable_name [ int_expr ] =expr assign the value of expr to the array variable_name at position int_expr.
#variable_name# is used to define a variable that will be saved to the trip and lap databse entries. You will typicaly want to have items generating database entries like this have the run always checkbox set. This will run the expression every second with trip and the lap timeframe values comming back for $item_name references. If you have items like this then you will be able to see the final value for the value in the ride details view. The items will be down the bottom after all the standard items. If you have a multi instance item like this then you will get an entery for every instance you have defined. In this list if you press on the item you will go to the user expression editor. You can eddit the expression here if you want and then go back to the history list and long press the ride and select re-evaluate stats to have the data replayed and your edited expression will be used. this is a good flow for working on this sort of expression.
$user_item_name#variable_name allows you to access a variable in a different user defined item. You can only read the value you can not assign to the value. Useful if you write code doing more than one thing. e.g. a moving average piece of code that also works out min and max values over the averaging time period is more efficient to execute and simpler to write than 3 separate bits of code. You can then just reference the variable result for the min or max value to have items that you can display.
instance is a special value returning the instance number for an multi instance item slot. Typically this will be used to index an array with a set of multiple but different results from one expression. See the av_power_periods and max_power_periods walkthrough below for an example.
Range / zone item considerations.
If you want you can referece standard items for the ranges / zones like heart rate and power. Note that if the zone is set per bike then the values and the number of zones can change dynamically as the bike is found. It's best to reset stuff $real_time < 1 so that the reset will only stop being done once the user has pressed start trip hopefully after the bike has been set. tn the The following put the apropriate zione name in front instead of name.
name_zone_count is the number of disserent zones.
name_zone_zone is the current zone.
name_zone_time is the time spent in the zone. You can use array access [] for a specific instance or you just get the curent instance.
name_zone_distance is the distance covered in the zone. You can use array access [] for a specific instance or you just get the curent instance.
name_zone_speed is the average speed in the zone. You can use array access [] for a specific instance or you just get the curent instance.
name_zone_max is the configured maximum for the zone. You can use array access [] for a specific instance or you just get the curent instance.
User input item. (from 2.4.2)
There is a checkbox Show plus minus buttons to enable 2 buttons to be added to the display item. These will let you increase or decreas a variable defined in the user item that you would then reference from some other user expression. The variable to be incremented is has to match the end of the name of the user item. e.g. and item named feed_item1 with a variable item1 as showen in the exaples. You do need to be sure that the variable is set to a valid value to ensure that it can be found by the code that executes when you press the buttons. e.g. have as a minimum #var=var for the expressions. the feeed_ examples save the variable to the database and have suitable initalisation for this to zero it at the start of the trip or lap.
Intergration with virtual power system.
In the virtual power system you can set the calories mode selection box for the formula style used to user defined item my_vp you then have a run_always enabled user defined item called my_vp and use it to calculate your own virtual power value that will get into the IpBike as the power value. Your mplementation can use the standard virtual power sub components for vp_rolling, vp_drag, vp_elevation, vp_acceleration if you want to have something similar to the standard formula.
Examples.
There are a set of example expressions that will be setup automatically. Expressions are stored in the IpBike files area in the user_defined_items directory. If you delete this directory the examples will be setup again automatically when IpBike next restarts. The expressions are in a text file. If you are doing something complex you may find it easier to edit the file manually. You are still likely to have to check in the expression editor to get the help of the syntax error hiliteing to remove the final errors. The examples are not configured by default to run all the time even though some are suitable for this type of usage. Go to the editor and enable this if you want to try them out.
custom_power_zone example walk through.
This expression oputput 1 for power < 85% of ftp. 2 for between 85% and 100% ftp and 3 for greater than fpt.
This can all be done in one line but separating things out makes changing it easier for your own purpose.
#ip=$power,
#v=$ftp,
#p=0.85*v,
(ip<p)?1:((ip<v)?2:3)
First line new variable #ip for input taking the real time power value $power
2nd line new variable #v using the ftp value $ftp. Easy to change to critical power if you want.
3rd line new variable #p for the low comparison value 0.85*v so you can easily change the percentage.
4th line where the work is. Read it as if ip less than p then 1 else if ip less than v then 2 else 3
Max incline example walk through.
This example displays the max incline over a timeframe e.g. trip or lap depending on how the item is configured. The example also works out the minimum incline. Note the incline can be a bit dodgy especially starting up which is why I don't have this item by default. This example stores the max and min values to the database for the trip and each lap and you would normally enable run allways if you are interested in it.
($real_time<2)?(#max#=-100,#min#=100):0,
(#v=$incline,
max=(max>v)?max:v,
min=(min<v)?min:v,
max)
First line. if real_time is 0 or 1 then do the reset code else the standard code.
Second line. The reset code new variables #max# and #min# reset to a low value for max and a high vale for min. The seccond # is there to make the values be stored to the database.
3rd line. The start of the standard code new variable #v for value set to the $incline.
4th line. Set max to either the current max or the current value if it is > max
5th line. Set min to either the current min or the current value if it is < min
6th line. Finally use max as the final value that will be displayed.
If you want to have min displayed you can just define another item as showen by the min_incline example and reference the min variable were with $max_incline#min
Other examples.
There are a number of other examples you can look at and adapt.
recent_av_min_max is a simple example of a moving average with min and max recording that could be easily adjusted to any stat or timeframe. recent_min and recent_max are used just to display the min and max values from this.
av_power_periods as a far more complex example it calculates the average power over a number of time periods e.g. 3,5,10,30,60,120 and 300 as the default time periods. It generates an array of items. av_power_periods_view is a simple multi instance item for viewing these multiple moving averages.
max_power_periods uses the power values from av_power_periods to recorde the max power seen over each time period. The values are stored to the database so post ride you can see you max power for each time period. The same is avalible for a lap. max_power_periods_view is a multi instance item for displaying these.
cadence_gear_zone is an example of using the zone information. It calculates the cadence in each gear. cadence_gear_zone_view is used for showing the indevidual cadence result value for the selected gear instance.
The feed_ items demonstrate the items with user input plus and minus buttons. They are setup to record your food intake duting a ride. Add the feed_item to the screen to see the buttons you can use for counting different food types. feed_cals_consumed then calclates the total calories and is there the calories per each food item are set as constants in the equasion. feed_cals_deficit lets you know the overall callories position for the ride so far. There is the concept of a calories alowance here working on the assumption that you can sustain a level of under eating (by using some fat) this amount is in this equasion as a calories you can sustain per hour constant.