Real-time solutions with RTKLIB and NTRIP using a cell phone as data link

As I mentioned in an earlier post, I’ve recently acquired access to some low cost dual frequency receivers, specifically a Tersus Precis BX306 and a pair of Swift Piksi Multis.  I have been playing with them over the past few weeks and plan to share my experiences with them over a series of posts.

Both receivers provide internal RTK solutions as well as raw measurements that can be processed with RTKLIB.  I’m interested in how the RTKLIB solutions compare to the internal solutions as well as how both of these compare to solutions derived from single frequency data collected simultaneously with the dual frequency data.

The first issue I ran into with this experiment, however, is that both receivers will only provide an RTK solution for real-time data, neither have the capability to post-process previously collected data.  This meant that I needed a way to provide a real-time stream of dual frequency base station data to the receivers.  I wanted to be able to  do this while driving a car around the local area so I needed more range than a low cost set of radios would give.

Fortunately, I have fairly good cell phone coverage in this area so I was able to rely on my cell phone for the data link.  In this post I will explain how I did that, both for an external CORS reference station and for my own base station.  In both cases I used  NTRIP server/caster/clients to do this.  NTRIP is a protocol for streaming of DGPS or RTK correction data via the internet using TCP/IP.  The NTRIP server sends out the data to an NTRIP caster and the NTRIP client receives it. For more details, there is a good description here.

Using this setup I was able to run real-time solutions with RTKLIB as well as with the intenal RTK engines in the Swift and Tersus receivers.  Here’s a diagram from the RTKLIB manual showing the setup I used for running a real-time RTKLIB solution using RTKNAVI.  When I ran a Swift or Tersus solution, the configuration was similar, but the NTRIP caster streamed the base station data to STRSVR instead of RTKNAVI, and STRSVR then streamed it to the receiver where it was combined with the raw receiver observations to create an internal RTK solution.  Also missing in this diagram is the cell phone which should be in between the internet and the rover PC.

ntrip.rtklib

The amount of free base station reference data that is available online on a real-time basis is a fair bit more limited that what is available after the fact for post-processing.  Fortunately I was able to find a CORS reference station about 17 km away that is available real-time through the UNAVCO NTRIP caster.  The service is free if the data is used for educational purposes and appropriately attributed.   Most of their stations are on the west coast of the U.S. but they do have some scattered across the rest of the country as you can see in this map from their site.  There are other networks available in other parts of the world that can be found by searching online.

unavco_map

To access the UNAVCO data I had to request access through email but the process was very simple and within a couple hours of my request I was all setup with an account and password.

Once I had my account set up, I used RTKLIB on my laptop computer to collect the data from the internet and stream it to the rover receiver over a serial port.  If I were doing this experiment within range of a wireless router then I could leave the computer connected to the wireless.  In this case though, I wanted to roam outside the range of my home wireless.  To do this, I enabled a hot spot on my cell phone and logged into that with my computer.

I was able to access the raw observation data stream from the UNAVCO NTRIP caster directly using the NTRIP client option in RTKLIB.  If I had wanted to generate a real-time RTKLIB solution, I would have configured the input streams of RTKNAVI but in this case I want to stream the raw data directly to the receiver so it can use the observation data for it’s internal solution.  I did this using the STRSVR app in RTKLIB.  I specifed the “NTRIP Client” option as input type and then entered the information from my UNAVCO account into the “Ntrip Client Options” as shown below.

ntrip_client

In this case I wanted the data from station P041 in RTCM3 format so I had to specify the Mountpoint as “P041_RTCM3”.  For other networks, the mountpoint details may be a little different.  Most NTRIP casters use Port 2101, and that was the case for this one.  For the STRSVR output type, I specified “Serial” and then configured the serial port options for whichever rover receiver I was using.  Before doing the configuration, I had connected the receiver to the laptop using a USB cable.

I then had to configure the receiver to tell it to get its base station data from the COM port and specify that it is in RTCM3 format.  The details for doing this on the two receivers are a little different but fairly straightforward in both cases.  You may also need to specify the exact base station location manually or the receiver may be able to get it from the data stream depending on the receiver and NTRIP stream details.

And that’s it.  With this configuration, either receiver was able to fairly quickly lock to a fixed RTK solution and continue to receive base data as long as I stayed in range of cell reception.  Any lag in the base station observations appeared to be less than a second.

That worked great for using an existing external reference as base station.  However, I also wanted to run another real-time experiment where I used one Swift receiver as base and the other as rover.   To do this, I needed to set up an NTRIP server to stream the data to  a caster on the internet as well as an NTRIP client to receive it.

I started by connecting the second Swift receiver to an old laptop with a USB cable and then downloading RTKLIB, the Swift console app,  and the right USB drivers.  The base station antenna is on top of my roof and the laptop is in the house so I was able to connect the laptop to the internet using my home wireless.

For the NTRIP caster, I found it convenient to use RTK2GO which is a community caster available for anyone to use at no cost.  To send the data to the caster, I used the “NTRIP Server” as the STRSVR output type and configured it as shown below.

strsvr_server

Again, the port is 2101.  You can choose any name for the mountpoint.  If that name is already in use, then rtk2go will assign a suffix to it, so it is best to choose a name that is unlikely to already be in use.  The password at the current time is BETATEST but that may change from time to time so it’s worth verifying it is still correct.

For the STRSVR input, I selected “Serial” and specified the correct COM port for the base station receiver.  In this case the raw observations are in Swift binary format which RTKLIB does not support so it sends them unaltered.  If they were in a format that RTKLIB did support, then they could be converted to RTCM3 to reduce bandwidth and make them more easily usable by someone else not using a Swift receiver as rover.  You can specify the conversion to RTCM3 using the “Conv” menu on the STRSVR output.

Start STRSVR and your base station observations are now accessible to anyone in the world through RTK2GO.com!

On the rover side, the NTRIP client is set up as I previously described using STRSVR except you want to use the same caster/mountpint/password as you just did on the base station.  In this case the user-id is left blank.  Again, set the STRSVR output to “Serial” to send it to the receiver.   Then set up the receiver to get it’s base station data from the serial port and, in this case, specify that it is in the Swift Binary Protocol (sbp).  Start the receiver and it should fairly quickly get a fix.  If you are seeing baseline data but not a solution, then most likely you have not specified the base station location to the rover.

I was now able to drive around almost anywhere and get continuous real-time RTK solutions using either my own base station or the CORS reference station as base.  In the next post I will discuss some of the data I collected and analyzed.

 

 

 

 

Newest U-blox M8N receivers not usable with RTKLIB

It looks like it is no longer possible to access the raw GPS measurements on the newest version of the u-blox M8N receiver.  Access to these raw measurements on the M8N has always been through debug messages not officially supported by u-blox.  Last year, when they migrated from the 2.01 version of firmware to the 3.01, version they scrambled the output of these messages so they were no longer readable by RTKLIB.

Until recently though, the units they were shipping still had an older 2.01 version of ROM.  With these units it is possible to downgrade the firmware to 2.01 using the instructions on their website.  With the older firmware loaded, the receivers revert to their previous behavior and the debug messages are no longer scrambled.

Apparently their newest units are shipping with a 3.01 version of ROM and this ROM is not compatible with the older 2.01 version of firmware.  If you attempt to load the older firmware it will appear to succeed but will still be running the newer code.

You can see what version of ROM and firmware your receiver is running using the UBX-MON-VER message from the u-center console.  The example below shows the message output for one of the newer modules with the 3.01 ROM after attempting to download the older firmware.  I believe the firmware listed under “Extension(s)” is the ROM version and the firmware listed under “Software Version” is the version of firmware loaded to flash.  In this case you can see that the ROM is version 3.01 and that the flash is still running version 3.01 even though it was attempted to load the 2.01 firmware.

fw_ver

In an older version of the M8N module, the ROM code listed under “Extension(s)” would have been 2.01 and the firmware listed under “Software Version” could be either 2.01 or 3.01 depending on how old the module was and what firmware had been downloaded to it.

There are a few more details about the issue on the u-blox forum in this thread.  Thanks to Marco for making me aware of the issue and Clive and Helge for providing a detailed explanation of what is going on.

If you are using the u-blox M8T, and not the M8N, then you will be using the officially supported raw measurement messages and would normally not care about access to the debug messages.  The only exception I know of is that the resolution of the SNR measurements are 0.2 dB in the debug messages and 1.0 in the official messages.  I have not confirmed that the debug messages on the 3.01 M8T firmware are scrambled but it is likely that they are.

[Note 6/25/17:  A couple of readers have pointed out that this is not the whole story.  It would have been more correct to say that the newest M8N modules are not usable with the publicly available versions of u-blox firmware and RTKLIB.  It turns out that u-blox did not use a particularly sophisticated method to scramble the debug messages and there are now several modified versions of u-blox firmware and RTKLIB floating around that have been hacked to unscramble the messages.  I don’t want to get into the question of ethics or legality of using these codes but just say that I personally am less comfortable using the debug messages in the modules where u-blox has made an obvious attempt to prevent this and have avoided any use of them at least for the time being.]

New b27 release of demo5 code

I’ve just released a b27  version of the demo5 code that incorporates all the changes in the b27 release of the official code.  I’ve also included some fixes for the Galileo satellites.  The biggest fix I added was for an array overrun that was causing solutions to intermittently report zero status when Galileo satellites were enabled.  Another fix was to correctly decode the range accuracy estimates in the Galileo ephemeris data.  The code can be downloaded from the code download section of the rtkexplorer.com website.   The source code is available in my Github repository.  Please let me know if you find any issues with this code, especially if it was something that was working in the previous code.

One issue I am aware of is the time tag feature which enables simulated real-time runs in RTKNAVI appears to be broken in the new code.  There was an existing incompatibility  between time-tag files that were created in the win32 version of RTKLIB and run in the win64 version or vice-versa.   It looks like an attempt to fix this in the latest release code actually made things worse and now the time-tag files don’t work at all, at least in the win32 version.

By the way, for anyone using the free starter edition of the Embarcadero compiler, be aware that it does not support building win64 executables.  The code will build, but the option to specify win64 is not available, so the compiler will just build the win32 code.  I hadn’t realized this until I tried to build the win64 version recently.

Also, I’ve recently got a hold of two low cost dual frequency receivers, one from Swift Navigation and one from Tersus, so I am collecting and analyzing data with them now.  I should have some results and comparisons to share in my next post soon.

Update to RTKLIB config file recommendations

I’ve just updated my “RTKLIB: Customizing the input configuration file” post from a few months ago with information on all of the new config parameters I have added to the demo5 code up through B26B.  I’ve also added more notes to some of the existing features based on my more recent experiences.

RTKLIB on a drone with u-blox M8T receivers

Drones are a popular application for RTKLIB and quite a few readers have shared their drone-collected data sets with me, usually with questions on how they can get better solutions. In many cases, the quality of this data has been fairly poor and it has been difficult to get satisfactory results. I was curious to understand why this environment tends to be so challenging since in theory a drone should have more open skies than just about any other application.

To do an experiment, I bought an inexpensive consumer drone from Amazon. I chose the X8C from Syma since it is beginner model and a little larger than some options. I figured the larger size should make it better able to carry some extra weight.

After a few practice flights to get the hang of flying it, I used some duct tape and double-sided foam adhesive to attach a u-blox antenna and 90 mm diameter ground plane to the top of the drone and a u-blox M8T receiver with my custom CHIP data logger underneath where the camera usually goes. I used the landing gear as a spool to wind the unnecessary five meters of antenna cable which was the heaviest part of the whole setup. From a weight perspective, the Emlid Reach units would have been a better choice, but I wanted to collect data from the Galileo constellation of satellites as well as GPS and GLONASS so I used my CSG receiver with the newer 3.0 firmware. I used a second CSG receiver mounted on top of my car as the base station.  Here’s a stock photo of the drone on the left and after my modifications on the right.

drone1drone2a

Although the drone was able to lift the extra weight fairly easily, it seemed to affect the stability of the flight control system and after a few minutes the prop motors would start to fight each other. At that point the drone would start to descend even at full throttle and the drone would land hard enough to usually bounce on its side or back. Still I was able to make a number of short flights which were adequate for testing purposes.

Here’s the observation data for the first set of flights, base station on the left and drone on the right. Red ticks are cycle-slips and gray ticks are half-cycle ambiguities. Ideally, the drone data would look as clean as the base but as you can see it is significantly worse and it turned out to be unusable for any sort of reliable position solution.  The regions without cycle-slips in the drone observations are the times in between flights in which the drone is sitting on the ground.

drone3

Clearly, while the drone is flying, something is interfering with the GPS receiver or antenna, most likely either EMI or mechanical vibration. I could have used a fancy test stand and RF sniffer to try and locate the source of interference but since this blog is focused on low-cost solutions I just used some duct tape, a steel bar, and the RTKLIB code instead.

I used two types of duct tape, both the polyester/fabric type that everyone calls duct tape, and also the metal foil type that is actually used to repair or install ducts. I first used the non-metal duct tape to securely attach the landing gear to the heavy steel bar. The steel bar was convenient because it was easy to attach but anything heavy enough to prevent the drone lifting off under full throttle would work fine.

I then started an instance of RTKNAVI on my laptop and connected it to the receiver on the drone.  The goal was to simulate a complete drone flight while the drone was sitting on the ground and at the same time watch the RTKNAVI observations to detect any degradation of the measurements.  I used a wireless connection but a USB cable would have worked too.

Unfortunately RTKNAVI won’t plot the observation data real-time, but by selecting the tiny “RTK Monitor” box in the bottom left corner of the main RTKNAVI screen, then choosing “Obs Data” from the menu, I was able to get a continuously updating listing of the observations.  Cycle-slips show up as non-zero values in the first column with the I heading. I chose a location outdoors with open enough skies that any degradation in the observation data would be obvious.

drone4

I first observed the cycle-slip column with the drone powered down to verify I wasn’t getting any cycle-slips on all but the lowest elevation satellites. I then continued to observe the cycle-slip column while sequencing through the steps required to fly the drone. I first powered on the drone, then powered on the transmitter, then issued the calibration/connection sequence, then turned on the throttle to low. So far, so good, no sign of cycle-slips. I then started moving the joysticks to issue steering commands which caused the motors to change speeds. All of a sudden I started getting cycle-slips, the more aggressive the steering commands, the more cycle-slips I saw. Aggressive changes in throttle also caused cycle-slips but full throttle with no adjustments or steering commands was fine.

Next I moved just the antenna, then just the receiver away from the drone while issuing steering commands. Moving the antenna away had no effect but moving the receiver away eliminated the cycle-slips.

At this point my guess was that the interference was coming from the relatively high power switching in the motor control circuits and that the antenna ground plane was shielding the antenna from this interference but nothing was shielding the receiver. To test this theory, I attached a layer of the metal duct tape to the bottom of the drone to act as a shield between the drone controller board and the receiver.  I then re-attached the receiver to the bottom of the drone and re-ran the experiment. This time there were almost no cycle-slips even with the most aggressive steering.

I then removed the steel bar and ran a second set of short flights with the layer of metal tape still in place. I was a little concerned that the new shield would interfere with commands sent from the transmitter to the drone so I first tested everything while still on the ground and then kept the drone fairly close during the flight. Fortunately I didn’t see any sign of commands not getting through.

The drone data looked much cleaner in this flight!  Unfortunately, this time the base data was no good with many simultaneous cycle-slips throughout the observation data. At this point I realized that I had placed the base station receiver directly on the top of the car when collecting the data which was very hot at the time. Usually I keep the receiver in the car to avoid this and only place the antenna on the roof. I have seen this kind of severe temperature effects cause simultaneous cycle-slips before but never to this extent. Again the data was completely unusable.

So, back out there again for a third round of flights. This time, everything looked much better. I still saw a few cycle-slips, especially when first applying the throttle at take-off, so my shielding was not perfect but a dramatic improvement over the first flight. The plots below show the results. The top two plots are position solutions for the z-axis. The top plot is with continuous ambiguity resolution and the middle plot is with fix-and-hold enabled. The bottom plot is the drone observation data.

drone5

I made three adjustments to the input configuration file from what I would normally use for my car based measurements.  First of all, since the drones have very open skies, I adjusted the minimum elevation angles from 15 degrees to 10 degrees.   Then, after plotting and observing the accelerations from an initial solution, I increased the vertical acceleration dynamics estimate (stats-prnaccelv) from 0.25 to 1.0.  Finally, because I was seeing slightly higher position variances in the initial solution than I usually do, I adjusted the position variance AR threshold (pos2-arthres1) from 0.004 to 0.1  Both of these last two changes would make sense if the level of vibration were higher in the drone than I am used to seeing, which is quite likely.

Each time the drone landed/crashed due to the unstable flight control system it would bounce to the side or upside-down and that is what is causing the cycle-slips and switch from fix to float at the end of each flight. As you can see though in every case I quickly get another fix after I put the drone upright again. The fixes are solid enough to hold through the entire flight even in continuous mode for all but one of the flights. With fix-and-hold enabled all flights maintained 100% fix rate. The data is as good as or better than similar experiments where I have mounted the rover on top of a car.

This is not surprising since the skies are more open in this experiment. Having over twenty satellites available for ambiguity resolution also helped. I used all the satellites (GPS/GLONASS/Galileo/SBAS) for ambiguity resolution and took advantage of the new feature in the demo5 b26 code that cycles through all the satellites and will throw a single one out if it is preventing a fix. This will automatically occur anytime the number of satellites available for ambiguity resolution is greater than the config parameter “pos2-mindropsats” which defaults to twenty.

I have added the raw data and the configuration file to the  sample data set section at rtkexplorer.com

I imagine different drones will have different issues and not all will be as easy to fix as this one, but the method described here or something similar should be helpful any time drone data is not looking as clean as the base station data.

The fix I chose was very easy to implement but a better fix would probably have been to wrap just the receiver in a shield rather than placing a shield between the control board and the receiver. This would protect the receiver better and avoid affecting commands sent from the transmitter.  In fact, based on these results, I suspect shielding the GPS receiver on a drone is always a good idea.

Zero baseline experiment

I’ve been busy with some consulting projects recently so it’s been a while since my last post but I’m finally caught up and had some time to write something.  I thought I would describe an experiment I did to both try out the “fixed” mode in RTKLIB and also provide some insight into the composition of the errors in the pseudorange and carrier phase measurements in the u-blox M8T receiver.

The “fixed” mode is an alternative to “static” or “kinematic” in which the exact rover location is specified as well as the base position and remains fixed.  The residual errors are then calculated  from the actual position rather than the measured position.  I describe it in a little more detail in this post.  It is intended to be used as a tool to characterize and analyze the residual errors in the pseudorange and carrier phase measurements.

The basic idea in this experiment was to connect two M8T receivers to a single antenna and then compare residuals between the two receivers.  I first looked at the solution using one receiver as base and the other as rover (the zero baseline case) and then compared solutions between each receiver and a local CORS reference station about 8 km away.

The M8T is typically setup to use an active antenna for which it provides power on the antenna input.  I was concerned about connecting the two antenna power feeds together, so to avoid this, I added a 47 pf capacitor in series in one of the antenna feeds to act as a DC block.  In the photo below, the capacitor is inside the metal tape wrapped around a male to male SMA adapter.  I cut the adapter in half, soldered the capacitor to each end, then wrapped it in metal tape as a shield.

zeroBL

The receivers are from CSG and each one is connected to a Next Thing CHIP single board computer, which logs the data and transmits it over wireless to my laptop.  They are very similar to the Raspberry Pi data loggers I described in a previous post, but the on-board wireless makes them more convenient to use.  At $9 each, they are also quite affordable, especially since they do not need micro SD cards like the Raspberry Pi Zeros.  They also have a built-in LiPo battery connector which can be convenient for providing power., although they can also be powered over the USB connectors.  They are also linux based, so setting them up is very similar to the instructions in my Raspberry Pi post.

I first looked at the zero baseline case where I used one receiver as base and the other as rover.  In this case the two receivers are seeing exactly the same signal from the single antenna.  Any error contributions from the satellites, atmosphere, or antenna should cancel and the only contributor to the residual errors should be from the receivers.

I collected about an hour of measurement data from my back patio.  It is next to the house and nearby trees so as usual, the data quality is only mediocre and will include both some multipath and signal attenuation.  I prefer to look at less than perfect data because that is where the challenges are, not in the perfect data sets collected in wide-open skies.

Here are the residuals for a high elevation, high signal strength GPS satellite.  Standard deviations are 0.24 meters for the pseudorange and 0.0008 meters for the carrier phase.

zeroBL1

For a lower elevation GPS satellite with low and varying signal strength, the standard deviations increased to 0.46 meters for the pseudorange and 0.0017 meters for the carrier phase.  Notice how the residuals increase as the signal strength decreases as you would expect.

 

zeroBL2

The GLONASS satellites had noticeably higher residuals.  Here is an example of a satellite with high elevation and reasonable signal strength.  The standard deviations were 1.02 meters for pseudorange and 0.0039 meters for carrier phase, more than twice the GPS residuals.

zeroBL3

I’m not quite sure how relevant it is, but the ratio between the pseudorange residuals and carrier phase residuals in each case is roughly 300, the same value I have found works best for “eratio1”, the config file input parameter that specifies the ratio between the two.

RTKLIB also estimates the standard devations of the GLONASS satellites measurements at 1.5 times the standard deviations of the GPS satellites which is less than the difference I see in the example above.

However, my numbers are for only the receiver components of the measurement errors, I’m not sure exactly which components the RTKLIB config parameters are intended to include.

For the second experiment, I calculated solutions for both receivers relative to a CORS reference station about 8 km away.  In this case, I was curious to see how close the two solutions are as they will have common satellite, atmospheric, and antenna errors but will differ in their receiver errors.  The plot below shows the residuals for a GPS satellite from each solution plotted on top of each other.  As you can see the errors are quite a bit larger than before and the correlation between the two receivers is very high.  Based on the frequency of the errors, I suspect they are dominated by multipath which will vary roughly sinusoidally as the direct path and reflected path go in and out of phase with each other.

I found it quite impressive to see how repeatable the errors are between the two solutions.  It indicates, at least at this distance, that the errors from the receiver are small compared to the other errors in the system.zeroBL4

Again, the GLONASS results were not as good as the GPS results and include a DC shift in the carrier phase that I’m not sure exactly what the cause is.

zeroBL5

I haven’t spent a lot of time trying to figure out how to best use the information in these plots but in particular I found the similarity between the two receiver solutions in the longer baseline experiment quite encouraging.  If the errors are dominated by multipath as I expect, then the baseline length isn’t that relevant and I would expect to see similar results with shorter baselines.  If that’s true, then it may be possible to derive information about the receiver’s environment from the multipath data.  People do this with more expensive dual frequency receivers to monitor things like tides and ground moisture content.  It would be interesting to see if it can be done with these low cost receivers.  Or maybe it already has been done …

 

New firmware, new satellites, new code

CSG Shop is now shipping all of their M8N and M8T u-blox receivers with the latest version 3 firmware.  This is not such good news for the M8N units since the raw measurements are scrambled and these receivers need to be downgraded to the previous firmware version before using with RTKLIB.  For the M8T receivers though, the new firmware is good news because it contains support for the Galileo satellite system.

I now have two of their M8T receivers with the new firmware and did a little testing to see how RTKLIB works with the Galileo measurements.  I did have to make a couple small changes to get things working.

First of all, the RNX2RTKP compile options for including the Galileo code was not enabled.  For some reason, all the other apps did have this option enabled.  To enable it, I had to add “ENAGAL” to the “Preprocessor Defintions”  for C/C++ in the Project menu in Visual Studio.

The second issue I ran into was in the decode_rxmrawx() function that decodes the raw u-blox RXM-RAWX messages.  There is a line of code in this function that sets the code type based on the system.

raw->obs.data[n].code[0]=
       sys==SYS_CMP?CODE_L1I:(sys==SYS_GAL?CODE_L1X:CODE_L1C);

This line sets the code to L1X for Galileo, but that code type doesn’t seem to be supported by RTKLIB and the measurements in the RINEX file for the Galileo satellites get left blank.  Changing the “L1X” in the above statement to “L1C” resolves the problem.  That leaves an unnecessary check in the code but I will leave it there at least until I understand what it was supposed to do.  After that everything else worked fine including ambiguity resolution with the Galileo satellites, so that was quite encouraging.

Next,  I put the two receivers outside in the front yard to collect a longer set of data.  Not an ideal environment because they were close to the house but fairly open skies otherwise.  In an hour of data collection I got measurements from 11 GPS satellites, 8 GLONASS satellites, 5 Galileo satellites, and 3 SBAS satellites. After collecting the data, I processed it with various constellation options to see how they compared.  For all the solutions, I set ambiguity resolution mode to “continuous”, position mode to “kinematic”, and opened up the position variance threshold for AR (arthres1) to allow the solution to lock up as early as possible.  I also enabled all constellations for ambiguity resolution in each case.  Here’s how they compared:

satcombos1a

satcombos1b

Note that the time scale on the GPS-only plot is very different than the others since it took much longer to lock up than any of the other combinations.  With the GPS satellites only, there was an initial short false fix after 14 minutes, then a good fix at 27 minutes that lasted a few minutes but it did not get a solid fix until 43 minutes after it started.  That’s a long time to wait!  Adding a second constellation significantly improved the results, with solid fixes coming after two minutes with GLONASS added, five minutes with SBAS added, and 7 minutes with Galileo added.  Adding a third consellation improved things even more, with times to first solid fix varying from 12 secs for GPS+SBAS+GLO, 3.5 min for GPS+GAL+GLO, and 6 min for GPS+SBAS+GAL.  Using all four constellations gave a time to first solid fix of 2 minutes, not the fastest time, but better than two out of three of the three constellation answers.

It is risky to conclude too much from one data set, but these results are consistent with other data I’ve looked at (for three constellations) that show the more satellites you use the better the answer.  This seems to make sense to me since more information should be better than less information.  However, I often hear or read recommendations to use only the GPS data for better results which I don’t understand.  If anyone has data to support that recommendation I would like to see it to understand it better.

I do sometimes see that one bad satellite can prevent or delay a solution no matter how many good satellites there are and this may be part of the answer.  The more satellites you use, the higher chance there is of having a bad one and RTKLIB is not great at rejecting a bad satellite.  The “arlockcnt” and “ARFilter” features do help prevent bad satellites from getting into the AR solution but they do not reject a satellite if it goes bad after being accepted into the solution.  I have added a new feature starting with the demo5 b26a code that does try to reject bad satellites after they have been accepted into the AR solution but have not had a chance to do a lot of testing on it yet.  It was enabled for the test above and may possibly have helped, I did not look into the details.  The feature is enabled by setting the “pos2-mindropsats” to a value lower than the number of satellites in the solution, in which case it will cycle through dropping all the satellites, one by one, one each epoch, and reject a satellite that has a large negative effect on the AR ratio.  If you try this feature, be careful not to set the minimum satellite threshold too low or you will increase the chances of a false fix.  I would recommend values no lower than 10 satellites.

I have released a new version of the demo 5 code (b26b) with the fixes for Galileo, a couple of new features and fixes, and GUI updates for RTKPOST and RTKNAVI for all the new input parameters for both b26a and b26b codes.  The binaries and a list of the changes are available here.  The source code is available on my Github page.