Warning: join(): Invalid arguments passed in /home/troyb/troybrant.net/blog/wp-content/themes/hybrid-hacked/hybrid-hacked/library/functions/breadcrumbs.php on line 79

Detecting Bad CoreLocation Data

CoreLocation can (and will) give you poor location data. Over the course of developing RunMonster, I have become painfully aware of this fact. It turns out, though, that you can detect and discard the most egregiously bad location data using a few simple tests.

When a new point comes in, it is invalid and can be discarded if it matches any of the following criteria:

  • The location is nil.
  • The location’s horizontalAccuracy is < 0.
  • The timestamp of the new location is earlier than the timestamp of the previous location, indicating the points came in out of order.
  • The timestamp of the new location is set to a time before your app was even initialized.

In regards to the last bullet, the CoreLocation framework seems to cache and report points from the last time the GPS unit was used. For instance, if you last ran the GPS in Montana and then open your app in Georgia, the first point could be the last cached point from Montana. If you are running a distance-tracking application, then your app would merrily add thousands of miles to your total distance.

The Code

The helper method below checks for these four cases to determine if the newly reported location is valid or not:

- (BOOL)isValidLocation:(CLLocation *)newLocation
    withOldLocation:(CLLocation *)oldLocation
{
    // Filter out nil locations
    if (!newLocation)
    {
        return NO;
    }
    
    // Filter out points by invalid accuracy
    if (newLocation.horizontalAccuracy < 0)
    {
        return NO;
    }
    
    // Filter out points that are out of order
    NSTimeInterval secondsSinceLastPoint =
        [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
    
    if (secondsSinceLastPoint < 0)
    {
        return NO;
    }
    
    // Filter out points created before the manager was initialized
    NSTimeInterval secondsSinceManagerStarted =
        [newLocation.timestamp timeIntervalSinceDate:locationManagerStartDate];
    
    if (secondsSinceManagerStarted < 0)
    {
        return NO;
    }
    
    // The newLocation is good to use
    return YES;
}

locationManagerStartDate is an NSDate that records when the CLLocationManager is initialized:

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];

locationManagerStartDate = [[NSDate date] retain];

That’s a Wrap

If you are developing any kind of distance-tracking application that uses the phone’s GPS, you should definitely consider using the filters above. These particular error cases were discovered through trial and error, and as Apple improves CoreLocation, they may very well fix these problems. However, these filters have helped RunMonster avoid the wacky GPS issues that plague many distance-tracking applications.

52 Responses to “Detecting Bad CoreLocation Data”

  1. The inner fire is the most important thing mankind possesses.

  2. Along with tyidosnns the whole thing that appears to be building throughout this specific subject matter, many of your points of view tend to be quite radical. However, I appologize, but I do not give credence to your whole suggestion, all be it refreshing none the less. It appears to us that your opinions are actually not entirely rationalized and in simple fact you are generally yourself not even entirely confident of the point. In any case I did take pleasure in reading it.

Leave a Reply