Updates to RTKLIB for the u-blox F9P receiver

I recently released a new version of the demo5 RTKLIB code (demo5 b33b2) with some more updates for the u-blox dual-frequency F9P receiver. Its taken a lot longer than I would have hoped, but for the first time, I feel like the demo5 code now has reasonably complete support for this receiver. Many of these improvements should help with other receivers as well, especially other dual-frequency receivers. In this post, I’ll describe some of the recent changes to the code. If you are more interested in a getting-started guide to using RTKLIB with the F9P rather than the latest code changes, then you might prefer this earlier post.

Here are the most important code changes to be aware of. They include changes made in the last couple of demo5 code versions.

  1. Support for F9P constellations/frequencies:
    I believe the latest code now supports all the F9P L1, L2, E1, E5b, B1, and B2 codes for the GPS, Glonass, Galileo, and Beidou constellations, both for u-blox raw binary formats and for the RTCM3 MSM7 messages. Raw and RTCM3 files are correctly converted to rinex format and processed in the position solution for all these codes. However, I did recently notice that there are still a few issues with RTKPLOT correctly plotting all the different codes, particularly the Beidou B2 observations.
  2. Frequency selection:
    Another change in the new code is a slight shuffling of the frequency grouping between constellations. Since RTKLIB memory use and CPU load increases significantly when enabling additional frequencies, I eliminated Galileo E5b processing in RTKLIB as a separate frequency and it is now processed with the other “L2” frequencies. This means to run a dual-frequency solution for all constellations on the F9P, you need to only enable “L1+L2” as the frequency option. Galileo E5a is still part of the “L5” frequencies so if you are using a receiver that outputs E5a instead of E5b you will need to enable “L1+L2+L5” as the frequency option when running an RTKLIB solution. Running dual frequency solutions still take longer than running single frequency solutions but the difference is smaller than it was.
  3. Receiver Configuration:
    A more significant change to the new code is that RTKLIB now much more fully supports configuration of the F9P receiver using a “.cmd” file. In the previous code, some commands still worked on the F9P such as turning on or off receiver messages or changing the observation output rate but other commands, particularly those to enable or disable constellations were broken since the format of these commands changed when going from the M8T to the F9P. In addition, only a small subset of the total commands available for either the u-blox M8T or F9P receivers were ever supported by RTKLIB.

    To make things more complicated, with the F9P, u-blox is also transitioning from the legacy UBX-CFG messages to a new configuration protocol. Although most of the legacy configuration messages still work on the F9P, they are recommending switching to the new format as stated in this quote from the F9P Integration Manual:

    “3.1.6 Legacy configuration interface compatibility There is some backwards-compatibility for the legacy UBX-CFG configuration messages. It is strongly recommended to adopt the new configuration interface, as the legacy configuration messages support will be removed in the future.

    Fortunately the latest demo5 code now fully supports the new configuration interface, thanks to code contributed by Nagarjun Redla. Under the new interface, instead of having different commands, each with its own format and various numbers of input parameters, configuration parameters are set individually using the VALSET command . For example, the legacy CFG-RATE command had 3 input parameters to set time source, measurement period, and navigation rate. Under the new interface each of these parameters has its own key and each is set with a call to the VALSET command with parameter key and value. The two examples below set the measurement rate to 200 msec and enable the Galileo observations.

    !UBX CFG-VALSET 0 1 0 0 CFG-RATE-MEAS 200
    !UBX CFG-VALSET 0 1 0 0 CFG-SIGNAL-GAL_ENA 1

    Currently, only the second of the first four numeric parameters is used and that is set to to the configuration layer to write to. In this case “1” writes to the RAM layer. Use “4” to write to the flash layer or “5” to write to both flash and RAM. “2” is used to write to the BBR (battery-backed up RAM). See the F9P Interface Description document for a list of all configuration key values as well as for more details on the VALSET command.

    All of the available key values are supported by RTKLIB, so any receiver configuration parameter that can be modified from u-center can now be modified from a command file in RTKLIB and the results can be saved to either RAM, flash, or both. The legacy commands that RTKLIB previously supported have not been removed so they will all still work as well.

    The one exception I am aware of is that the key values to set the individual frequencies do not seem to work from either u-center or RTKLIB. This is either a bug in the F9P or a misunderstanding on my part. However, in the Generation 9 Configuration View in u-center, the “Advanced Configuration” command is used for all parameters except GNSS configuration which uses the legacy command. This makes me believe it is actually a bug. Since RTKLIB does not support the legacy GNSS configuration command for dual-frequencies, this means that RTKLIB can enable and disable constellations but not individual frequencies within a constellation.
  4. Ambiguity Resolution:
    Although as I demonstrated in an earlier post, the demo5 code was working well for solutions with moving rovers, the results were less consistent for stationary rover solutions. In some examples, especially those with moderate amounts of multipath in the rover observations, the RTKLIB solution was not getting a fix even after several minutes, while the real-time internal solution and even the single frequency RTKLIB solutions were converging much more quickly.

    Most of my experiments focus on moving rovers and I tend to think of them as more challenging than stationary rovers because of the large number of cycle slips and the continuously changing set of satellites available as the rover’s sky view keeps changing and different satellites come in and out of view behind obstructions. However, stationary rovers have their own set of challenges and in particular multipath is a greater challenge in the stationary rover case than it is in the moving rover case.

    This is because, for the stationary rover, the paths from satellites to receiver antenna stay relatively constant and change only slowly as the satellites move across the sky. This means that the errors introduced by the combination of direct and indirect paths (reflections) between satellite and antenna have very long time constants. In the moving rover case, the errors are still present but are changing much more quickly with rover movement, have much shorter time constants, and average out to zero much more quickly.

    The existing partial ambiguity resolution algorithm in the demo5 code turned out to be more sensitive to the long time constant multipath when the number of observations increased with the dual frequency receivers. I had previously added a step to the ambiguity resolution algorithm to exclude a different satellite each epoch whenever the number of satellites was above a defined minimum (Min Drop Sats) to try and detect “bad” satellites. To minimize the increased risk of false fixes while the kalman filter was still converging, I had only done this after first fix. It turns out that with large numbers of observations, it becomes important to extend this test to before the first fix, and this is the change I made to the code.

    False fixes appear to be much less common with the F9P than the M8T, presumably due to the increased number of observations, so the increased vulnerability while the filter is converging is not much of a concern with the F9P. However if using the latest code with the single frequency M8T, you may need to adjust the configuration parameters slightly to avoid increasing the risk of false fixes while the kalman filter is converging. The best way to do this is usually to adjust the maximum position variance threshold (Max Pos Var for AR) to a slightly lower value. This will delay the start of ambiguity resolution attempts until after the filter is better converged. The trade-off is that if set too low it can delay time to first fix so it may require a little experimentation for best results. I might suggest starting at a value of 0.05 meter for the M8T and 0.1 meter for the F9T but optimal values will vary with configuration so adjust as needed. Time to first fix is less important if you are post-processing with a “combined” solution so you can tighten these numbers even more in this case. For post-processing high quality observations with the M8T I usually set this value to 0.004 meters.
  5. Precise ephemeris:
    This last change is not related to the F9P receiver but is worth mentioning anyways. I don’t use precise ephemeris files very often but other people do, especially for PPP solutions. Use of the MGEX files has become much more popular since they include the Galileo and Beidou orbital data as well as GPS and Glonass. These files usually have capitals in their extension unlike the older files. (.SP3 vs .sp3). Due to a bug in the RTKLIB code it was rejecting the “.SP3” files without reporting an error which could be very confusing to the user. The newest code now accepts files with “.SP3” extensions as well as “.sp3” extensions.

I think those are the most important changes but you can always review the demo5 Github repository for more details on code changes or if you want to build the code for linux platforms.

I do my best to test the code before I release it but I don’t have the time or resources to do this properly on all the different variations that RTKLIB can support so please treat new releases as beta, and if you see results that don’t make sense, it’s a good idea to compare results between the newest version of code and an older version that you have confidence in. If you do find degraded results in the new version, please let me know, and if possible, send logs of the observations and config file along with a detailed description of the issue. I rely on users to validate the code and treat any reported issues where a newer version of the demo5 code performs poorly compared to either a previous version or the official 2.4.3 code with the highest priority I can.

One last thing. You may notice that I have added an optional contribution button to the code download page. I do this work to promote low-cost precision GNSS and because I enjoy it, not to get rich and I want to emphasize that contributions are completely optional. However, if you are a regular user of the demo5 code, find value in the software, and would like to share that value, then any contribution is much appreciated.   I have also added a field to the contribute page to describe any feature or bug fix that you would like to see added to the demo5 code and will try to prioritize popular requests when making future code updates.

RTKLIB documentation tips

The RTKLIB software package has an enormous amount of capability and flexibility. Between all of the different applications, the configuration parameters and input options, it is very powerful, but it can also be a little difficult to navigate at times.  I get a lot of questions on how to do various tasks in RTKLIB so I thought it would be worth going over the available documentation as well as mentioning a couple of tips and tricks for finding information on some of the less documented features.

The first place to look is the official RTKLIB manual .  It is well written and fairly thorough, at least in many parts.  If you are using  RTKLIB and have not been through the manual recently (or have never read it), it is well worth going back and taking another look.  Almost every time I go back to it, I find some detail I have missed in the past, not because it is difficult to find, but just because there is so much information in there.  Especially when using the GUI apps there is a tendency to think the manual is not necessary since everything should be intuitive, but in this case there are many features that are not so obvious.  For example, at least to me, it is not overly intuitive that the tiny little unlabeled square (the RTK Monitor Window) above the Start/Stop button in the image below is one of the most important buttons in RTKNAVI and will give you access to up to 35 different windows of useful information.

navi1

Here is an image of  a few of the various monitor windows I frequently find useful.

navi3

Click on a few more of the small inconspicuous triangles, squares and rectangles on the RTKNAVI, and you can change the solution coordinates to pitch/yaw, open up sky views for the base and rover, open up a baseline compass heading plot, and many other things.  If you haven’t read the manual, it’s easy to miss some of these options.

navi2

Unfortunately, although the manual has lots of useful information, both for the command line and GUI apps, it has not been updated in six years, so some of the newer features are not included.

This is especially true for the linux command line apps like STR2STR and RTKRCV.  One tip for getting more up to date information for any  of the command line apps is to use the embedded help messages, since, for the most part, these have been kept up to date.  For example,  let’s first look in the manual at the stream options and command line options for the STR2STR app.  We find that there are 6 stream options and 13 command line options listed.

str2str_1

str2str_1a

Now let’s bring up the embedded help message in STR2STR by typing “str2str -h” and we get the following:

str2str_2

str2str_2a

Notice that the number of stream options has increased from 6 to 8 and the number of command line options from 13 to 24.  This is a significant number of additional options to work with!

Another thing to be aware of  is that all of the RTKLIB apps are using a common core code, and for the most part it is only the user interfaces that are different.  This means that if a feature is available in one app, say for example RTKNAVI, then it is very likely also available in another app, say RTKRCV.  It may just be harder to find information on how to enable it there.  However, if you know what you are looking for, and you know that it’s most likely there somewhere, then this usually makes it easier to find.

Another resource that can be helpful is this post I wrote a while back which includes description of most of the additional features I have added to the demo5 version of RTKLIB to optimize it for low cost receivers, as well as additional information on all of the previously existing config parameters that I typically find useful to modify.  This post is not guaranteed to be fully up to date but I do try and update it with new information as I add new features to the demo5 code.

The above resources will be enough to answer many questions but sometimes they will not be enough and you will need to dig a little deeper.  The next step is to look at the source code which is available on Github, both for the official and the demo5 versions of RTKLIB.  The first place to look is the “options.c” file as it lists all of the supported input configuration parameters as well as their valid input values in a format that is easy to read.  Here is the beginning of the tables of valid option values and parameters.

options

Going through these tables, I found about a dozen parameters in the official code that are not mentioned in the manual and a few more in the demo5 code that are not mentioned in my documentation.

If you still need more information, the next level is to look at the top-level source file for each app.  For example in the “rnx2rtkp.c” file you will find the help menu listed at the top and then in the main() function lower down you will see where the options are actually parsed.  This should answer most questions.  You can go even deeper into the code if you have to, but I will warn you, things do get a bit more challenging once you get to the next layer.

The last tip that I can offer is that I have written about a number of RTKLIB features in my posts over the last few years, so using the search window at the top right corner of this page will occasionally bring up some useful information.

Anyway, hope at least some of this is helpful to those of you trying to learn a little bit more about some of RTKLIB’s less well documented features.

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.

Event logging with RTKLIB and the u-blox M8T receiver

Event logging is a nice feature that has been available in the Emlid version of RTKLIB for a long time.  In the latest version of the demo5 code (b29e), I have ported this feature from their open-source code repository.  Their version is specifically for the u-blox M8T receiver but I have extended it to support the Swiftnav receiver as well.  I mentioned this feature in my previous post and had a couple requests for more information, hence this post.

Both the u-blox and Swiftnav receivers have hardware/firmware to capture the precise time an external pin changes state and send out a binary message with this information.  The RTKLIB event logging code decodes these messages and logs the events to the rinex file.  The events in the rinex file are then used in post-processing to generate a position log containing an interpolated position for each timing event. The most popular use for this feature is probably to record camera shutter times but it can also be used for other purposes such as marking survey locations in the data stream.

Here is an example of a drone flight from a data set containing events that I downloaded from the Emlid forum.  On the left is the ground track of the standard position solution plotted with RTKPLOT.  It includes one point for every rover observation epoch.  On the right is a plot of the event positions from the new event position file.  In this case there is one point for every event which gives precise locations for each camera image.  This is very useful information when processing the images.

event1

Here are the positions of the two plotted on top of each other, green dots are the rover observation epochs from the position file and the blue dots are the events from the event position file.  As you can see from the plot, the event positions are interpolated from the observation epochs.

event4

 

There is information in the Emlid and Swiftnav documentation on how to connect an external trigger to their hardware so I won’t cover that here.

Instead, I will go through an example using an M8T receiver from CSGShop.  I will also use this example to try and validate this feature since there has been some discussion on the Emlid forum about potential issues that as far as I can tell have not been completely resolved on the forum.

The CSGShop M8T receiver comes in several variations.  To use event logging you will need to choose a board that provides access to the external interrupt pins.  You can use either EXINT0 or EXINT1.  For this experiment I also use the TIMEPULSE pin to provide triggers for the event logging.  Here is an image of the receiver and the interface pins.

event9

The goal of this experiment is to generate events for which I know their precise timing so I can use them to validate the RTKLIB event logging results.  To do this, I configured the M8T TIMEPULSE output for a period of two seconds and a falling edge that occurs at 0.2 seconds, all in GPST time.  I then connected the TIMEPULSE output pin to the EXTINT1 input pin so that each state change of the output pulse will be recorded as an event.  Although the M8T will record both rising edges and falling edges, RTKLIB is setup to record only the falling edges.

To configure the timing pulse, I used the u-blox u-center app to setup the UBX-CFG-TP5 command as shown below.

event2

I then enabled the UBX-TIM-TM2 messages which the receiver uses to output the event information.  Next, I opened the table view in u-center and configured it to log GPS time, and the rise and fall times for EXTINT1.  This information is extracted from GPRMC and TIM-TM2 messages.  As you can see the falling edges of the pulse are occurring at exactly 0.2 seconds on the even seconds in GPS time so it looks like we have correctly configured the output pulse

event3

Now that I have external events occurring at precisely known times, I can use these to test the RTKLIB code.   The u-blox example command files that I include with the demo5 executables already are setup to enable the UBX-TIM-TM2 messages, so there is no need to make any changes there.

The next step is to collect some base and rover data using the modified receiver as rover.  I did that, and then converted the raw .ubx files to rinex using the new demo5 version of RTKCONV.  The events appear with a time stamp followed by a 5 in the next field to indicate an external event as shown below.  The zero in the last field indicates it is a valid time mark.

event5

The observation epochs are occurring every second, so notice that the event is being logged out of sequence with a one sample delay.  I did not see this with the Emlid data set example described above.  However, I do see the same delay  if I use the Emlid code to convert the binary file instead of my code.  I don’t know if the Emlid hardware has somehow been configured to avoid this sequencing issue or whether it can occur on the Emlid hardware as well.  I’ll get back to this in a minute.

Next I ran RTKPOST to calculate a position solution.  With the new code changes, a *.events.pos file is generated in addition to the *.pos file.  It is the same format as the *.pos file but contains the event positions instead of the observation epoch positions.  Note, that it will be generated for absolute solutions (XYZ,LLH) LLH but not for relative (ENU) solutions.

I first did this with the Emlid code and got the following result when plotting both the position file and event position file.

event6

The events are occurring at the correct times, but note that unlike the previous example, the positions are not being correctly interpolated between the two closest observation epochs.  In fact, if you look carefully you will see they are being extrapolated from the two previous observation epochs.  This is most obvious in the N-S axis points and is occurring because the events are being logged out of sequence.

To fix this, I modified the interpolation code to use the nearest observation epochs even when the event logging was delayed by one sample.  Here is the result using the latest demo5 b30 code.

event7

Looking at the time stamps from the position log and the event position log, shown below, you can see that the observation epochs are occurring on the integer seconds and the events are occurring 0.2 seconds later on the even seconds, all in GPST time, just as we set them up to occur and verified with u-center.

event8

So I don’t fully understand why the time stamps are appearing out of sequence with the CSGShop M8T data and not in the Emlid M8T data.  It may be that Emlid has configured the hardware somehow so this can not happen.  If this is true, then there should be no issue using the Emlid RTKLIB code with Emlid data but be careful using it with data from other hardware.  If anybody has any additional insight into this discrepancy please leave a comment.

I should also mention that all these code changes are in the core code so are present in both the command line apps as well as the GUI apps.  The most recent demo5 executables (b29e) do not contain the fix for interpolating delayed events and will function the same as the Emlid code.  The Github respository does have this fix.  The fix will also be in the demo5 b30 executables which I hope to release soon.

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.