Even cheap smart phones in the UK now have GPS capability. The rapid expansion in spatially aware devices has been driven by the potential for commercial use of location data. Location to nearest postcode is good enough for many of these purposes, but more accurate fixes are needed for Sat Nav. Contemporary phones therefore use a combination of network based methods and satellite GPS to obtain a fix. Accuracy, once a GPS fix has been obtained, is assumed to be within 10m.
Students carrying out field research projects could therefore potentially use their own mobile phones to log positions. However are phones suitable for scientific use? Do they provide reliable data? In order to be used for research is vitally important to have some measure of the reliability of positional information. How accurate are cell phone GPS fixes? How does accuracy vary?
I recently acquired two new, but low end Android phones (Hyundai Pulse Mini) for family use. These cost just thirty pounds (600 pesos) each, plus ten pounds phone credit. Almost unbelievably cheap. These phones are clearly bottom end devices. Nevertheless I have been pleasantly surprised by how useful they are. They provide me with all the usual smart phone services I need, including perfectly acceptable Sat Nav and good general mapping capability including the recording of apparently reliable track logs and waypoints in gpx format. The Android operating system is very intuitive to use. The only real problem with the devices themselves is short battery life. But, could they be used for georeferencing research sites?
This was not an easy question to answer as I could find no detailed information online regarding the specifications of the GPS chipset that they contain. It is not even clear whether such phones use EGNOS (the European equivalent of WAAS). All cell phones have “enhanced GPS”, but this refers to the method used for improving the speed of the fix by using network signals in built up areas. EGPS does not improve accuracy as such. So the main issue for research applications is lack of knowledge regarding how precision may vary and what factors influence variability.
The android Market has a large number of useful GPS tools, including the default Google maps,a useful app called “GPS essentials” and the Locus app. A promising little tool for analysing positional error and correcting it is GPS averaging.This tool logs the position at regular intervals and calculates the mean position over a time period. If errors were random over time then the mean should provide a very accurate fix. I tested this by running the app for several ten minute periods.
The good news was that the overall accuracy of the GPS was always within 4 metres of the target. The bad news was that positional errors were correlated over relatively short time periods, so taking a mean did not increase accuracy by much, due to the overall bias over all the measurements.
I tried this test several times over the space of a few days. The pattern was always similar. The GPS fixes tended to have a correlated bias over a period of up to an hour or more. Overall accuracy was always within 5m, but apart from removing the effect of odd extreme outlier, averaging did not improve the precision by much. A more systematic study over a longer period would provide more quantitative details and even reveal patterns in the bias that may be associated with the satellite positions.
However, I had another idea. I have two very similar phones. It occurred to me that if the positional error turns out to be the same for both I could build my own differential GPS by connecting them using Blue Tooth and sending the position of one to the other. I couldn’t find a pre-built app for this so I tried out the Python scripting environment for Android. This can be downloaded and installed here.
I had never programmed in Python, so the code is very scrappy. However it was not difficult to adapt some of the code given in the example scripts in order to cobble together a very rough and ready proof of concept script.
It ran fine, but the results were not as I expected. I found that each phone registered quite different positions when placed together (something I could in fact have easily tested before by taking a tracklog or using GPS averaging without the need to write the Python script!). The error turned out to be as much as 6m, but tended to fall over time to around 50 cm over the space of twenty minutes under a clear sky. So the two phones could not really be used as a differential GPS, although the overall accuracy of either seems to be acceptable for many general types of field work that do not involve site surveying.
Anyway the Python code I came up with is provided below in case it is of use to anyone. The script can be downloaded by clicking here — differentialgps.py
There are some known issues with the code. If these were tackled it might be possible to improve the results I got. The most important defect was that the readLocation() method did not always return a result, so I used getLastKnownLocation() instead, in order to get the script working. This meant that the two fixes may not have been calculated at identical times. Even taking this into account the readings from the two phones had much larger differences than I expected. Another obvious issue with the general approach I used here is the limited range of blue tooth and the fact that I did not add any way of handling exceptions when the Bluetooth signal was lost.
The script must be placed on both phones and run in a console in SL4A. First run the script on one phone to make it a server then connect the second as a client. Close the server first for a clean exit. The results are written to two files on the client phone.
import android import time import math droid = android.Android() droid.startLocating() fclient = open('GpsClientLog.txt', 'w') fserver = open('GpsServerLog.txt', 'w') droid.toggleBluetoothState(True) droid.dialogCreateAlert('Be a server or client?') droid.dialogSetPositiveButtonText('Server') droid.dialogSetNegativeButtonText('Client') droid.dialogShow() result = droid.dialogGetResponse() is_server = result.result['which'] == 'positive' if is_server: droid.bluetoothMakeDiscoverable() droid.bluetoothAccept() timelapse = droid.getInput('GPS server', 'Enter number of seconds between readings').result while True: time.sleep(int(timelapse)) event=droid.readLocation() location = droid.getLastKnownLocation().result if location['gps'] is not None: location = location['gps'] method="gps" else: location = location['network'] method="network" lat=location['latitude'] lon=location['longitude'] print method+','+str(lon)+','+str(lat) fserver.write(str(lon)+','+str(lat)+'\n') droid.bluetoothWrite(method+','+str(lon) +','+str(lat)+ '\n') fserver.close() else: droid.toggleBluetoothState(True) droid.bluetoothConnect() while True: ServerPosition = droid.bluetoothReadLine().result print ServerPosition event=droid.readLocation() location = droid.getLastKnownLocation().result if location['gps'] is not None: location = location['gps'] method="gps" else: location = location['network'] method="network" lat=location['latitude'] lon=location['longitude'] slon=float(ServerPosition.split(',')) slat=float(ServerPosition.split(',')) dist=round(math.sqrt(math.pow((slon-lon)*69930,2)+math.pow((slat-lat)*111122,2)),2) print "Approximate distance="+str(dist)+"metres" print method+','+str(lon)+','+str(lat) fclient.write(time.asctime()+','+method+','+str(lon)+','+str(lat)+'\n') fserver.write(time.asctime()+','+ServerPosition+'\n') fserver.close() fclient.close()