Accuracy of Core Location

2019-01-31 14:54发布

I'm currently working on a location tracking app and I have difficulties with inaccurate location updates from my CLLocationManager. This causes my app to track distance which is in fact only caused by inaccurate GPS readings.

Inaccurate location readings

I can even leave my iPhone on the table with my app turned on and in few minutes my app tracks hundreds of meters worth of distance just because of this flaw.

Here's my initialization code:

- (void)initializeTracking {
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    self.locationManager.distanceFilter = 5;

    [self.locationManager startUpdatingLocation];
}

Thanks in advance! :-)

4条回答
Fickle 薄情
2楼-- · 2019-01-31 15:17

I've used this method to retrive the desired accuracy of the location (In SWIFT)

let TIMEOUT_INTERVAL = 3.0
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
    let newLocation = locations.last as! CLLocation
    println("didupdateLastLocation \(newLocation)")
    //The last location must not be capured more then 3 seconds ago
    if newLocation.timestamp.timeIntervalSinceNow > -3 &&
        newLocation.horizontalAccuracy > 0 {
            var distance = CLLocationDistance(DBL_MAX)
            if let location = self.lastLocation {
                distance = newLocation.distanceFromLocation(location)
            }
            if self.lastLocation == nil ||
                self.lastLocation!.horizontalAccuracy > newLocation.horizontalAccuracy {
                    self.lastLocation = newLocation
                    if newLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy {
                        //Desired location Found
                        println("LOCATION FOUND")
                        self.stopLocationManager()
                    }
            } else if distance < 1 {
                let timerInterval = newLocation.timestamp.timeIntervalSinceDate(self.lastLocation!.timestamp)
                if timerInterval >= TIMEOUT_INTERVAL {
                    //Force Stop
                    stopLocationManager()
                }
            }
    }

Where:

if newLocation.timestamp.timeIntervalSinceNow > -3 &&
        newLocation.horizontalAccuracy > 0 {

The last location retrieved must not be captured more then 3 seconds ago and the last location must have a valid horizontal accuracy (if less then 1 means that it's not a valid location).

Then we're going to set a distance with a default value:

            var distance = CLLocationDistance(DBL_MAX)

Calculate the distance from the last location retrieved to the new location:

if let location = self.lastLocation {
                distance = newLocation.distanceFromLocation(location)
            }

If our local last location hasn't been setted yet or if the new location horizontally accuracy it's better then the actual one, then we are going to set our local location to the new location:

if self.lastLocation == nil ||
        self.lastLocation!.horizontalAccuracy > newLocation.horizontalAccuracy {
            self.lastLocation = newLocation

The next step it's to check whether the accuracy from the location retrieved it's good enough. To do that we check if the horizontalDistance of the location retrieved it lest then the desiredAccurancy. If this is case we can stop our manager:

if newLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy {
                        //Desired location Found
                        self.stopLocationManager()
                    }

With the last if we're going to check if the distance from the last location retrieved and the new location it's less the one (that means that the 2 locations are very close). If this it's the case then we're going to get the time interval from the last location retrieved and the new location retrieved, and check if the interval it's more then 3 seconds. If this is the case, this mean that it's more then 3 seconds that we're not receiving a location which is more accurate of the our local location, and so we can stop the location services:

else if distance < 1 {
                let timerInterval = newLocation.timestamp.timeIntervalSinceDate(self.lastLocation!.timestamp)
                if timerInterval >= TIMEOUT_INTERVAL {
                    //Force Stop
                    println("Stop location timeout")
                    stopLocationManager()
                }
            }
查看更多
放荡不羁爱自由
3楼-- · 2019-01-31 15:20

One of the ways I solved this in a similar application is to discard location updates where the distance change is somewhat less than the horizontal accuracy reported in that location update.

Given a previousLocation, then for a newLocation, compute distance from the previousLocation. If that distance >= (horizontalAccuracy * 0.5) then we used that location and that location becomes our new previousLocation. If the distance is less then we discard that location update, don't change previousLocation and wait for the next location update.

That worked well for our purposes, you might try something like that. If you still find too many updates that are noise, increase the 0.5 factor, maybe try 0.66.

You may also want to guard against cases when you are just starting to get a fix, where you get a series of location updates that appear to move but really what is happening is that the accuracy is improving significantly.

I would avoid starting any location tracking or distance measuring with a horizontal accuracy > 70 meters. Those are poor quality positions for GNSS, although that may be all you get when in an urban canyon, under heavy tree canopy, or other poor signal conditions.

查看更多
女痞
4楼-- · 2019-01-31 15:20

There's really not a whole lot more you can do to improve what the operating system and your current reception gives to you. On first look it doesn't look like there's anything wrong with your code - when it comes to iOS location updates you're really at the mercy of the OS and your service.

What you CAN do is control what locations you pay attention to. If I were you in my didUpdateLocations function when you get callbacks from the OS with new locations - you could ignore any locations with horizontal accuracies greater than some predefined threshold, maybe 25m? You would end up with less location updates to use but you'd have less noise.

查看更多
别忘想泡老子
5楼-- · 2019-01-31 15:35

This is always a problem with satellite locations. It is an estimate and estimates can vary. Each new report is a new estimate. What you need is a position clamp that ignores values when there is no movement.

You might try to use sensors to know if the device is actually moving. Look at accelerometer data, if it isn't changing then the device isn't moving even though GPS says it is. Of course, there is noise on the accelerometer data so you have to filter that out also.

This is a tricky problem to solve.

查看更多
登录 后发表回答