Pregunta

I have implemented a GPS Tracker for Android. So far it is working quite nice but I have problems computing the right height difference for the track. I want to sum up all meters the device "climbed" and "descended". I do this in a background service comparing the current location object with the previous one and store the difference directly as a column in the database. If I sum this up after the track is finished I get a value that is approximately 2.5 times as high (1500m vs 650m) as measured with a bicycle speedometer that uses a barometer.

I know the measured altitude of the GPS device is inaccurate. Is there any way to "normalize" the measured altitude? Should I, for example, ignore all altitude changes below 2 meters? Another possibility would be to use additional sensors as some devices also have a barometer. But that would only help on some devices.

Thanks for any advice or hints on this issue!

EDIT 28.05.2013: The answer of Bryce got me on the right track. I started searching the web and found a very simple low pass filter that is easy to implement. I did this in c++

A node class representing one waypoint:

class Node {
private:
    double distance;
    double altitude;
    double altitudeup;
    double altitudedown;
    double latitude;
    double longitude;
    long timestamp;

public:
    Node(double dist, double alti, double altiup, double altidown, double lat, double lon, long ts);
    double getAltitude();
    double getAltitudeup();
    double getAltitudedown();
};

Here is the function that does the actual work and computes the values for total ascend and descend:

void SimpleLowPass::applySLP()
{
    double altiUp = 0;
    double altiDown = 0;
    double prevAlti = this->nodeList[0]->getAltitude();
    double newAlti = prevAlti;
    for (auto n : this->nodeList)
    {
        double cur = n->getAltitude();
//        All the power of the filter is in the line
//        newAlti += (cur - newAlti) / smoothing.
//        This finds the difference between the new value and the current (smoothed)
//        value, shrinks it based on the strength of the filter, and then adds it
//        to the smoothed value. You can see that if smoothing is set to 1 then the
//        smoothed value always becomes the next value. If the smoothing is set to
//        2 then the smoothed value moves halfway to each new point on each new
//        frame. The larger the smoothing value, the less the smoothed line is
//        perturbed by new changes.
        newAlti += (cur - newAlti) / 20.0;
        std::cout << "newAlti: " << newAlti << std::endl;
        if (prevAlti > newAlti)
        {
            altiDown += prevAlti - newAlti;
        }
        if (newAlti > prevAlti)
        {
            altiUp += newAlti - prevAlti;
        }
        prevAlti = newAlti;

    }
    std::cout << "Alti UP total: " << altiUp << std::endl;
    std::cout << "Alti DOWN total: " << altiDown << std::endl;
}

This is a quick and dirty implementation. But with a value of 20 for smoothing I get pretty good results. Still I will need to record more tracks and compare the results. Also there is Frame-Rate independent implementation on the website where I found this low-pass filter and I want to play with a moving average implementation.

simple low-pass filter

Thanks for all your answers!

¿Fue útil?

Solución 2

Use the barometer if the device has it, but either way you're going to have to apply a smoothing filter of some sort. Without looking at the data you're collecting, I can only speculate as to the cause, but it is probably caused from spikes when you lose sync with a satellite.

Otros consejos

GPS altitude bounces around a lot, and each of these bounces looks like an ascent or descent. In my experience the barometer sensor bounces around a much narrower range.

What you want to do is measure each climb (where a climb is defined as a constant increase in altitude), and sum the climbs to determine the total height climbed.

With any sensor (GPS or baro) the altitude will bounce around a little and we don't want those little bounces to be registered as short descents and climbs. So when we are climbing, we want to ignore small dips in altitude.

double THRESHOLD = 10;
Direction climbingOrDescending = Direction.NONE;

double totalAscent = 0;
double totalDescent = 0;

double climbStart;
double maxAltitude;

double descentStart;
double minAltitude;

public void onSample(double sample) {
    if (climbingOrDescending == Direction.NONE) {
        // First sample
        climbingOrDescending = Direction.CLIMBING; // Arbitrary
        climbStart = sample;
        maxAltitude = sample;
    } else if (climbingOrDescending == Direction.CLIMBING) {
        if (sample > maxAltitude) {
            maxAltitude = sample;
        } else if (sample < (maxAltitude - THRESHOLD) ) {
            // bounces in sample that are smaller than THRESHOLD are ignored. If 
            // the sample is far below maxAltitude... it is not a bounce, record
            // the climb and move to a descending state
            double altitudeGainedThisClimb = maxAltitude  - climbStart;
            totalAscent +=  altitudeGainedThisClimb;
            // Prepare for descent.
            climbingOrDescending = Direction.DESCENDING;
            descentStart = maxAltitude;
            minAltitude = sample;
        }
    } else { // climbingOrDescending == DESCENDING
        // similar code goes here to measure descents
    }
}

public double getTotalAscent() {
    if (climbingOrDescending == Direction.CLIMBING) {
        return totalAscent + (maxAltitude - climbStart);
    } else {
        return totalAscent;
    }
}

When working with the sum of imprecise measurements, you'll always end up with a massive margin of error. It's a basic statistical certainty.

Instead of storing the difference between one measurement and the next, you should instead be considering each measurement as an independent data point. For instance, take the minimum altitude of all points, and subtract that value from all measurements.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top