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.


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

21 thoughts on “Dual-frequency PPK solutions with RTKLIB and the u-blox F9P”

  1. Dear Tim! In the most recent b33a release it seems like you have changed some of the compiler settings, since I got the following error code when calling rnx2rtkp:
    “The code execution cannot proceed because VCRUNTIME140.dll was not found.” I suspect this is related to Visual Studio, on the same computer b33 works just fine. Also I do not find the usual 64 bit rnx2rtkp_win64 executable, so that also supports my suspect that you have changed compiler settings. It would be great to have some sort of fix for this. Thanks, Balint


  2. After running RTKconv on F9P data logging RAWX and SFRBX messages, I end up with nav files for every GNSS system: gnav(GLO), lnav(GAL), and nav(GPS). Is there any reason to splice these together in a combined file for RTKpost? Or put them all into RTKpost?
    I am just curious if the additional nav files can be used with RTKpost, and if they improve anything if used.


    1. Hi JJ. In RTKPOST, the output format (LLH or ENU) is specified in the Options/Output menu under “Solution Format”. Note that in RTKNAVI this option is grayed out and you need to specify the solution format from the Output menu.


  3. Hi Tim,

    Great post! It was exactly this kind of information that I had wished was more readily available when first starting to work with RTKLIB.

    For PPK, you’re recording both the UBX-RXM-RAWX and UBX-RXM-SFRBX messages. Can you confirm if these are the only two messages required for PPP as well? Do any of the other messages provide any use when creating a RINEX file from the raw collected data?



    1. Hi Adam. For online PPP solutions you need only the observation messages (RXM-RAWX). For RTKLIB PPP solutions you will need more precise ephemeris/clock information which I usually get from the SSR correction messages as I describe in this post. For RTK/PPK solutions using surveyed base stations, you might want to collect base position/antenna info messages as well. RTKLIB supports the 1005, 1006, 1007, 1008, and 1033 messages.


      1. Thanks, Tim!

        I collected some data with the ZED-F9P and submitted a RINEX file to NRCan’s CSRS-PPP tool the other day.
        I receive the message: “Warning : Some or all of the GPS signal(s) in your RINEX file are not currently supported by CSRS-PPP. A dual-frequency GLONASS only solution has been processed. The currently supported signals for GPS are: C1C L1C C2C L2C C1W L1W C2W L2W and for GLONASS: C1C L1C C2C L2C C1P L1P C2P L2P. Other modulations are planned for support once specific code biases become available.”

        Does this mean that PPP tool does not support the L1C/A signal as of yet? I’m curious if you received a similar message.



  4. hi, i have a m8t and im planning to buy a second antenna to make a rover/base rtk rig, what would you reccomend, the base is going to be stationary and the rover goes in a moving tractor, should i buy a second m8t and use rtklib or a z9p? in this case should i use the z9p as a rover or base?


    1. Hi Diego. A dual-frequency solution will require dual frequency base and rover receivers so if you want to use an existing M8T your only real option is another M8T. A F9P would work but the solution would only be single frequency so there would be no advantage in using the more expensive receiver.


  5. Do to know if there’s any way to run your demo5 code on an Android tablet?

    I’m also wondering if there’s a way to log position events with the f9p. The aim is to have a single f9p on a pole as a rover connected to an Android tablet via Bluetooth. I want to be able to log the raw observations and also save position events and then post process it against a local CORS station. Is this viable?


  6. wow how incredibly helpful! Thank you so much for creating this. Your postings related to rtklib have been invaluable in helping me understand how to get the most out of RTKLIB and my ublox 8t.

    I do not own a f9 but have been looking into it. What do you suggest as the best antenna for the f9? one that might produce the best results in a canopy and canyon constrained environment?


        1. Hi JJ. For PPP solutions on the OPUS website, you should specify “NONE” for the antenna option when using the ANN-MB-00. I am not aware of any calibration data available for the ANN-MB-00. The adjustments are usually very small in the horizontal axes (a few mms) and a little larger in the vertical axis. If you need more precise solutions than this, you will need to use a survey grade antenna from the dropdown list on the OPUS page.


          1. Thanks, Do you have a survey grade antenna you can recommend? I see some of them are tough to find and some are not L1 L2/E5b


          2. Hi JJ. A more complete set of antennas with calibration data than what is in the igs14.atx file is available at https://geodesy.noaa.gov/ANTCAL/#. I would suggest one of the Harxon antennas, either GPS500, GPS600, or GPS1000. SwiftNav has sold GPS500 and GP1000 antennas with their receivers. The GPS1000 antenna is available new from the SwiftNav wibsite for $425 but you may be able to find better prices elsewhere or you can look for used antennas.


          3. I am also getting an error when trying to rtkpost my obs of no position in rinex header. I’m assuming it is in my obs file not the unavco station file. Can i manually enter the position in the header?


          4. Hi JJ. The “No position in rinex header” error can be deceptive as it often means that RTKLIB just can’t find the observation file at all. See this post for more details on getting better debug info from RTKLIB. You could manually enter the base location in the rinex file header but normally it should not be missing in files from any kind of CORS reference station. For non-CORS base rinex files, it would usually be simpler to add the location to the config file under the antenna settings than modifying the rinex files.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.