Decimeter Precision GPS

Last year I wrote some special software to help me define GPS waypoint coordinates for guiding my autonomous robot car, Johnny Five.  This actually helped a lot, as it cut down on the steps I needed to perform on the day of competition for the Sparkfun AVC.  However, the software I wrote had to rely on the accuracy of Google Maps and, through experimentation, I'd discovered that the positions displayed in Google Maps could be off my several meters in some cases.  Since the accuracy of the GPS I use in Johnny Five, the U-blox LEA-6H, only has a rated accuracy of 2.5 meters CEP, any inaccuracy in placing navigation waypoints only added to the overall inaccuracy.  However, if I could discover a way to get the precise position of one, or more visible landmarks I could locate near the AVC course, I reasoned I could use this to compute an adjustment offset to improve the accuracy of the waypoints I defined using Google Maps.

U-Blox's Precise Point Positioning

Surveyors use a variety of techniques to improve the accuracy of the reading they take using professional, dual frequency GPS receivers.  However, the cheapest dual frequency receivers cost thousands of dollars, so that approach was out of my budget.  U-Blox makes a GPS module called the NEO-6P that claims to use something called Precise Point Positioning, or PPP, to improve it's measurement of static GPS locations.  Taking a reading requires leaving the receiver in one location for several minutes and, over time, the NEO-6P is supposed to improve the accuracy of its readings using techniques that the manufacturer does not actually describe other than to claim a "precision of < 1 meter".  I was skeptical, especially since the NEO-6P is not cheap, but decided to give it a try anyway.  The NEO-6P is rather hard to find in the form of an assembled module with antenna, so I settled on one sold by CSG Shop that takes an external antenna.  Here's a photo of the module I purchased:

Click for larger view

The module connects to the NEO-6P's built in USB serial interface and also provides header pins for TX, RX, SDA and SCL, so you can talk to it either via serial, or I2C.  I elected to use the built in USB interface.  So, the next challenge was to write some software in order to collect some data for analysis.  U-Blox makes software for this purpose, but it only runs on Windows and I wanted to have something I could use on my MacBook Air in the field without having to use BootCamp or Virtual PC, as I get tired of having to maintain and update dual environments.  Also, I like having the flexibility to tweak things to my liking.

The Java-based software I wrote, UBloxSatMap, was designed to mimic some of the features provided by U-Blox's u-center software, such as a realtime readout of various values, such as HDOP, etc.  It can also display a sky map showing the current location of all the GPS satellites it's tracking, as well as showing which ones are using the special "smoothing" algorithm that supposed to be a part of the secret sauce that lets the NEO-6P do PPP.  Here's a screenshot that shows the Sat View screen in operation:

Click for larger view

The shape of a sat is round if it's being used by the smoothing algorithm, else it's drawn as a square.  Likewise, the shape is filled if using SBAS corrections for that satellite, or unfilled, if not.  Also, it's colored blue if it's currently used for navigation, gray if not used and red if the quality of the fix is less than 4.  The text to the right of each sat shows it id number and which GPS block it's part of (IIF, IIR, etc.) and, inside the parenthesis, CNO and elevation above horizon in degrees.)  Finally, the special SBAS satellites that provide WAAS correction data are shown by the names, Anik FIR, Galaxy 15 and Inmarsat 4F3.)  The main propose of the Sat View tab is to give me a quick way to visually evaluate the overall status of the fixes available from each satellite and compare this to the local environment where things like trees, buildings, etc. might block a particular satellite.

Next, I added a screen to display a scatter plot of the Lat/Lon coordinates being reported over time.  This provides a way to see how far the fix wanders around relative to an average position reading.  The idea was that this would give me a way to see if, and how quickly the special smoothing algorithm settled onto a more accurate fix.  Here's what what display looks like in a typical run:

Click for larger view

Each ring is one meter from the center so, in the positions plotted in the image above, all are within a 1 meter radius of the average position, which is fairly good and seems to fit with the claims made for the module.  However, I wanted to find a way to get even better readings by taking advantage of another feature built into the NEO-6P.

Pseudorange and Carrier Phase

About the time I was working on writing the code for UBloxSatMap , I stumbled across a slide set (and corresponding YouTube video) by two Australian authors, Ben Nizette and Andrew Tridgell from the Australian National University CanberraUAV.  This was from a presentation entitled "Affordable Differential GPS," in which they explore the idea of using corrections data from a fixed reference station to improve the accuracy of readings obtained from commercial, single frequency GPS receivers, such as the LEA-6H module I use in Johnny Five.  The current conclusion seems to be that this doesn't work so well in the LEA-6H module due to some shortcuts that were taken in how support for this feature was implemented.  However, in further email conversations with Ben Nizette I learned that the NEO-6P module had a hidden feature I thought was only available in the even pricier NEO-6T module, which is the ability to get what are called "RAW" readings from the module.  With RAW readings it's possible to use more advanced algorithms running on an external CPU. RTKLIB is an open source program that can do this kind of processing.

RTKLIB uses a technique called Differential GNSS, which uses a fixed reference station to differentially correct a roving station's position to get a more accurate fix.  You can't do this using the Lat/Lon values a typical consumer GPS spits out.  I only works if you have access to the raw data the GPS receiver uses to compute it's position (which are called pseudo range and carrier phase) as the corrections have to be applied to these measurements before they're used to compute a position.  Actually, the use of carrier phase is a modern addition, as early GPS receivers needed only the pseudo range data to compute a fix.  However, with the development of advanced mathematical techniques, it began to be possible to measure and use the phase of the actual carrier signal to greatly improve the accuracy of a GPS receiver.  With Differential GNSS, a CORS (Continuously Operating Reference Station) provides a stream of real-time data that can be used to correct the fix of a roving receiver that's a short distance away from the location of the CORS.

The correction data comes in the form of RTCM (Radio Technical Commission for Maritime Services) that some in several flavors, such as RTCM 2.x and RTCM 3.x.  RTCM 2.x is largely superseded by RTCM 3.x, as only this new set of messages contains the data needed to get really precise positioning (cm, or even mm level precision.)  Ben and Andrew, the Australian guys mentioned above, were trying to see whether the older RTCM 2.x messages, which can be interpreted by receivers like the UBlox LEA-6H, could be used to improve GPS accuracy.  This is particularly important to them because the WAAS system broadcasts that greatly improve the resolution of GPS receivers in the Northern Hemisphere are not available in Australia due to the position of the satellites.  I got interested because I was curious whether using RTCM 2.x corrections could, in some cases, be more accurate than using WAAS corrections.  I'm still investigating this, but Ben and Andrew concluded that the LEA-6H was not up to the task.  And, unfortunately, as far as I can tell, making use of RTCM 3.x correction messages requires the use of an expensive, dual frequency GPS, as I've yet to locate a consumer grade GPS receiver that was capable of using RTCM 3.x. 

Excuse Me, Do You Speak RINEX?

In addition to using the RTCM protocol to perform corrections in real time, there are also systems that can accept uploaded data files and process these against archived data recorded from a network of CORS receivers.  However, again, nearly all of these systems could only work with RAW data from dual frequency receivers.  However, in further conversations with Ben, I discovered that he'd found a Canadian system called the Canadian Spatial Reference System (CSRS), that can do this with pseudo range and carrier phase data from a single frequency receiver like my humble NEO-6P.  Curiously, the Canadian system also called the post processing service they provide "Precise Point Positioning", but Ben explained that PPP has become a catch-all term for systems that use high-precision models to correct the pseudo range and carrier phase data in order to produce more accurate position readings.  It can requires several hours of recorded data to get a really accurate fix, perhaps down to the decimeter level, or better depending upon conditions.

The barrier to entry to using the Canadian system, like most post-processing systems, is that it requires the uploaded pseudo range and carrier phase data to be uploaded in a special, text-based format called "Receiver Independent Exchange Format ", or RINEX.  Someday I wish at least a few of the people on on the committees that come up with these kinds formats would have a computer science background, but the RINEX standard is a mishmash of fixed fields mapped onto a text file where each line that can be no longer than 80 characters (were punch cards still around?) and must follow a strict format.  The first part of the file is a series of header lines that provides information about type of receiver and antenna used to record the data, the approximate position where the data was recorded (in "Earth-Centered, Earth-Fixed", or ECEF format, not Lat/Lon/Altitude format), the time of the first and last readings in the file, and so on.)  This web page gives a good overview of a RINEX 2.10 file and, if you hover the mouse pointer over a fields it will display information about the formatting of that field.  The rest of the RINEX file consists of a series of lines that record the  pseudo range and carrier phase values for any currently visible satellites.  Each block of data begins with one, or two lines that lists the time of the reading in GPS time and what satellites are used (it takes to two lines if there are more than 12 satellites visible.)  Next, the each satellite uses a line of text to record its  pseudo range and carrier phase values.

This web page gives a good overview of a RINEX 2.10 file and, if you hover the mouse pointer over a fields it will display information about the formatting of that field.  The rest of the RINEX file consists of a series of lines that record the  pseudo range and carrier phase values for any currently visible satellites.  Each block of data begins with one, or two lines that lists the time of the reading in GPS time and what satellites are used (it takes to two lines if there are more than 12 satellites visible.)  Next, the each satellite uses a line of text to record its  pseudo range and carrier phase values.  Here's a sample of the header, and the first few entries of a RINEX file:

     2.11           OBSERVATION DATA    M (MIXED)           RINEX VERSION / TYPE

UBloxSatMap         Wayne Holder        2014 03 31 17:53:22 PGM / RUN BY / DATE 

                                                            MARKER NAME         

                                                            MARKER NUMBER       

                                                            OBSERVER / AGENCY   

                                                            REC # / TYPE / VERS 

                                                            ANT # / TYPE        

 -2441636.8100 -4770935.2400  3446751.9300                  APPROX POSITION XYZ 

        0.0000        0.0000        0.0000                  ANTENNA: DELTA H/E/N

     1     1                                                WAVELENGTH FACT L1/2

     2    C1    L1                                          # / TYPES OF OBSERV 

  2014     4     1     0    54   14.9990000     GPS         TIME OF FIRST OBS   

  2014     4     1     1    41   53.0000000     GPS         TIME OF LAST OBS    

                                                            END OF HEADER       

 14  4  1  0 54 14.9990000  0 13G28G 8S35S38G19G 7G13G26G11G17G10G 5

                                G 9

  20776759.466    -2044417.102  

  20579501.550    -2175020.714  

  36955253.098    -1845080.7812 

  36810832.888    -3350174.0972 

  23079943.093     -772263.106  

  20628618.425    -1681938.684  

  22867793.999      154123.366  

  22195721.644    -2995185.438  

  23014934.331    -2476041.896  

  23269910.438    -3725242.974  

  24904157.681    -1494878.5033 

  24529092.664    -1115645.860  

  20032203.958    -2467019.209  

 14  4  1  0 54 19.9990000  0 14G28G 8S35S38G19G 7G 1G13G26G11G17G10

                                G 5G 9

  20769694.649    -2081543.958  

  20571786.084    -2215563.789  

  36948404.245    -1881070.3882 

  36803986.836    -3386149.8482 

  23075730.811     -794400.336  

  20622471.778    -1714241.326  

  24463774.528    -3733419.7343 

  22864396.511      136271.258  

  22186143.909    -3045513.511  

  23006886.064    -2518337.526  

  23259774.549    -3778502.028  

  24899763.201    -1517971.0423 

  24523537.091    -1144833.904  

  20024209.987    -2509024.814  

Survey grade receives come with software that can translates that receiver's RAW pseudo range and carrier phase data into RINEX format.  The RTKLIB software mentioned earlier can also do convert the raw binary format output from the UBlox NEO-6P (which you can record using the UBlox u-center software) into RINEX format.  However, having just written most of the software I needed to do this, I decided to add a RINEX export feature to my UBloxSatMap program.  One gotcha in writing out a RINEX file is that it requires a 2nd pass to either add, or update the header line that shows the time stamp of the last data block.  I chose to handle this by building the record in a text area where I can simply write over the header lines as each new block of data is added.  Then, when I've finished recording, I simply write the contexts of the text area to a file.

Post Processing Precision

Once I had the RAW to RINEX conversion process working, I ran several tests using readings taken indoors in my upstairs bedroom.  This is far from an ideal location, but the Canadian CSRS system seems to work best with readings taken over a fairly long interval (ideally a 24 hour period) and I have not yet figured out a way to collect a set of readings without leaving my equipment unattended in some fairly visible locations.  Nor have I had the patience to sit for hours watching my equipment while it collects data.  However, given a long enough sample period, the power of post processing seems to produce some fairly good results even when using an indoor antenna. To get an idea how well it works, take a look at the file below named test4b.pdf, which is the report file generated by CSRS after processing readings taken over an 8 hour interval.  However, the following section from page 1 of the report shows the take home facts:

I'd have to check this position estimate with a precision, commercial GPS to know if the computed answer is correct, but the Sigmas(95%) readings suggest that post processing has improved the precision of my location from 2.677/3.256 meters to 0.336/0.034 meters, which is almost a 10 fold improvement.  Once I have time to take some decent readings outdoors, I suspect I'll get even better results.  One test I hope to try is to measure the position relative to a known geodetic reference point, such as the antenna of a CORS station.  

BTW, I'm not going to post the source code for my UBloxSatMap program at the moment, as it's still under development and is a bit creaky in places.  However, if anyone is interested, please contact me at wayne dot holder at gmail dot com.