“Make it even better than Nike+” — How to filter locations (Tracking Highly Accurate Location in…

コンテンツ

In the last two sessions, we added a background tracking engine + map drawing to our sample code.

Having a short run with the sample app makes you feel it already works like a normal running app as Runtastic.

But you might encounter some situation where your app doesn’t work correctly.
Especially when you are running ..

  • under cloudy weather
  • in an alley surrounded by tall buildings
  • in a forrest or park with many trees

To make your app work more accurate as Nike+ under such situation, you need to make your app log “good locations only”.

In this blog post, I’m going to explain how to make various filters to log good locations only.
Logging accurate locations only helps the app not only draw beautiful path on the map, but also calculate accurate distance or speed from those locations.

Open onLocationChanged() method and replace locationList.add(newLocation) with filterAndAddLocation().

Instead of simply adding new location to the list, we pass the location object to filterAndAddLocation() and add the location to list only when the location is accurate enough.

We do all the filtering in filterAndAddLocation(). Let’s check the code.

We do three types of filtering here.

Filter by timestamp

Location class has an instance function named getElapsedRealtimeNanos that returns when the phone’s GPS hardware obtains the location information.

The returned value from getElapsedRealtimeNanos is elapsed time since the system boot in nano seconds. We compare the value with SystemClock.elapsedRealtimeNanos which is also elapsed time since the system boot.

The diff between these two values is “how old this location information is”.

Here is the code to get this “oldness” of the location.

You may think why we get old locations from GPS ?

GPS is a sensor, but type of sensor which returns the value asynchronously. How quickly a location information is obtained from GPS is affected by below factors.

  • Location of GPS satellites — GPS satellites are not geostationary satellites, thus number of satellites and their location above the user change from time to time.
  • Obstacles between GPS satellites and the user’s phone — Buildings, trees, cloud and etc.
  • Locations of 3G/4G base stations — Type of GPS chip embedded in normal Android phones are Assisted GPS or A-GPS which uses assistance of 3G/4G base stations to calculate the user’s location. Accessibility to base stations affects the speed of location information acquisition (and the accuracy of the location information).
  • Obstacles between 3G/4G base stations and the Android such as buildings.

When above condition is bad, the GPS hardware won’t get any location. You may have a experience of the Google Map not showing your location when you were in a building. It was because of such situation.

In this case, LocationManager gives a cached location to the app. Cached location is a location which was obtained earlier when the above condition was better.

Cached location is not the user’s current location, thus showing it on the map makes your app look inaccurate.
To avoid logging and showing cached locations, let’s filter out the old locations by using getLocationAge() function we made above.

In this sample app, we filter out locations if the returned value of getLocationAge() is larger than 10 seconds.

A user could run around 40 meters in 10 seconds. Without this filter, the user’s location will be shown 40 meters behind the actual location.

Filtered by horizontal accuracy

Location class has an instance function named getAccuracy() which returns the horizontal accuracy of the location object (We earlier used this value to draw the circle around the user’s current location on the map).

The horizontal accuracy is the value indicating which accuracy range (in meters) the location would be in. Say if the value is 20, the actual user’s position can be within a circle with the radius of 20 meters from the location value.

We first validate the horizontal accuracy to be equal to or more than 0 meter.
Apple’s document says,

“A negative value indicates that the location’s latitude and longitude are invalid”

If the horizontal accuracy is negative value, the location information is invalid. We filter this location out.

If the horizontal accuracy is non negative value, we will further examine the value.
In this sample if the horizontal accuracy is more than 100 meters, we filter the location out (which means we log locations with their accuracy value less than 100 meters).

You may want to change this threshold from 100 based on your app’s purpose.

If your app is like Uber, less than 100 meters may be suitable. If you are making a running app and calculating the distance and pace based on location information, you may set it more strict like 50 meters or 30 meters.

Below is the screenshot where I set the threshold as 10 meters. The yellow dots are the locations filtered out by this filter and the blue path is the track connecting location which passed the filter. Find the best value for your app.

Filter by Kalman Filter

Filters I’ve explained so far is enough to get accurate locations in most cases, but I have observed locations which passed those filters but still dotted at the wrong position on the map in the past.

Those locations have fresh timestamp and good accuracy value, but still wrong.

I’ve seen those mal-locations once or twice while running some kilometers at the time of Android 4.x.
Nowadays, it’s so rare and I’ve never seen these mal-locations while making and testing this sample app.

Android API documents says the reliability of getAccuracy() value is 68%.

So still, Android could give you fake accuracy values.

Again it’s so rare nowadays with recent phones and GPS & 3G/4G environment in Tokyo, but if you need to support old phones or your users are in the area where 3G/4G network is weak, you may see those mal-locations on your app.

At the time of Android 4.x, I made and used Kalman filter to filter out those mal-locations.

Kalman filter give you a rough assumption of the user’s future location based on his/her past track.
My filter compare this assumed location and actual location of the user, and if it’s so different, filter out the location.

Check Google to learn more about Kalman filter itself. My Code is below.

At the code number 13, I give latitude, longitude, horizontal accuracy, elapsed time, and current pace in meters per second to the Kalman filter.
This method returns a assumption of the next location of the user.

In this sample if the distance between the assumption and the actual is longer than 60 meters, we filter out the location.

In my past experience, mal-locations are “so mal” and always far from my actual locations, thus 60 meters of the threshold was enough in my case.

My sample code draws the green circle that covers 60 meters (the threshold) around the assumed location by the Kalman filter. This is the area where my filter passes locations.

You use this green circle and check your threshold of this filter is appropriate for you case.

Let’s compare with RunKeeper and Nike+

Ok, we have coded enough.
I tested the sample app till here and compared its performance with Runkeeper and Nike+.

I opened both my app and Runkeeper on my Android and run for about 3 kilometers.

Here is the tracked path

Run Keeper and my app

I did the same with Nike+

Nike+ and my app

These two trials are not enough to be called as an experiment, but the filter I explained above seems to have made our app to perform the same as Runkeeper and Nike+.

Even better tracking engine

There is still some room to make this tracking engine even better.

If you run in a forest on a day of heavy rain with your phone in your backpack, you might see your app tracks nothing.
If you see such case, your filter might be too strict.

Last few steps to make the tracking engine greater is to make your filter adaptive to the environment.

I won’t go deeper in this but here is a couple of hints

  • Knowing the condition from average horizontal accuracy
  • Knowing the condition from temporal interval between location callbacks
  • Knowing the weather

Take up the challenge, and make your engine even greater!

I’m running an app development studio in Tokyo called Goldrush Computing.
If you need any development force to empower your app with location tech magic, feel free to contact me any time.

[email protected]
@goldrushcomp

要約する
The article discusses the importance of filtering and logging accurate locations in a running app to improve accuracy under various conditions like cloudy weather or areas with obstacles. It explains filtering methods based on timestamp, horizontal accuracy, and Kalman filter to eliminate inaccurate locations. The author suggests adjusting the filtering thresholds based on the app's purpose. Comparisons with popular running apps like Runkeeper and Nike+ are made to showcase the effectiveness of the filtering techniques. The article also mentions the potential for further improvements in the tracking engine by adapting filters to environmental conditions. Lastly, the author encourages developers to enhance their tracking engines for better performance. The article provides insights into location technology and offers development services through Goldrush Computing in Tokyo.