M0UNTAIN 0F C0DE

ForRunners ⭐ Calculation

FOSS running

I recently started running again, always loved it but never really found the time to until recently. I also love data and record each run I go on. I did a bunch of research to see if I could find a good FOSS app for Android, I wanted something really simple

There are amazingly few apps that meet these criteria. The one I settled on is called ForRunners, it did everything I needed and had a couple of nice-to-have extras. One feature it had was each run was given a star rating, I didn't really understand what made the rating go up or down. I was especially confused when one of the runs was given a rating of -0.1⭐???

View The Source Luke

After trying to figure out how it was being calculated, it occurred to me that the app is opensource, I can go and see exactly how it is calculated. Easy. One search for "GitHub ForRunners" later turned up the GitHub repo, which had subsequently been moved to GitLab.

As I started browsing the repo I couldn't believe that it was built using web tech, I know this. I started by locating the views where the star rating was displayed and work backwards from there to find the algorithm.

The view I was interested in was sessions.html, specifically these lines:

<span class="badge badge-lower" style="display: block; vertical-align: middle; text-align:center; font-size:11px; width: 30px; margin-left:5px;">
    {{ session.overnote }} <i class="icon ion-star"></i>
</span>

Bingo! overnote is the variable I was looking for. Tracing this back, it seems the view is rendered by controller.js, which gave me what I was after:

session.overnote = (
    parseInt(gpxspeedwithoutpause) *
    1000 *
    (miliseconds / 1000 / 60) *
    0.000006 +
    (Math.round(eleUp) - Math.round(eleDown)) * 0.04
).toFixed(1);

It references a bunch of variables defined further up, but it boils down to:

SpeedInKmPerHour × DurationInMinutes × 0.006 + TotalElevationChange × 0.04

Taking data from one of my actual runs and plugging it in matched what I saw in the app:

11.26Km/h × 21mins × 0.006 + (73m - 80m) × 0.04 = 1.1⭐

This calculation broadly makes sense, go faster or run for longer you get a higher rating. At first, I was surprised that there were no points for distance, but it dawned on me that Speed x Time is distance that made me wonder... If we convert the time into hours we get SpeedInKmPerHour × DurationInHours × 0.36, which can then be simplified to DistanceInKm × 0.36 because distance = speed × time.

I assume they chose to calculate it the way they did because they wanted to use the speed ignoring any stops.

So Why The Negative Rating?

As to why I got a negative rating, I think this is caused by GPS error. If eleDown is ever greater than eleUp then there will be a negative term, this is possible if you end the run downhill of where you started. All my runs have been circular, so the total up and total down should be equal, but the GPS error, especially at the start, will be relatively high and give the wrong elevation.