Building a simple u-blox F9P data logger with a Sparkfun OpenLog board

Based on the number of views, one of my all time most popular posts is one I wrote nearly three years ago describing how to build a GPS data logger using a Raspberry Pi Zero. Although it specifically describes using a Pi Zero to do nothing except configure the receiver and log raw data to an SD card, the platform itself is quite general and can easily be extended to more complete options including running a real-time RTKLIB solution on the Pi. It is a little out of date now but I think it can still be useful.

However, if what you want is just a raw GPS data logger and nothing more, then, while the above choice may still be the lowest cost solution, it is not the simplest option to implement.

In this post I describe another inexpensive alternative using the very popular OpenLog data logger board available from Sparkfun which currently sells for $15.50. In this particular example, I have used it to log data from an Ardusimple u-blox F9P receiver but with a few minor modifications the design should work with many other popular receivers. For reasons described below it does require the board to have both a USB and a UART port available as well as easy access to 3.3 volts.

Here’s a couple of photos of the front and back of the Sparkfun OpenLog board. As you can see, it is only slightly larger than the size of the microSD card it uses to store the data.

Sparkfun OpenLog board, front and back

The chip on the front side of the board is an Arduino processor which comes pre-loaded with code to automatically log all incoming data from the RX/TX lines directly to the microSD card. The source code is open and available on Github, so if you need to modify it you can, but in most cases it should work fine as is.

To connect the OpenLog to the receiver is very simple. First connect VCC and GND on the OpenLog to 3V3_OUT and GND on the Ardusimple receiver. Fortunately, the pin spacing for the two boards is the same so I was able to use a two pin header to connect power and ground and rigidly mount the OpenLog at the same time. You can see the details in the two photos below. I also added a small piece of double sided foam tape between the two boards to strengthen the physical connection between them.

Back of Ardusimple board with OpenLog. The two boards are physically attached using the two pin header shown on right to connect power and ground. The top right cable is connected to the antenna and the bottom right cable is connected to a USB charger for power or a PC to configure the receiver.
Front of Ardusimple board. The GND/3.3V holes used to connect the two boards are visible just below the u-blox chip. The edge of the microSD card is visible just below the power LED

Then connect the RX/TX data lines on the Open Log to TX1/RX1 on the Ardusimple making sure to swap the two so that RX goes to TX1 and TX goes to RX1. On many boards this will be all you need, but the Ardusimple also has a IOREF input which selects the voltage levels of the GPIO pins. In this case we will connect that to 3.3 volts. You can see these three jumpers on the top photo above.

That’s it for the hardware. The next step is to configure the data logger. To do this you will first need to format a microSD card. Then create a file with the name config.txt, cut and paste the text below into this file and save it to the microSD card.

115200,26,3,0,1,1,0
 baud,escape,esc#,mode,verb,echo,ignoreRX

This is what the data logger uses when it powers up for configuration parameters. The only detail that matters in the above text is the first number which should be set to the same baud rate that UART1 on the receiver is configured to. The maximum baud rate that the OpenLog supports is 115200, so that is what I am using. For more information on the other numbers in this file or about the OpenLog board in general, Sparkfun has an excellent tutorial available here.

The last step is to configure the F9P receiver to output the appropriate messages to UART1. This is where things become much simpler by having both UART and USB ports available on the receiver board. To configure the receiver we will use the u-blox u-center app running on a PC and connected to the receiver through the USB port. Once the receiver is configured and the results saved to flash, we can then unplug the USB cable from the computer and plug it into a USB charger to provide power to the receiver and data logger while they are collecting data.

For this tutorial I will assume you have already downloaded the u-center app from u-blox and are somewhat familiar with using it to configure u-blox receivers. If not, there are many tutorials out there including some of my earlier posts that will help you.

One thing to be aware of is that the messages going out of the receiver to the USB port will generally be different from those going out to UART1, so just because you have the right messages coming out the USB port does not mean they will also be coming out of the UART port. Also be aware that if you use the “Messages View” in u-center to enable and disable messages, this method only affects the active port and so you will be enabling them for USB but not for UART1.

To enable and disable the messages for UART1, you can use the CFG-MSGOUT option from the “Generation 9 Configuration View” which is opened from the “View” tab on the main menu in u-center. I find this method nice for listing which messages are enabled and disabled but rather clunky for actually changing their status, so I used the MSG message from the “Configuration View” ( also opened from the “View” tab) to actually enable and disable the messages. I show this in the screenshot below. If you do it this way, make sure you issue a CFG-CFG message when you are done to save everything to flash.

There are many NMEA messages enabled by default on UART1. You will probably want to disable most or all of these to avoid using unnecessary UART bandwidth and microSD file space.

If you already have raw base observations streaming to the receiver and are using the internal RTK engine to calculate position solutions real-time then you will just need to enable the NMEA GLL messages to log position. These will give you the LLH positions in text format.

If in the more likely case that you are logging raw data for later post-processing, then you can enable either the appropriate RTCM3 messages or the UBX-RXM-RAWX messages to get the raw observations. To minimize the load on the logger, I would suggest using RTCM3 messages for the raw observations and not logging the navigation messages. You only need a single set of navigation messages and in most cases it is easier to log those on the base station. It is simplest to enable the same set of RTCM3 messages for both the USB and UART port. If you need to make these different for any reason, be aware that the F9P does not handle the RTCM3 end of epoch flag independently for both ports, so the last message in each epoch must be the same for both ports or you will have problems.

That should be it. At this point, every time you power up the receiver/logger, it should start a new log file on the microSD card and log all incoming messages from the receiver. The log file names will be in the format LOGxxxx.TXT where “xxxx” increments each run. Simply remove the microSD card from the OpenLog and plug it through an adapter into a PC to transfer the log files. Be sure to be careful when removing the microSD card from the OpenLog. The card locks in with a spring and needs to be pushed in to unlock it. Occasionally I have found that the card catches on the spring and needs to be gently coaxed out or you will break the spring as I found out the hard way.

If using RTKCONV to convert the raw data, you will need to specify the data type (UBX or RTCM3) since the file extension will not be correct for auto format detection.

Here’s a plot of some raw observations I collected this way, then converted to Rinex format with RTKCONV, and then plotted with RTKPLOT, using navigation messages collected separately on my base station.

RTKPLOT of observations collected with the OpenLog logger

The data logger performance is limited by a relatively small buffer size and it is possible that you will see missing samples in your data if the logger buffer overflows while writing to the microSD card. However I did not see any missing samples in my data while collecting dual-frequency GPS, Glonass, and Galileo RTCM3 observations at 5 HZ.

This is the simplest method I am aware of to turn an eval board into a relatively fully functional receiver but if anyone has an easier way, please leave a comment. All it needs now is a 3D printable box to protect it and enclose it from the weather to turn this into a general purpose low-cost dual receiver for real world data collection, at least for post-processing.

For another interesting option, check out this post from the Ardusimple website that describes combining an Ardusimple board with a bluetooth module and smartphone for real-time RTK.

Dual-frequency PPK solutions with RTKLIB and the u-blox F9P

With previous generations of u-blox receivers there has been a lower priced option available without an internal RTK engine, such as the popular M8T in the generation 8 modules. This does not appear to be the case with the new dual-frequency generation 9 modules, as the F9T, without internal RTK solution, is currently priced higher than the F9P with internal solution.

As the u-blox internal RTK solution in the F9P appears to be very robust, there is probably no good reason to ever use RTKLIB for real-time solutions with the F9P. However, it often still makes sense to use RTKLIB to post-process raw data previously collected by the F9P since the F9P is not capable of post-processing solutions.

Post-processed (PPK) solutions have several advantages over real-time solutions. The rover hardware is simpler, less expensive, lighter, and lower power since post-processing does not require a real-time data link between base and rover. Post-processed solutions also tend to be more robust than real-time solutions, both because they are not subject to data dropouts in the base data link and because they allow for solution techniques that take advantage of both past and future observations, not just past observations. When the solution is not required in real-time, it often makes more sense to collect the data first and then process it later.

Collecting data and processing RTK solutions for the dual-frquency F9P with RTKLIB is not very different for doing this for the single-frequency u-blox M8T, and if you are already familiar with doing that, you will probably not have much trouble adapting to the F9P. However, since it’s been a long time since I did a post on this subject, I thought it would be worth going over again with some updated tips for the new receiver.

Step 1: Configuring the receiver:

To process an RTKLIB solution, we will need raw observation messages from both rover and base receivers and navigation data messages from one of the receivers. The receivers do not output these messages by default so we will need to configure them to do this. With the u-blox M8T it was possible to do this directly with RTKLIB using a command file but this is not an option with the F9P as RTKLIB does not currently support the new F9P configuration messages.

Instead we will download the u-blox u-center app and use this to configure the receivers, then save the results to the on-board flash. There are detailed instructions on how to do this in the F9P documentation available on the u-blox website but here’s a quick summary of the process.

  1. Plug the receiver into a Windows PC using a USB cable if the board supports USB or with an FTDI serial/USB converter if the receiver only has a UART port.
  2. Start the “u-center” app and connect to the receiver with the “Connection” command on the “Receiver” tab. If it is a USB connection, baud rate won’t matter, but if it is a UART->USB connection through FTDI, then you will have to set the correct baud rate from the “Receiver” tab. If all is well, you should see the green connection indicator flashing at the bottom of the screen
  3. From the “View” tab, open the “Messages”, Configure”, “Gen 9 Configure”, and “Packet Console” windows
  4. If using the UART port, click on “PRT (Ports)” from the “Configure” window, set the Target to “1-UART1” and “Baudrate” to the desired baud rate, and click on “Send”. I typically set this to 115200 baud. You will then need to change the baud rate in u-center to the new baud rate. If you are using the USB port directly, you can skip this step.
  5. From the “Configure” window, click on “RATE”, and set “Measurement Period” to the desired time between observation samples, then click on “Send”. I typically set this to 200 ms which gives a 5 Hz sample rate.
  6. From the “Gen 9 Configure” window, select “GNSS Configuration”, enable the desired constellations and signals, select “RAM” and “Flash” under “Layer Selection”, then click on “Send Configuration”. The F9P supports GPS L1C/A and L2C, Glonass L1 and L2, Galileo E1 and E5b, BediDou B1 and B2, and QZSS L1C/A.
  7. From the “Messages” window, right click on “NMEA” and then click on “Disable Child Messages” to disable all the NMEA messages. None of these are needed for an RTK solution but if you want any of the messages for other reasons you can then individually enable the ones you need.
  8. From the “Messages” window, double click on “UBX” then “RXM”. Right click and enable “RAWX” to enable raw observation messages and “SFRBX” to enable navigation messages. Alternatively, you can enable the RTCM3 messages from the “Gen 9 Configure” window. In this case you will want to enable the 1077,1087,1097,and 1127 messages. I have occasionally had trouble enabling the RTCM3 messages on the F9P and have had to use the “Revert to default configuration” option under the “CFG” command first to get this working.
  9. If an antenna is connected to the receiver and is not completely blocked, verify that you see RAWX and SFRBX messages appear in the “Packet” window.
  10. From the “Configure” window, select “CFG”, then “Save current configuration” then “Send” to save these settings to the flash on-board the F9P module.
  11. Repeat this procedure for the base receiver except set the “Measurement Period” under “RATE” to “1000 ms” for a 1 Hz sample rate. You will only need one set of navigation data so you can choose not to enable the SFRBX messages on the base. I tend to leave them enabled just because it makes plotting slightly easier later if each set of observations has its own navigation data.

If you have any trouble with the above summary, you might find this YouTube video from Robo Roby useful. It is intended for setting up the F9P for real-time solutions, not post-processing, but there is a lot of overlap between the two.

In the descriptions below STRSVR, RTKCONV, RTKPLOT, and RTKPOST are all RTKLIB GUI apps. They can be opened individually or you can start by opening RTKLAUNCH and run the individual apps from there. I do not believe the official 2.4.2 or 2.4.3 versions of RTKLIB fully support the F9P receiver yet so I would recommend using the demo5 version of RTKLIB available here.

RTKLAUNCH used to open the different RTKLIB apps

Step 2: Collecting the data:

  1. For this exercise I will connect both base and rover directly to a Windows PC through the USB port. You can connect both receivers to one PC or each to a separate PC.
  2. Launch two instances of STRSVR, one for each receiver
  3. Set the input stream to “Serial”, click on the input “Opt” button and set the port and baud rate. Set the output stream to file and click on the output “Opt” to set the file name. Click on the “?” to get a list of keyword replacements for the file name. I like to add “_%h%M” to the end of the file name which will append the hour and minute of the data to the file name. If you are collecting long data sets you might want to set the “Swap Intv” to break up the data into manageable file sizes. Note that you will need to use the keywords in this case to avoid overwriting the same file repeatedly. Give the file name a “.ubx” extension to let RTKLIB know that it is u-blox binary data.
  4. Click “Start” to start collecting data.
STRSVR used to collect the raw data

Step 3: Convert the observation data to rinex format:

  1. Start the RTKCONV app
  2. Click on the “…” button to the right of the “RTCM, RCV RAW or RINEX OBS” field and select the observation file created in the previous step.
  3. If the file extension is not “.ubx” set the “Format” to “u-blox”, otherwise leave as “Auto”
  4. Click on the “Options” button and select “L1”, “L2/E5b”, and all GNSS constellations collected (usually “GPS”,”GLO”,”GAL”, and possibly “BDS” (Bediou) depending on your location. Then close the options menu.
  5. Click on “Convert” to convert from binary to rinex format.
RTKCONV used to convert the raw data from binary format to rinex text format

Step 4: Review the observation data:

  1. Before processing the solution, it is a good idea to look at the data first and make sure it is complete, of reasonable quality, and at the right sample rate.
  2. From the RTKCONV main window, click on “Plot” to plot the observations you just converted.
  3. Verify there are observations from all constellations. Green indicates dual frequency measurements, yellow is single frequency. The GPS observations will be a mix of single and dual frequency since only about half of the satellites currently support L2C used by the F9P, but the other constellations should be nearly all dual frequency.
  4. Red ticks indicate cycle slips. Too many of these will make it difficult to get a decent solution. Gaps in the data usually indicate the receiver lost lock and these are not good unless they are in the low elevation satellites.
  5. If all the satellites are in gray, this usually indicates you are missing the navigation data. The previous step should have generated a “.nav” file as well as a “.obs” file. If just a few satellites are in gray, this normally indicates that they are below the elevation threshold which can be adjusted in the options menu selected in the top right corner with the star-like icon.
  6. Check both rover and base observations.
  7. In some cases you may only have one set of navigation data and so not have a matching “.nav” file for one of your observation files. In that case you can manually specify the navigation data with the “Open Nav Data…” option in the “File” tab.
Plot of raw observations

Step 5: Generate the position solution

  1. Open RTKPOST
  2. From the “…” buttons on the right hand side of the GUI, select the rover observation file, the base observation file, and the navigation file as shown in the example below.
  3. Click on the “Options” button and then the “Load” button. Select the “demo5_m8t_5hz.conf” file from the same folder as the demo5 RTKLIB executables, and then click on “Open”
  4. From the “Setting1” tab in the “Options” menu, enable “Galileo” and if applicable “Bediou”. “GPS” and “GLO” should already be enabled.
  5. From the “Setting2” tab in the “Options” menu, set “Integer Ambiguity Res (GLO)” to “On”. We are able to use the “On” setting in this case because the receivers are identical and so the Glonass hardware biases cancel. If you are not using an F9P receiver for base, then leave this field set to “Fix-and-Hold” which will automatically calibrate out the biases.
  6. From the “Setting1” tab in the “Options” menu, change the “Frequencies” from “L1” to “L1+L2”. This is the only change you should need to make to switch from processing single-frequency data to dual-frequency data for the F9P. The Galileo second frequency for the F9P is actually E5b not L2 but to simplify and improve the processing speed, I have modified the demo5 code to include “E5b” processing as Galileo’s second frequency. This won’t be the case for the 2.4.2 or 2.4.3 code. I don’t believe it’s currently possible to include the E5b data with these versions of RTKLIB but if I’m wrong please let me know
  7. Click on “OK” to close the Options menu.
  8. Click on “Execute” to run the solution. The bar at the bottom of the GUI will show the solution status as it runs and will report any errors. You should see a mix of Q=1 and Q=2 as the solution runs. If you see only Q=0, something is wrong. In this case, open the “Options” window, select the “Output” tab and set “Output Debug Trace” to “Level3”, exit the Options menu, and rerun the solution. Then open the “.trace” file in the solution folder for additional information on what went wrong.
  9. Click on “Plot” to plot the solution with RTKPLOT
RTKPOST used to generate a PPK solution
Plot RTKPOST generated PPK solution

This was just meant to be a quick summary of the process. For more details please see the references below.

References:

  1. u-center User Guide
  2. u-blox F9P Interface Description
  3. RTKLIB manual
  4. Updated guide to the RTKLIB configuration file

A first look at the u-blox ZED-F9T dual frequency receiver

Back in November last year, I wrote a post on my first experiments with a dual frequency u-blox F9P  based receiver.  At the time it was quite difficult for those without good connections to u-blox to get a hold of the F9P and even now, nearly three months later, it still is not readily available.  Ardusimple, the lowest price provider of F9P receivers still has all their receivers on back order till next month and low cost dual frequency antennas are even harder to get.  Hopefully all that will change fairly soon though.

Meanwhile, thanks to “clive1” and “cynfab” from the u-blox forum, I have been lucky enough to have been given a prototype receiver based on the dual frequency u-blox F9T, the next product from u-blox in the Generation 9 series.  Like the previous generation M8T, this is intended for timing uses and does not include an internal RTK engine.  Otherwise I believe the F9T hardware is nearly identical to the F9P.  In theory it should be less expensive than the F9P, just as the M8T is less expensive than the M8P but meaningful pricing is not yet available.

In many of my posts, I have focused on post-processing short baseline data sets using a local base station and identical receivers for base and rover.  For this particular  combination, I have shown that the differences between a single frequency solution and a dual frequency solution are typically fairly small.  This assumes that the single frequency solution includes Galileo and possibly SBAS while the dual-frequency solution includes only GPS and Glonass.  This makes the total number of observations fairly similar between the two cases.   At least until very recently this has been a reasonable assumption given that most existing CORS or other reference base stations and reasonably priced dual frequency receivers offered only GPS and Glonass.  It’s also true that time to first fix is longer in the single frequency solutions but post-processing with a combined solution generally eliminates the need for a fast fix.

However there are many other cases where there are definite advantages to using a dual frequency solution.  In particular the most important advantages occur for:

  • Longer baselines where linear combinations of L1 and L2 can cancel ionospheric errors
  • Use of an existing CORS or other reference base station which typically has only GPS and Glonass and hence is not an ideal match-up with a single frequency receiver using additional constellations
  • Real-time solutions where time to first fix is more critical
  • PPP (Precise Point Positioning) solutions for the same reasons as the long baseline cases.

So for my initial experiments with the F9T I focused on including some of these conditions.  In particular I ran two experiments, the first a real-time RTK solution with an existing UNAVCO reference base (P041) located 17 km away.  For the second experiment I compared an online PPP solution from the Canadian Spatial Reference System (CSRS) with an RTKLIB SSR based PPP solution.

For the first experiment, I connected the F9T receiver to the dual frequency antenna on my roof and ran a quick five minute RTKLIB real-time solution against the UNAVCO base station using the demo5 b31 RTKLIB code.  Other than changing the frequency mode from L1 to L1+L2 I used the exact same configuration file I normally use for the u-blox M8T single frequency receiver.  Even though the rover was stationary in this case, I ran the solution as kinematic for better visibility to any variation in the solution.  Here’s the result.

f9t_1

Overall the solution looked excellent.  First fix occurred within a few seconds, fix rate was 100% after first fix, horizontal variation was  roughly +/-0.5 cm and vertical variation was roughly +/-1 cm.

The solution residuals, both pseudorange and carrier-phase also looked very clean.

f9t_3

I only made a brief look at the raw observations but did not see anything unusual there either.  At only five minutes of data, it is not much more than a quick sanity check, but so far, so good.

For the second experiment I collected four hours of raw observations, again with the F9T receiver and my rooftop antenna, a ComNav AT330.  I then submitted this data to CSRS for their online PPP solution as well as running an RTKLIB SSR solution as I described in this post.  Below are the results for both solutions.  The plots are all relative to my best estimate of the location of the rooftop antenna based on previous PPP solutions with Swift and ComNav receivers as well as RTK solutions from nearby CORS stations.  The left plots shows the first hour of solution with a +/-0.25 meter vertical scale.  The right plot shows the second through fourth hours with a +/-0.06 meter vertical scale.

f9t_2

Both solutions get to below 6 cm of error in each axis after 1 hour and below 3 cm of error after four hours.  The CSRS solution gets down to almost zero error in all three axes after four hours but I don’t believe my reference is this accurate so I think this was partially luck.  The reported accuracies (95%) for the CSRS solution were 1 cm, 4 cm, and 5 cm for latitude, longitude, and height respectively.  My previous experience running RTKLIB SSR PPP solutions with other low cost dual frequency receivers is that after running many solutions, they generally all fall within +/-6 cm accuracies in all axes after four hours.  Both solutions include only GPS and Glonass observations because both the SSR correction stream I used from the CLK93 source, and the CSRS online PPP algorithm use only GPS and Glonass.

Being able to run accurate PPP static solutions can be a big advantage since it can make it much simpler to precisely locate a base station for RTK solutions with a dynamic rover, especially in more remote areas where there may not be any nearby CORS or other reference stations to run an RTK solution against.

As always, this post is intended to be just a quick snapshot and not an extended analysis of any type, but so far I have been very impressed with both the F9P and F9T and with their compatibility with RTKLIB.

 

 

A first look at the u-blox ZED-F9P dual frequency receiver

The new low cost dual frequency receiver from u-blox, the ZED-F9P, is just now becoming available for purchase for those not lucky enough to get early eval samples from u-blox.  CSGShop has a ZED-F9P receiver in stock for $260 which seems quite reasonable, given that it is only $20 more than their NEO-M8P single frequency receiver.

Even better, Ardusimple is advertising an F9P  receiver for 158 euros (~$180) + 20 euros shipping , although their boards won’t ship until January.  As far as I’m aware of, this is actually less than anybody today is selling the M8P receiver for today!

Of course, this is still a fair bit more than a u-blox M8T single frequency receiver without an internal RTK engine, which is available from CSGShop for $75, but the F9T will be coming out next year also without internal RTK engine, which should bring down the price for the lowest cost dual frequency receivers.

Unfortunately I am not one of the lucky ones who got eval boards directly from u-blox yet.  However, I do have two prototype boards from Gumstix, given to me by them for evaluation.  Gumstix offers both off-the-shelf boards and semi-custom boards designed from their libraries of circuits.  I haven’t worked with them directly but it looks like an interesting and useful concept.  The F9P boards from Gumstix won’t be available for sale until at least Feburary next year but I thought I would share the results of some initial testing.  From a performance perspective, I would expect these boards to be similar to F9P boards from other suppliers.

For a first look, I chose to compare the F9P to an M8T for one of my typical driving-around-the-neighborhood exercises.  I looked at both the internal real-time F9P solution and the RTKLIB solutions, both real-time and post-processed.

Experiment Setup:

For the base stations, I connected a CSGShop M8T receiver and a Gumstix F9P  receiver through an antenna splitter to a ComNav AT330 dual frequency antenna on my roof.  Since RTKLIB doesn’t yet fully support the receiver commands needed to setup the F9P, I used the most recent version (18.08) of the u-blox u-Center app run on a Windows laptop to configure the F9P receiver using the documentation on the u-blox website.  I then saved the settings to flash.  The receivers were connected to a laptop with USB cables and I broadcast the base observations over the internet on a couple of NTRIP streams using STRSVR and RTK2GO.com as I’ve described previously.  I configured the F9P to send RTCM3 1005, 1077, 1087, 1097, 1127, and 1230 messages which include base location, raw observations, and GLONASS biases.

For the most part the u-blox documentation is well written and this exercise was fairly straightforward, but I did run into a couple of issues.  First of all, when I plugged the F9P receiver into the laptop, Windows chose the standard Windows COM port driver instead of the u-blox GNSS COM port driver that it chose for the M8T receiver.  You can see this in the screen snapshot below where COM17 is the M8T and COM21 is the F9P.

drivers

Both drivers allow the user to set the baudrate in the properties menu available by right clicking on the device name.   With the u-blox driver, the baudrate setting doesn’t seem to matter which makes sense since it is a USB connection.  I have always left the u-blox driver baudrate at the default of 9600 baud without any issue.  With the windows driver, however,  I found that I had to increase the baudrate setting to 115200 to avoid data loss issues.  I have run into a similar problem before for sample rates greater than 5 Hz when the M8T is accessed through it’s UART interface and an FTDI converter is used to translate to USB, rather than communicating directly through it’s USB interface.  I verified though, that in this case the board is using the USB interface on the receiver and not the UART interface.   Not a big deal, and it may be unique to this board, but something to be aware of in case you run into a similar problem.

The second problem I ran into is that the F9P module seems to be sensitive to my antenna splitter, a standard SMA DC block and tee which I have used on many other receivers before without issue.  It works fine if the F9P power is blocked but if the M8T power is blocked, the F9P seems to detect the tee and shut off the antenna power.  Again, not a big deal, but something to be aware of.

For the rovers, I used a u-blox ANN-MB-00 dual-frequency antenna for the F9P receiver.  This is the antenna u-blox provides with its F9P eval units.  I had planned to split this antenna signal to both receivers as I usually do, but I ran into the problem described above, and not fully understanding the issue yet, ended up using a separate Tallysman TW4721 L1 antenna for the M8T receiver.  Both antennas were attached directly to the car roof which acted as a large ground plane.

I used a hot spot on my cellphone to stream the NTRIP base station observations from the phone to a laptop and then to the F9P receiver and to two instances of RTKNAVI, one for each rover receiver.

Streaming the base observations to the F9P, while simultaneously logging the internal RTK solution and the raw rover observations, and also sending the raw rover observations to RTKNAVI, all over a single serial port can be challenging since only a single application can be connected to the serial port at one time.  Fortunately RTKLIB has a little trick to deal with this.  If the “Output Received Stream to TCP Port” box is checked in STRSVR and a port number specified as shown below, all data coming from the other direction on the serial port will be redirected to a local TCP/IP port.  This data  can then be accessed by any of the other RTKLIB apps as a TCP Client with server address “localhost” using the specified port number.

str2str1

I set up the F9P rover to output both raw observation and navigation messages (UBX-RXM-RAWX/ UBX-RXM-SFRBX) and solution position messages( NMEA-GNGGA).  RTKNAVI then logged all of these messages to a single log file.  RTKCONV and RTKPLOT can both extract the messages they need from this file and ignore the rest so combining them was not an issue.

The NMEA-GNGGA messages from the F9P default to a resolution of 1e-7 degrees of latitude and longitude which works out to roughly 1 cm.  For higher resolution you can increase the resolution of the GNGGA message by setting a bit in the UBX-CFG-NMEA message.   Unfortunately I did not realize the resolution issue until after I collected the data and so my results for the internal F9P solution for this experiment were slightly deteriorated by the lower resolution.

I used the most recent demo5 b31 code to calculate all of the RTKLIB solutions.  Both the demo5 and the 2.4.3 versions of RTKLIB have been updated to translate the new dual frequency u-blox binary messages.  The demo5 solution code will process all the dual frequency observations but I don’t believe 2.4.3 code is able to process the E5b Galileo measurements yet.  The RTKLIB 2.4.2 code however does not have any of these updates.

The demo5 code updates made in the recent B30/B31 versions are based on the updates from the 2.4.3 B30 code but include some modifications to the u-blox cycle slip handling that I had previously added to the demo5 code for the M8T.  Since the demo5 code is primarily aimed at low cost receivers I also made some changes to make the E5b frequency a little easier to specify and faster to process.

To run the RTKNAVI F9P real-time solution, the only significant change I needed to make to the default M8T config file was to change the frequency option from “L1” to “L1+L2+E5b”.  I should have also changed the base station position to “RTCM Antenna Position” to take advantage of the F9 base station RTCM 1005 base location messages but neglected to do this.  This caused the RTKNAVI solution to differ from the F9P solution by small constant values due to the approximate base location used in the RTKNAVI solution.  I later used exact base locations for the RTKLIB post-processing solutions to verify that the different solutions did in fact all match.

Once I had everything set up, I then drove around the local neighborhood, emphasizing the streets with most challenging sky views since I knew both receivers would perform well and be difficult to distinguish if the conditions were not challenging enough.

Results:

I first converted the binary log files to observation files using RTKCONV and verified that the F9P was logging both L1 and L2 measurements for GPS, GLONASS, and Galileo.  I had the Bediou constellation enabled as well but as I verified later, there were no fully operational Bediou satellites overhead when I collected the data.

Here is an plot of the L1 observations for the M8T on the left and the F9P on the right.  I have zoomed into just two minutes during some of the more difficult conditions to compare the two.  The red ticks are cycle slips and the grey ticks are half cycle ambiguities.

f9_obs1

First, notice that the F9P does not log observations for the SBAS satellites, while the M8T does, giving the M8T a couple more satellites to work with.  However, what’s also interesting, and I don’t know why, is that the F9P collected quite good measurements from the Galileo E27 satellite, while the M8T did not pick up this one at all.  Of course the F9P also got a second set of measurements from the second frequency on each satellite and so overall ended up with nearly twice as many raw observations as the M8T.

Also notice that the F9P reports somewhat less cycle slips and many less half cycle ambiguities than the M8T.  Some of this might be because of the different antennas, but particularly the large difference in half cycle ambiguities suggests that u-blox has made other improvements to the new module besides just adding the second frequencies.

Another thing to notice is the number of Galileo satellites.  If you compare these plots to earlier experiments I’ve posted, you’ll notice there are more Galileo satellites now as more and more of them are starting to come online.  The extra satellites really help the M8T solutions because as you can see, they tend to have the highest quality observations through the most difficult times.  Again I don’t know why this is.  It doesn’t appear to be as true for the F9P though.

Next I looked at the real-time solutions.   First, the RTKLIB solutions with RTKNAVI for both receivers.  For the full driving route, the M8T solution had a 77.3% fix rate and the F9P solution had a 96.4% fix rate.  Here is a zoom into the most challenging part of the drive, an older neighborhood with narrower streets and larger trees, the M8T is on the left, and the F9P on the right.  Fixed solutions are in green and float in yellow.  Clearly here the F9P significantly outperformed the M8T.

f9_1

The F9P internal solution did even better with a 99.2% fix rate, as shown in the plot below.  All three solutions agreed within 2 cm horizontal, a little more in vertical, and none of them showed any sign of any false fixes.

f9_2

I didn’t do any static testing to characterize time to first fix as I sometimes do, but for this one run the RTKLIB time to first fix for the M8T was 18 seconds while the RTKLIB F9P solution reached first fix in 6 seconds.  In both cases, RTKLIB was started after the hardware had time to lock to the satellites and acquire navigation data for all satellites.  The demo5 RTKLIB code has an additional fix constraint based on the kalman filter position variance to minimize false fixes while the filter is converging and so this can sometimes affect time to first fix.  I had increased this parameter to 0.1 meter for this experiment since the large number of measurements reduces the chance of a false fix.  This constraint did not limit the M8T time to first fix but it did so for the F9P, meaning the F9P would have reached first fix even faster if this constraint were opened up more.   I can’t tell what the equivalent number would be for the internal F9P solution from this data since it had already been running and achieved a fix before I started logging the data but generally the F9P seems to acquire first fix very quickly.

Next I post-processed both data sets with RTKLIB using the combined-mode setting to run the kalman filter both forwards and backwards over the data.  This noticeably improved the results, bringing the fix rate for the M8T up from 77.3% to 96.1% and the F9P fix rate from 96.4% to 98.8%.

f9_3

Conclusion:

Obviously this is not enough data to make any definitive conclusions, but so far I am very impressed with the F9P!  Both the raw observations and the internal RTK solutions for the F9P look as good as anything I’ve seen from receivers costing many times what this one cost.

If anybody would like to look at the data from this experiment more closely, I have uploaded it to here.  I should mention that all the fix rates I specify in this post and other posts won’t exactly match the fix rates in the raw solutions, since I adjust the data start and end times to be consistent between data sets and to start after all solutions have achieved first fix.  I believe this is the fairest way to compare multiple solutions, especially when there is a mix of internal and RTKLIB solutions

Also, I’d like to thank Gumstix again for making these modules available to me for evaluation!

Update: 12/2/18:

Reviewing the config files I used for this experiment I discovered that, while I had intended the real-time and post-processing config files to be identical, there were in fact some small differences between them.  One difference in particular, that appears to have affected the results as described above, is that I reduced the minimum number of consecutive samples required to hold ambiguities (pos2-arminfix) from 100 to 20 for the post-processed config files.  A value of 100 corresponds to 20 seconds at the experiment’s 5 Hz sample rate which is a value I have typically used.  However, with lower ambiguity tracking gain (pos2-varholdamb=0.1) and the increase in observations coming from including Galileo, the chances of false fixes is reduced and I have been tending to use lower values of arminfix in more recent experiments.   Reducing this value appears to explain a large part of the jump in percent fix for the M8T between real-time and post-processing, rather than the switch from forward-only to combined that I attribute it to above.  These differences only affect the comparisons between RTKLIB real-time and post-processed results, and not between the M8T and the F9P since the config files were consistent between the two receivers.

This was only intended to be a quick first look at the F9P.  It will require more data and more analysis to properly characterize the F9P so I  won’t try to do that here but I will share the table shown below which includes a few cases I have run since the original post.  I hope to dig into the details in future posts.

Fix percent
Real-timePost-processPost-processPost-process
ARMIN=100ARMIN=100ARMIN=20ARMIN=20
forward-onlyforward-onlyforward-onlycombined
M8T/RTKLIB77.3%81.2%96.0%96.1%
F9P/RTKLIB96.4%99.1%99.3%98.8%
F9P internal99.2%

One last point worth making is that while at first glance the post-process fix percent increase from M8T=96.0% to F9P=99.3% may not sound that significant, it is in fact a factor of nearly six if you consider it as a decrease in float from 4.0% to 0.7%.

Updated guide to the RTKLIB configuration file

It’s been quite a while since I’ve updated my guide to the RTKLIB configuration file.  Since the last update I’ve added a couple of new features and learned a bit more about some of the existing features.  For previous updates,  I’ve just updated the original post, but this time I thought I would re-publish it to make it easier to find.

One of the nice things about RTKLIB is that it is extremely configurable and has a whole slew of input options available. Unfortunately these can be a bit overwhelming at times, especially for someone new to the software. The RTKLIB manual does briefly explain what each option does, but even with this information it can be difficult to know how best to choose values for some of the parameters.

I won’t try to give a comprehensive explanation of all the input options here, but will explain the ones I have found useful to adjust in my experiments and include a little about why I chose the values I did. I describe them as they appear in the configuration file rather than how they appear in the RTKNAVI GUI menu but the comments apply to both. I created this list by comparing my latest config files to the default config file and noting which settings were different. The values in the list below are the values I use in my config file for a 5 Hz rover measurement rate.  The same config files can be used for either RTKNAVI, RTKPOST, or RNX2RTKP.

The settings and options highlighted in blue below are available only in my demo code and not in the release code but otherwise much of what I describe below will apply to either code.  Most of my work is done for RTK solutions with Ublox M8N and M8T receivers and short baselines and these settings will more directly apply to these combinations but should be useful at least as a starting point for other scenarios.

This post is intended to be used as a supplement to the RTKLIB manual, not as a standalone document, so please refer to it for information on any of the input parameters not covered here.

SETTING1:

pos1-posmode = static, kinematic, static-start, movingbase, fixed

If the rover is stationary, use “static”. If it is moving, use “kinematic” or “static-start”. “Static-start” will assume the rover is stationary until first fix is achieved and then switch to dynamic mode, allowing the kalman filter to take advantage of the knowledge that the rover is not moving initially.  You can use “movingbase” if the base is moving as well as the rover, but it is not required unless the base is moving long distances.  I often find that “kinematic” gives better solutions than “movingbase” even when the base is moving.  “Movingbase” mode is not compatible with dynamics, so be sure not to enable both at the same time.  If the base and rover remain at a fixed distance apart, set “pos2-baselen” and “pos2-basesig” when in “movingbase” mode.   Use “fixed” if you know the rover’s exact location and are only interested in analyzing the residuals.

pos1-frequency = l1

“l1” for single frequency receivers,  “l1+l2” if the rover is dual frequency GPS/GLONASS/Bediou,  “l1+l2+e5b” if Galileo E5b is included.  Starting with the dem05 b33 code, Galileo E5b is included in the L2 solution, so “l1+l2” is equivalent to “l1+l2+e5b” 

pos1-soltype = forward, backward, combined

This is the direction in time that the kalman filter is run. For real-time processing, “forward” is your only choice. For post-processing, “combined” first runs the filter forward, then backwards and combines the results. For each epoch, if both directions have a fix, then the combined result is the average of the two with a fixed status unless the difference between the two is too large in which case the status will be float. If only one direction has a fix, that value will be used and the status will be fixed. If both directions are float then the average will be used and the status will be float. Results are not always better with combined because a false fix when running in either direction will usually cause the combined result to be float and incorrect. The primary advantage of combined is that it will usually give you fixed status right to the beginning of the data while the forward only solution will take some time to converge. The 2.4.3 code always resets the bias states before starting the backwards run to insure independent solutions. The demo5 code doesn’t reset the bias states to avoid having to lock back up when the rover is moving if ambiguity resolution is set to “continuous” but does reset them if it is set to “fix-and-hold”.  I only use the “backward” setting for debug when I am having trouble getting an initial fix and want to know what the correct satellite phase-biases are.

pos1-elmask = 15 (degrees)

Minimum satellite elevation for use in calculating position. I usually set this to 10-15 degrees to reduce the chance of bringing multipath into the solution but this setting will be dependent on the rover environment. The more open the sky view, the lower this value can be set to.

pos1-snrmask-r = off, pos1-snrmask-b = off,on

Minimum satellite SNR for rover (_r) and base(_b) for use in calculating position. Can be a more effective criteria for eliminating poor satellites than elevation because it is a more direct measure of signal quality but the optimal value will vary with receiver type and antenna type so I leave it off most of the time to avoid the need to tune it for each application.

pos1-snrmask_L1 =35,35,35,35,35,35,35,35,35

Set SNR thresholds for each five degrees of elevation. I usually leave all values the same and pick something between 35 and 38 db depending on what the nominal SNR is. These values are only used if pos1-snrmask_x is set to on.  If you are using dual frequencies, you will need to also set “pos1-snrmask_L2”

pos1-dynamics = on

Enabling rover dynamics adds velocity and acceleration states to the kalman filter for the rover. It will improve “kinematic” and “static-start” results, but will have little or no effect on “static” mode. The release code will run noticeably slower with dynamics enabled but the demo5 code should be OK. Be sure to set “prnaccelh” and “prnaccelv” appropriately for your rover acceleration characteristics.  Rover dynamics is not compatible with “movingbase” mode, so turn it off when using that mode.

pos1-posopt1 = off, on (Sat PCV)

Set whether the satellite antenna phase center variation is used or not. Leave it off for RTK but you set it for PPP. If set to on, you need to specify the satellite antenna PCV file in the files parameters.

pos1-posopt2 = off, on (Rec PCV)

Set whether the receiver antenna phase center variations are used or not. If set to on, you need to specify the receiver antenna PCV file in the files parameters and the type of receiver antenna for base and rover in the antenna section. Only survey grade antennas are included in the antenna file available from IGS so only use this if your antenna is in the file. It primarily affects accuracy in the z-axis so it can be important if you care about height. You can leave this off if both antennas are the same since they will cancel.

pos1-posopt5 = off, on (RAIM FDE)

If the residuals for any satellite exceed a threshold, that satellite is excluded. This will only exclude satellites with very large errors but requires a fair bit of computation so I usually leave this disabled.

pos1-exclsats=

If you know a satellite is bad you can exclude it from the solution by listing it here. I only use this in rare cases for debugging if I suspect a satellite is bad.

pos1-navsys = 7, 15,

I always include GLONASS and SBAS sats, as more information is generally better.  If using the newer 3.0 u-blox firmware with the M8T I also enable Galileo.

SETTING2:

pos2-armode = continuous, fix-and-hold

Integer ambiguity resolution method. “Continuous” mode does not take advantage of fixes to adjust the phase bias states so it is the most immune to false fixes.  “Fix-and-hold” does use feedback from the fixes to help track the ambiguities.  I prefer to use “fix-and-hold” and adjust the tracking gain (pos2-varholdamb) low enough to minimize the chance of a false fix.  If “armode” is not set to “fix-and-hold” then any of the options below that refer to holds don’t apply, including pos2-gloarmode.

pos2-varholdamb=0.001, 0.1 (meters)

In the demo5 code, the tracking gain for fix-and-hold can be adjusted with this parameter. It is actually a variance rather than a gain, so larger values will give lower gain. 0.001 is the default value, anything over 100 will have very little effect. This value is used as the variance for the pseudo-measurements generated during a hold which provide feedback to drive the bias states in the kalman filter towards integer values.  I find that values from 0.1 to 1.0 provides enough gain to assist with tracking while still avoiding tracking of false fixes in most cases.

pos2-gloarmode = on, fix-and-hold, autocal

Integer ambiguity resolution for the GLONASS sats.  If your receivers are identical, you can usually set this to “on” which is the preferred setting since it will allow the GLONASS sats to be used for integer ambiguity resolution during the initial acquire. If your receivers are different or you are using two u-blox M8N receivers you will need to null out the inter-channel biases with this parameter set to “fix-and-hold” if you want to include the GLONASS satellites in the AR solution. In this case the GLONASS sats will not be used for ambiguity resolution until after the inter-channel biases have been calibrated which begins after the first hold. There is an “autocal” option as well, but I have never been able to make this work in the 2.4.3 code.  In the demo5 code I have added the capability to this feature to preset the initial inter-channel bias, variance, and calibration gain.  I then set the biases to known values for the particular receiver pair and set the gain very low.  This defeats the auto calibration aspect of the feature but does provide a mechanism to specify the biases which is otherwise missing in RTKLIB.  When “autocal” is used, the GLONASS satellites will be used for the initial acquire.  The “autocal” feature can also be used to determine the inter-channel biases with a zero or short baseline using an iterative approach.

pos2-gainholdamb=0.01

In the demo5 code, the gain of the inter-channel bias calibration for the GLONASS satellites can be adjusted with this parameter. 

pos2-arthres = 3

This is the threshold used to determine if there is enough confidence in the ambiguity resolution solution to declare a fix. It is the ratio of the squared residuals of the second-best solution to the best solution. I generally always leave this at the default value of 3.0 and adjust all the other parameters to work around this one. Although a larger AR ratio indicates higher confidence than a low AR ratio, there is not a fixed relationship between the two. The larger the errors in the kalman filter states, the lower the confidence in that solution will be for a given AR ratio. Generally the errors in the kalman filter will be largest when it is first converging so this is the most likely time to get a false fix. Reducing pos2-arthers1 can help avoid this.  

pos2-arfilter = on

Setting this to on will qualify new sats or sats recovering from a cycle-slip. If a sat significantly degrades the AR ratio when it is first added, its use for ambiguity resolution will be delayed. Turning this on should allow you to reduce “arlockcnt” which serves a similar purpose but with a blind delay count.

pos2-arthres1 = 0.004-0.10

Integer ambiguity resolution is delayed until the variance of the position state has reached this threshold. It is intended to avoid false fixes before the bias states in the kalman filter have had time to converge. It is particularly important to set this to a relatively low value if you have set eratio1 to values larger than 100 or are using a single constellation solution. If you see AR ratios of zero extending too far into your solution, you may need to increase this value since it means ambiguity resolution has been disabled because the threshold has not been met yet. I find 0.004 to 0.10 usually works well for me but if your measurements are lower quality you may need to increase this to avoid overly delaying first fix or losing fix after multiple cycle slips have occurred.

pos2-arthres2

Relative GLONASS hardware bias in meters per frequency slot.  This parameter is only used when pos2-gloarmode is set to “autocal” and is used to specify the inter-channel bias between two different receiver manufacturers.  To find the appropriate values for common receiver types, as well as how to use this parameter for an iterative search to find values for receiver types not specified, see this post.  This parameter is defined but unused in RTKLIB 2.4.3

pos2-arthres3 = 1e-9,1e-7

Initial variance of the GLONASS hardware bias state.  This parameter is only used when pos2-gloarmode is set to “autocal”.  A smaller value will give more weight to the initial value specified in pos2-arthres2.  I use 1e-9 when pos2-arthres2 is set to a  known bias, and 1e-7 for iterative searches.  This parameter is defined but unused in RTKLIB 2.4.3

pos2-arthres4 = 0.00001,0.001

Kalman filter process noise for the GLONASS hardware bias state.  A smaller value will give more weight to the initial value specified in pos2-arthres2.  I use 0.00001 when pos2-arthres2 is set to a  known bias, and 0.001 for iterative searches.  This parameter is defined but unused in RTKLIB 2.4.3

pos2-arlockcnt = 0, 5  

Number of samples to delay a new sat or sat recovering from a cycle-slip before using it for integer ambiguity resolution. Avoids corruption of the AR ratio from including a sat that hasn’t had time to converge yet. Use in conjunction with “arfilter”. Note that the units are in samples, not units of time, so it must be adjusted if you change the rover measurement sample rate.  I usually set this to zero for u-blox receivers which are very good at flagging questionable observations but set it to at least five for other receivers.  If not using the demo5 RTKLIB code, set this higher since the “arfilter” feature is not supported.

pos2-minfixsats = 4

Minimum number of sats necessary to get a fix. Used to avoid false fixes from a very small number of satellites, especially during periods of frequent cycle-slips.

pos2-minholdsats = 5

Minimum number of sats necessary to hold an integer ambiguity result. Used to avoid false holds from a very small number of satellites, especially during periods of frequent cycle-slips.

pos2-mindropsats = 10

Minimum number of sats necessary to enable exclusion of a single satellite from ambiguity resolution each epoch.  In each epoch a different satellite is excluded.  If excluding the satellite results in a significant improvement in the AR ratio, then that satellite is removed from the list of satellites used for AR.

pos2-rcvstds = on,off

Enabling this feature causes the the measurement variances for the raw pseudorange and phase measurement observations to be adjusted based on the standard deviation of the measurements as reported by the receiver. This feature is currently only supported for u-blox receivers. The adjustment in variance is in addition to adjustments made for satellite elevation based on the stats-errphaseel parameter.  I generally get better results with this turned off.

pos2-arelmask = 15

Functionally no different from the default of zero, since elevations less than “elmask” will not be used for ambiguity resolution but I changed it to avoid confusion.

pos2-arminfix = 20-100  (5-20*sample rate)

Number of consecutive fix samples needed to hold the ambiguities. Increasing this is probably the most effective way to reduce false holds, but will also increase time to first hold and time to reacquire a hold.  As the ambiguity tracking gain is reduced (i.e. as pos2-varholdamb is increased), and the number of observations increases, arminfix can be reduced.  Note that this value should also be adjusted if the rover measurement sample rate changes.

pos2-elmaskhold = 15

Functionally no different from the default of zero, since elevations less than “elmask” will not be used for holding ambiguity resolution results but I changed it to avoid confusion.

pos2-aroutcnt = 100 (20*sample rate)

Number of consecutive missing samples that will cause the ambiguities to be reset. Again, this value needs to be adjusted if the rover measurement sample rate changes.

pos2-maxage = 100

Maximum delay between rover measurement and base measurement (age of differential) in seconds. This usually occurs because of missing measurements from a misbehaving radio link. I’ve increased it from the default because I found I was often still getting good results even when this value got fairly large, assuming the dropout occurred after first fix-and-hold.

pos2-rejionno = 1000, 0.2

Reject a measurement if its pre-fit residual is greater than this value in meters. I have found that RTKLIB does not handle outlier measurements well, so I set this large enough to effectively disable it. With non-ublox receivers which typically are not as good at flagging outliers, I sometimes have to set this back to the default of 30 or even lower to attempt to handle the outliers but this is a trade-off because it can then cause other issues, particularly with initial convergence of the kalman filter.

Outlier rejection has been improved in the demo5 code starting with version b33.  In addition to better handling of the outlier measurements, the way this number is applied to code and phase measurements has changed.  Previously this value was applied without adjustment to both code and phase measurements.  In the newer version, this value is still applied without adjustment to the phase measurements but is multiplied by eratio for the code measurements.  This allows it to be set to values appropriate for the phase measurements.  I usually set it to 0.2 which is very helpful to catch and reject unflagged cycle slips.

OUTPUT:

out-solformat = enu, llh, xyz

I am usually interested in relative distances between rover and base, so set this to “enu”. If you are interested in absolute locations, set this to “llh” but make sure you set the exact base location in the “ant2” settings. Be careful with this setting if you need accurate z-axis measurements. Only the llh format will give you a constant z-height if the rover is at constant altitude. “Enu” and “xyz” are cartesian coordinates and so the z-axis follows a flat plane, not the curvature of the earth. This can lead to particularly large errors if the base station is located farther from the rover since the curvature will increase with distance.

out-outhead = on

No functional difference to the solution, just output more info to the result file.

out-outopt = on

No functional difference to the solution, just output more info to the result file.

out-outstat = residual

No functional difference to the solution, just output residuals to a file. The residuals can be very useful for debugging problems with a solution and can be plotted with RTKPLOT as long as the residual file is in the same folder as the solution file.  

stats-eratio1 = 300
stats-eratio2  = 300

Ratio of the standard deviations of the pseudorange measurements to the carrier-phase measurements. I have found a larger value works better for low-cost receivers, but that the default value of 100 often work better for more expensive receivers since they have less noisy pseudorange measurements. Larger values tend to cause the kalman filter to converge faster and leads to faster first fixes but it also increases the chance of a false fix. If you increase this value, you should set pos2-arthres1 low enough to prevent finding fixes before the kalman filter has had time to converge. I believe increasing this value has a similar effect to increasing the time constant on a pseudorange smoothing algorithm in that it filters out more of the higher frequencies in the pseudorange measurements while maintaining the low frequency components.

stats-prnaccelh = 3.0

If receiver dynamics are enabled, use this value to set the standard deviation of the rover receiver acceleration in the horizontal components. This value should include accelerations at all frequencies, not just low frequencies. It should characterize any movements of the rover antenna, not just movements of the complete rover so it may be larger than you think. It will include accelerations from vibration, bumps in the road, etc as well as the more obvious rigid-body accelerations of the whole rover.  It can be estimated by running a solution with this value set to a large value, then examining the accel values in the solution file with RTKPLOT

stats-prnaccelv = 1.0

The comments about horizontal accelerations apply even more to the vertical acceleration component since in many applications the intentional accelerations will all be in the horizontal components. It is best to derive this value from actual GPS measurement data rather than expectations of the rigid-body rover. It is better to over-estimate these values than to under-estimate them.

ant2-postype = rinexhead, llh, single

This is the location of the base station antenna. If you are only interested in relative distance between base and rover this value does not need to be particularly accurate. For post-processing I usually use the approximate base station location from the RINEX file header. If you want absolute position in your solution, then the base station location must be much more accurate since any error in that will add to your rover position error. If I want absolute position, I first process the base station data against a nearby reference station to get the exact location, then use the ”llh” or “xyz”option to specify that location. For real-time processing, I use the “single” option which uses the single solution from the data to get a rough estimate of base station location.

ant2-maxaveep = 1

Specifies the number of samples averaged to determine base station location if “postype” is set to “single”. I set this to one to prevent the base station position from varying after the kalman filter has started to converge since that seems to cause long times to first fix. In most cases for post-processing, the base station location will come from the RINEX file header and so you will not use this setting. However if you are working with RTCM files you may need this even for post-processing.

MISC:

misc-timeinterp =off,on

Interpolates the base station observations.  I generally set this to “on” if the base station observations sample time is larger than 5 seconds.

Please help me update this list if you have had success adjusting other options or using different settings for these options, or if you disagree with any of my suggestions. I will treat this as a working document and continue to update it as I learn more.

New release of demo5 B29e RTKLIB code

With the recent upgrades to the SwiftNav firmware and the upcoming release of the u-blox F9 receiver the last couple months have been an exciting time in the world of low-cost precision GNSS.!  It has kept me very busy, both making necessary updates to the demo5 version of the RTKLIB code and with consulting work related to the new receivers.  Unfortunately, this has meant I haven’t got a blog post out in over two months.

I have, however, just recently released a new version (b29e) of the demo5 RTKLIB code with some fairly significant changes from the previous version.  These changes have been much more of a group effort than my previous releases, so I first want to thank everyone who helped with the new features.

Here’s a list of the most important changes:

1)  U-blox F9 support:  Support for the new dual-frequency u-blox raw binary messages.  The updated code will now run real-time and post-processed solutions for the F9 receiver using all available raw binary observations and navigation messages.

2) Swiftnav F/W 2.0 support:  Support for the new Galileo and Bediou Swiftnav binary messages.  The updated code will now run real-time and post-processed solutions for the Piksi Multi receiver using all available raw binary observations and navigation messages.

3) Galileo E5b frequency support:  Both the u-blox F9 and the Swiftnav receiver are using the E5b frequency for the second Galileo frequency.  It was difficult to set the option for this frequency in the RTKLIB solutions and including it caused the solutions to run quite slowly.  Since the demo5 code is focused on low-cost receivers, and both SwiftNav and u-blox, the two most popular low-cost dual frequency receivers, are both using E5b, I have re-ordered the frequency tables in RTKLIB so that a three frequency solution now includes L1, L2, and E5b.  Previously, you would need to run what was effectively a five frequency solution to include E5b which caused RTKLIB to run noticeably slower.

4)  Event logging and event position logging:  This is a nice feature that has been available in the Emlid version of RTKLIB for a long time.  I have ported the code over from their open-source code base and have extended support to the Swiftnav receivers as well as the u-blox receivers.  Any events recorded by the receivers (e.g. camera triggers) are decoded from the binary messages and added to the rinex files.  Post-processing the rinex files will now generate two position logs.  The first is unchanged from before, with a solution position for every rover time stamp.  The second, only includes positions for the logged events which are interpolated from the time stamp positions.

5) Fix for using time-tag files to emulate real-time RTKNAVI solutions with file inputs:  This is a really useful feature that was broken by changes ported from the official 2.4.3 code quite a while ago, so it is really nice to have it working again.  Thanks to Christophe for figuring this one out and giving me the necessary code fixes!

6) Reduce unnecessary NTRIP connection requests:  RTKLIB was behaving quite badly on both server and client side whenever a receiver was disconnected without shutting down an NTRIP caster connection and was hammering the caster with nearly continuous connection requests.  This was causing bandwidth issues for the NTRIP casters, and was causing some users (including me) to get temporarily banned for misuse.   Thanks to David from SNIP for helping resolve this one and also for helping me to test the code.

7)  Improve cycle-slip handling for non-u-blox receivers:  RTKLIB was ignoring cycle-slips in cases where the carrier-phase was not set or set to zero.  This was causing it in some cases to ignore valid cycle-slips which can significantly degrade the solution.  The u-blox receiver code already had a fix for this so this change primarily affects non-ublox receivers

Several of these changes were written specifically for clients that needed the features or fixes for their own use but were willing to share them with the larger community.  I appreciate their willingness to share and hope I can continue to bring more changes this way into the open-source code in the future.

I’ve had a chance to run real-time and post-processed solutions with this code with raw observations from both the u-blox F9 receivers and with the SwiftNav receivers with F/W 2.0 and am getting great results with both of them.  I hope to share more results in the near future, but just wanted to say that the quality and number of raw observations I am seeing from both receivers is excellent.

If you’d like to try the new code, Windows executables can be downloaded here and the source code is available here.

 

 

 

 

 

 

 

Using SSR corrections with RTKLIB for PPP solutions

If you have been following recent announcements in precision GNSS, you may have been hearing a lot about SSR (State State Representation).  SwiftNav recently announced their Skylark corrections service, and u-blox announced a partnership with Sapcorda to provide correction service for their upcoming F9 receivers.  Both of these services are based on SSR corrections.

So, what is SSR?  Very briefly, it refers to the form of the corrections.  In traditional RTK with physical base stations or virtual reference stations (VRS), the corrections come in the form of observations in which all of the different error source are lumped together as part of the observation.  This is referred to as OSR (Observation Space Representation).  In SSR corrections, the different error source (satellite clocks,  satellite orbits, satellite signal biases, ionospheric delay, and tropospheric delay) are modeled and distributed separately.  There are many advantages to this form but what seems to be driving industry towards it now is that it allows the current VRS model where each user requires a unique data stream with observations tailored for their location to be replaced with a single universal stream that can be used by all observers.  This is a requirement if the technology is going to be adopted for the mass-market automotive industry for self-driving cars, since it is not practical to provide every car with it’s own data stream.

For more detailed information on SSR, Geo++ has a one page summary here and IGS has an 18 minute video presentation on the topic here.  Both are excellent.

Below is an image I borrowed from the IGS presentation which shows the flexibility of the SSR format.  It is intended to show how the same SSR data stream can be used globally for PPP quality corrections and also regionally for RTK quality corrections but it is also a good visual for understanding the message details I describe below.

ssr1

The RTCM standards committee is still in the process of finalizing the messages used to send the different correction components.  They have split the work into three phases.  Phase 1 includes the satellite clock, orbit, and code biases.  Phase 2 includes satellite phase biases and vertical ionosphere corrections, and phase 3 includes ionospheric slant corrections and tropospheric corrections.

There are several real-time SSR streams accessible for free today.  Unlike the paid services, they do not contain enough detailed regional atmospheric corrections to use as a replacement for a VRS base but they can easily be used for static PPP solutions.

I used the CLK93 stream from CNES for an experiment to test how well RTKLIB handled the SSR corrections.  It includes the Phase 1 and Phase 2 RTCM messages but not the Phase 3 messages.  Here is the format of the the messages in the CLK93 data stream:

clk93

You can register for free access to the CLK93 (and other) streams from any of these locations:

Unfortunately, RTKLIB currently only supports the Phase 1 RTCM messages and even this is not complete in the release version.  I have gone through the code and made a few changes to make the Phase 1 SSR functional and have checked those changes into the demo5 Github repository.  I also added some code to handle the mixed L2 and L2C observations from the ComNav and Tersus receivers.  After a little more testing I plan to release this code into the demo5 executables, hopefully in the next week or two.

With only phase 1 measurements, the RTKLIB PPP solutions will work much better with dual frequency receivers than with single frequency receivers.  This is because single frequency receivers require ionospheric corrections for longer baselines.  For this reason, I did not bother with collecting any single frequency data.  Instead, I collected both L1/L2C data with a Swiftnav Piksi Multi receiver and L1/L2/L2C data with a ComNav K708 receiver and a Tersus BX306 receiver.

RTKLIB is usually used to calculate PPP solutions without SSR corrections but this requires downloading multiple correction files for orbital errors, clock errors, and code bias errors and it is usually done with post-processing rather than real-time, after the corrections are available.  With SSR, the process is simpler because the solution can be done real-time and there is no need to download any additional files.  It does, however, require access to the internet to receive the real-time SSR data stream from an NTRIP caster.  The solution can be calculated real-time or the SSR corrections and receiver observation streams can be recorded and the solution post-processed.

To enable the use of SSR corrections in RTKLIB, you need to set the “Satellite Ephemeris/Clock (pos1-sateph) input parameter to either “Broadcast+SSR APC” or “Broadcast+SSR CoM”.  Note that CoM stands for Center of Mass and APC for Antenna Phase Center.  They refer to the reference point for the corrections.  The CLK93 corrections are based on antenna phase centers.

To generate my PPP solution I set the solution mode to “PPP-Static”,  ephemeris/clock (pos1-sateph) to “brdc+ssrapc”, ionosphere correction (pos1-ionopt) to “dual-freq”, and troposphere correction (pos1-tropopt) to “est-ztd”.  I also enabled most of the other PPP options including  earth tides,  satellite PCVs, receiver PCVs, phase windup, and eclipse rejection.

RTKLIB PPP solutions don’t support ambiguity resolution so the ambiguity resolution settings are ignored.  I specified the satellite antenna file as “ngs14.atx” which is the standard antenna correction file and is available as part of the demo5 executable package.  I also needed to include the CLK93 data stream as one of the inputs in addition to the receiver observations (and navigation file if post-processing).

I collected a couple hundred hours of observations with the SwiftNav receiver connected to a ComNav AT-330 antenna on my roof with moderately good sky visibility.  I then ran many four hour static solutions over randomly selected data windows.  I also collected a small amount of raw data from a ComNav K708 receiver and a Tersus BX306 receiver.

Below is a typical 12 hour static solution for a SwiftNav and a ComNav receiver.  The SwiftNav solution is in green and the ComNav solution is in purple.  Zero in these plots represents an online PPP solution from CSRS from data collected over a month earlier.  In this particular example, the SwiftNav solution is slightly better but this was not always the case.

 

ssr2

Here is a shorter data set from a Tersus BX306 receiver.  With the relatively small amount of Tersus and ComNav data I collected, I did not notice any differences in convergence rates or final accuracy between any of the three receivers.

ssr3

The solutions generally all converged to less than 6 cm of error in each axis after 4 hours with one or two minor exceptions that seemed to involve small anomalies at the day boundary.  Since the RTKLIB PPP solutions don’t include ambiguity resolution they do take longer to converge but the eventual accuracy should be similar.

I’ve uploaded some of the raw observation data for the different receivers and the CLK93 data stream as well as the config file that I used for the solution here.

This seems like a good start and I hope that RTKLIB will support phase 2 and phase 3 corrections in the future.