Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gpsrec] Higher precision for track length #1523

Closed
bernhardreiter opened this issue Feb 28, 2022 · 13 comments
Closed

[gpsrec] Higher precision for track length #1523

bernhardreiter opened this issue Feb 28, 2022 · 13 comments
Labels
type-bug Something isn't working

Comments

@bernhardreiter
Copy link

Affected hardware version

Bangle 2

Your firmware version

2v12

The bug

When plotting a track the length is shown to coarse, it seems to be rounded toward 2 digits.

Expected: Round it to three digits precision.

The problem when running a track like 12.4 or 12.5 km is that it will be shown as 12 km or 13 km, though the different is possibly just hundred meters. On the other hand, 12 km shown can be 11.51 km or 12.49 km, which is almost 1000m difference.

@bernhardreiter bernhardreiter added the type-bug Something isn't working label Feb 28, 2022
@bernhardreiter
Copy link
Author

Here is the code for gpsrec (the problem also persists in other apps like run)

g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20);

This probably refers to the build-in locale module, where indeed, no rounding to precision is done:
https://github.com/espruino/Espruino/blob/f148c737313cce1eedbad6be65b396a3c8ebbf78/libs/js/banglejs/locale.js#L24

Maybe this can be replaced with something like Number.toPrecision for values >=1000 meters.

@gfwilliams
Copy link
Member

Espruino doesn't have toPrecision - but toFixed could be used.

I think the best bet would just be to modify the locale app to calculate the distance string more accurately.

@GrandVizierOlaf
Copy link
Contributor

Would this impact the distance tracked by the run app? I ran my first run with my bangle2 and also had Google Fit running on my phone (what I'm trying to move away from) and the distances tracked were 9.6 miles for the run app on bangle and 10 miles for google even though the GPS tracks look practically identical.

@GrandVizierOlaf
Copy link
Contributor

Would this impact the distance tracked by the run app? I ran my first run with my bangle2 and also had Google Fit running on my phone (what I'm trying to move away from) and the distances tracked were 9.6 miles for the run app on bangle and 10 miles for google even though the GPS tracks look practically identical.

To follow up on my own question, I think I found a bug in exstats' calcDistance, where it was using a.lon-b.lon rather than b.lon-a.lon. Further digging into the calculation, I don't think it needs to be in radians, but I'm going to test it tomorrow and open a PR if it seems to help.

@gfwilliams
Copy link
Member

Hi - I guess we're talking about:

function calcDistance(a,b) {
  function radians(a) { return a*Math.PI/180; }
  var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
  var y = radians(b.lat-a.lat);
  return Math.sqrt(x*x + y*y) * 6371000;
}

I'm pretty sure it makes no difference since when you do x*x any difference in sign is lost - try running the function with two different lat/lon values, then change it, and see what I mean.

There have been a lot of discussions on the forum about track length calculations where folks have done tests with the existing app. I think 9.6 miles vs 10 miles is probably expected. If you get another tracker too you'll probably get a different distance.

Why? Well the values from the GPS will never be entirely accurate and they have some randomness. You get them each second, so every second the distance might be 10cm off - in one minute that's 600cm, and then over time that value goes up.

@bernhardreiter
Copy link
Author

Would this impact the distance tracked by the run app?

If the change is made in the modules that are used by many apps (like locale), then it would affect all apps that use it. I'm assuming that run uses locale, so it would be affected

However the aim of this issue is to display more precision of the value. It is not about calculation problems (which probably are also there).

As where to implement this best, I think the needed precision should be determined by the app, because it depends on the use case. For outdoor running, the displayed decision is not sufficient, but for other applications is might be fine or even better.

@gfwilliams
Copy link
Member

In that case I guess you could just implement the relevant changes in the gpsrec app (and recorder/run apps). The issue is that locale also provides locale-specific distances (miles in the USA, km in europe, and so on) so we don't want to lose that functionality.

@bernhardreiter
Copy link
Author

To improve the overall situation, my idea was to give the precision to be displayed to the locale.distance function as optional parameter, then the unit conversion could still happen there. But this maybe an API change...

@gfwilliams
Copy link
Member

my idea was to give the precision to be displayed to the locale.distance function

That sounds like a good idea to me... It wouldn't affect anything else and would be backwards compatible

@gfwilliams
Copy link
Member

So right now, distance looks like this:

function (m) { 
  return (m<1000)?Math.round(m)+"m":Math.round(m/160.934)/10+"mi" // meters to "123m" or "1.2mi" depending on size
}

I'm thinking something like:

function (m, dp) { 
  if (dp===undefined) dp=1;
  return (m<1000)?Math.round(dp)+"m":(m/160.934).toFixed(dp)+"mi" // meters to "123m" or "1.2mi" depending on size
}

So the default is 1 decimal place, but if you call it with 2 you get what you want.

However you might still get things like 1234.45mi which seems a bit much.

We could always do something along the lines of:

function toPrecision(n, dp) {
  var p = dp - Math.floor(Math.log(n)/Math.log(10));
  return n.toFixed(p);
}

but is that overkill?

@GrandVizierOlaf
Copy link
Contributor

Hi - I guess we're talking about:

function calcDistance(a,b) {
  function radians(a) { return a*Math.PI/180; }
  var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
  var y = radians(b.lat-a.lat);
  return Math.sqrt(x*x + y*y) * 6371000;
}

I'm pretty sure it makes no difference since when you do x*x any difference in sign is lost - try running the function with two different lat/lon values, then change it, and see what I mean.

There have been a lot of discussions on the forum about track length calculations where folks have done tests with the existing app. I think 9.6 miles vs 10 miles is probably expected. If you get another tracker too you'll probably get a different distance.

Why? Well the values from the GPS will never be entirely accurate and they have some randomness. You get them each second, so every second the distance might be 10cm off - in one minute that's 600cm, and then over time that value goes up.

To close the loop on this, I ended up getting the GPX from my google fit data and analyzed it and the bangle GPX with a few different tools and they both came out to 9.6 miles, so it seems that the google fit app live distance calculation is in the wrong instead. Thanks!

@gfwilliams
Copy link
Member

@GrandVizierOlaf great - thanks for letting us know!

@bernhardreiter
Copy link
Author

@gfwilliams thanks for making an improvement. I'll try this next time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants