Preventing sporadic coordinates using CoreLocation - iphone

Basically I'm making an app that is supposed to record a path and data that someone travels along. I'm having some trouble with accuracy and determining inaccurate reports. Here is an image of the path that my iPhone recorded. The red line is the recorded path, the pink is how I actually walked (apologies for the huge screenshot):
My delegate for recording the data looks like this:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation.horizontalAccuracy < 0) return;
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
// The "> 50.0f" is to hopefully throw out inaccurate points
if (locationAge > 5.0 || [newLocation distanceFromLocation:oldLocation] > 50.0f) return;
[[self locationPoints] addObject:newLocation];
[self updateView];
}
Some advice that I've seen is to use filters to check if the data is appropriate for the projected path. Is this the best way to go?

You could add checking for newLocation.horizontalAccuracy:
if ((newLocation.horizontalAccuracy > 0.0) && (newLocation.horizontalAccuracy < 10.0))
Or, for your case:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if (newLocation.horizontalAccuracy < 0) return;
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
   
    if ((locationAge > 5.0)||(newLocation.horizontalAccuracy < 0.0)||(newLocation.horizontalAccuracy > 10.0)) return;
    [[self locationPoints] addObject:newLocation];
    [self updateView];
}
This (locationAge > 5.0) condition seems weird. Do you really want it? If you keep it in your app will stop updating if device looses proper GPS signal for >5.0s.
One more thing: did you remeber to setup your locationManager with:
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
You should also know that this eats up quit a lot of battery, but for testing...

Related

CLLocationManager holds cache value

This part of code of CLLocationManager is used to calculate the distance travelled. But the location cache is not removed even after using timeIntervalSinceNow.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if(newLocation != nil && oldLocation != newLocation)
{
tempNewLocation = newLocation;
tempOldLocation = oldLocation;
}
NSLog(#"New Location Found");
NSLog(#"- Latitude: %f", newLocation.coordinate.latitude);
NSLog(#"- Longitude: %f", newLocation.coordinate.longitude);
NSLog(#"- Altitude: %f", newLocation.altitude);
NSLog(#"- Course: %f", newLocation.course);
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"The location age %f",locationAge);
if (locationAge > 2.0)
{
}
else
{
if (tempOldLocation.coordinate.latitude == tempNewLocation.coordinate.latitude && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude)
{
NSLog(#" Fix location found ");
}
else
{
if(tempNewLocation.coordinate.latitude == tempOldLocation.coordinate.latitude && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude)
{
NSLog(#"First Time Location Update");
latitudeLongitude.text = [[ NSString alloc] initWithFormat:#"%g , %g", tempNewLocation.coordinate.latitude, tempNewLocation.coordinate.longitude];
totalDistance = 0;
distance.text = #"0 miles";
}
else if ([tempNewLocation distanceFromLocation:tempOldLocation] - tempNewLocation.horizontalAccuracy >= 0)
{
totalDistance += [tempNewLocation distanceFromLocation:tempOldLocation] - (tempNewLocation.horizontalAccuracy / 2);
}
else{
totalDistance += [tempNewLocation distanceFromLocation:tempOldLocation];
}
if (totalDistance < 0) {
distance.text = #"0 miles";
}
else
milesdistance=0.000621371192*totalDistance;
distance.text = [[ NSString alloc] initWithFormat:#"%.1f", milesdistance];
odometerreading.text = [NSString stringWithFormat:#"%09.1f", milesdistance];
mileagerate.text = [[NSUserDefaults standardUserDefaults] valueForKey:#"savedstring"];
float mileagefloat=[self.mileagerate.text floatValue];
amount.text = [NSString stringWithFormat:#"%.2f",mileagefloat * milesdistance];
amountstatus.text=[NSString stringWithFormat:#"$%.2f",mileagefloat * milesdistance];
newnumber=totalDistance;
}
This code doesnt work for me, and when I start tracking, distance is calculated from the place where I last stopped the tracking.
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"The location age %f",locationAge);
if (locationAge > 2.0)
I use a counter that counts how many times didUpdateToLocation is called.
I only use the location received after at least 3 calls.
I know 3 is a magic number but i have found that the first 3 calls are cache or very inaccurate.
Take a look at the answer to this question, as it includes code from Apple's sample app "LocateMe" and provides a bit more detail as to what you are trying to do:
https://stackoverflow.com/a/12848776/346098
You want to check the timestamp property of the new CLLocation object in your delegate method. By the sounds of it are only interested in lat/long that are no older than XXX seconds.
NSTimeInterval timeInSeconds = [newLocation.timestamp timeIntervalSinceNow];
if (timeInSeconds > YOUR_CUSTOM_TIME_IN_SECONDS)
{
// Do something
}
I found the answer for removing cache. For the first time didUpdateToLocation is called, the newlocation fetches the cache value, and the old location is null.
And in the second call, newlocation value is swapped to oldlocation and the newlocation is updated. And hence to get the updated value, the function has to be called twice.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
static CLLocation *locationanalysis1;
NSLog(#"New Location Found");
NSLog(#"- Latitude: %f", newLocation.coordinate.latitude);
NSLog(#"- Longitude: %f", newLocation.coordinate.longitude);
NSLog(#"- Altitude: %f", newLocation.altitude);
NSLog(#"- Course: %f", newLocation.course);
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = -[eventDate timeIntervalSinceNow];
if (howRecent > maximumElapsedTimeForCachedLocation) {
locationanalysis1=newLocation;
return;
}
if((locationanalysis1.coordinate.latitude-oldLocation.coordinate.latitude)==0){
NSLog(#"Old Location in location analysis is %#",oldLocation);
return;
}
NSLog(#"New location accuracy %.0fm", newLocation.horizontalAccuracy);
if ((newLocation.horizontalAccuracy < 0) || (newLocation.horizontalAccuracy > 10)) return;
if(oldLocation!=NULL && newLocation!=NULL){
totalDistance += [newLocation distanceFromLocation:oldLocation];
}else return;
}

best way to get changed location iPhone sdk?

My ultimate goal is that i need to send lat and logitude to web server, every time when location changes.
I am using below code for sending lat and longitude of a device to a web server after every 2 minutes but it is not giving sometimes correct latitude and longitude as location changes.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation
{
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"Location Age%#",[NSString stringWithFormat:#"%d",locationAge]);
if (locationAge > 5) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
NSString *stringUrl;
// BOOL check = FALSE;
NSLog(#"Before condition condition");
if(bestEffortAtLocation == nil || bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy){
NSLog(#"condition");
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= locmanager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
[locmanager stopUpdatingLocation];
locmanager.delegate = nil;
}
//check = TRUE;
}
stringUrl = [NSString stringWithFormat:URLSAVELAT,stringUserId,[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.latitude],[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.longitude]];}
For location manager i am using below code
{
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
locmanager.distanceFilter = 10.0;
//locmanager.distanceFilter = kCLDistanceFilterNone;
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locmanager startUpdatingLocation];
}
Any,even small help would be appreciated, Thank u in advance
You should use the location update call backs from the API and use updateLocation method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) {
[self.delegate locationUpdate:newLocation];
}
}
Then in the viewcontroller do this:
- (void)locationUpdate:(CLLocation *)location {
//DO WHATEVER YOU WANT HERE, INCLUDING SENDING TO SERVER
}
You also need to define two protocol methods, one of which is the locationUpdate:
#protocol CoreLocationControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
I would not recommend doing all that you do in the didUpdateLocation: method.

CLLocationManager didUpdateToLocation checking failing

I am trying to get the location coordinates using CLLocationManager. Here is my code
- (void)viewDidLoad {
[super viewDidLoad];
//instantiate location manager and set delegate
self.locationManager=[[CLLocationManager alloc]init];
locationManager.delegate=self;
// can be set to 100m,1km,3km etc.
//locationManager.distanceFilter=10.0f;
locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
//start updating the delegate
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
// Check if the coordinates are different from the old ones
if (newLocation.coordinate.latitude != oldLocation.coordinate.latitude &&
newLocation.coordinate.longitude != oldLocation.coordinate.longitude) {
NSLog(#"not equal");
} else {
NSLog(#"equal");
}
}
However i find the condition is called twice. First time the condition is satisfied and prints not equal and immediately its called again and prints "equal". Can some1 help me out ? What am i doing wrong ?
Thanks
This is because CoreLocation cache your last location and return it immediately after you called startUpdatingLocation so you have to validate coordinate timestamp and it is too old, you can ignore old coordinate.
UPDATE:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([newLocation horizontalAccuracy] < 0.0f) return;
if(fabs([[newLocation timestamp] timeIntervalSinceNow]) > kCLLocationMaximumLocationDataAge) return;
if(fabs([[oldLocation timestamp] timeIntervalSinceNow]) < kCLLocationMaximumLocationDataAge && [newLocation getDistanceFrom:oldLocation] < 0.1f && [newLocation horizontalAccuracy] == [oldLocation horizontalAccuracy])
return;
if(((runningHighPreciseLocationDetectionService||runningLowPowerLocationDetectionService) && ([newLocation horizontalAccuracy] <= kCLLocationAccuracyHundredMeters))){
NSLog(#"---> \n%#\n%#\nHorizontal accurecy: %f\nLocation age: %fs\nOld location age: %fs", NSStringFromSelector(_cmd), newLocation, newLocation.horizontalAccuracy, fabs([[newLocation timestamp] timeIntervalSinceNow]), fabs([[oldLocation timestamp] timeIntervalSinceNow]));
} else {
NSLog(#"\n-------------- BAD ---------------\n%#\n%#\nHorizontal accurecy: %f\nLocation age: %fs\nOld location age: %fs\n----------------------------------", NSStringFromSelector(_cmd), newLocation, newLocation.horizontalAccuracy, fabs([[newLocation timestamp] timeIntervalSinceNow]), fabs([[oldLocation timestamp] timeIntervalSinceNow]));
}
if(((runningHighPreciseLocationDetectionService||runningLowPowerLocationDetectionService) && ([newLocation horizontalAccuracy] <= kCLLocationAccuracyHundredMeters))){
[self stopLocationImprovementTimer];
} else [self createLocatinoImprovementTimer];
}
createLocatinoImprovementTimer method used to launch timer, which will work for certain amount of time and if it wasn't stopped it will send and update notification with location, which was last. This timer will help to wait for coordinate with better accuracy before notify controllers.

how to find latitude and longitude in iphone4.0?

i am new to iphone
by using CLLocation i can find latitude and longitude but it is not working in iphonesimulater4.0 working in 3.2.1,please any one tell me how to calculate latitude & longitude in iphone4.0.
Thanks in advance
CLLocationCoordinate2D location =
[[[mapview userLocation] location] coordinate];
//NSLog(#"Location found from Map: %f %f",
location.latitude,location.longitude);
this concept use in directly in ur app delegte and check it ur latitude and long.
#pragma mark locationManager delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session
if(abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120)
{
//CLLocation *test = [[CLLocation alloc] initWithLatitude:-33.857034 longitude:151.035929];
currentLocation = newLocation;
coordinates = newLocation.coordinate;
latitude = currentLocation.coordinate.latitude;
longitude = currentLocation.coordinate.longitude;
[locationManager stopUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"%#", [error description]);
}
Location only shows on a real device. You may find the values in the CLLocationManager will work in the Simulator (possibly from your exchange - although it wont be very accurate) but the blue pin on the map will always be in CA!

CLLocation, getting new locations

In More iPhone Programming book, the author does:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([newLocation.timestamp timeIntervalSince1970] < [NSDate timeIntervalSinceReferenceDate] - 60)
locationCoordinate = newLocation.coordinate;
return;
...
To make sure the data was taken in the last minute. Two questions:
1) What is the if statement doing. It seems like on the left hand side, you are getting the time difference in seconds between when this method fires and the 1970 date. Then on the right hand side, you get the difference in seconds between the 2001 date and now minus 60 seconds. So to me, the if statement would never be valid since the data on the left is always going to be a greater amount of seconds. Or am I understanding it wrong?
2) What does return in a void function do? Is that considered good coding here? Thx.
I don't know what is going on here, its confusing statement, I have use something like this
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if( abs(howRecent) > 1.0 )
return;
////process your event here
}
It is right to put return in void method, as I don't want to execute the statement next for some conditions..the same code can be written as
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if( abs(howRecent) < 1.0 ){
///process your event
}
}
it just depends upon your need.
for the if block :
the value return by timeIntervalSinceReferenceDate could be negative. see the description .
If the receiver is earlier than the
reference date, the value is negative.
So if condition could be false.
For the return statement.
if you want your function to return the control to the calling function before reaching the function closed bracket on some condition. See the eg.
-(void) SomeFunction
{
if(Condition1)
{
return;
}
}