RTKLIB: Tips for using a CORS station as base

Generally, you will get the best RTK/PPK solutions using two matched receivers, one as rover, and one as a local base. This will give you the shortest baseline, maximum number of usable constellations, and no issues with the Glonass hardware biases that come from using unmatched receivers. To do this, you will first need to determine the precise location of your local base receiver. Running a post-processed kinematic (PPK) solution with your own local base receiver as rover and a nearby Continuous Operating Reference Station (CORS) as base is usually the easiest way to do this.

Of course, If you have a CORS station near enough, it is also possible to run solutions directly from your rover to the CORS base but I generally opt for the local base since the solutions will be more accurate and more robust.

For the most part, running a PPK solution against a CORS base is very similar to the local base solutions I describe in many of my other posts but there are a few important differences that I will try to go over in this post. I will describe using CORS stations inside the U.S. with u-blox receivers and the demo5 RTKLIB code since this is what I am most familiar with, but most of the information in this post will apply to other receivers as well as to CORS stations in other countries.

The first step is to find a nearby CORS station. In the U.S, the easiest way to do this is to go to the NOAA User Friendly CORS website and click on the CORS Map link. Zoom into your local area and if you are lucky you should see something like the screen shot below with several nearby choices. If you’re not so lucky you may find only one or two distant choices.

Notice that some stations are GPS only and some are labelled as “GNSS” which indicates that they support multiple constellations, usually GPS and Glonass, but sometimes Galileo as well. Ideally you will find a “GNSS” site within 20 kilometers but if not you may be successful generating fixed solutions with stations up to 100 km or more away. If you are using a dual frequency receiver and solving for a stationary rover you can usually use more distant stations. Be aware that longer baselines will increase accuracy errors so it is a good idea to run longer solutions and average the results from multiple stations if possible. Station sample rate is less important than distance and number of constellations but a higher sample rate is always better if you have the choice.

In addition to the NOAA CORS website, it is also worth checking if your state has its own network of reference stations. These are usually run by the state department of transportation and their data is normally free although you may need to sign up to access it. There is a slightly dated state by state list available here.

If your base station is sampling slower than a 1 second rate then I often find that interpolating between base observation samples improves the solution. In RTKPOST, this is done by setting enabling “Time Interpolation of Base Station Data” in the “Misc” tab of the options menu. In RNX2RTKP, this is done by setting “misc-timeinterp =on” in the config file.

Assuming your rover is stationary, you can run the solution mode as “Static” and this will improve your chance of getting a fixed solution. I prefer to run a “Kinematic” solution if possible, however, since the variation in solution position over time gives some insight into what the accuracy of the solution is, especially if you have collected several hours of observation data.

Since the receiver manufacturers will almost always be different between base and rover in these solutions, you will usually need to deal with the Glonass hardware biases. I describe the different options to account for these in detail in this post so I would recommend reading or reviewing that post for the details. To quickly summarize though, the simplest option is to set “Integer Ambiguity Resolution” in the options menu for Glonass to “Fix-and-Hold” in which case RTKLIB attempts to calibrate the biases. In some cases, this will be good enough to get a fixed solution. However, you are more likely to get a fixed solution if you account for the biases directly. You can do this by setting Glonass ambiguity resolution to the poorly named “Autocal” option and then specifying the biases directly with the “GLO HW bias” option in RTKPOST or “pos2-arthres2” option in the config file. Again, see the above post for the details on how to determine the correct biases and the table of biases by receiver manufacturer. Note that these ambiguity resolution options are only available in the demo5 version of the RTKLIB code.

If the HW biases for both base and rover are close to zero then it’s generally OK to ignore them and set Glonass ambiguity resolution to “on”. This will not be true for a u-blox M8T rover since it’s bias is not zero. However the u-blox F9P bias is close to zero so if you are using it as rover and your base receiver is manufactured by Trimble, Septentrio, Topcon, Spectra Physics, Javad, or Ashtec then go ahead and set Glonass ambiguity resolution to “on”. The receiver manufacturer will be listed in the header of the base rinex file.

The base rinex file header also includes the base antenna type and it’s precise location. Note that the precise location is in the header field labelled “APPROX POSITION XYZ”. Setting the base station position in the options menu to “RINEX Header Position” will cause this value to be used in the solution. If you would also like to include the base station antenna calibration in the solution, then check the “Antenna Type” box and specify “*” in the box below. This tells RTKLIB to use the antenna type listed in the rinex header. You will also need to point to an antenna calibration file in the “Files” tab of the options menu. You can use the “igs14.atx” file that is included with the demo5 binaries for this.

It is important to keep in mind that the accuracy of the solution is going to get worse as the distance to the base station increases as shown in this chart taken from a Novatel tutorial.

If you are using a single frequency receiver then there are usually no good alternatives to using a distant CORS station. The best you can do is collect multiple longer data sets from multiple stations and average the results. If you are using a dual frequency receiver then you also have the option of running a Precise Point Positioning (PPP) solution, either with RTKLIB or through an online service as I describe in this post.

Well, that’s all I can think of at the moment. If anyone else has any additional tips or questions, please add them to the comments below.

19 thoughts on “RTKLIB: Tips for using a CORS station as base”

  1. Are there tutorials out there for how to get STRSVR to deal with public CORS information. I’ve been unsuccessful in getting maCORS as a public base station and then making the corrections…


    1. Hi Bostonmacosx. STRSVR is a stream server app that can be used to input a data stream from one source and send it to another but will not process the data itself. I’m assuming you are trying to use it to stream NTRIP data from a real-time CORS station to a receiver for an RTK solution. Documentation for using STRSVR is in the RTKLIB manual. I also have some tips on doing this in this post


      1. Hi there….so I think now I know I want to use RTKNAVI to realtime correct the antenna data…so 1 rover and the public CORS…what is happening though is that the public CORS is timing out repeatedly although my username port address and mount_point are all correct…..hmmm


  2. Hi, thanks a lot for your work.
    As a drone mapping compagny, we work with the EMLID RS2.
    Do you know if this workflow can apply to collect GCPs if you stand within a 50km radius from a CORS station ? (free rinex files from state operated stations)


    1. My experience with F9P (L1/L2, no L5 collection) is that fix is much better if Galileo is available at CORS station. If only GPS+Glonass are available, 50 km could be challenging (although GCPs for drone are supposed to be in open field areas so it could be easier). With GPS + Galileo, it should not be a problem.


    2. Hi MF Drone. Accuracy will decrease as you get farther from the CORS station, so ideally you would be closer than 50 km, but with a dual frequency receiver, you should usually be able to get a fixed solution at this distance. You might also consider using free online PPP solutions from CSRS or other similar services.


  3. Side question. This week-end, I was in an area that was surrounded by a half-dozen of reference stations… between 50 and 60 km away. Is there any method to calculate his own Virtual Reference Station using data from surrounding stations?


    1. Hi Eric. I’m not aware of any open source or reasonably priced software to generate VRS observations. One option is to run solutions against all the nearby bases and combine the results for higher fix rates and better accuracy.


  4. Hello!
    Thank you again for the great work!
    I used the last demo (demo5_b33c) to process some data from the phones Mi8 and Pixel4.
    I noticed that when I look at the multipath indicators (MP) for E1 versus elevation it does not show me anything but it shows to me the MP values versus elevation for E5.
    Do you have any hint on the source of the issue?
    Many thanks again

    Liked by 1 person

  5. I’m using a f9p receiver as a rover with a local CORS station (within 1km) as the base, and using Lefebure NTRIP client for android for an RTK connection, however the altitude reported out of it when I use Mapit GIS seems to only change in 0.1m increments and the number is always .x449. Is anyone using this same setup and experienced this? I’ve tried using the mapit GIS NTRIP client which uses (some) version of rtklib, but could never get it to work.


    1. Found the solution to this, by default the NMEA messages output from the F9P only have 1dp for the altitude and 5dp for lat/long. Enabling CFG-NMEA-HIGHPREC in the config gives 7dp for lat/long and 3dp for alt, so fixes this problem.


  6. I am curious how best to get the difference to set in GLO HW BIAS when dealing with CORS hardware which is predictably different.

    RTKLIB seems to ignore the offset in RTCM MT1230. I think it also ignores the GLONASS COD/PHS/BIS record in the RINEX3 file from CORS.

    I am not sure why that is, but surely it would make sense to use the actual biases from the base rather than the prediction from your extended “Wanninger” table so I am wondering whether I can enter these manually but I am a bit lost.

    eg you have Trimble=-0.7cm but CORS with a TRIMBLE ALLOY has +19.06m in RTCM/RINEX
    eg you have Leica=+2.3cm but a CORS with a LEICA GR30 has -71.94m in RTCM/RINEX

    Are these dealing with the same concept in a different manner? Is there a formula to convert between these two types?


    1. Hi Arl. Yes, RTKLIB ignores the COD/PHS/BIAS records in the RINEX files, and does not decode the RTCM MT1230 messages. I agree that these would be nice additions to RTKLIB and they are on my list of possible future code improvements. None of the CORS stations near me include COD/PHS/BIS records in the rinex files so I do not know if they are equivalent to the values used by RTKLIB and the Wanninger table. I describe how to find/verify the correct bias values for RTKLIB in this post, or if you’d like to send me rover and base data for an example with these fields, I’m curious to see if this is true. Note that if you do this experiment yourself and just want to verify a proposed bias value, you do not need to modify the initial variance or process noise (pos2-arthres3 and pos2-arthres4) for the hardware bias states. You can just set Glonass AR to “autocal”, the Glonass HW bias (pos2-arthres2) to the proposed bias value, run the solution, and then plot the residuals with RTKPLOT as described in the above post. If the proposed bias is correct, the Glonass carrier phase residuals should converge to near zero after the solution achieves fix.


      1. Hi Arl. One more thought on automating the Glonass hardware bias input to RTKLIB. Even with the existing code, it would be fairly easy to write a short python script to extract either the receiver type or bias from the rinex file and use the result to update the bias parameter in the config file before running the RTKLIB solution.


        1. Indeed – but first we need to work out how to convert one measurement to the other!

          I shall have to do some experimentation I think (or send you some data)

          Did you see the Gsilib fork which purported to save and load Glonass biases from a .tbl file (indexed by the Receiver type string I think)?

          I notice that the CORS MSM messages show L1P and L2P data, but Ublox is L1C/A and L2C/A, will that be an issue?


          1. Hi Ari. I haven’t seen the Gsilib fork but I will take a look at it. It’s OK to combine the L1P/L2P and the L1C/L2C observations in an RTK solution, although if one receiver provides a mix of the two, it can confuse RTKLIB.


    1. Hi Sbd. If you are using rinex files generated from VRS data streams for base station data, then just about everything in the post should apply. I find that most of the time VRS data works well, but sometimes there seems to be large errors in the data, and I get a much better solution from the nearest CORS station. This is with single frequency receivers though, I don’t know if this applies to dual frequency solutions as well.


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: