Improving RTKLIB solution: Fix-and-Hold

Integer ambiguity resolution is done by RTKLIB after calculating a float solution to the carrier phase ambiguities to attempt to take advantage of the fact that the carrier phase ambiguities must be integers. Constraining the solution to integers improves both the accuracy and convergence time.

RTKLIB provides three options for the integer ambiguity resolution: instantaneous, continuous, and fix-and-hold. “Instantaneous” is the most conservative and relies on recalculating the phase bias estimates every epoch. “Continuous” is the default option and uses the kalman filter to estimate the phase biases continuously over many epochs. In general, this provides much less noisy estimates of the phase biases and is essential for working with low cost receivers. The downside of the continuous solution is that if bad data is allowed to get into the filter outputs it can remain for multiple epochs and corrupt subsequent solutions, so some care must be taken to avoid that.

Fix-and-Hold” takes the concept of feeding information derived from the current epoch forward to subsequent epochs one step farther. In the “Continuous” method, only the float solution is used to update the phase bias states in the kalman filter. In the “Fix-and-Hold” method, an additional kalman filter update is done using pseudo-measurements derived from the fixed solution. This is only done if the fixed solution is determined to be valid. All of this is explained in greater detail in Appendix E.7(5) of the RTKLIB user manual.

In general, taking advantage of all the information we have this epoch to improve the solution for the following epochs seems to be a good idea, especially given the high levels of noise in the low-cost receivers and antennas. Even more so than in the “Continuous” method, however, we need to be careful about feeding erroneous data into the kalman filter which may take a long time to work its way out.

Testing the “Fix-and-Hold” method on a few data sets shows the results we would expect, the solution usually does improve but can occasionally cause it to have difficulty recovering from a period of bad data where we have corrupted the phase-bias estimates.

To minimize the chance of this happening, we need to do a better job of validating the solution before feeding it forward. Looking at a couple examples of bad data, what I find is that the errors are introduced when solutions are derived from a very small number of valid satellites. The current integer ambiguity validation is based only on the ratio of residuals between the best solution and the second best solution and does not take into account the number of satellites used to find the solutions.

I have introduced two new input parameters, “minfixsats”, and “minholdsats” into the code. These set the number of satellites required to declare a fixed solution as valid, and the number of satellites required to implement the fix-and-hold feature. I have found setting the minimum number of satellites for fix to 4 and fix-and-hold to 5 seems to work quite well for my data, but I have made them input parameters in the config file to allow them to be set to any value.

I won’t include all the code here, but it is available on GitHub at on the demo1 branch

The two key changes are:

For minfix, in resamb_LAMBDA() from:

if ((nb=ddmat(rtk,D))<=0) {
no valid double-difference\n”);


if ((nb=ddmat(rtk,D))<(rtk->opt.minfixsats-1)) { // nb is sat pairs
    errmsg(rtk,”not enough valid double-differences\n”);

and for minhold, in holdamb() from:

if (nv>0) {
    for (i=0;i<nv;i++) R[i+i*nv]=VAR_HOLDAMB;

    /* update states with constraints */
    if ((info=filter(rtk->x,rtk->P,H,v,R,rtk->nx,nv))) {
    errmsg(rtk,”filter error (info=%d)\n”,info);


if (nv>=rtk->opt.minholdsats-1) { // nv=sat pairs, so subtract 1
    for (i=0;i<nv;i++) R[i+i*nv]=VAR_HOLDAMB;

    /* update states with constraints */
    if ((info=filter(rtk->x,rtk->P,H,v,R,rtk->nx,nv))) {
    errmsg(rtk,”filter error (info=%d)\n”,info);

Again, the changes to the position solution are subtle and difficult to see in a plot, but are much more obvious in the Ratio Factor for AR validation. A higher ratio represents greater confidence in the solution. The green is before the changes, the blue is after. The RTKLIB code limits the AR ratio to a maximum of 1000.


As you can see, there is a very significant increase in the AR ratio with the change.  The improvement is coming from switching the ambiguity resolution from continuous to fix-and-hold, not from the code changes which we made to try and reduce the occasional occurence of corrupting the filter states with bad data.

Let’s also look at the metrics described earlier for both this change and the bug fix described in the previous post. On the x-axis, 1-3 are from before the two previous changes, 4 is with the bias sum bug fix and 5 is with fix-and-hold and the min sat thresholds for fix and hold.


From the metric plots you can see that at this point we have maxed out the % fixed solutions and median AR ratio metrics and have got the distance metric down below 0.5 cm so I will stop here and declare success, at least for this data set.

If you’d like to try this code with your data, the code for all the changes I have made so far are available at on the demo1 branch.

If anyone does try this code on their own data sets please let me know how it goes. I’m hoping these changes are fairly universally useful, at least for open skies and low velocities, but the only way to know is to test it on multiple data sets.

Update 4/17/16:  Enabling the “fix-and-hold” feature on other data sets has had mixed success.  I still see “fix-and-hold” locking to bad fixes and corrupting the states.  It looks like the extra checks I added are not sufficient to prevent this.  So, for know,I recommend turning off this feature, or if you do use it, be aware that it can cause problems.  I hope to take another look at this soon.

19 thoughts on “Improving RTKLIB solution: Fix-and-Hold”

  1. Impressive work – congrats!
    Will try out your code with BINR data collected with a NV08C-CSM chip.
    I’m the developer of the RasPiGNSS low-cost GNSS receiver for the Raspberry Pi – glad to provide you with hardware for testing, if you find time to.



    1. Hi Franz. Thanks, I’d be interested to hear how things go. I’d also love to take a look at your hardware. Emlid was nice enough to make a similar offer and I just received their hardware yesterday. It would be fun to run some trials to compare the M8N to the M8T to the NV08C-CSM chips. I’ll contact you by email.


  2. Hello. Interesting subject. I’ve had much trouble with RTKLIB AR fix and hold, Particularly in less than ideal environments. I could get fixes with mm-cm resolutions, but I could not get consistent believable values. I could get the correct location – if I knew which fix to use.

    I downloaded the DEMO1 version and tested it. To my surprise, the jumps in fixed locations reduced to cm/mm levels as I would hope to be the case. I get longer consistent fixes.

    My environment is an industrial area with two story buildings each side of a parking lot with a string of perhaps 50 – 100 foot tall dense pine trees down the center of the parking lot obscuring much of the sky.

    My data is post processed from two rover setups from Emlid Reach which allows me to set the signal mask just below the maximum strength. RTKLIB is used to screen and reject obvious satellites with bad slips. Fortunately, this left me with enough good satellites to obtain good fixes as Emlid Reach uses the Ublox GPS receiver with GPS/Glonass dual capability.

    (I also was curious about jump from fix to float when a new satellite was added.)
    I know one or two tests does not prove anything conclusively, but it has certainly encouraged me to keep pursuing this approach. I’ll be looking for any new insights.



  3. Thank you for your sharing about RTKLIB.
    As a lost receiver, ublox M8N or M8L.
    If i bind it on a bike(Not a car), driving about the crowed city.
    How can i get the perfect result with RTKLIB.
    any help will be thankful.


    1. Hi Layne. I don’t think you will get the results you are looking for with RTKLIB and low-cost single frequency receivers in a city environment. The combination of obstructed satellite views and multipath will be too difficult given the current capabilities of the technology. It is much more suitable for applications having open skies.


      1. Thank you for your reply, ulbox M8L with embedded 3-axis accelerometer and gyroscope sensor.
        Have you ever tried combining RTKLIB with IMU? The result should be encouraging.


  4. Hi,
    Thanks for this blog – I’ve read it with interest as a new RTKLIB user. I have been a little surprised at the lack of “beginner” level info available, so it has been very useful to read your insights. I have built your modified version, and run my test data through each change. I noticed some improvements but not to extent that you did. What really did increase my fix percentage was changing to the “combined” filter (forwards & backwards) – I got a jump from the mid 50’s to the mid 90’s. Do you have any thoughts on this? Also interested to hear any insights on the various options for satellite ephemera – is it worth sourcing and using the precise ephemeris files? One thing that I noticed was that running the locally built console post processing exe was over 7 times (!) quicker than running the RTKPOST GUI on the same data. I have no idea why..
    BTW I am also running a pair of Reach modules, so it will be interesting to see your results if they do provide you with a set. My interest is very much post-process only, logging sonar data from a boat for mapping.


    1. Hi Matt. I hope to switch to real-time processing at some point but if you are only interested in post-processing I can’t think of any good reason not to use the combined filter, assuming the additional computation time is not an issue. I have seen significant improvements using it as well.

      I’ve not noticed much improvement when using the precise ephemeris files with my data. I suspect for short baselines, the ephemeris errors are cancelled out by the differencing in the solution process, and so are not significant. For larger separations between the receivers they might help more.

      Sorry to hear my changes didn’t help much with your data. There are many possible reasons why you might not get good results, my changes probably only address a small percentage of those. If you would be willing to share some of your data with me, I’d be happy to take a look, see if I can make any suggestions. I’m trying to build up a larger collection of data sets for evaluating my changes … it would be great to have some data collected over water. I understand reflections from the water can be an issue, but don’t have any personal experience with that.


      1. Hi,
        Happy to share any of my data, but at the moment all I have is some walking on the beach. I have just built 2 x waterproof boxes to mount fore and aft on my kayak and hope to gather some proper data next week. Initially I plan to use your (very nifty) trick of diffing two solutions 1. as an accuracy test and 2. (if 1 works out) to use the difference to calculate a heading (basically the functionality of a GPS compass). I then plan to use local (well – about 20km away) CORS data to improve the absolute solution. Your changes did improve things and I think they are well worth including – I just didn’t see the step change in fix % that you did, but that must just be due to my data. The problem for me is that there is such a huge parameter space in RTKLIB that it is hard to know where to begin..
        One thing I have been wondering about is the possibility of creating a virtual reference station from historical RINEX files. I know some services do this on the fly, but I haven’t seen a post processing solution. I am surrounded by freely available reference data but none closer than around 20 km. Could it be as simple as a linear interp of common satellite data based on distance? It seems to me that it should be possible but I have no idea how to start going about it..


        1. Hi Matt. My guess is that linear interpolation of the raw data is not going to be enough to create a virtual reference station. Maybe you could create virtual raw data for all 3 stations (2 real, 1 virtual) from just the ephemeris data and station locations, then adjust the data for the virtual station based on a combination of the errors between the virtual data and real data for the two actual stations? Not sure that’s going to work either, but may get you closer? I’ll contact you offline about getting some of your data.


  5. Hi, I’m trying your demo1. Currently I’m using the windows version. Are minfixsats and minholdsats tunable parameters? If yes where I can find them on the rtkpost interface?


  6. Hi
    Thanks for a very interesting blog about the rtklib. It has helped me a lot to start to understand some of the items that is not fully described in the manual pages like “integer ambiguity res.”

    The last few days I have been trying to make my own RTCM3 base station. So I need a good fix on my location. I have been logging raw data to a ubx file for several hours and than used the rtkpost to do PPP static analyse of the data using igu sp3 file for the ephemerid data. The strange thing is that using rtkpost 2.4.2 p11 i get good lock (Q=6) and the plots looks quite reasonably, but than I have been trying the 2.4.3 version using the same data, but it is impossible to get Q=6 I only get Q=5. I checked and double checked the settings and they are the same as I use for 2.4.2 which works.

    Can you think of any thing that can cause this problem, I should also mentioned that I have tried your version of 2.4.3 without any luck in PPP mode.

    Again keep up the good work, I am very pleased to have found your blog.


    1. Hi Assar. I have not done any work with the PPP mode in RTKLIB so I’m afraid I can’t help. I don’t believe any of my changes should affect PPP for better or for worse.

      Anybody else have any idea what Asser may be running into?


  7. Hello.
    I’m really happy that someone takes a new look at RTKLIB. Your findings until now are very encouraging. After the Easter holiday I will make some tests with your modified RTKLIB.

    One point which would give the solutions of RTKLIB a big leap would be to address the inter channel bias of Glonass. Receiver modules like NVS08C seems to be fabric calibrated for interchannel bias but it is necessary to manage and additional bias offset to use it with e.g. Ntrip data because the calibration of inter channel bias seems to be different from manufacture to manufacture so that a constant inter channel bias offset remains that has to be eliminated. NVS for example stated that here calibration is very similar to Novatel and Leica receivers but differs from Trimble. A solution would be fantastic and would make a low cost single frequency RTK much more stable and usable.

    Please keep on with your cool work.


    1. Hi Martin. I’m very interested to hear how your testing goes! Hopefully you can share your results.

      I agree with your comment that inter channel bias calibration for Glonass would be a big improvement for RTKLIB since it would allow the Glonass sats to be used for fixed solutions. It’s a challenging problem though … I’m not sure I’m the right guy to do it. Another big improvement, maybe even more important, at least for the data sets I am working with, would be some sort of correction for cycle slips. I’ve started to look into this one, but again, it’s quite a bit tougher than the changes I have made so far, so I’m not expecting anything in the immediate future.


  8. Hi! I am one of the guys behind Reach RTK. Very impressive work here, we are running tests on our datasets now. Would gladly provide you with hardware for your tests, also happy to discuss RTKLIB. You can contact me over email in this comment.


    1. Hi Igor. Thanks for your kind words! Looks like you guys are doing some great stuff for the future of low cost RTK!

      It would be great to be able to include some of your hardware in my experiments … I’ll contact you offline by email.


    2. HI Igor

      I am using two UBLOX RECEIVERS NEO M8T and trying to use RTKLIB. i want some guidance regarding rtknavi>




Leave a Reply

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

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

Google photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s

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