Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Definitive algorithm for determining most accurate returned from iPhone CoreLocation?

Has anyone nailed this down yet? I've read a lot of forum postings and I still can't tell if this is a settled question...

Given that didUpdateToLocation() can return cached or inaccurate information how do you tell when you have an accurate fix?

When you set desired accuracy to kCLLocationAccuracyNearestTenMeters, HundredMeters, Kilometer, ThreeKilometers, it seems obvious that you can compare the horizontal accuracy of points returned against the desired accuracy to decide when to accept a point.

But the values of kCLLocationAccuracyBestForNavigation and kCLLocationAccuracyBest are -2 and -1 respectively so how do I know when I have the desired accuracy??

I currently check the age of the fix and reject any fix that is too "old" timewise. I then check to see if the horizontal accuracy is negative and reject that if it is. if I get a positive verticalAccuracy then I generally use that fix since the corresponding horizontal accuracy is also good.

But these checks were used when I has looking for accuracy in the 10-100s of meters... I don't know what if anything to check when I'm running ...AccuracyBestForNavigation or ...AccuracyBest?? Am I suppose to level the locationManager running constantly and never expect to shut it off and don't filter any results??

Anyone wiser than I with an answer??

Thanks

like image 462
morgman Avatar asked Oct 06 '10 22:10

morgman


2 Answers

It's not really a definitive, perfect algorithm (I doubt there is one for this task, because of external conditions, I mean, you can try get ur location on plain field or inside a tomb), it's an ad-hoc one, and it works for me.

I did a wrapper for LocationManager, like

@protocol LocationManagerWrapperDelegate <NSObject>

@required

- (void) locationUpdated: (CLLocation *) locationUpdate;
- (void) errorOccured: (NSError *) error;

@end

@interface LocationManagerWrapper : NSObject <CLLocationManagerDelegate>
{
    CLLocationManager *locationManager;
    id delegate;
    CLLocation *mostAccurateLocation;
    int updatesCounter;
    BOOL m_acceptableTimePeriodElapsed;
}

@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) CLLocation *mostAccurateLocation;
@property (nonatomic, assign) id <LocationManagerWrapperDelegate> delegate;

- (void) startUpdatingLocation;

- (void) locationManager: (CLLocationManager *) manager
    didUpdateToLocation: (CLLocation *) newLocation
           fromLocation: (CLLocation *) oldLocation;

- (void) locationManager: (CLLocationManager *) manager
   didFailWithError: (NSError *) error;

+ (LocationManagerWrapper *) sharedInstance;

@end

Implementation

#define NUMBER_OF_TRIES 4   
#define ACCEPTABLE_TIME_PERIOD 15.0

- (void) startUpdatingLocation
{
NSAssert(self.delegate != nil, @"No delegate set to receive location update.");

updatesCounter = 0;
self.mostAccurateLocation = nil;
m_acceptableTimePeriodElapsed = NO;
[NSTimer scheduledTimerWithTimeInterval:ACCEPTABLE_TIME_PERIOD
                                 target:self
                               selector:@selector(acceptableTimePeriodElapsed:) 
                               userInfo:nil
                                repeats:NO];
[self.locationManager startUpdatingLocation];
}

- (void) acceptableTimePeriodElapsed: (NSTimer *) timer
{
@synchronized(self)
{
    m_acceptableTimePeriodElapsed = YES;
    // TODO: if period is set by user - check we have mostAccurateLocation at this point
    [self.delegate locationUpdated:self.mostAccurateLocation];
    [self.locationManager stopUpdatingLocation];
}
}

- (void) locationManager: (CLLocationManager *) manager
    didUpdateToLocation: (CLLocation *) newLocation
           fromLocation: (CLLocation *) oldLocation
{
@synchronized(self)
{
    if (m_acceptableTimePeriodElapsed) return;
    NSLog([NSString stringWithFormat:@"lat: %@, long: %@, acc: %@", 
           [ [NSNumber numberWithDouble:newLocation.coordinate.latitude] stringValue],
           [ [NSNumber numberWithDouble:newLocation.coordinate.longitude] stringValue],
           [ [NSNumber numberWithDouble:newLocation.horizontalAccuracy] stringValue]  ] );

    updatesCounter++;
    // ignore first returned value
    if (updatesCounter <= 1) return;
    if (self.mostAccurateLocation == nil ||
        self.mostAccurateLocation.horizontalAccuracy > newLocation.horizontalAccuracy)
    {
        self.mostAccurateLocation = newLocation;
    }
    if  (updatesCounter >= NUMBER_OF_TRIES)
    {
        [self.delegate locationUpdated:self.mostAccurateLocation];
        [self.locationManager stopUpdatingLocation];
    }
}
}

The code is not excellent (neither formatting is), but the idea, I think, is simple and clear, get first location, throw it out, it's a cached one, do 3 tries max for a the most accurate location. It can take a long time, and if user is waiting (as in my case), define a time limit. One more time, it works for my app, but feel free to tweak it or take another approach.

like image 120
fspirit Avatar answered Nov 17 '22 12:11

fspirit


I know this is an old thread I'm bringing back, but I came across this question because I was also looking for a most accurate solution, and after reading your solution fspirit, i like it a lot. Like morgman, I was also pretty much thinking something similar, but you just put our thoughts in code, lol. Also I like your forward-multi-threaded thinking ;)

But I actually have a question/suggestion, if you will. When I try to get location data on the iphone, I get at least 3 sets of coordinates with the same horizontal accuracy right off the bat. So a good number of tries would have to be more than 4. But the question then, is how many tries is good?

So i suggest that instead of changing the number of tries, we can make a slight tweak to the code, so that the number of tries counter goes up Only if the horizontal accuracy is significantly less than the previous one, or less than the most accurate one, something like that. I'm just thinking out loud here. Because I took a look at all the location data I got from my iphone 4 (and I'm not sure how it works on other devices), and judging from what i saw, the location is getting updated pretty constantly, and the horizontal accuracy stays relatively the same for the first couple of updates, then after a while it suddenly jumps down from say, 400 to 100, and then after a second or two more, it jumps down again to about 30. All this is over the course of about 30-50 updates, so in this situation a max number of tries of 4 might not work, unless you're only counting the jumps. What do you guys think?

like image 44
Omar Avatar answered Nov 17 '22 11:11

Omar