<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Backspace Prologue &#187; gps</title>
	<atom:link href="http://troybrant.net/blog/tag/gps/feed/" rel="self" type="application/rss+xml" />
	<link>http://troybrant.net/blog</link>
	<description>Mistakes and learnings of an iPhone developer</description>
	<lastBuildDate>Fri, 08 Jul 2011 22:15:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Detecting Bad CoreLocation Data</title>
		<link>http://troybrant.net/blog/2010/02/detecting-bad-corelocation-data/</link>
		<comments>http://troybrant.net/blog/2010/02/detecting-bad-corelocation-data/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 06:21:57 +0000</pubDate>
		<dc:creator>Troy</dc:creator>
				<category><![CDATA[iPhone Development]]></category>
		<category><![CDATA[cllocation]]></category>
		<category><![CDATA[cllocationmanager]]></category>
		<category><![CDATA[corelocation]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[runmonster]]></category>

		<guid isPermaLink="false">http://troybrant.net/blog/?p=64</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p><code>CoreLocation</code> can (and will) give you poor location data. Over the course of developing <a href="http://www.runmonster.com/">RunMonster</a>, 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.</p>
<p>When a new point comes in, it is invalid and can be discarded if it matches any of the following criteria:</p>
<ul>
<li>The location is nil.</li>
<li>The location&#8217;s horizontalAccuracy is &lt; 0.</li>
<li>The timestamp of the new location is earlier than the timestamp of the previous location, indicating the points came in out of order.</li>
<li>The timestamp of the new location is set to a time before your app was even initialized.</li>
</ul>
<p>In regards to the last bullet, the <code>CoreLocation</code> 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.</p>
<h2>The Code</h2>
<p>The helper method below checks for these four cases to determine if the newly reported location is valid or not:</p>
<div class="code">
&#45; (<span class="primitive">BOOL</span>)isValidLocation:(<span class="built_in_type">CLLocation</span> *)newLocation<br />
&nbsp;&nbsp;&nbsp;&nbsp;withOldLocation:(<span class="built_in_type">CLLocation</span> *)oldLocation<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// Filter out nil locations</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (!<span class="var">newLocation</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span> <span class="keyword">NO</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// Filter out points by invalid accuracy</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (<span class="var">newLocation</span>.<span class="property_call">horizontalAccuracy</span> <span class="var">&lt;</span> <span class="number">0</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span> <span class="keyword">NO</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// Filter out points that are out of order</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in_type">NSTimeInterval</span> <span class="var">secondsSinceLastPoint</span> =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[<span class="var">newLocation</span>.<span class="property_call">timestamp</span> <span class="method_call">timeIntervalSinceDate</span>:<span class="var">oldLocation</span>.<span class="property_call">timestamp</span>];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (<span class="var">secondsSinceLastPoint</span> <span class="var">&lt;</span> <span class="number">0</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span> <span class="keyword">NO</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// Filter out points created before the manager was initialized</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="built_in_type">NSTimeInterval</span> <span class="var">secondsSinceManagerStarted</span> =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[<span class="var">newLocation</span>.<span class="property_call">timestamp</span> <span class="method_call">timeIntervalSinceDate</span>:<span class="ivar">locationManagerStartDate</span>];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> (<span class="var">secondsSinceManagerStarted</span> <span class="var">&lt;</span> <span class="number">0</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span> <span class="keyword">NO</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// The newLocation is good to use</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span> <span class="keyword">YES</span>;<br />
}
</div>
<p><code>locationManagerStartDate</code> is an <code>NSDate</code> that records when the <code>CLLocationManager</code> is initialized:</p>
<div class="code">
<span class="ivar">locationManager</span> = [[<span class="built_in_type">CLLocationManager</span> <span class="method_call">alloc</span>] <span class="method_call">init</span>];<br />
<span class="ivar">locationManager</span>.<span class="property_call">delegate</span> = <span class="keyword">self</span>;<br />
[<span class="ivar">locationManager</span> <span class="method_call">startUpdatingLocation</span>];</p>
<p><span class="ivar">locationManagerStartDate</span> = [[<span class="built_in_type">NSDate</span> <span class="method_call">date</span>] <span class="method_call">retain</span>];
</div>
<h2>That&#8217;s a Wrap</h2>
<p>If you are developing any kind of distance-tracking application that uses the phone&#8217;s GPS, you should definitely consider using the filters above. These particular error cases were discovered through trial and error, and as Apple improves <code>CoreLocation</code>, they may very well fix these problems. However, these filters have helped <a href="http://www.runmonster.com/">RunMonster</a> avoid the wacky GPS issues that plague many distance-tracking applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://troybrant.net/blog/2010/02/detecting-bad-corelocation-data/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

