RTKLIB: Demo 4 vs 2.4.3 B16 code

Over the last six months or so I have made a number of changes to the RTKLIB code. A couple of these (ArlockCnt bug and M8N half-cycle bit) have made it back into the officially released code on Github but most of them have not. While I was in the mode of comparing solutions, I thought it would be worthwhile comparing solutions from the latest demo4 code from my Github repository to the latest released code (2.4.3 B16) to see how much they differ. The demo4 code is based on the 2.4.3 B12 released code but I do not believe the differences between releases B12 and B16 should affect this comparison.

I used the same data sets and input configuration files I used for the M8T vs M8N comparisons I described in the last few posts. The only differences being that I removed the options and input parameters that do not exist in the released version from the configuration files for the released code runs.

Here are the solutions from the previous post for both the pair of M8N receivers and the pair of M8T receivers using the latest demo4 code.

     M8N                                                                             Reach M8Trelease1

Here are the solutions for the same data sets using the 2.4.3 B16 code, both RTKCONV and RNX2RTKP.

     M8N                                                                             Reach M8Trelease2

A quick look at the vertical scales as well as the shape of the plots shows that the M8N solution is completely invalid whereas the M8T solution looks reasonably close although with a noticeably lower fix ratio. The difference between the M8N and the M8T is much greater with the release code than it was with the demo4 code. This is consistent with observations from other users that the M8T is significantly better than the M8N, something I did not really see in the demo4 solutions.

Let’s also look at the differences between solutions since they can indicate errors. Here is the difference between the demo4 M8N and M8T solutions from the previous post. Remember that this difference should be a circle with a radius equal to the distance between the rover antennas since the data is from two different receivers mounted on the same rover. I have only plotted data for the fixed points since those are the ones we have highest confidence in.


There is no point in looking at the release M8N solution since it is so poor, but we can compare the M8T solutions from the two code versions. In this case, because we are using two solutions from the same data set, the difference should be zero. Here is a plot of the difference between those two solutions for the M8T data set, again only for the fixed solution points.


Here is the same data, plotted by axis.


The differences are quite large, up to nearly a meter in x and y, and more in the z axis. Based on the previous comparison between the M8N and the M8T with the demo4 code, I have fairly high confidence in the demo4 solution so I suspect the errors are in the release solution. We can verify this though by looking for discontinuities in the solutions at the erroneous points.

Let’s pick the point at 01:22:47 which shows a large difference between solutions in all 3 axes. Here are the two solutions zoomed into this point in time.

Reach M8T: demo4                                Reach M8T: 2.4.3 B16release6

Notice the large jump in the released code solution. Since this data is from a car driving on roads, the large discontinuities in the y and z axes are not real and confirm the error is in the release code and not the demo4 code.

So, several people now have asked if these changes will make it into the official code. As I’ve mentioned before in one of my comments, I’ve chosen not to submit all of my code changes to the official code repository. This is because my changes are focused on one small corner of the world of GPS (low cost) and tested on an even smaller corner (low-cost Ublox) and I am not sure how well they all will translate into the larger realm that RTKLIB supports. At minimum, it seems they would require a fair bit of testing on multiple hardware platforms which I don’t have the time or resources to do. I’m also not sure some of them would all be considered sufficiently mathematically rigorous for general widespread use. But I will continue to make them available in my Github repository for anyone that would like to incorporate them into their code.

I have just submitted my most recent change, the improvement in decoding cycle-slips from the M8T raw data, as an issue to the official Github repository.


Update 8/28/16:  I now have a demo5 version of this code in which I have made the GUI versions (RTKNAVI and RTKPOST) fully functional with all of the demo4 features.  The code is in a new demo5 branch in my Github repository and the executables are here


9 thoughts on “RTKLIB: Demo 4 vs 2.4.3 B16 code”

  1. Hi, Tim( ? not sure)
    I’ve tested with your advice, re-compile rtkrcv with lapack/blas support, then it seems that “Age=” issue almost disappeared, meanwhile when I increase BBB’s load, that’s as you said, “Age=” come again, so mightbe still with bandwidth of comm-link (I’m using wifi between base which is on laptop and rover which is BBB), but for now you’re right that it should be more related with power & load of BBB.
    For today, I’ve test for a while and after long time FLOAT, also long time FIX happened, I’m satisfied with this solution, but still dont know why this FIX is so long, here’s the record data, do you mind to have a look? Tks
    http://pan.baidu.com/s/1o7UlBxK (I dont know how to directly upload files in wordpress, sorry…)


    1. Hi Roger. I realize the link to the BBB compile options was wrong in my last comment. The correct link is here (I’ve fixed it in my previous comment as well). The comparison of run times is at the very end.

      I also found the compile options I used in my makefile for the BBB hardware floating point when building rtkrcv. They were: “-mfpu=neon” and “-ffast-math” I didn’t enable the lapack/blas support but that seems like a good idea as well. In the comparisons from the above link, floating point math was faster than LAPACK but they did not test both enabled at once (maybe they are not compatible?)

      Your data looks good to me. I ran a solution (on my laptop) using my demo5 code and config file and got a fix within two minutes and no loss of fix for the rest of the data set. I posted the data and result here.

      I did notice you are missing GLONASS measurements in your base data so the solution is GPS only. (In a recent comment to another reader I did not see the GLONASS measurements because I converted the RTCM data with RINEX 3.xx format, but in this case I double-checked and am pretty sure the GLONASS data is actually missing)



  2. Hi,
    Impressive job! I’m a newbie in RTKLib and truly met some problems. Could you pls help me on it?
    What I want to do is using two M8T (one for base, one for rover) in BBB, but after try a lot, still solution is FLOAT, rarely FIX.
    Here’s the RTKLib version I’m trying: RTKLIB-2.4.3-b18 and your github Demo5;
    Base is running in PC by using str2str, rover is running in BBB by rtkrcv, the two M8T config is the same: 10Hz , 115200 baudrate, GPS RAW in UART1, here’s the cmd file:
    !UBX CFG-RATE 100 1 1

    !UBX CFG-MSG 2 21 0 1 0 0 0 0

    !UBX CFG-MSG 2 19 0 1 0 0 0 0

    !UBX CFG-PRT 1 0 0 2240 115200 1 1 0 0

    !UBX CFG-MSG 2 21 0 0 0 0 0 0

    !UBX CFG-MSG 2 19 0 0 0 0 0 0
    and for base in str2str, the config is almost like this:
    ./str2str -in serial://ttyUSB0:115200:8:n:1:off#ubx -t 1 -out tcpsvr:@:8989#rtcm3 -c ./ubx_m8t_raw_10hz.cmd -msg “1002, 1006, 1013, 1019” -p 52.14271937 3.244610005 502.222

    and here’s the config for rover (sorry, it’s a little big, and it’s almost the conf but not complete, such as tcpsvr IP I didn’t type it):
    # RTKNAVI options (2016/08/24 12:37:44, v.2.4.2)

    pos1-posmode =static # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed)
    pos1-frequency =l1+l2 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l2+l5+l6,5:l1+l2+l5+l6+l7)
    pos1-soltype =forward # (0:forward,1:backward,2:combined)
    pos1-elmask =15 # (deg)
    pos1-snrmask_r =off # (0:off,1:on)
    pos1-snrmask_b =off # (0:off,1:on)
    pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0
    pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0
    pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0
    pos1-dynamics =off # (0:off,1:on)
    pos1-tidecorr =off # (0:off,1:on,2:otl)
    pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:vtec_sf,9:vtec_ef,10:gtec)
    pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad)
    pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
    pos1-posopt1 =off # (0:off,1:on)
    pos1-posopt2 =off # (0:off,1:on)
    pos1-posopt3 =off # (0:off,1:on)
    pos1-posopt4 =off # (0:off,1:on)
    pos1-posopt5 =off # (0:off,1:on)
    pos1-exclsats = # (prn …)
    pos1-navsys =1 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp)
    pos2-armode =fix-and-hold # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
    pos2-gloarmode =off # (0:off,1:on,2:autocal)
    pos2-bdsarmode =off # (0:off,1:on)
    pos2-arthres =3
    pos2-arlockcnt =0
    pos2-arelmask =0 # (deg)
    pos2-arminfix =10
    pos2-elmaskhold =0 # (deg)
    pos2-aroutcnt =5
    pos2-maxage =30 # (s)
    pos2-syncsol =off # (0:off,1:on)
    pos2-slipthres =0.05 # (m)
    pos2-rejionno =30 # (m)
    pos2-rejgdop =30
    pos2-niter =1
    pos2-baselen =0 # (m)
    pos2-basesig =0 # (m)
    out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea)
    out-outhead =off # (0:off,1:on)
    out-outopt =off # (0:off,1:on)
    out-timesys =gpst # (0:gpst,1:utc,2:jst)
    out-timeform =hms # (0:tow,1:hms)
    out-timendec =3
    out-degform =deg # (0:deg,1:dms)
    out-fieldsep =
    out-height =ellipsoidal # (0:ellipsoidal,1:geodetic)
    out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
    out-solstatic =all # (0:all,1:single)
    out-nmeaintv1 =0 # (s)
    out-nmeaintv2 =0 # (s)
    out-outstat =off # (0:off,1:state,2:residual)
    stats-eratio1 =100
    stats-eratio2 =100
    stats-errphase =0.003 # (m)
    stats-errphaseel =0.003 # (m)
    stats-errphasebl =0 # (m/10km)
    stats-errdoppler =1 # (Hz)
    stats-stdbias =30 # (m)
    stats-stdiono =0.03 # (m)
    stats-stdtrop =0.3 # (m)
    stats-prnaccelh =10 # (m/s^2)
    stats-prnaccelv =10 # (m/s^2)
    stats-prnbias =0.0001 # (m)
    stats-prniono =0.001 # (m)
    stats-prntrop =0.0001 # (m)
    stats-clkstab =5e-12 # (s/s)
    ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm)
    ant1-pos1 =90 # (deg|m)
    ant1-pos2 =0 # (deg|m)
    ant1-pos3 =-6335367.6285 # (m|m)
    ant1-anttype =
    ant1-antdele =0 # (m)
    ant1-antdeln =0 # (m)
    ant1-antdelu =0 # (m)
    ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm)
    ant2-pos1 =0 # (deg|m)
    ant2-pos2 =0 # (deg|m)
    ant2-pos3 =0 # (m|m)
    ant2-anttype =
    ant2-antdele =0 # (m)
    ant2-antdeln =0 # (m)
    ant2-antdelu =0 # (m)
    misc-timeinterp =off # (0:off,1:on)
    misc-sbasatsel =0 # (0:all)
    misc-rnxopt1 =
    misc-rnxopt2 =
    file-satantfile =
    file-rcvantfile =
    file-staposfile =
    file-geoidfile =
    file-ionofile =
    file-dcbfile =
    file-eopfile =
    file-blqfile =
    file-tempdir =
    file-geexefile =
    file-solstatfile =
    file-tracefile =

    inpstr1-type =serial # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr2-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr1-path =ttyUSB0:115200:8:n:1:off
    inpstr2-path =:@IP:8989/:
    inpstr3-path =
    inpstr1-format =ubx # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
    inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
    inpstr3-format =rtcm2 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
    inpstr2-nmeareq =latlon # (0:off,1:latlon,2:single)
    inpstr2-nmealat =0 # (deg)
    inpstr2-nmealon =0 # (deg)
    outstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    outstr1-path =
    outstr2-path =
    outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea)
    outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea)
    logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr1-path =
    logstr2-path =
    logstr3-path =
    misc-svrcycle =10 # (ms)
    misc-timeout =10000 # (ms)
    misc-reconnect =10000 # (ms)
    misc-nmeacycle =5000 # (ms)
    misc-buffsize =32768 # (bytes)
    misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr)
    misc-proxyaddr =
    misc-fswapmargin =30 # (s)

    and then, when I almost put the base and rover near together (distance about 10cm), and it’s easy for me to get FLOAT, but FIX is hard, meanwhile, the skyview is very good: sunning no cloud and open-sky. So did I miss sth in config? such as for base in str2str, did I need to get the very accurate position for base (str2str … -p )? Another thing is I just using a normal antenna for the two M8T: GPS and Beidou antenna buy from here: https://item.taobao.com/item.htm?spm=a230r.1.14.16.B8eWLb&id=38499894179&ns=1&abbucket=8#detail

    any help will be very grateful! Tks, 🙂

    Liked by 1 person

    1. Hi Rogerzyj. I would start by verifying that you have valid observations. You can either set the RTK Monitor window in RTKNAVI to observations or log the input streams and use RTKCONV to convert the raw data to RINEX observation files. Check both rover and base to make sure you have pseudorange and phase from all satellite systems, that the update rate is correct and that you don’t have missing or extra observations. If all that looks good, then use RTKPLOT to plot the RINEX observation files. Set “Cycle-Slips” to “LLI” in the RTKPLOT options menu, and the elevation mask to 15 degrees, and verify that you are not getting more than a small number of cycle slips for any of the satellites. If all of that looks good and you are still not getting fixes, then send me your raw data files and I will take a look.

      One more thing you might try is reducing the sample rate for your base down to 1 Hz or less. I don’t know how you are sending the base data to your rover but 10 Hz might be overwhelming your data link. Since the base is not moving you should be able to get by with a lower sample rate.

      Liked by 1 person

      1. Tks!
        I’ve merged the configuration file in your github demo2, another change is to place antennas of base and rover > 2 meters, then, both base and rover is 1Hz with 115200, and tried again, then find I can get some fix for a long while (about 20 mins) when both base and rover stationary.
        Still weird thing is when I increase to 5Hz for rover, it’s very easily to error as “age = 20.xx/30.xx”, then ratio will be jumping down and up but never meet the threshold of fix. So first thing I wonder is that this “age” should be as small as possible (0/1 second?), it that right? Another thing I doubt that is my rover is running on BBB which is a 1GHz Cortex-A8, should be not fast enough for 5Hz then cause “age” issue?


        1. Hi Roger. I suggest using one of my more recent config files from here.

          I have seen a comment elsewhere about keeping the antennas separated to avoid potential EMI leakage issues but have not had any trouble myself even when the antennas are only a couple centimeters apart.

          The “ages” are the difference in time between the base and rover measurements for a given solution sample and large values usually indicate that the base data stream is not keeping up with the data from the base receiver. I would check both observation files to see if either is missing large numbers of observations.

          I have run the demo4/5 code on a BBB at 5 Hz with GPS and GLONASS enabled without any problem. I monitored the BBB CPU clock frequency using cpufreq as described here to get an idea of how much load I was putting on the CPU. I found that the clock frequency was running at 100% only about half the time which suggests there is still margin leftover so I suspect your problem is not CPU power unless you are using a lot of CPU bandwidth for other tasks. Another possibility is that you did not compile the BBB code with the right options to enable hardware floating point. I can’t find the exact compile options I used but there is some info here comparing RTKLIB run times for different compile options on the BBB.

          Liked by 1 person

  3. The Bernese software has a RINEX simulation component which is useful for software validation; quoting from their docs:
    Simulation of GNSS observations
    – According to a given geometry (satellite orbits and station positions) GNSS observations can be computed
    – Assumptions with respect to the noise level, receiver/satellite clocks, ionosphere, troposphere, and cycle slips can be introduced
    – These synthetic data can be processed on zero-difference or double-difference level
    – The correct integer ambiguity is known to be zero in case of ambiguity resolution tests


  4. Please consider open Github issues for the other issues/fixes. While the testing may be limited to particular hardware or setup, it would be good to flag the potential issues/fix for others.


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: