RTKLIB: Static-start feature

The static-start feature is something I added to the demo4 code a while ago but never got around to explaining, so I will do it now.

As I’ve mentioned before, I always like to initially leave the rover stationary after first turning on the receiver long enough to get a first fix-and-hold before allowing it to move. This significantly reduces the chances of getting an initial false fix. However, we could benefit even more from doing this if we could tell RTKLIB that the rover was stationary during this time. This is because we would remove the uncertainty of rover motion from the solution and the kalman filter would converge faster. By doing this we should be able to reduce the time to first fix.

RTKLIB has a solution mode for a moving rover (kinematic) and one for a stationary rover (static) but currently no way to switch between the two. What the new static-start mode I have added does is to start the solution in static mode and then switch to kinematic mode after the solution first qualifies for a fix-and-hold. It does not require fix-and-hold to be enabled, it will still make the switch to kinematic mode when that qualification occurs, even when fix-and-hold is not enabled.

Below is the only functional code modification and it is in the relpos() function in rtkpos.c. The new line of code is in red. There are also a handful of bookkeeping changes to handle the new option in the input configuration file that I won’t include here but can be seen in the demo4 code.

/* hold integer ambiguity if meet minfix count */
if (++rtk->nfix>=rtk->opt.minfix) {
    if (rtk->opt.modear==ARMODE_FIXHOLD)
    /* switch to kinematic after qualify for hold if in static-start mode */
    if (rtk->opt.mode==PMODE_STATIC_START)

This feature is enabled by changing “pos1-posmode” in the input configuration file from “kinematic” to “static-start”.

So, let’s do a little testing to see how it does. I used my latest demo4 data set and ran three solutions. The initial acquire for all three are plotted below.


The first two are both in kinematic mode. For the first one I have used the default value of 100 for “stats-eratio1”, the ratio of variances between pseudorange and carrier-phase measurements. In the second plot, I have used my preferred value of 300. This is unrelated to the static-start modification but is relevant to the acquire time so I have brought it up again. As you can see changing this value reduced the time to first fix from roughly eight minutes to a little less than five.

In the third plot, I changed “pos1-posmode” from “kinematic” to “static-start” to enable the static start feature and again used 300 for “stats-eratio1”. This reduced the time to first fix from a little less than five minutes to about two and a half minutes, nearly a factor of two. The actual times to first fix will vary fairly significantly depending on signal quality, number of satellites and quality of the sky view but the trends shown here should hold even if the times change.

To understand this change a little better it would be good to understand what is the difference between “static” mode and “kinematic” mode in RTKLIB, so let’s discuss that next.

In my earlier post describing the RTKLIB receiver dynamics feature, I explained how the kalman filter makes two estimates each sample, where the first estimate is a prediction of how far the rover has moved since the last sample. If receiver dynamics is enabled, this estimate is made using the estimated velocity and acceleration of the rover, if not, RTKLIB simply using the pseudorange measurement for the current sample along with its large uncertainty.

In either case, the uncertainty (or variance) of the position states are increased after this update because of the unknowns of what happened during that time interval. The second kalman filter estimate (the measurement update) will then reduce the variances again using the additional information from the carrier-phase measurements. So for each sample, the uncertainties of the position states will be increased by the prediction estimate, and then decreased by a larger amount with the measurement update, zigzagging towards zero The smaller the variances, assuming they are accurate, the more likely it is that the integer ambiguity resolution will resolve a fix.

If however, we know that the rover did not move during that time, there is no need for the kalman filter to increase the variances with passing time, since the rover will be exactly where it was one sample earlier., and the variances can converge towards zero more quickly. That is exactly what RTKLIB does. If static mode is enabled, then RTKLIB skips the prediction update step entirely and just assumes the rover is where it was last sample and that the uncertainty in that position has not changed. Here is a plot of the variances from the last two solutions above comparing kinematic to static-start.  I show only the z-axis because it tends to be the limiting factor to finding a fix,at least when the rover is stationary.  This is because the geometric diversity of the satellites is always most limited in the up-down direction, since all the satellites below the antenna are obscured by the earth.


The sudden drop in variance in both traces occurs when the integer ambiguities are first resolved and the solution switches from float to fix. The step up in the static-start trace occurs when fix-and-hold first occurs and the solution switches from static to kinematic. At this point, the uncertainties from a moving rover are introduced and the variance jumps accordingly. The reason the line is smooth for the kinematic case and not zigzagging as I described above is because the data I am plotting is from the output position file and includes only one variance value for each sample. This is the value at the end of the sample, after the measurement update.

So what happens if the rover is not left stationary long enough and there is no fix before the rover starts moving? If static start is not enabled, a fix will very likely be found while the rover is moving. The chance of this fix being wrong can be fairly high however, which leads to an incorrect solution that RTKLIB reports with high confidence of being correct (i.e. fixed), although it is not.

If static-start is enabled and no fix is found before the rover starts moving, then the chance of finding any fix, correct or incorrect, while the rover is moving is almost zero.  This is because the model the kalman filter is using so poorly matches the actual rover. If it did find a fix, it would not be maintained for more than a very short time, since again, the kalman filter is incorrectly assuming that the rover is not moving.

I would argue this is a win-win situation. Not only have we reduced the time to first fix, but we have also reduced the chance of RTKLIB reporting data as being valid when it is not. Any time RTKLIB reports a bad solution as good, it can significantly undermine confidence in the entire solution.


18 thoughts on “RTKLIB: Static-start feature”

  1. The static-start is a great feature, thanks a lot for it! I am post-processing data and I can see it is working nicely – testing a static rover with the static/static-start settings and one can clearly see that the fixed solution in static-start mode has more variance than the static-only solution since it switched to kinematic mode after achieving first fix.


  2. Hey,

    just a short question: I cannot find RTKPOST in your RTKLIB-demo4_b12 folder…. Would you please also upload the GUI. Without GUI’s I am a little bit lost as I do not have the means to build the code….



    1. Hi Markus. I’ve only recently been able to compile the GUIs after I got the Embarcadero compiler and have never used RTKPOST before. I compiled the code and tried it today and found the GUIs need to be updated to give access to my new options. I went ahead and added new options to existing commands (gloarmode=fix-and-hold,posmode=static-start) since that was fairly easy. I did not add the new input parameters that I have added to the code (minfixsats,minholdsats, arthres1, arfilter) since that requires re-configuring the GUI layouts. I ran RTKPOST on the most recent data with just the new options set (new input parameters all at default) and it ran reasonably well. Differences between the RTKPOST runs and my previous RNX2RTKP runs were less than 4 cm with some loss in fix ratio. I’ve uploaded the RTKPOST executable to the demo4_b12 folder and rtkpost config files to the data folder if you want to run it but if you want all my new options you will still need to use RNX2RTKP.

      I also noticed some of the raw data files were missing from the niwot2_car folder so I added them as well.


      1. Thanks for your fast reply. I just wanted to test the new static start feature and the glonass fix and hold feature…. I also compared my results of the demo2 rtkpost (with kinematic=posmode) and with demo4 rtkpost(with posmode=static start). Demo4 rtkpost works better and very good. (Sry I kind of like to work with GUIS I did not realize that I also could use the CUI RNx2RTKP)

        So in the new post i just cannnot use these features: (minfixsats,minholdsats, arthres1, arfilter) – thats ok at first.

        However I also realized, that the when turing on the GLNOASS fix and hold – I got the same result when I turned it off. I guess that is because I am using a NEO-M8P ublox chip.

        I hope I can solve that issue. As you wrote in one of your posts M8N chips cannot solve the GLNOSS AR whereas M8T can. I just would like to know how do you know that? I also would like to find out if M8P receiver can be used to solve the AR.


        PS:: Thanks for all your work here! It is amazing how RTKLIB can still be improved even though its a lot of work.


        1. Hi Markus. I’m glad to hear the demo4 code is working well for you. In theory, GLONASS AR should work anytime you are using two identical receivers since the inter-channel biases should cancel. I do not know exactly why it doesn’t work on the M8N receivers but found that out just through trial and error. Tomoji Takasu also has mentioned seeing the same thing in at least one of his documents. I would expect AR to work with the M8P since that chip officially supports raw data like the M8T and your experience seems to support that since you are getting good results without my fix-and-hold enhancements.


  3. Hello!

    I use reach from emild. i did see in a post that you are in conntact with igor. is it possible to insert your code in reach? or does igor do it?

    i have problems to get fix solutions with reach over a longer time. i want use it for argicultural.
    could you give me a settings tip? or how to integrate your code in reach?


    1. Hello Andreas,

      In a reply to me on the Reach forum, Igor said Emlid is testing and adding code that they feel improves Reach. One item is problem with lock problem on new satellite. I’ve also noted that Emlid has recently modified some of the dynamic entries in the .conf files.

      See GitHub ReachView folder for details.

      Richard J0hnson


    2. Hi Andreas. I have heard from Igor that Emlid has put some of my changes into their code and are evaluating others but I don’t know the details. If you just wanted to see if my changes make any difference, you could log the data to a file then post-process it with my code. It wont help you with real-time use, but it could tell you if these changes would help with your problems.

      I have included input configuration files with all my data sets, you can look at those for tips on at least what works well for my data, it’s quite possible they will help with your data as well.


  4. Hi again,

    Decided to use Kinematic mode instead of static mode. Now “Reverse” mode is mostly fixed and “Combined” mode is mostly float. Not what I would expect. But still a good usable improvement…


    1. Hi Richard. Thanks for the feedback. There are lots of possible configurations for RTKLIB of which I am only able to test my changes on a few, so I appreciate you letting me know when you find one that doesn’t work.

      Using static-start mode in backward or combined mode does require the rover to be stationary for a period of time at the end of the data as well as the beginning of the data to allow the acquire to happen when running the data backwards. That’s probably a good practice in any case when you are using the combined or backwards modes to reduce the chance of a false fix. I just ran the demo4 data set in backwards and combined mode with fix-and-hold enabled for both armode and gloarmode. Both gave good, mostly fixed solutions. I also ran another data set for which the rover was not stationary at the end, and as expected, the acquire never happened in either backward or when running backward in the combined mode, and so the results were very poor.

      If you’re following these guidelines and still having trouble, feel free to send me the data and the config file you are using and I’ll be happy to take a look.


  5. Hello again.

    I’m getting good fixes quickly with static-start Demo4 in RTKPOST processing.
    I use satellite visibility plots to determine best satellites to use. Also, I try to screen satellites in real time by tight control of SNR mask. Getting close to 100 percent static fixes. Looks good so far.

    One thing I noticed is that reverse processing seems to be around 100 percent float. Doesn’t affect me much as forward processing and combined processing will take care of my needs. Maybe the code only works for now in the forward mode?

    Thanks again.


  6. Hello
    great job, compliments
    I use the demo version 4 on two uBlox m8n with excellent results.
    I am a surveyor and also use two NV08C-CSM.
    I tried the demo 4 and also works with these receivers. Also use even the VRS of the Campania Region (Italy) with excellent results. By day, the nearest station is 11 km, the evening is at 38 Km.
    day of the fix I get between 3 and 5 minutes in the evening between 5 and 10 minutes.
    Tomorrow I go for a cadastral survey in the country, hopefully good.
    Thank you for so much work.
    See you soon
    Saverio Siciliano


  7. Hi
    I recently start working with RTKLIB and your blog has been really useful, first of all tank you for your hard work.
    I am working with a NavSpark NS-RAW and tanks to your blog I got a floating RTK solution in a easy configuration with a base an a rover receiver.
    I would like to increment that to a fix solution, I found a first answer in your post about the Cycle Slips and now I reduced them but I cannot get a fix because I am obtaining a Large Residual error.

    I know it is not exactly the place to ask but can you suggest me how to remove or decrease that error or give me some suggestion to better understand his nature?


    1. Hi Alessandro. My suggestion would be to start simple and work up. You can download one of my data sets and try that first to see if your problem is in your data or your RTKLIB setup. If the problem is with your data, then start with stationary receivers with open skies and ground planes on your antennas, and make sure RTKLIB is getting the base position (normally through the Rinex header). Start with post-processing instead of real-time. If you are still having trouble, enable the trace output and look at the trace file, there are often clues there to what is going wrong. If you haven’t already done so, click on the “Getting Started” category on my blog and read those posts starting from the end of the list and working up.


  8. Hi,
    I’m using the demo 4 code with rtkrcv on a raspberry Pi with an M8N and as a base a VRS and everything is running much smoother with your modifications. I still have to do a bit more testing. If you wish I can share some data with you.


Leave a Reply

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

WordPress.com Logo

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

Google+ photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s

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