PHP Looping through a GPX to calculate total ascent/descent of a track
Asked Answered
F

3

7

I want loop though a gpx file and calculate the total ascent and descent. I have a function that can calc the difference in elevation between two sets of lat long points and I've set up simplexml to read & loop through the gpx file trkseg points.

The problem is, that this is not accurate (really not accurate as it is in real).

This two lines will result in different ascent and descent, as it is in the real life:

$total_ascent += ($val - $last_elevation);
$total_descent += ($val - $last_elevation);

Does somebody know, how to calculate more accurate the total ascent and descent of a track?

This is my current code snippet to calculate it ($track_elevations is an array with elevations of whole track):

if (!empty($track_elevations)) {
    $total_ascent = $total_descent = 0
    $lowest_elevation = $highest_elevation = $last_elevation = null;
    
    foreach ($track_elevations as &$val) {
        if (!is_null($last_elevation)) {
            if ($last_elevation < $val) {
                $total_ascent += ($val - $last_elevation);
            }
            elseif ($last_elevation > $val) {
                $total_descent += ($last_elevation - $val);
            }
        }

        if (is_null($lowest_elevation) or $lowest_elevation > $val) {
            $lowest_elevation = $val;
        }

        if (is_null($highest_elevation) or $highest_elevation < $val) {
            $highest_elevation = $val;
        }
        
        $last_elevation = $val;
    }
}

Example of $track_elevations array:

$track_elevations = array(
    327.46,
    328.27,
    329.32,
    330.11,
    329.46,
    329.39,
    329.68,
    331.04,
    333.23,
    333.46,
    332.97,
    332.88,
    332.99,
    332.75,
    332.74,
    334.01,
    333.62
)

In real, I was riding bike on the flat road. But my snippet of code will calculate, I have ascended and descended couple meters. Maybe I should add there some limitation of precision between two elevations in a row...

What I want to achieve:

I will try to explain it more better - when I ride f.e. 20 km on flat road (almost with no ascent and descent), the total ascent and descent should be close to 0. But when I sum $track_elevations (like in my snippet of code), I will get in $total_ascent and $total_descent f.e. 500 meters... Its because of between each array element in $track_elevations is difference couple centimeters, but I am still riding on the flat road... And in the total sum it will gather to a large number of meters... Hope now it is more clear.

Famulus answered 21/5, 2015 at 9:4 Comment(6)
can you provide some example values for the track_elevations array?Insignificance
I probably misunderstood the question, but it looks like you did ascend and descend a couple of meters (based on the array provided). What exactly do you want to calculate?Anesthetist
I will try to explain it more better - when I ride f.e. 20 km on flat road (almost with no ascent and descent), the total ascent and descent should be close to 0. But when I sum $track_elevations (like in my snippet of code), I will get in $total_ascent and $total_descent f.e. 500 meters... Its because of between each array element in $track_elevations is difference couple centimeters, but I am still riding on the flat road... And in the total sum it will gather to a large number of meters... Hope now it is more clear.Famulus
So just to be really clear - do you want to know your overall ascent or descent from the original starting position, or the sum of all ascents and descents? e.g. if you start at 100m, go up 10, down 9, up 5 and down 6 - do you want your total ascent to be calculated as 15 or 0?Insignificance
Yes, but I think, I should use some precission, because when I am going on the flat road, where the elevation is still, lets say, 349.0 m - 351.0 m, it will return f.e. after 20 kilometers total ascent and descent about 500 meters, but of course, thats not true, its just calculated piece by piece for each difference in about couple centimeters...Famulus
Can't you please quit that pointless question editing business? Thank you in advance.Quintal
Q
1

The problem is that if you calculate $lastHeight - $track_elevations[$i] for ascentet you get values lower than 0 and thats why you get high differences between $total_asc and $total_desc.

<?php
$track_elevations = array(
    327.46,
    328.27,
    329.32,
    330.11,
    329.46,
    329.39,
    329.68,
    331.04,
    333.23,
    333.46,
    332.97,
    332.88,
    332.99,
    332.75,
    332.74,
    334.01,
    333.62
);

$lastHeight = $track_elevations[0];
$total_ascent = 0;
$total_descent = 0;
for ($i=1;$i<count($track_elevations);$i++) {
    if ($track_elevations[$i] > $lastHeight) {
        $total_ascent += -1 * ($lastHeight - $track_elevations[$i]);
    }
    else {
        $total_descent += ($lastHeight - $track_elevations[$i]);
    }
    $lastHeight = $track_elevations[$i];
}
echo $total_ascent ."\n";
echo $total_descent . "\n\n--\n";
echo $total_ascent  - $total_descent . "\n";

--

$ php -f gpx.php
8.1
1.94

--
6.16

-- manual calculates values:

Ascent:
0.81
1.05
0.79
0.29
1.36
2.19
0.23
0.11
1.27
---
8.1

Descent:
0.65
0.07
0.49
0.09
0.24
0.01
0.39
---
1.94    
Quail answered 26/5, 2015 at 11:22 Comment(3)
My snippet of code will never get values lower than 0... When you are ascending - if ($last_elevation < $val) {, than this $total_ascent += ($val - $last_elevation); will be greater than 0; when you are descending - elseif ($last_elevation > $val) {, than this $total_descent += ($last_elevation - $val); will be greater than 0. Also btw: I am using abs function at the end of my calc function. But this will still not solve the problem, that it is different as in the real life...Famulus
When I ran your code with your example data i get $total_descent = -1.94. I've calculated your example data with hand and added it to my answer.Quail
Yes, I know. But this is not the problem - the difference between $total_ascent and $total_descent. AD1: I am using abs(), so it will be greater than 0. AD2: in my example there are only few of elevations, normally there are about 1000 elevations, and the total ascent and descent is about 500 meters. But as I said, I was riding bike 20 kilometers on the flat road, so the total ascent and descent should be only couple meters (f.e. 5 - 10, not 500). This is the real problem of my question... And in this couple elevations I provided, I for sure not ascended 9.1 m, but maybe only 50 cm...Famulus
N
1

Are you sure this is "flat" ? flat? Can you provide full data set? Also I don't think that this is a precision issue from PHP. Your datapoints have only two digit precision. Maybe the sensor is rounding ?

Norge answered 1/6, 2015 at 6:47 Comment(1)
Its not the problem in PHP. Sensor is rounding it somehow strange. Its still between 328 - 334 m, but the road was flat. I am just asking, if I should use some precission, to not count small changes of elevation...Famulus
H
1

Even if you ride a perfectly flat road, elevation data gathered from GPS will always go up and down a little. GPS is not very accurate with altitude, even in perfect conditions.

If you use raw GPS input to calculate the total amount of climbing/descending, these little errors will sum up quickly with every single point and give completely unrealistic results.

There are a number of options to get better results, but they are all more or less complex: You could "smooth" the elevation curve with proper algorithms. You could discard GPS altitude data and replace it with pre-recorded altitude data for all coordinates on earth (called SRTM data).
You could use the SRTM data and mix it intelligently with your own GPS data.

In any case, getting proper altitude values is a difficult topic. You could try the simple way of not counting differences below 10m or some such, but it will most likely not lead to good results.

Heterogynous answered 27/8, 2015 at 15:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.