RTKLIB solution accuracy

OK, so let’s say you’ve just gone out and collected some decent raw measurement data, everything looks like it is working properly and you get a nice-looking solution from RTKLIB, maybe something like this.


The next thing you might want to know is how accurate is that solution?  Fortunately, RTKLIB does include accuracy estimates in the solution file.  These are expressed as standard deviations, one for each axis.  Here’s an example for a solution calculated in ENU (east/north/up) coordinates.  The sde, sdn, and sdu columns are the standard deviation estimates for each solution point and are given in meters.  If the solution were calculated in XYZ coordinates, the columns would be labelled sdx, sdy, and sdz.


You can display these on the solution plot with RTKPLOT by setting “Error Bar/Circle” in the options menu to “Dots” or “Bar/Circle”.  You can see the gray lines in the plot below that represent the solution value plus and minus one standard deviation.


Visually, I prefer to see three standard deviations plotted, rather than just one.  Three standard deviations represents 99.7% of the distribution, so the correct value should nearly always appear between the two gray lines.  One standard deviation, on the other hand,  represents only 68% of the distribution which is hard for me to attach any physical meaning to.  This can be easily changed in RTKLPLOT by replacing SQRT(s[j]) with 3*SQRT(s[j]) all three places it appears in the plotdraw.cpp file and recompiling RTKPLOT which gives this:


Of course these are just estimates of the solution uncertainty made by the kalman filter in RTKLIB and we can not assume they are accurate without some analysis.  They are a function of the input parameters that set the input measurement uncertainties and process noises for the kalman filter.  These are all in the “stats” section of the input configuration file.  Even if these are all set to correctly match your actual configuration, there will be additional errors in these estimates caused by non-linearities in the system, non-gaussian distributions, and time-correlated measurements among other things.

So, let’s do a little analysis to get a feel for how useful these estimates are.  We’ll start with the above data set which includes eight hours of measurements from a stationary u-blox M8T receiver and a CORS reference station 8 km away.  I enabled fix-and-hold for ambiguity resolution with relatively low tracking gain (pos2-varholdamb=0.1).  I ran both static and kinematic solutions on the data, then turned off ambiguity resolution and re-ran the solutions to get examples of both fixed and float solutions for static and kinematic modes.

After running the solutions, I pulled the solution files into matlab for plotting and analysis.  Since the rover was stationary and I knew it’s precise location I was able to easily calculate the true errors.  I then plotted for each solution point, the absolute value of the errors and three times the standard deviation estimate for each point, similar to the above RTKPLOT plot.  The raw data is in E/N/U coordinates but I combined the East and North values into a single horizontal error and error estimate.  After finding that in some cases the error estimates were too low, I also plotted a line using double the error estimate, to see if that might be a usable value .  In the title of each plot I’ve included the percent of samples that were inside the error lines, the first number is for the undoubled estimate, the second is for the doubled estimate.  I also made one more modification to the error estimates by limiting them to a minimum value.   In the case of the static solutions, the RTKLIB error estimate will continue to decrease almost all the way to zero but this is not realistic since there are errors that are not visible to the solution.  I arbitrarily limited each horizontal axis standard deviation to no less than 5 mm, and the vertical axis to 1 cm.   I don’t have good justification for these particular numbers but do believe there needs to be some limits set.

For a perfect Gaussian distribution, plus or minus three standard deviations should include 99.7% of the data.  Given that these are not perfect distributions and will also contain outliers, I would consider the estimates useful if more than 95% of the data fell within them.

Here are the plots for the above data set run with static solutions, float on the left, and only the fixed values of the solution with ambiguity resolution enabled on the right.  The blue line is the actual error, the red line is the RTKLIB estimate, and the yellow line is double that.  The top plots are for the horizontal axes and the bottom plots for the vertical axis.  In the static cases, all the error lines dropped below the minimum estimate values I set above fairly quickly, so only the initial convergence of the float solution was really of any interest.   Still the error estimates in that region look somewhat reasonable, although the undoubled estimates are clearly optimistic. The undoubled estimates (red) are not visible on the plots where both estimates have dropped below the minimum and they get overwritten by the doubled estimate.


Next are the same plots for the kinematic solutions.  Just to confuse you, I have accidentally put the float solution on the right this time.  Again, the solution with ambiguity resolution enabled (on the left) only includes points that were fixed.  These are more interesting than the previous plots since they are not dominated by the arbitrary minimum error estimate limits I added.  Looking at the float solution first, the undoubled estimates again look too optimistic with only 92.2% and 75.2% of the data within that limit.  At 100% and 99.6% the doubled values (yellow lines) appear to be better estimates.  For the fixed values on the left however the undoubled estimate percentages and plot lines appear to be fairly reasonable.


In one last example, I used a different data set, this one is one of the sample data sets on my website which was taken with two M8T receivers, one on each end of a kayak out on the ocean.  In this case we know that the distance between the two receivers will remain constant so we can use that information to do a similar analysis as above.  Because the kayak is moving in all three axes with the waves we can not separate the horizontal and vertical components but can do an actual error to estimated error comparison for the three axes combined.

The float solution is back on the left again, just the fixed values from the ambiguity resolution enabled solution on the right.  Based on the calculated percentages and the shapes of the curves, it seems fairly reasonable to again choose the doubled estimates for the float solution and the undoubled estimates for the fixed values.  Even with the doubling, the percent of solution values within three standard deviations is still only 88.5% which is rather low but most of the outliers were in the initial convergence where we might expect more issues.


So, based on these few examples I do see correlation between the RTKLIB error estimates and the actual errors, not as much as I would have liked, but there is some.   Maybe these adjustments I made would hold up for other cases as well, but I would not have a lot of confidence without trying more examples first.

Clearly these error estimates can not be taken at face value.  Do they have any value?  It probably depends on what you are trying to do with them.  If you are just trying to get a rough idea of the accuracy of the measurements, especially if it is in a statistical sense, and you have done some previous analysis with similar data sets, then you can most likely derive some value from them.  If the absolute accuracy of a single measurement is important to you then you will probably need to find another solution.

What about trying to adjust the input configuration parameters (measurement and process noises) to make the accuracy estimates more accurate?  You may be able to make small improvements but I suspect they will not be significant enough to avoid post-solution adjustments.  You will also find that adjusting these parameters will affect the quality of the solution and it will be difficult to optimize for both.

I am interested, though, if anyone has any ideas for simple (or at least only moderately complicated) code changes that could be made to RTKLIB to improve these estimates or any other ideas on how to improve them.





New code, new gps data

I’ve just released the b28 version of the demo5 code.  It includes all of the updates in the b28 update of the official RTKLIB 2.4.3 code.  It also now supports both Tersus and Swift low cost dual frequency receivers.  The Tersus updates were part of the official 2.4.3 release although I did make a few changes to fully support the L2 measurements as well as some changes to the makefiles to get all apps to build.  The Swift receiver support is based on code I pulled from the Swift RTKLIB Github page.  I suspect the receiver specific RTKLIB code for both receivers could use some improvements in translating from the raw binary formats to the Rinex/internal observation formats but at least this is a starting point.  The executables are available from the download section at rtkexplorer.com.  The source code is available on my Github page.

I’ve also uploaded some data sets comparing the Swift Piksi Multi and the u-blox M8T as well as between the Tersus BX306 receiver and the u-blox M8T.  This data is also available from the download section at rtkexplorer.com.



Tersus/M8T moving rover comparison

In my last couple of posts I compared a u-blox M8T single frequency receiver to a Tersus BX306 dual frequency receiver for a static rover using a fairly distant CORS receiver for base data.  Both receivers had over twenty raw phase measurements, but the Tersus receiver had much better overlap with the CORS receiver with twelve measurements available for ambiguity resolution (GPS L1 and L2) while the M8T had only six (GPS L1).  Not surprisingly, the Tersus provided a much better solution than the M8T.  I also compared the RTKLIB solution and the internal Tersus RTK solution and showed that they appeared to be roughly comparable.

In this post, I will add a second M8T receiver and compare a M8T to M8T short baseline solution to the Tersus to CORS longer baseline solution.  While this may not sound like a fair comparison, it could be a reasonable choice given that two M8T receivers are still significantly less expensive than one Tersus receiver.   Also, to make things more interesting,  I will use a moving rover this time rather than a stationary one.

For the experiment, I mounted both receivers in a car, each with it’s own antenna on the roof.  Given that we are making a comparison to a relatively expensive solution I felt it wouldn’t be unreasonable to add $20 to the M8T solution and upgraded its antenna from the standard $20 u-blox antenna I usually use to a Tallysman 1421 antenna available at Digikey for $42.   For the Tersus receiver I used a Tallysman dual frequency 3872 antenna which I believe is roughly a $200 antenna.  For the M8T base station, I used the same antenna on my house roof as in the previous experiment which gave a baseline less than 1 km for most of the M8T pair solution whereas the Tersus/CORS baseline was roughly 16-18 km.  For RTKLIB post-processing, I also ran a solution using base data from the nearest CORS station which gave a baseline of 7-9 km but I couldn’t use this data for the Tersus internal RTK solution because it is not available real-time.   Also, it should be noted that I collected all this data a few weeks ago before Tersus released their most recent firmware so it was all done using their previous version.

I chose a driving route very similar to the one I used for this M8N to M8T comparison in which I drive through a residential neighborhood with a moderate tree canopy.  This time I added a section of the route in a parking lot with no tree obstructions.  The parking lot is intended to be a low-stress environment and the neighborhood streets a moderate-stress environment.  Here’s a Google Earth image of the previous route to give a feel for the terrain.  Unfortunately this map feature no longer works in RTKLIB because Google has discontinued the API to Google Earth.



In this case the M8T  was receiving signals from the GPS, GLONASS, SBAS, and Galileo satellites and started the data set with a total of 21 phase measurements.  All of these can be used for ambiguity resolution since the two receivers are identical hardware.   The Tersus receiver measured only GPS and GLONASS but for all but a couple of satellites got both an L1 and an L2 measurement.  It started the data set with 24 phase measurements of which I would expect that only the 14 GPS phase measurements are available for ambiguity resolution because the receivers are not identical.

The previous time I ran this experiment I was able to get a nearly 100% fix solution from both the M8N and the M8T  receiver pairs but had to use some solution tracking gain (fix-and-hold) to achieve that.

In this case, with the extra Galileo satellites and the more expensive antenna, I was able to get nearly 100% fix using continuous ambiguity resolution instead of fix-and-hold. Continuous AR has the advantage of reducing the chances of locking to a false fix and is normally a preferrable solution if it is achievable.  The only float part of the solution was at the very end of the route where I parked the car underneath a large tree.

Here are three versions of the M8T receiver pair solution all run with continuous ambiguity resolution.  In all the plots, green is a fixed solution and yellow is a float solution.  The top left solution was run with 5 Hz measurements which is what I normally use for moving rovers.  I then realized that the Tersus data was only 1 Hz, so I re-ran the M8T solution after decimating the raw data down to 1 Hz (the latest Tersus firmware supports 5 Hz RTK solution).  The decimation can sometimes cause problems because the cycle slips aren’t always handled properly in the decimated data but in this case it seemed to work fine as can be seen in the plot on the top right.   The only noticeable difference is that the 1 sec data took a little longer to get to first fix.  This is less important in post-processed solutions because the solution can always be run in combined (forward/backward) mode which will usually get a fix for the beginning of the data.  This can be seen here in the bottom left solution which was run in combined mode.


The zig-zag line from 21:22 to 21:26 is the lower stress circles in the parking lot followed by the moderate stress route through the residential neighborhood.

Next, let’s look at the Tersus solutions.  The internal Tersus RTK solution was run with the Tersus default settings.  The user interface for the Tersus console app is much simpler than RTKLIB so there are many fewer options to play with.  For most users this is probably an advantage because it avoids the rather overwhelming array of options that RTKLIB gives.   The RTKLIB solution was run with continuous ambiguity resolution with settings very similar to the M8T solution, just adjusted for dual frequency.  The internal solution is on the left and the RTKLIB solution on the right.


The two solutions are fairly similar, both did well in the lower stress parking lot environment but struggled with the moderate stress on the residential streets.  The internal solution did a little better with scattered fixes in the latter part of the data.

Comparing differences between the internal and RTKLIB solutions and between the Tersus and M8T solutions for only the fixed points, it looks like most of the errors between the different solutions when they have a fix are small.  The Tersus/M8T differences are indicated by the distance from the circle as I have described before. I’m not too worried about the DC offsets between them.  It is somewhat tricky to get all the offsets correct and I did not spend a lot of time on that.  It is likely to be a issue with coordinate differences or handling of antenna offsets that explains the DC shifts.


The above Tersus RTKLIB solutions were run with only GPS ambiguity resolution as I would not expect the GLONASS measurements to be useful for ambiguity resolution because of the inter-channel bias differences between the non-identical receivers.  However I was surprised to find that I did get fixes with the GLONASS ambiguity resolution set to “On” in the RTKLIB configuration file.  The solution was slightly worse than the GPS-only AR but I did verify that the GLONASS satellites were included in the ambiguity resolution.  I’m not quite sure what to make of this observation, whether or not it makes sense to include the GLONASS measurements in the ambiguity resolution, but I suspect it makes sense to leave them out for the reason mentioned above.


I then ran another RTKLIB post-processed solution using the Tersus and base station data from a closer CORS base station.  This was to see how reducing the baseline affected the answer.  Here’s the result from a base station that is only 7-9 km away.


Even though we reduced the baseline by a factor of two the solution only got slightly better and time to first fix actually increased.  This suggests that the long baseline may not be the primary reason for the poorer Tersus solution.

My suspicion is that it is a combination of two things,  at least for the RTKLIB solutions.  First of all I believe there is a mismatch between how RTKLIB interprets a cycle slip flag and how the cycle slip flag is defined in the Rinex spec.  The problem is that RTKLIB resets the phase bias estimate in the same epoch as the cycle slip is logged regardless of whether the receiver has had time to relock or not.  This can cause large errors in the bias estimates if the receiver flags a cycle slip before it has recovered from it.  In some of my earlier posts I have described having the same problem with the M8T receiver but in that case I have made some changes in the u-blox specific RTKLIB code to delay the cycle slips until the receiver has re-locked.  Something similar may need to be done for other RTKLIB receiver specific code  including the Tersus or it may be possible to modify the main RTKLIB code to better interpret these cycle slip flags.

Maybe more important, though, is the difference in the measurements between the two receivers.  As mentioned before, the M8T receiver has 21 phase measurements all of which can be used for ambiguity resolution while the Tersus has 24 of which only 14 can be used for ambiguity resolution assuming we don’ t try and use the GLONASS satellites.  Note, though, that there are only seven different satellite-receiver paths for the Tersus since each satellite is providing two measurements.  This compares to the 21 satellite-receiver paths for the M8T receiver where each satellite only provides a single measurement.  Now imagine that the receivers are under a partial tree canopy and four of the satellites are obstructed for both receivers.   The M8T will lose four measurements and still have 17 to work with but the Tersus receiver will lose 8 measurements and only have six to work with.  This is a significant disadvantage and I suspect can explain a large part of the difference in results.

If I had used a local Tersus base station, then the matched Tersus receiver pair would enable use of the GLONASS satellites for ambiguity resolution.  In the case of four obstructed satellites, the two cases would be much more similar with 17 available measurements for the M8T and 16 for the Tersus.  As more satellites were obstructed the M8T would start to gain a bigger advantage since the Tersus would lose two measurements for each obstructed satellite and the M8T would only lose one.  Of course the M8T would tend to have more obstructed satellites than the Tersus since it has more satellites to start with that can be obstructed.  That would work in favor of the Tersus reciever.  It’s hard to say which would give a better solution but my suspicion would be that if the cycle slip handling issue in RTKLIB was fixed the two solutions would be fairly similar when calculated with RTKLIB.  I don’t know enough about the internal Tersus RTK engine to predict how it would do.  Hopefully I can get my hands on a second full dual frequency receiver and run this experiment soon.

Although I ran this experiment at a random time without looking at the satellite alignment first, it may be that the satellite alignment was such that it accentuated this effect.  Note in the observations (Tersus on the top, M8T on the bottom) that the Galileo (Exx) and SBAS (Ixx) satellites have less cycle slips than any of the other satellites.


Looking at the skyplot for those observations we see that three of the four Galileo satellites are at very high elevations which will tend to be blocked less from nearby trees. This would have helped the M8T solution since the Tersus receiver did not have access to these high elevation satellites.


I will try to summarize what I think this data suggests but let me first emphasize that this is by no means intended to be any sort of rigorous analysis.  I don’t have the time, resources or knowledge to do that.  Instead, please take these as no more than the sharing of my thought process as I try to understand some of the differences between single and dual frequency RTK solutions.

Rover to CORS or other traditional dual frequency receiver:  Tersus has a significant advantage over the M8T both because of more matched measurements and opportunities to take advantage of the nature of the dual frequency measurements.  This advantage applies both to the RTKLIB solution and the Tersus solution although I suspect the Tersus solution takes better advantage of the dual-frequency measurements.  The advantage also increases as the baseline increases.

Matched pair of receivers with short baseline:  Good results with the RTKLIB solution will be limited to low stress environments for a pair of Tersus receivers because of limitations in the cycle slip flag handling.   With the M8N and M8T, RTKLIB can also handle moderate stress environments because of receiver specific changes in the RTKLIB cycle slip handling code.   Relative to a Tersus/CORS combination, the M8T matched pair solution will in general be superior for short baselines because of more matched measurements.

Matched pair of receivers with long baseline:  The data in this experiment doesn’t cover this case but as the baseline increases the dual frequency receiver pair should have a greater advantage because of the additional information that can be derived from the dual frequency measurements.

From a cost trade-off perspective, this suggests that the ideal way to combine these receivers might be to build the base with both an M8T single frequency receiver and a Tersus dual frequency receiver, both sharing a single antenna.  The rover would then be a second M8T receiver.  This would give the advantage of the dual frequency receiver for locating the absolute position of the base using long baseline solutions to distant reference stations or even PPP solutions while taking advantage of the matched pair of lower cost receivers for the moving rover piece of the solution.


RTKLIB with a Tersus BX306 dual frequency receiver

[Update 6/27/17:  There is a significant error in the data in this post.  I used the RINEX files from the CORS website for the base station data for the post-processing solutions described below. These contain only GPS data.  However, the real-time stream I used from UNAVCO for the same receiver contains GLONASS observations as well.  I did not realize this when I compared the Tersus real-time solution to the RTKLIB post-processed solution and concluded that the Tersus solution was better than the RTKLIB solution.  Once I re-processed the RTKLIB solution with the GLONASS measurements, the two solutions were much more similar.  See the following post for more details]

Last post I finished up by comparing some raw observation data collected from a moving rover with both Tersus and Swift receivers.  Before analyzing that data I will start with some static data collected simultaneously with the Tersus receiver and a u-blox M8T, both connected to a dual frequency antenna through a signal splitter.

I’d like to compare the RTKLIB solution for the Tersus data with the solution from the internal Tersus RTK engine as well as compare solutions for the Tersus data to solutions with the u-blox M8T data.  Since Tersus does not provide any post-processing tools I needed to run the experiment in real-time.  For the base data I used the closest available CORS station with real-time data access.  This was a GPS only station located 17 km from my home.  This makes it a fairly challenging exercise both because of the long distance between receivers and the small number of base station measurements.

The Tersus receiver does not offer a configuration setting for static or kinematic mode, it always assumes the receiver may be moving.  To put both receivers on equal footing, I also set up RTKLIB for a kinematic solution with continuous ambiguity resolution .  Therefore, although the rover was not actually moving, neither the internal Tersus RTK engine or RTKLIB knew this, and both treated it as if it were a moving rover.  To make the experiment more interesting, I intentionally obstructed the antenna view fairly severely every few minutes to simulate a rover passing under a heavy tree canopy or other obstruction.   I did this because I wanted to compare how well the RTKLIB and internal solutions recovered from losing a fix.

In addition, the location of the “rover” antenna was not ideal.  It was located on one edge of a low angle sloping roof.  This meant partial blockage from the roof as well as a few nearby trees and probable multipath from a few metal vents on the roof.  As always, I choose non-ideal conditions to add stress to the solution and make it more representative of real-world conditions.

Here are the raw observations, M8T above and Tersus below (yellow are single freq measurements, green are dual freq)


I show only the GPS observations since they are the only ones with matching observations in the base station data and hence the only ones that double differences can be calculated for.  At the beginning of the data set, the M8T has six GPS observations (all L1) and the Tersus has twelve (L1+L2).  The points where I obstructed the antenna are obvious in both data sets from the cycle slips.  The additional cycle slips seen in the Tersus data occur on the L2 observations for the most part.

First let’s look at the M8T RTKLIB solution.  With only six double difference observations and a 17 km baseline, the opportunity to resolve the ambiguities is just too limited and nearly the entire solution is float rather than fix.  In some similar data sets the solution may be better than this, but in general I find when using only the L1 GPS satellites there is very little margin and the results can vary tremendously from run to run.



Here are the solutions for the Tersus receiver.  Yellow/Green is the internal solution and Olive/Blue is the RTKLIB solution.  They are both significantly better than the M8T solution with fixes acquired reasonably quickly then broken by the antenna obstructions, followed by a re-acquire.



In this case having 12 double-differenceable observations to work with instead of 6 makes a huge difference, and for this particular comparison, there doesn’t seem any point in spending more time examining the M8T solution.

What is more interesting is the differences between the internal solution and the RTKLIB solution.   The Tersus advertises a 60 second time to first fix and most of the time, it achieved that easily even with the long baseline, significantly outperforming the RTKLIB solution which often took two minutes or more to recover. In the worst case however, (around 1:00 in the above plot), RTKLIB did significantly better than the internal solution acquiring a fix in just over two minutes while the internal solution required over eight.  I think this must be a glitch in the Tersus firmware.  For this excercise I used the new firmware just released last week but it does not appear to be perfect yet.  They acknowledge that they are still maturing the firmware and it should improve with time.  I don’t know what they are doing differently in their internal solution from the RTKLIB solution that gives them significantly faster re-acquire times, but if I had to guess, I would suspect that they are taking better advantage of the dual frequency measurements as I discussed in my previous post.

Here is a zoom in of the previous plot showing some of the higher frequency smaller amplitude differences.  I don’t believe the small DC offsets are significant, they most likely come from me not paying close attention to the various offsets in the setup.  Notice that the Tersus solution often loses fix momentarily where the RTKLIB solution stays fixed.  This may just be a more conservative approach in the Tersus solution to declaring a fix.  The momentary float values do not appear to add much error to the solution.


The above example was done with a fairly distant reference station to meet our requirement for real-time base station data. What if we don’t need real-time?  There are many more CORS stations available for post-processing than real-time so that often means being able to use a closer base station, maybe one that is more likely to have GLONASS satellites as well.  In my case, the closest CORS station is only 7 km away and does have GLONASS measurements as well as GPS.  The receivers are not identical so the GLONASS measurements can only be used for the float solution, not for ambiguity resolution, but they should still help some.  Here are the results using that base station.  Yellow/Green is the Tersus RTKLIB solution and Olive/Blue is the M8T RTKLIB solution.


Clearly more satellites and shorter baselines helps.  At this point the Tersus solution is still better than the M8T solution but the difference is not as dramatic.

So to summarize, this one example suggests that given the case of a single local receiver working with a distant reference station, there could be a significant advantage in using a Tersus dual-frequency receiver over a u-blox M8T single frequency receiver and that there is also an advantage in using the internal real-time RTK solution over the RTKLIB solution.  Part of this advantage is simply because the satellite set that the dual frequency receiver uses (L1+L2) better matches what is available from the reference stations and allows for more double difference pairs.

It would be unwise to conclude too much from this one example but hopefully it at least provides a little insight in how the two receivers and the two RTK engines differ.

So this example was a comparison between one dual frequency receiver and one single frequency receiver, both paired with a fairly distant base station.  In the next post I will compare a pair of matched local single frequency receivers to the same dual frequency receiver again paired with a fairly distant base.

A first look at RTKLIB with dual frequency receivers

As I mentioned in my last couple of posts, I have recently been exploring the use of RTKLIB with a couple of different low-cost dual frequency receivers.  Low-cost is a relative term here.  At $600 to $1700 for the receivers, plus the cost of the antenna, these configurations are significantly more expensive than the u-blox based single frequency versions I usually work with.  Still, they are quite a bit less expensive than models from the more traditional manufacturers.

The first receiver I have is a Piksi Multi from Swift Navigation.


It is available from their website for $595 for the receiver board, or $1995 for a complete evaluation kit including two receivers, antennas, and radios.  This receiver relies on the new L2C codes for the second (L2) frequency and so does not support the traditional P2 codes.  L2C is an unencrypted code that is only available on the newer GPS satellites.  Roughly half the GPS satellites are currently broadcasting these codes but this number will increase as newer satellites are launched.  This does mean that the Multi can only make dual frequency measurements on the satellites that have L2C capability.  Also, although the receiver hardware is capable of supporting GLONASS G1/G2, BeiDou B1/B2, Galileo E1/E5b, QZSS L1/L2 and SBAS signals, these constellations are not supported in the current firmware.  This means that the current capability of this receiver is somewhat limited, but it should improve as they release new firmware and more satellites are launched.

The second receiver I have been evaluating is a more expensive option, the Precis-BX306 from Tersus which is available from their website for $1699.

BX306 (2)


This receiver does support the P2 codes on the L2 frequency and therefore is able to receive dual frequency signals from all the GPS satellites.  It also supports Glonass G1/G2 and Beidou B1/B2 in the current hardware and firmware.  Tersus also has similar receivers that are less expensive but also less capable than this one.  The Precis-BX305 fully supports GPS L1/L2 but only has support for GLONASS G1 and Beidou B1/B3.  The Precis-BX316R supports all the same constellations as the BX306 but only provides raw measurements, it has no internal RTK engine.  Both of these models sell for $999.

In the spirit of full disclosure, I should mention that Tersus gave me the BX306 receiver to evaluate and one of my consulting clients gave me permission to use their Piksi Multi receiver for this evaluation.  I appreciate both of them for their generosity.

Before digging into the details of the receivers, it’s worth first discussing what the advantages of a dual frequency receiver are over a single frequency receiver and also to what extent RTKLIB is capable of exploiting these advantages.  All of this is fairly new to me so the following analysis is based on my somewhat limited understanding.  If I get anything wrong, I am hoping one of my more experienced readers will jump in and correct me.

The most obvious advantage of the dual frequency receiver is that it provides more measurements than the single frequency receiver for the same satellite constellation.  However, if this were the only advantage, then the Piksi Multi, with GPS support only, would still be less capable than the u-blox M8T when the additional GLONASS, SBAS, and Galileo measurements are all taken into account.  Dual frequency receivers do also tend to have more high-end circuitry and tend to be paired with more expensive antennas.

The biggest advantage, though, comes from having multiple measurement of the same path through the atmosphere made with different frequencies.  Using linear combinations of these pairs of measurements in different ways we can glean information that is just not available with the single frequency measurements.  Two linear combinations that are particularly useful are the ionosphere-free combination and the wide lane combination.

The ionosphere-free combination takes advantage of the fact that the ionospheric delay is inversely proportional to the square of the frequency.  By taking the difference of the squares of the two phase measurements,  more than 99% of the ionospheric delay error can be eliminated.  The ionosphere-free combination provides the ability to deal with much longer baselines between the two receivers and also makes possible accurate PPP measurements.

The wide lane combination is simply the difference of the phase measurements made at the two frequencies and the advantage of this combination is that the effective wavelength of this measurement is a function of the difference in frequencies between the two measurements.  In the L1/L2 case, the difference in frequencies is 348 Mhz and the wavelength is 86 cms.  Resolving integer cycle ambiguities over an 86 cm cycle is significantly easier than resolving them over the much shorter L1 wavelength of 19 cm, the only option available with the single frequency receivers.  Once the wide lane ambiguities have been resolved, they can be used to assist in resolving the shorter cycle L1 and L2 ambiguities.  This can lead to much faster times to first fix with the dual frequency receivers.

Of course, these additional opportunities are only valuable if the solution algorithm takes advantage of them.  Unfortunately RTKLIB appears to be quite disappointing in this regard.  For the most part, the default configuration of RTKLIB for RTK handles the two frequency measurements independently and takes very little advantage of the linear combinations.  This makes them no more valuable than if they were two measurements from different satellites.  There is an option to enable ionosphere free combinations (pos1-ionoopt =dual-freq) in the config file which uses the ionosphere-free combinations to estimate the phase biases instead of the individual measurements.  The user manual indicates, though, that the ionosphere-free model is not applied for the RTK solution modes and I have found that setting this option when running an RTK solution breaks the ambiguity resolution.  There is also an option in the code for a wide lane ambiguity resolution but this option is not mentioned in the user manual and if set it attempts to call an external function that is not included with the RTKLIB source code.  There may be a little more support for dual frequency in the PPP solution modes.  However, the current RTKLIB version does not make any attempt at ambiguity resolution in the PPP modes.  The 2.4.2 release of RTKLIB does include what the manual describes as a beta version of ambiguity resolution but that has been removed in the 2.4.3 release.  Without ambiguity resolution, my experience with PPP solutions has been that I can get much better solutions using some of the free online PPP services that do use ambiguity resolution than I can get with RTKLIB.  I am hoping someone can prove me wrong and provide a config file that generates an RTK or PPP solution with RTKLIB that takes full advantage of the linear combinations of the dual frequency measurements but from everything I can see, there is not much code to support this capability.

Fortunately, both receivers do include the capability to calculate their own RTK solutions without RTKLIB.    So the goal in the following experiments will be to both compare the two receivers against an M8T single frequency receiver and also to compare their internal solutions to the RTKLIB solutions.  Unfortunately, neither receiver is set up to handle the post-processing of previously collected measurements and so all of the internal RTK solutions need to be done in real-time.  In my last post I described how I configured the receivers to receive real-time base station data over a cell phone link.

So, let’s start by taking a look at some actual measurement data.

Here is a set of measurement observations collected simultaneously from two receivers on a moving car.  The observations on the left are from a u-blox M8T receiver and on the right are from the Tersus receiver.  Satellites with lock to L1 only are indicated in yellow, those locked to L1 and L2 are in green.


At the start of the data set, the M8T is locked to 8 GPS, 7 Glonass, 4 Galileo satellites, and 3 SBAS, for a total of 21 measurements.  The Tersus receiver is locked to 8 GPS L1, 7 GPS L2, 6 Glonass L1 and 5 Glonass L2 for a total of 26 measurements.  The greater number of satellites should give the Tersus an advantage over the M8T even before considering the extra advantages of the L1/L2 combinations or the more expensive electronics and antenna.

Here is a similar set of data.  The M8T receiver is on the left again, this time the Swift is on the right.  Again yellow is a single frequency measurement, green is for measurements at two frequencies.


swift_obs This time there were a few less satellites in the sky.  At the start of the data set the M8T is locked to 7 GPS, 7 Glonass, 2 Galileo, and 3 SBAS for a total of 19 measurements.  The Swift receiver has 6 GPS L1, and 4 GPS L2 for a total of only 10 measurements.  Particularly for RTKLIB which does not take advantage of the extra information in the L1/L2 combinations, it will be difficult to make up for the small number of measurements.

As mentioned before, this should improve as Swift releases firmware to support GLONASS, BeiDou, Galileo, QZSS, and SBAS, and as more GPS satellites are launched with L2C capability.

In my next post I will compare solutions generated with these different measurements, both from RTKLIB and from the internal RTK engines.







New b27 release of demo5 code

I’ve just released a b27  version of the demo5 code that incorporates all the changes in the b27 release of the official code.  I’ve also included some fixes for the Galileo satellites.  The biggest fix I added was for an array overrun that was causing solutions to intermittently report zero status when Galileo satellites were enabled.  Another fix was to correctly decode the range accuracy estimates in the Galileo ephemeris data.  The code can be downloaded from the code download section of the rtkexplorer.com website.   The source code is available in my Github repository.  Please let me know if you find any issues with this code, especially if it was something that was working in the previous code.

One issue I am aware of is the time tag feature which enables simulated real-time runs in RTKNAVI appears to be broken in the new code.  There was an existing incompatibility  between time-tag files that were created in the win32 version of RTKLIB and run in the win64 version or vice-versa.   It looks like an attempt to fix this in the latest release code actually made things worse and now the time-tag files don’t work at all, at least in the win32 version.

By the way, for anyone using the free starter edition of the Embarcadero compiler, be aware that it does not support building win64 executables.  The code will build, but the option to specify win64 is not available, so the compiler will just build the win32 code.  I hadn’t realized this until I tried to build the win64 version recently.

Also, I’ve recently got a hold of two low cost dual frequency receivers, one from Swift Navigation and one from Tersus, so I am collecting and analyzing data with them now.  I should have some results and comparisons to share in my next post soon.

Update to RTKLIB config file recommendations

I’ve just updated my “RTKLIB: Customizing the input configuration file” post from a few months ago with information on all of the new config parameters I have added to the demo5 code up through B26B.  I’ve also added more notes to some of the existing features based on my more recent experiences.