PPK vs RTK: A look at RTKLIB for post-processing solutions

The “RTK” in RTKLIB is an abbreviation for “Real-time Kinematics”, but RTKLIB is probably used at least as often for “PPK” or “Post-Processed Kinematics” as it is for real-time work.  In applications like precision agriculture, where the solution is part of a real-time feedback loop, RTK is obviously a requirement, but in many other applications there is no need for a real-time solution.  For example, drones are often used for collecting photographic or other sensor data but only need precision positions after the fact to process the data.  PPK is simpler than RTK because there is no need for a real-time data link between GPS receivers and so is often preferable if there is a choice.  The downside of course is that if there is something wrong with the collected data, you may not find out until it’s too late.

For the most part, RTKLIB solutions are identical regardless if they are run on real-time data (RTK) or run on previously collected data (PPK).  The most significant exception to this rule is what RTKLIB calls the “Filter Type”.  This is selected in the configuration and can be set to forward, backward, or combined.  Forward is the default and this is the only mode that can be used in real-time solutions.  In forward mode, the observation data is processed through the kalman filter in the forward direction, starting with the beginning of the data and continuing through to the end.  Backward mode is the opposite,  data is run through the filter starting with the end of the data and continuing to the beginning.  In Combined mode, the filter is run both ways and the two results are combined into a single solution.   This mode is set using the “Filter Type” box in the Options menu if using one of the GUI apps, or with the “pos1-solytpe” input parameter in the configuration file if using a CUI app.

There are two advantages to a combined solution over a forward solution.  First of all, it gives two chances to find a fix for each data point.  Let’s say there is an anomaly in the middle of the data set that causes the solution to switch from fix to float and not come back to fix for some period of time.   It may cause both the forward and backward solutions to lose fix but they will lose fix on opposite sides of the anomaly.  By combining the two solutions we are likely to get a fix for everywhere except right at the anomaly.  Another case where it often helps is in recovering the beginning of a data set.  Let’s say the first fix didn’t occur until five minutes into the data set.  With a forward solution, you would need to guarantee that nothing important happened during that five minutes, but with a combined solution, the backward pass will normally provide a fix all the way to the very beginning of the data set so there is no lost data.

The second advantage of the combined solution is that it provides an extra level of validation of the results.  To understand how this happens, it’s important to understand how RTKLIB combines the forward and reverse solutions.  For each solution position point there are three possibilities; both passes are float, one is float and one is fix, or both are fixed.  If both passes generate a float position, then the combined result will be a float with a value equal to the average of the two positions.  If one is float, and the other is fix, the float is thrown away and the fix is used.  In the case where both are fixed, then RTKLIB will attempt to validate the result by comparing the two values.  If they differ by less than four sigma, then the result will be a fix, otherwise it will be downgraded to a float.  Either way, the value will be the average of the two positions.  This degrading the solution type when the answers from opposite directions differ provides an increased confidence in the solution, at least for points for which we got two fixed values.

I will show a couple examples of the differences between forward and combined modes.  The first example is a more typical case and demonstrates how combined mode will normally give you a higher fix percentage while at the same time increasing confidence in the solution.

The plots below were taken from an M8N receiver on a sailboat using a nearby CORS station as base.  With ambiguity resolution mode set to fix-and-hold, I was able to get a solution with nearly 100% fix except for the initial convergence, but I would prefer to use continuous ambiguity resolution because of the higher confidence of the solution.  In the position plots below, the top was run in forward mode, the middle in backwards mode, and the bottom in combined mode, all in continuous ambiguity resolution mode.


As you can see the forwards and backwards mode solutions are not bad but both have gaps of float in the middle as well as floats during the initial acquisition.  The combined solution though has almost 100% fix rate and in addition includes the additional confidence knowing that every point found the same solution when running the data in opposite directions.

This second example comes from a data set posted on the Emlid Reach forum with a question on why the combined solution was worse than the forward solution.  In the plots below, the top solution is forward, the middle is backward, and the bottom is combined.


This data was GPS and SBAS only, so had a fairly low number of satellites, also included a mix of poor observations and the solution was run with full tracking gain (i.e fix-and-hold with the default gain).  Both forward and backward runs found fixed (green) solutions and tracked them all the way through the data set.  However, at least one of them was most likely a false fix, causing the fix to be downgraded to float (yellow) for most of the combined solution as can be seen be seen in the bottom plot.

To confirm this, the plot below shows the difference between the forward and backward solutions.  As you can see, the two differ by a fairly substantial amount and it is not possible from this data to know which one is correct.


In this case, turning off fix-and-hold and running ambiguity resolution in continuous mode sheds some light on what may be going on.  The plots below are again forward, backward, and combined.  This time the forward solution loses fix early on and never recovers it, whereas the backwards solution maintains a fix through the whole data set and is probably correct since without fix-and-hold enabled, it is very unlikely to stay locked that long to an incorrect solution.  The backward solution is also consistent with the beginning of the forward solution, since the combined solution remains fixed in the early part of the data set where both forward and backward solutions are fixed.


Again, this can be confirmed by looking at the difference between the forward and backward solutions.  In this case they agree everywhere that both are fixed.


As this example demonstrates, if post-processing is an option, it often makes sense to run in combined mode with continuous ambiguity resolution instead of forward mode with fix-and-hold enabled.  The additional pass will increase the chances of getting a fixed solution without the risk of locking onto a false fix that fix-and-hold can cause.  Even if you find you can not disable fix-and-hold completely, it may allow you to reduce the tracking gain (pos2-varholdamb)

So one last question is why are there still some float values in the middle of the combined solution? We would expect that since the backwards solution is fixed and the forward solution is float, that the combined solution should just become the backwards solution and all but the very end should be fixed.

The answer to this question turns out to be the way the reverse pass of the kalman filter is initialized.  I have chosen in the demo5 code to not reset the filter between forward and reverse passes if continuous ambiguity resolution is selected.  If fix-and-hold is selected then the demo5 code does re-initialize the kalman filter between passes.  This is different from the release code which always resets the filter between passes.

In this case, the results would have been slightly better if the filter were re-initialized but most of the time I find that allowing the filter to stay converged avoids a large gap in the backwards solution during the active part of the data set where the filter is reconverging. With fix-and-hold enabled I have found the chance of staying locked to an incorrect fix is too high and so it is better to reset the filter.  This is a recent change and hasn’t yet made it into the released version of demo5 but I should get it out soon.  The current version of the demo5 code (b28a) does not reset the filter for either case.

Modifying the if statement in the existing code in postpos.c to match the line below will give you the newest behavior.  Removing the if statement altogether will cause the filter to always be reset and will match the release code.


The other factor to consider when deciding whether to run the filter type in forward or combined mode is that combined mode will take nearly twice as long to run since it is processing each data point twice.  Most of the time this shouldn’t be an issue since it is not being run in real-time.

So to summarize, my recommendation would be to use combined mode if you do not need a real-time solution as the only real cost is a small amount of additional computation time and it will give you both higher fix percentages and more confidence in those fixes.


28 thoughts on “PPK vs RTK: A look at RTKLIB for post-processing solutions”

  1. Hi, can I ask a question, how to select armode Before I run the PPK code? for example, when should I use fix-and-hold and when continuos?


    1. Fix-and-hold will generally give better fix rates but can be a little more susceptible to false fixes. I usually use fix-and-hold for moving rovers but sometimes switch to continuous AR for static rovers where false fixes are more likely due to higher multipath errors.


    1. Hi Nguyen. Yes, if you see that a particular satellite has poor signal quality in RTKPLOT, you can exclude it from the RTKPOST or RNX2RTKP solution. List the satellites you would like to exclude in the “Excluded Satellites” option box on the Setting1 tab in the options menu.


      1. May I ask, how is the satellite import method excluded? G16, G28, ….. or G16 G28 or G16 + G28. Thanks very much


  2. I use Rtklib to process PPK data for phantom 4 RTK (drone mapping). When I select ‘combine’ all ‘float’ values are converted to ‘fix’, although floats are 25% before. I would like to ask when selecting ‘combine’, is the result reliable? Thanks in advance !


    1. Hi Duonganhtoan. “Combined” mode runs the solution forwards and backwards over the data and combines the two results, so you will usually get a higher fix rate this way, especially for the beginning of the data set where the forward-only solution is still converging. Combined mode also compares the forward solution to the backward solution for each point where both are fixed and if they differ by more than expected, the result will be downgraded to float. This helps eliminate false fixes and will make the result more reliable in addition to usually having a higher fix rate.


    1. Hi Nguyen. In general, post-processed solutions should be better than real-time solutions because there is more information available. However, there will always be occasional exceptions in particular cases where random variation causes the same data post-processed to be worse than the real-time solution.


  3. Hi,

    I’ve been comparing the results of RTKNAVI and RTKPOST (both with forward and combined filters) with the m8t_niwot_0606 data and configuration you uploaded but with the original version of RTKLIB and not the demo5, at least for now. I obtained the following results:
    -RTKPOST with forward filter -> FIX:7.1% FLOAT:92.9% SINGLE 0.0%
    -RTKPOST with combined filter -> FIX:13.9% FLOAT:86.1% SINGLE 0.0%
    -RTKNAVI (forward filter) -> FIX:6.9% FLOAT:19.8% SINGLE 73.3%

    The RTKPOST results make sense according to what you explained in this post; the RTKNAVI, on the other hand, seems to be much worse. Moreover, the RTKNAVI output shows quite a lot of false floats 50m far from the road.

    My questions are:
    -Why is the RTKNAVI solution so worse in terms of ambiguity resolution?
    -Why could these false floats occur?

    Thanks in advanced,


    1. Hi Paul. I have found that there are several issues when trying to post-process data with RTKNAVI that don’t occur when you are using it for a real-time solution. I would recommend sticking to RTKPOST for post-processing. If you do want to compare results from the two apps, I would run real-time with RTKNAVI and then compare to post-processed results with RTKPOST. I would expect these two cases to be quite similar. I also suggest that you will get better results with the demo5 code than you will with the original version of RTKLIB.


  4. Hi,

    I am doing post-processing on my GPS data. I am wondering if you can tell me how to input ZTD and TEC for Troposphere and Ionosphere corrections. Are there any template files of input ZTD and TEC?

    Thanks in advance,



    1. Hi Nguyen. Troposphere and ionosphere corrections can be fed into RTKLIB by setting the “Ionosphere Correction” and “Troposphere Correction” options and pointing to the files in the Files menu. You can find a more complete explanation in the RTKLIB users manual. In general, this will help with PPP solutions much more than it will with RTK solutions.


      1. Hi! Can you send me the link to some more precise explanation of feding ZTD to RTKLib throught external file? As I see, this option is not available in 2.4.2 and for 2.4.3 b30 (option: Input ZTD) there is no manual yet since it is beta version?
        Nguyen, did you manage to solve your problem?
        Thank you.


  5. I wasn’t quite sure where to post this comment so I figured I would just post it here. Anyway, been using your guidance for to learn how to use rtklib and I will tell you without it I would not have gotten to the point of asking this question. Anyway, now that it looks like I can get a solution using rtknavi (real time) how to send the corrected info back to rover vehicle (I am using an autonomous rover) so it knows exactly where it is. I know I can send the solution file data over serial but I want to reduce the amount of data, how to I do that?



    1. ok. Figured it out. Just change output to nmea0183 and then I can process with any gps decode software on the other the end. Guess I have to look at the options a little more closely 🙂


  6. Hi, how to post-processing if I just have Ublox M8T rover RAW data with .ubx ? Could I just put this data into RTKNAVI (rover input(input type-file: ***.ubx, base input(input type ntrip CORS), then log the base data as RTCM3, and then using these two files in RTKPOST? But if so, how can I deal with timetag for larger Age diff?


    1. Hi Roger. RTKCONV will convert the raw .ubx files to Rinex which can then be processed with RTKPOST. Time tags are used to simulate data link delays in real-time processing. No need to use them for post-processing.


  7. So, the real time RTK solution is always worse then post-process RTK at combine mode. If real time RTK solution is better then the post process RTK (combine mode) than there is a false fix somewhere in the real time solution. I think this is a good method to find out the false fixed. Is the false fixed considered a software bug or it always happens in someway? Thanks


    1. It’s either real-time kinematic (RTK) or post-processed kinematic (PPK), it can’t be both (“post-processed RTK”). Using the same software and settings, and assuming the data comes in with no gaps, RTK should be equivalent to forward-only PPK. RTK should be worse than combined-mode PPK considering the entire session. RTK can be as good as PPK for a given period of interest within the session. And false fixes are always a risk under poor reception conditions and with few satellites visible (think forested areas).


    2. Hi Dan. As Felipe says, the real-time (forward) solution will not always be worse than the post-process (combined) solution. In fact, it’s actually possible for the forward solution to be better than the combined solution. In the example I gave, the forward solution had a false fix but the backward solution was good. If the opposite were true, then the forward solution would be high accuracy fix and the the combined solution would be low accuracy float. In general though, the combined solution will have a higher confidence level than the forward solution because of the extra validation that comes from running the data in both directions. False fixes are always possible due to the probabilistic nature of the integer resolution algorithm but conservative configuration settings should help reduce the chance of the false fixes. Of course they also reduce the chance of a good fix which is part of the trade-off of finding a satisfactory configuration.


      1. Thanks for all.
        The following is my summary. Please let me know if any misunderstand
        (I am not use RTK and PPK instead just forward and backward since real time RTK only have forward which is same as PPK’s forward)
        1) If forward and backward are all FLOAT then Combine = FLOAT (average two float)
        2)If forward is FIX and backward is FLOAT then Combine = FIX (which is forward solution)
        3)If backward is FLOAT and forward is FIX then Combine = FIX (which is backward solution)
        4)If forward is FIX1 and backward is FIX2 and |FIX1 – FIX2| < 4sigma then Combine = avgFIX
        5)If forward is FIX1 and backward is FIX2 and |FIX1 – FIX2| > 4sigma then Combine = FLOAT

        In case 5 the forward solution maybe better than combine solution, but most likely there is a false fix in forward (or backward. I hope it at forward :-)). Assume we use fix-and-hold mode.

        At this time, we can’t confirm which is better accuracy between FLOAT and false FIX. but false FIX seems getting worse until RTKLIB find it.

        So far, RTKLIB can’t change parameters settings based on environment.



          1. Yes, you are right. Do you have an example compare false fixed solution to float position? or how to find false solution at real time. Thanks


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 )

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.

%d bloggers like this: