How accurate is CLLocation accuracy? - iphone

I'd like to use reliable locations, even on an old iphone. However, many readings (particularly from cell towers) are too inaccurate. I think.
When I plot my position + accuracy radius (or look at google maps app), I notice the center of the estimated circle is generally close to my physical location. I'm guessing that if I cut the "accuracy" number in half, I'll still be in the circle 99% of the time.
I believe this is a probabilistic game - the location manager is trying to provide an estimate that's correct 99.99999% of the time, so they give a deliberately wide margin. Any thoughts/info?

The CoreLocation framework gives you the radius of the circle for every CLLocation you get using the horizontalAccuracy/verticalAccuracy properties. You can specify to the CLLocationManager a desiredAccuracy property that use these types:
kCLLocationAccuracyNearestTenMeters, kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer, kCLLocationAccuracyThreeKilometers;
So you get notifications when you get inside your desired range. That said, when you use the CLLocationManager the first event is given to you ASAP, and then the proceeding events are the ones that satisfy your conditions.

When you're using CoreLocation, you're getting back "answers" that get better and better. I've noticed that the "best" answer is almost always accurate to within 100m, so theoretically you could probably cut down on the "buffer" that you're normally given. The only way to really know, though, and this is what I would do, is to test test test. Find iphones and ipods from all generations and see what types of accuracies you're getting and what types of results you're getting. In a lot of ways, it depends on the type of app you're making, but if you want to deliver sensitive or important information based on where the user is, you should really wait for the framework to give you a nearly exact location.

Related

Finding distance using accelerometer in iPhone

Please suggest some beginning point in this process of finding distance displaced by an iPhone. The requirement of accuracy in current system is in cm, and displacement can be in 3D.
What I have already done is
1. Tried using sound to calculated distance between between 2 iPhones, but I need distance calculation with one iPhone only, i.e need displacement.
2. Tried CMMotionManager and its accelerometer data, but values received is helpless.
I think I need a good filter to get useful data out of that junk. I already used Kalman Filter and gone through link
iphone accelerometer speed and distance,
How to calculate distance using accelerometer using iphone sdk?,
How do I measure the distance traveled by an iPhone using the accelerometer?,
Basic calculus behind this problem is in the expression
Tried DCT-II algorithm and Multidimensional DCTs to filter data.
I dont know what did I miss, or where should I go from here, as it is hard to believe that no one has used accelerometer for such an accuracy, because there are so many practical examples of it being used for greater accuracy.
Please provide me some pointer that suggest some way out of current situation.
You can't achieve cm accuracy. The reason is, surprisingly, the orientation error.
The above link contains some tips what you can do if you need displacement.
An even better alternative is to use orientation in you application, if you can.

(iOS) Multiple notifications via locationManager:didExitRegion: when exiting a region

I'm working on a location-based app that makes use of the CLLocationManager region monitoring.
I'm using a single CLLocationManager and single delegate (which are set up in the main app delegate at startup), and I'm noticing that I often get a burst of multiple calls to my delegate (on locationManager:didExitRegion:) when exiting a monitored region -- usually two calls, but sometimes more. Has anyone else experienced this, or have any ideas what can be going wrong?
I'm instantiating the CLLocationManager as follows, in a class that is instantiated in the app delegate:
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
_locationManager.delegate = self;
I'm setting up region monitoring like this:
// The region instance has a radius of 300 meters
[_locationManager startMonitoringForRegion:region desiredAccuracy:1000];
As I understand from the documentation, providing the desired accuracy of 1000 means that locationManager:didExitRegion: should only be called once we're 1000 meters outside of the region.
On additional point -- as far as I've seen, I only get a burst multiple notifications if I'm in the car (and therefore travelling quite quickly). It doesn't seem to happen if I'm on a bike or on foot. Any pointers as to what I'm doing wrong (or if this is an issue that others have already encountered) are appreciated.
tl;dr: It's really quite simple - you're getting as much information as Apple can give you about the fact that you're crossing cell tower boundaries - meaning, not really good data at all.
Now the real story:
Generally, there are only a couple of ways that CoreLocation can determine one's position:
By GPS. This is highly accurate (tens of meters), but takes lots of power to use.
By WiFi. This is generally accurate, though wifi base stations can and do change, which makes it fuzzy. This method cross-references the wifi stations in the area vs some known accurate locations - so it knows when it sees "FooWifiStation" that it's associated with a particular area, measured by precise instruments, or perhaps even other phones with GPS turned on (which is controversial, we may never know if Apple uses this method)
By cell tower locations. These don't move, so it knows you're within a big fuzzy dot of coverage when you're associated with a tower. This is the least accurate, but least power-consuming, because your phone is already doing the work to stay in contact.
You can even see this if you go into the maps application "cold": you start out immediately with a big fuzzy blue dot, (at least 1km where I am), then it shrinks as it gets a wifi location fix, then it more or less disappears when GPS gets its fix. It's doing [cell tower] => [wifi] => [gps] accuracies in real time.
From my experience, the "significant location change" clause means "We'll let you know whenever you move in a big way, as long as we don't have to do any more work or expend any more power to get you that data. This means de facto that the very best you can rely on is using transitions between cell towers. Apple deliberately left this vague, because if another app uses something that has better resolution - say, you open Maps.app, and it gets a GPS fix - it is possible that you will suddenly get a great fix on location, but you can't depend on that always being the case. You've asked for a "weak reference" to location.
Now think about what happens when you are wandering about in your car: your cell phone has to manage that transition. It gets handed off, talks to multiple towers at once, that sort of thing, to manage a seamless transition which must be viable while you are having a conversation. Just that is a pretty neat feat for any little box to do. Necessarily, this will cause you to see a bit of bounce in location updates, because, to the phone, you're vibrating between cell towers at this time as it negotiates the transition.
So what the radius really means is that you're interested in data of roughly that accuracy - but the API will not guarantee that you get updates within that radius. You can think of it as Apple saying, "We're going to bucket your accuracy into one of 3 groups - but we didn't give you an enumeration, because we want to reserve the right to develop better methods of fixing your location without you having to change your code". Of course, in reality, any real app will change if they change their method of getting location, because they are annoyingly vague about this location stuff.
In other words, you will get a location fix at the cell tower with some totally made up guess as to how good that accuracy is; when you move to the next tower, you will instantly jump to its location, with a similarly fuzzy fix - does that make sense? CoreLocation is telling you you're at the cell tower with accuracy of however far the cell tower's signal reaches; as you move to another tower, you will probably get the bounciness of the handoff.
So when it comes to it, to really do a good job, you have to assume that the data is one of "great", "ok", or "bad" and use other methods - like Kalmann filters - if you really need to have a better guess at where the user is. As a zeroth-order approximation, I would just debounce the callbacks based on the time of the update, which is given, and assume that the user isn't really leaping kilometers back and forth within a few seconds, but rather, travelling in the direction of the first new update.
I think you'd be better off, using a desiredAccuracy that is smaller than the radius of 300m, i.e. kCLLocationAccuracyHundredMeters. Have you tried that?
There is no documentation about the underlying logic, but I'd assume, that desiredAccuracy can be regarded as the minimium distance you'd have to travel that the movement counts as a "border crossing".
Region monitoring is based on "significant location events", not GPS – otherwise the battery wouldn't last half a day.
If you use such a high desiredAccuracy, the system might get more than one significant location event (these seem to be generated about every 500m – also depending how many wifi networks you have in the area.
In that case, the system might compare the current location resulting from the significant change with the distance to all sides of your region.
If you're just outside 1000m from opposite side of your region, it might notify again and only stop notifying once your outside the 1000m from each side of your region.
The reason for the accuracy parameter is rather to avoid border crossings, if you are too close to the border, so you're not seeing inside-outside-inside-outside etc while traveling just outside the border...
In my apps, I tried many many different combinations of radius and accuracy and settled on 500m/100m and 100m/10m – those work very well in my real work within-city szenario.
(see also the excellent article series http://longweekendmobile.com/2010/07/22/iphone-background-gps-accurate-to-500-meters-not-enough-for-foot-traffic/)
I'll bet this is your issue, locationManager:didExitRegion: gets called for EVERY region that every location manager in every application on your iPhone has registered. You need to compare the region's identifier string sent as a parameter with the region's identifier string of the region you want your app to currently do something with.
When you send [_locationManager startMonitoringForRegion:region desiredAccuracy:1000]; you're creating a region, if it doesn't already exists to be monitored for. This is NOT the same as adding an observer to NSNotification Center. Apple's region object blindly sends the notification to EVERY CLLocationManager which then sends the message to the delegate.
First, the documentation does not indicate that desiredAccuracy alone determines how far out of a region you need to be, before didExitRegion event is generated. If you want to fine-tune how often events are fired, you need to use the distanceFilter as well, which determines the horizontal movement you need to have moved before an event will be fired.
If use of the distanceFilter does not work, then I would recommend the following:
If you are using NSNotificationCenter, then ensure that you have removed other classes from notification, via [[NSNotificationCenter defaultCenter] removeObserver:self]. You can optionally specify a name and object to this call.
1000 Km is a large radius, which has a high chance of intersecting with many regions in the vicinity. I would try a lower number for this parameter to see if that doesn't decrease the number of exit notifications that you are receiving. The only thing that indicates that this may not be the solution is that you did not say you are receiving blasts of didEnterRegion as well.
Lastly, I would check the identifier of the CLRegion being passed in the didExitRegionEvent, to see if you can't set up an NSDictionary of regions yourself. You'll have to set a region to the dictionary on didEnterRegion, and remove it on didExitRegion. So, on didExitRegion, all you have to do is ensure that you are interested in the region by checking that you have the region already. I would guess that CLRegion is already equipped with isEqual: and hash to allow it to be stored in a collection.
Good luck!
I found that in order to save battery you have to use monitorForSignificantLocationChange.
My solution is to filter out multiple alerts coming within 60 seconds for the same region:
-(BOOL)checkForMultipleNotifications:(GeoFenceModel*)fence
{
GeoFenceModel *tempFence = [fenceAlertsTimeStamps objectForKey:fence.geoFenceId];
if(tempFence == nil){
fence.lastAlertDate = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]];
[fenceAlertsTimeStamps setObject:fence forKey:fence.geoFenceId];
NSLog(#"checkForMultipleNotifications : no Notifications found for Region : %#, Adding to Dictionary with timestamp %.1f",fence.geoFenceId,fence.lastAlertDate.doubleValue);
}
else if(([[NSDate date] timeIntervalSince1970] - fence.lastAlertDate.doubleValue) <= 60.0){
NSLog(#"checkForMultipleNotifications : Multiple region break notifications within 60 seconds, skipping this alert");
return NO;
}
return YES;
}

Translate GPS coordinates to location on PDF Map

I'd like to know (from a high level view) what would be required to take a pdf floor plan of a building and determine where exactly you are on that floor plan using GPS coordinates? In addition to location, the user would be presented with a "turn by turn" directions to another point on the map, navigating down hallways, between cubicles, etc.
Use case: an iPhone app that determined a user's location and guided them to a conference room or person's office in the building.
I realize that this is by no means trivial, but any help is appreciated. Thanks!
It's an interesting problem. When you're using Core Location, you're not necessarily using GPS. Using WiFi and cell tower triangulation, you can get pretty good location results. So from Core Location you get a latitude and longitude fix. (You might also get altitude info, since GPS data is 3-dimensional. You also will get an accuracy value.)
So you have lat and lon. You need to map these coordinates to the PDF plan's coordinates. Assuming that the plan is aligned with the latitude and longitude lines, and that you have a lat-long fix for one of the points on the plan, you need to calculate the x-axis scale and y-axis scale. Then it's some calculations to map the lat-long to x-y coordinates on the PDF plan.
GPS may not be accurate enough for this purpose, especially indoors. Assuming errors on
the order of 10 meters, you'll have difficulty determining which floor the user is on.
Here's a neat (?) idea that might work: can you post some "You are here" placards
at various locations around the building? You could label each one with a unique,
machine-readable location code (maybe a QR code or something similar), then take an
image using the camera, have your app read that image and interpret the location code,
and use that instead of GPS to determine the start location.
GPS inside? That's your first -- and biggest -- hurdle.
Next hurdle is knowing the GPS coordinates of at least three points on that PDF to define the plane of of your map in the real world. (The PDF will need to be to scale, of course.)
So that gives you where you are on the PDF. Now you'll need to figure out some way to determine where you can walk (or where you can't) to get directions.

How accurate is the reading for GPS in iPhone's SDK?

Using iPhone's SDK GPS API, how accurate can I get? Is it within a few meters or kilometers? I'm interested in the accuracy when it is indoor. My software will only be used in door.
The best possible accuracy seems to be 9 meters. Common values (outdoor, good coverage) is 17 m, 23 m and 49 meters. With trees covering the sky you'll probably stay under a hundred meters, but hardly accurate enough for GIS or anything like that.
The API has a property or method that returns the current accuracy of the location measurement. If your goal is only to use the location if accuracy is within some limit then you should make sure that you check the returned accuracy, since the location may be only accurate to within a few thousand meters initially as its just using your location from the cell towers, and it will typically get better and better accuracy as the GPS powers up and starts getting a fix.
Most standard GPS chips (and the iphone is that) can get around 10 meters accuracy.
Best results are outside on a clear sky obviously.
The difference between GPS chips is usually how quickly they can reception and how well they can hold it. Accuracy is pretty constant except for those using WAAS sattelite (which the iphone GPS doesn't do)
Based on my own experience it's within meters.

Detect the iPhone rotation spin?

I want to create an application could detect the number of spin when user rotates the iPhone device. Currently, I am using the Compass API to get the angle and try many ways to detect spin. Below is the list of solutions that I've tried:
1/ Create 2 angle traps (piece on the full round) on the full round to detect whether the angle we get from compass passed them or not.
2/ Sum all angle distance between times that the compass is updated (in updateHeading function). Let try to divide the sum angle to 360 => we could get the spin number
The problem is: when the phone is rotated too fast, the compass cannot catch up with the speed of the phone, and it returns to us the angle with latest time (not continuously as in the real rotation).
We also try to use accelerometer to detect spin. However, this way cannot work when you rotate the phone on a flat plane.
If you have any solution or experience on this issue, please help me.
Thanks so much.
The iPhone4 contains a MEMS gyrocompass, so that's the most direct route.
As you've noticed, the magnetometer has sluggish response. This can be reduced by using an anticipatory algorithm that uses the sluggishness to make an educated guess about what the current direction really is.
First, you need to determine the actual performance of the sensor. To do this, you need to rotate it at a precise rate at each of several rotational speeds, and record the compass behavior. The rotational platform should have a way to read the instantaneous position.
At slower speeds, you will see a varying degree of fixed lag. As the speed increases, the lag will grow until it approaches 180 degrees, at which point the compass will suddenly flip. At higher speeds, all you will see is flipping, though it may appear to not flip when the flips repeat at the same value. At some of these higher speeds, the compass may appear to rotate backwards, opposite to the direction of rotation.
Getting a rotational table can be a hassle, and ensuring it doesn't affect the local magnetic field (making the compass useless) is a challenge. The ideal table will be made of aluminum, and if you need to use a steel table (most common), you will need to mount the phone on a non-magnetic platform to get it as far away from the steel as possible.
A local machine shop will be a good place to start: CNC machines are easily capable of doing what is needed.
Once you get the compass performance data, you will need to build a model of the observed readings vs. the actual orientation and rotational rate. Invert the model and apply it to the readings to obtain a guess of the actual readings.
A simple algorithm implementation will be to keep a history of the readings, and keep a list of the difference between sequential readings. Since we know there is compass lag, when a difference value is non-zero, we will know the current value has some degree of inaccuracy due to lag.
The next step is to create a list of 'corrected' readings, where the know lag of the prior actual values is used to generate an updated value that is used to create an updated value that is added to the last value in the 'corrected' list, and is stored as the newest value.
When the cumulative correction (the difference between the latest values in the actual and corrected list exceed 360 degrees, that means we basically don't know where the compass is pointing. Hopefully, that point won't be reached, since most rotational motion should generally be for a fairly short duration.
However, since your goal is only to count rotations, you will be off by less than a full rotation until the accumulated error reaches a substantially higher value. I'm not sure what this value will be, since it depends on both the actual compass lag and the actual rate of rotation. But if you care only about a small number of rotations (5 or so), you should be able to obtain usable results.
You could use the velocity of the acceleration to determine how fast the phone is spinning and use that to fill in the blanks until the phone has stopped, at which point you could query the compass again.
If you're using an iPhone 4, the problem has been solved and you can use Core Motion to get rotational data.
For earlier devices, I think an interesting approach would be to try to detect wobbling as the device rotates, using UIAccelerometer on a very fine reporting interval. You might be able to get some reasonable patterns detected from the motion at right angles to the plane of rotation.