Fix-and-Hold extended to GLONASS and SBAS

I have just added a demo3  branch to my GitHub repository with a couple of new features.  The first is an extension of the fix-and-hold feature to enable ambiguity resolution for the GLONASS and SBAS satellites. This is what I will discuss in this post. I have also added a ambiguity resolution filter to prevent misbehaving satellites from being added to the set of satellites used for AR but I will leave that to a future post.

A couple posts back I discussed double differences of the raw data and the kalman filter phase-bias states, in the context of cycle slips. I will do something similar here but this time focusing on the initial acquire, when the solution first locks on to the correct set of integer ambiguities.

First, let’s go over a little background material.

The kalman filter can have a varying number of states depending on the input configuration settings but the most important states are the position states and the phase-bias states. The position states are estimates of the receiver position. The phase-bias states are estimates of the missing offsets that need to be added to the carrier phase measurements. There is one for each satellite, and they represent single differences between measurements from the two receivers. Subtracting one phase-bias state from another results in a double difference, which is what we looked at in the earlier post. If all error sources are counted for exactly, then the double differences will always be integers for geometric reasons.

At the end of each epoch, after the phase-bias states have been updated, the integer ambiguity resolution algorithm attempts to map the set of double differences float values to a set of integers. If it can do that with enough confidence to meet the ambiguity resolution criteria, then we have a fix and the plot line in RTKLPOT will switch from yellow to green. RTKLIB then uses the phase-bias estimates to update the position states. If we have a successful ambiguity resolution, the position states are updated from a position derived from the set of integers and is referred to as a fixed solution. If the ambiguity resolution was unsuccessful, the position update is derived from the non-integer phase-bias values instead and is referred to as a float solution.

In the example below, from RTKPLOT, the first successful ambiguity resolution occurs between 17:30 and 17:31, at which point you can see the switch from yellow to green, and the sudden jump in position when it is first derived from the integer values instead of the float values.


Unlike the position states, the phase-bias states are always updated from the float values and not the integer values, whether a successful fix occurred or not. Hence there is no corresponding jump in the double difference phase-biases when the first fix occurs. You can see this in the plot of a phase-bias double difference plot below for the same example as above.  There is no jump where the first fix occurred between 17:30 and 17:31 in either plot line. The red line is for a run with continuous ambiguity resolution, the blue line for one with fix-and-hold enabled.

So that’s a quick attempt to describe the ‘fix” in “fix-and-hold” What about the hold?

In the plot above, you can see in the red line for the continuous AR run that there is no discontinuity at all. The phase-bias double difference gradually and continuously approaches the the actual double difference integer of 4. That is what happens when there is no “hold”. When fix and hold is enabled however, and the hold criteria are all met, then an additional update is made to the phase bias states using the set of integer values from the ambiguity resolution. This is a very high gain update and the response in the phase-bias filter states is almost immediate. In the plot above, hold is enabled between 17:31 and 17:32, and you can see the response in the sudden jump in the blue line.

In the plot below, the same phase-bias DD is plotted on the left with fix-and-hold enabled. The lower plot is zoomed into when the hold occurs. You can see the correction is nearly immediate and the result is very close to the actual integer value on the first correction. This is for a GPS satellite. The significant errors for the GPS satellites are all accounted for,at least for short baselines, and so the initial correction can be quite accurate.  The corrections continue every epoch for which the hold criteria are met, and if the remaining error is visible to the kalman filter, the value will continue to converge to the integer value.


Below is the same plot for a GLONASS satellite. In this case, there is a significant unaccounted for error in the double difference, namely the inter-channel bias that we’ve discussed before, and which comes from the fact that the GLONASS system uses multiple frequencies. This error is invisible to the kalman filter and hence the double difference never converges to the actual integer value. You can see below, the jump to near zero from the hold update, but then the line does not converge towards zero after that.

But we know the double difference really is an integer, and at this point we should have accounted for all the other significant errors, so it might not be entirely unreasonable to assume this remaining difference is caused by the inter-channel bias and remove it, especially if we remove it slowly enough that the removal does not interact with any other feedback path.  We need to be careful how we handle it though. It won’t work to try and simply push the bias-estimate to the nearest integer. If we did that, the feedback loop would see the error and push it back. Instead we create a new array of variables to hold the inter-channel biases and move the error for each GLONASS satellite into this array. We can then adjust the double differences by these error values before feeding them into the kalman filter. To see exactly how this is done, you can look at the changes in holdamb() where the biases are adjusted and ddres() where the IC biases are removed from the kalman filter errors. To avoid upsetting anything else in the loop, I chose to be quite conservative about how quickly the adjustment occurs. It does not need to be done quickly. The plots below shows the error removed from the phase-bias state at a 0.5% per epoch rate (red) and a 1% (yellow) rate.  Again, the lower plot is zoomed in to after the hold.



This is fast enough to remove enough error to resolve the GLONASS ambiguities in 1 to 2 minutes after the GPS ambiguities have been resolved.  If necessary it could probably be done much more quickly.   Note that we do need to wait until the GPS ambiguities are resolved before beginning this process because before that point we have not yet accurately determined the other error terms.

Here’s an example ambiguity resolution output from the trace file for a run with this feature enabled.


Each double difference is made up of a reference satellite and a fix satellite. They are listed in the first two lines. “N(0)” is the float solution for the double differences. “N(1)” is the set of integers with lowest residuals, and “N(2)” is the set of integers with the second lowest residuals. “Ratio” is the ratio of the residuals between the best two sets. In general, the larger this number, the more confidence we have in the solution. Satellite numbers less than or equal to 32 are GPS, 33 to 59 are GLONASS. In this example there are seven GPS satellite pairs, and four GLONASS pairs. The other three pairs are SBAS satellites paired with a GPS satellite. I’m not sure why SBAS satellites are not usable without this feature since they use the same single frequency as the GPS satellites, but at least with the NEO-M8N, I have found that until I added this feature, I had to disable them. Unfortunately, unlike the GLONASS satellites, RTKLIB does not have a mechanism to allow SBAS satellites to be used for positioning without ambiguity resolution so they have to be removed completely.

In this example, after adding the SBAS satellites, enabling this feature has doubled the number of satellite pairs used for ambiguity resolution, and increased the number used for positioning by almost 25%.

So far, I’ve tried this on several data sets and have consistently resolved the ambiguities on the GLONASS and SBAS satellites, but I would say it is still fairly experimental at this point. If you’d like to try it on your data, you can download the code from the demo3 branch. To enable the feature for the GLONASS satellites, set “pos2-gloarmode” in the config file to “fix-and-hold”. If you want to enable the SBAS satellites as well, set bit1 in “pos1-navsys” .

If you do try it, let me know how it goes. I’d be happy to help if you have any difficulties with it. You can always contact me at

For those of you that read my previous post on GLONASS integer ambiguity resolution, this method is related to that one, but I think this should do a better job of driving the IC bias errors to zero because of the more continuous, lower gain nature of the updates to the IC biases.


New Data: Moving Rover / Fixed Base

All of the analysis I have done so far has been done on data sets where both receivers were attached to the rover. The only exception was one post where I used a CORS reference station as the base. This made the solution verification easier than the more normal case where one receiver is fixed and the other is attached to the rover since the solution is always a circle. There are some reasons however why the two moving receiver case is not identical to the typical fixed base case. The most obvious differences are shorter baselines, correlated antenna orientation, and more cycle slips when both receivers are moving.

Yesterday I collected some more data, the first moving receiver data I have collected myself since December. This time I used the two Ebay receivers, a GY-GPSV3-NEOM8N and a GPSV5-NEOM8N (identical except one has a magnetometer that I did not use) and the two antennas that came with these receivers. Total cost for both receivers, antennas, and shipping was $56.

I again drove around a parking lot with good sky views with one receiver attached to the car roof, but this time the second receiver was sitting on a rock next to the parking lot. Here’s a couple of photos of the two receivers, the first one stuck on to the top of the car with some double sided foam tape, the second sitting on a rock to raise it above the surrounding long grass.



The car roof acted as a ground plane for the moving receiver. I forget to bring a ground plane for the fixed antenna but managed to create something vaguely ground-plane-like from a discarded beer can I found nearby. While this is certainly in the spirit of ultra-low cost, I’m not sure how effective it was and plan to go back to my 40 cent pie tin next time.
I took three fairly short data sets. The first was without a ground plane on the base antenna, the second was after adding my beer can ground plane, and the third was with the sample rate increased from 1 Hz to 5 Hz. All three data sets included GPS, GLONASS, and SBAS satellites in the raw data, although only GPS and GLONASS were used in the solution, and only GPS was used for ambiguity resolution.

In order to get the 5 Hz sample rate to avoid missing samples I had to increase the baud rate from 115K to 230K. I did still have some NMEA messages enabled that RTKLIB doesn’t use. The lower data rate would probably have worked if I had disabled these messages. I was not certain the 5 Hz would work since seen I have seen it stated online that the NEOM8N does not support 5 Hz data but in my case, it seemed to work fine.

I ran my Demo2 code and configuration file  on all three data sets and got clean solutions for all three. The third data set was intended to run longer but the battery died on one of my laptops fifteen minutes before I finished collecting the data. For the 5 Hz data set I should have modified the config file to adjust the inputs that are in units of counts instead of seconds to account for the different sample rate, but since the results looked good even with the sub-optimal settings, I did not bother to go back and re-run it after I realized my mistake.
Here are the ground tracks, positions, and velocities for the three cases

  No ground plane: 1Hz                  Ground plane: 1 Hz                      Ground plane: 5 Hz

Ground tracks:track1.png



While encouraging from a performance standpoint, this data does not give me much opportunity to make improvements since it is quite clean. I hope to go back in the next few days and take some more data, this time increasing the distance between base and rover and including more minor sky obstructions to see if I can stress the solution more.

These results also strengthen my belief that for relatively friendly environments and with some additional robustness improvements, an ultra-low cost hardware set combined with RTKLIB could be a usable solution. Of course it will take more data to make this more than just a suggestion.


Double Differences and Cycle Slips

In this post I am going to look at some of the raw satellite data directly without using RTKLIB to calculate a solution.  Because of the complexity of the full solution, it is easy to start treating RTKLIB as a black box, adjusting input parameters to see how they affect the output without really understanding what is going on inside. It is often possible, however, to simplify the problem down to something we can solve, or at least analyze, with some very simple calculations. Doing this can provide some real insight into what is going on inside the more complex full solution.

In this case, I have a data set from my two M8N receivers, both stationary and within a couple meters of each other with skies partially obscured by trees. There are enough cycle slips in the data to cause RTKLIB some trouble with the solution. The eventual goal here is to improve RTKLIB’s response to cycle slips, but to start with I just want to understand more about what the signals look like during the cycle slips.

Since the two receivers are very close together, double differencing should be very effective at cancelling errors from the ionosphere and troposphere as well as the receiver and satellite clock biases. Since the receivers are stationary, the position component of the double differences will be constant and can be ignored. Double differencing is a very powerful error cancellation technique and is the basis for all differential GPS solutions.  I’ll skip a detailed tutorial here, but if you aren’t familiar with how and why it works, a Google search will quickly bring up many explanations better than I could give.

To get the double differences, we first calculate the single difference value for each satellite by subtracting the raw carrier phase measurement from one receiver from the raw carrier phase measurement from the other receiver. Since the satellite clock bias and atmospheric error terms are in both measurements, they will be cancelled or at least minimized by this subtraction.

Next, we subtract the single difference value from one satellite from the single difference value from a second reference satellite.  The result is the double difference. This second subtraction will cancel the receiver clock biases, further reducing the errors. Since the receivers are stationary (relative to each other) the position component of the double differences will be constant and so the dominant remaining component will be the phase bias. The phase bias should also be constant unless there is a cycle slip.  So, what we expect to see in the double differences is a constant value if there is no cycle slip, and a jump equal to the size of the slip if there is a slip.  For this exercise we don’t care about the actual values of the phase biases, only any changes in the values.

The cycle slips are reported by the receiver in the raw data. One thing to be aware of it that the receiver is reporting possible cycle slips, not confirmed cycle slips, so not all the reported slips are real.  How many of the reported slips are real is something I hope to be able to tell by looking directly at the double differences.

I wrote a simple matlab script to parse the raw observation files (*.obs). This is quite a bit easier if the observation files are in Rinex 3 format rather than the older Rinex 2 format. This is a configuration option in RTKCONV and CONVBIN to select this. Unfortunately it does not seem to work in CONVBIN so I had to use RTKCONV to create the observation files. Here is a snippet of the Rinex 3 observation file for a typical cycle slip on a single satellite.


The top line is the time stamp, each line below is for one satellite. In this example, the first column is the satellites number, the third column is the carrier phase. A cycle slip shows up as a fourth digit after the decimal point in the carrier phase measurement. In this example there is a cycle slip for satellite R8.

Here is another example, but in this case, the cycle slip is reported for all satellites.


This is very difficult for RTKLIB to deal with since the cycle slips, whether they are real or not, immediately cause it to reset the phase bias estimates. In this case, RTKLIB resets all the bias bias estimates and has to start over completely. We’ll use this example to look more closely at what is going on inside the solution.

Let’s look at the G13 satellite first. We’ll use G12 as the reference satellite since that is what RTKLIB used. Here are the carrier phase measurements for both satellites from the two receivers, pulled from the observation file.


Note the y-axis has a scale of 10^6. Even though the receivers are not moving relative to the earth, the distance between the satellites and the receivers is changing quite quickly. This is because the satellites are moving and because the earth is rotating.

Below is the single difference measurement for G13, calculated by subtracting the rover measurement (yellow line above) from the base measurement (purple line above). The mean is also subtracted to center the plot around zero. The red circles are where cycle slips occurred.


The cancellations that occur from the subtraction have reduced the y-axis scale down from 10^6 to just tens of cycles but the remaining variation is still too large to see a cycle slip. Again, this calculation is done directly on the raw data from the observation file, RTKLIB is not used at all to process the data.

Next we get the double difference by subtracting the single difference measurement for the reference satellite (G12 in this case) from the single difference for G13 plotted above. Again the mean of the result is removed to center the result around zero. This results in the plot on the left below. Again, the red circles are where cycle slips occurred.


We have now cancelled some additional errors and the variation on the y-axis is very small, in fact small enough to see a cycle slip. It is quite encouraging how this very simple mathematical operation on the raw data can give us such meaningful results.

The above plot on the right comes from data in the RTKLIB state output file and shows the kalman filter estimate of the phase-bias for satellite G13. Again the mean is removed so only the variation is relevant. The large excursions occur when the kalman filter states are reset because of the reported cycle slips. The filter states are re-initialized using the pseudorange measurements which are much less accurate than the carrier-phase measurements but give an absolute value rather than just a relative number. As you can see, in this case it takes several minutes for RTKLIB to fully recover the phase bias estimate but when it does, it converges back to the same value as before the reported slip.

Looking back at the plot on the left, we can see for the first cycle slip there is no jump in the measurement. If there was a cycle slip we would expect a jump in this measurement equal to the size of the cycle slip. For the second cycle slip there is a brief half cycle discontinuity which I don’t understand, but since it quickly returns to zero we’ll ignore it, at least for the time being.

What our very simple calculation is telling us is in this case is that neither potential cycle slip reported by the receiver was actually real and RTKLIB would have done much better to not have reset the phase bias estimates. This is also confirmed by RTKLIB since it eventually converges back to the same phase-bias estimate as it had previous to the potential cycle slip.

Let’s look at another satellite from the same reported cycle slip.  On the left below is the double difference for G18 calculated directly from the raw data just as we did for G13 above. On the right again is the kalman filter estimate of the phase bias from RTKLIB and in both plots, the reported cycle slips occur at the red circles.


This time the first cycle slip is real and you can see the two cycle jump in the double difference value on the left. On the right you can see that RTKLIB eventually settles on the same two cycle slip, but takes several minutes to figure it out. The second cycle slip again causes a brief half cycle deviation in the double difference but then returns to zero, and again we will ignore it.

Based on the plots on the left which are generated with only three basic subtractions using the raw carrier phase data, it appears that RTKLIB could be doing a significantly better job of handling cycle slips. Not only in determining if potential reported cycle slips are real or not, but also in correcting the cycle slip more quickly when it is real. It is true that the baseline in this example is very short and with longer baselines the errors in the double differences will be greater, making things more difficult, but I still have to believe there is opportunity for improvement here.

In the example above, of the thirteen satellites processed by RTKLIB, all of which were reported in the raw data as having cycle slips, only four of them actually did. Even if RTKLIB reset the phase-bias estimates for the four satellites with slips, it would still handle the slip much better using the other nine satellites than it does now where it resets all thirteen phase-bias estimates. If it could correct the slip as well as correctly identify it, the robustness to slips would be even greater.

I am actually quite surprised how clear cut the cycle slip examples I looked at are.  I expect this is not always the case or cycle slip correction would probably have been added to RTKLIB a long time ago.  Still, I hope to use this approach to try and add some amount of cycle slip detection and correction to RTKLIB, even if it can only be applied in some subset of cases.

Anyone else have experience trying something like this?

Raw data collection: Cycle Slips


Recently, I have been given several raw data sets from readers to take a look at. Some of them I have been successful at improving the results and some of them I haven’t. In general, success or lack thereof, seems to be most dependent on the number of cycle slips in the data. So, it’s worth spending a little time discussing this subject.

Cycle slips occur when the receiver loses lock with a satellite and loses count of the number of carrier phase cycles. They can occur on either the base or the roving receiver but tend to be more common when the receiver is moving. They can be caused by obstructions, reflections, high accelerations, vibration, EMI, lack of antenna ground planes, or anything else that degrades the quality of the satellite signal. Once a cycle slip has occurred, the receiver has lost track of the cycle count and can not recover it. This means that the kalman filter state in RTKLIB that is estimating the cycle count offset for that satellite (the phase-bias) must be reset. Even if the cycle slip occurs for only a single epoch, the cycle count is lost for good, and the phase-bias estimate must be reset and re-converged. This can easily take 30 secs or longer.

The best way I have found to evaluate the quality of the raw data regarding cycle slips is to plot the observation data with RTKPLOT. I have had trouble with the 2.4.3 version of RTKPLOT when plotting observation data and have switched back to using the 2.4.2 version for doing this.

[Note: 12/14/16:  RTKPLOT in the more recent versions of 2.4.3 code appear to be fine.]

To plot the data, select “Open Obs Data” from the file menu, and select the observation data file (*.obs) for the base receiver. Select “Options” from the Edit menu, and set the “Cycle-Slip” option to “LLI Flag”. Then open a second RTKPLOT window, and do the same for the rover observation data. You should see something like this.



This is the observation data for the parking lot data set used in demo1. Each horizontal yellow line is a different satellite. Each vertical red tick is a cycle slip. The left plot is for the base receiver, the right plot is for the rover receiver. As you can see, some satellites have many more cycle slips than others. In general, the low elevation satellites will have many more cycle slips. In the solutions I ran for this data, I had the elevation mask set to 15 degrees to filter out the lowest elevation satellites. We can remove these satellites from this plot by setting “Elevation Mask” in the RTKPLOT options menu to 15. This gives me the plots show below.


As you can see, the number of cycle slips is significantly reduced by eliminating these satellites. This exercise can be useful when trying to decide what elevation mask to use in the solution configuration file.

Notice that there are still many slips between 18:13 and 18:15 in the data. During this period of time, I had left the parking lot and was driving at higher speeds on roads with obstructed skies. I did not use this part of the data set in my examples and am not able to get good results for this data because of the number of cycle slips.

Here is an example of a data set I was given for which I was not able to get any decent solution for. Again the elevation mask is set to 15 degrees.


In this case the base data is very clean, only a single cycle slip but as you can see, the rover data is very poor for most of the satellites. In this case, the rover receiver was mounted on a drone so the sky should have had good visibility but there may have been antenna, vibration, or EMI issues.

In general, it is worth spending the time up front to minimize the number of cycle slips rather than trying to deal with them later by adjusting RTKLIB input configuration settings. You can use these plots to determine which receiver and/or which satellites are causing most of the cycle slips and then focus on those .

Be sure you are using decent ground planes for your antennas. Ublox recommends using 50-70 square mm ground planes but larger will work as well. There are more suggestions in this document from Ublox for antenna set-up and EMI interference guidelines.

Anything you can do to minimize accelerations will also reduce cycle slips, whether this is reducing maximum acceleration of the rover directly, or improving the mounting so there is not additional vibration or indirect accelerations (e.g. receiver mounted  on top of a post).

If nothing else works, you may need to consider investing in higher quality antennas.

New Github Branch: Demo2


I have created a new Github branch in my repository and called it demo2.  It includes the code and configuration changes as well as the data from the two sets of kayaking data in the last few posts.

Specifically it includes the following modifications from demo1:


Both data sets are in the rtklib\data\demo2 folder. Fore1.ubx and Aft1.ubx are the first data set. Fore2.ubx and Aft2.ubx are the second data set. Note that both data sets have 5 samples per second. In demo1, the data had only 1 sample per second. This will affect any input configuration parameter that has units of counts, since generally the time periods should not be dependent on the sample rate. The receiver is actually sampling at a much higher rate than the output so, in general, increasing the output sample rate should only increase the resolution of the data, not the precision or accuracy.


  • Added an additional position variance constraint for fix-and-hold to avoid erroneous holds occurring before the kalman filter has had time to converge as described in the previous post.
  • Updated the writes to the trace file to make the trace output more meaningful for my experiments

Configuration File:

  • pos2-arthres: 0.999 → .002 ( variance threshold, the original value was unused)
  • pos2-arlockcnt: 30 → 150 (Both values are 30 secs, different sample rates)
  • pos2-arminfix 10 → 100 (10 sec → 20 sec)
  • pos2-minfixsats 4 → 5   (minimum valid satellites for fix)
  • pos2-minholdsats 5 → 6  (minimum valid satellites for hold)
  • remove unused parameters (arthres2, arthres3, arthres3, armaxiter)

I’m always interested in other people’s experiences. Please leave a comment if you find other interesting observations with this data or code or configuration changes, or if you have any questions about them.

Another Kayak Data Set: Fix-and-Hold Fails Again

Matt from Reefmaster was kind enough to send me a second data set from another two hour kayak session on the water so I thought I’d run it with the latest configuration/code. I ran it with fix-and-hold enabled both with and without GLONASS ambiguity resolution enabled. With GLONASS AR, everything looked great. Without GLONASS AR I got another false fix that corrupted the kalman filter states and caused the rest of the solution to be very poor. At this point I am really starting to question the value of fix-and-hold, but I’m not quite ready to give up on it yet.

The previous two false fixes I looked at had fairly obvious causes. In the first case the fix occurred with only a very small number of valid satellites. In the second case, the error occurred before the kalman filter states had time to converge. This case, unfortunately, does not have any obvious single cause.

Before getting into the details, lets review all of the input configuration constraints that need to be met for fixes and holds to occur. Here they are along with the values I used for this experiment

Fix Constraints:

  • AR ratio > pos2-arthres                                                      (3.0)
  • # of valid satellites > pos2-minfixsats                           (4)
  • # of samples since satellite lock > pos2-arlockcnt    (150)  30 sec*5 samples/sec
  • elevation for each sat > pos2-arelmask                         (15) 

Hold Constraints:

  • # of consecutive fixes > pos2-arminfix                          (50) 10 sec*5 samples/sec
  • # of valid satellites > pos2-minholdsats                        (5)
  • position variance < pos2-arthres1                                   (.002)
  • elevation for each sat > pos2-elmaskhold                    (0)

The constraints in blue are the ones I have either added or fixed. Note that pos2-armaxiter, pos2-arthres2, pos2-arthres3, pos2-arthres4 are listed in the configuration file but are not used by the code.

OK, time for the details. From the trace file I can see that the very first fix attempt after the position variance constraint was met is a false fix. A short time later after the minimum number of consecutive fixes constraint (arminfix)  is met, the hold occurs, and the bad fix is fed into the kalman filter. There were five valid satellites both when the first fix occurred and when the hold occurred.   

To make this easier to see, I have added some additional writes to the trace file into the code.  This includes the satellites used for fix and the position variance.  N(0) is the float solution, N(1) is the lowest residual fixed solution, and N(2) is the 2nd lowest residual fixed solution.

Output from trace file:

3 P[0]=0.001998
3 ddmat :
3 refSats= 2 2 2 2
3 fixSats= 5 7 9 30
3 N(0)= -18.475 -9.131 -6.555 16.554
3 N(1)= -19.000 -9.000 -7.000 17.000
3 N(2)= -17.000 -6.000 -1.000 18.000
3 resamb : validation ok (nb=4 ratio=4.56 s=82.25/375.07)

By plotting the solutions using “fix-and-hold” and “continuous” modes I can see that in continuous mode, the false fix lasted for approximately 16 seconds (blue/yellow) before unlocking. With fix-and-hold enabled, the false fix continued for much longer (blue/green).


From these observations it is apparent that the false hold could be prevented by adjusting any one of several input parameters. Specifically, increasing arthres, arthres1, arminfix, or minholdsats would avoid the false hold.

With just one example it is difficult to know which is the best parameter or parameters to adjust.  I chose to increase minholdsats from 5 to 6, and increase arminfix from 10 seconds to 20 seconds. Since, in this example, there were 5 valid satellites, and the false fix lasted for 16 seconds, either change by itself will avoid the erroneous hold, but we’ll change both.  By making these changes, fix-and-hold will get invoked less, but we will have higher confidence that it is not being invoked in error.

Rerunning with these changes and then calculating my standard metrics for the results produced the following plot, where the cases on the x-axis are:

  1. GLONASS AR off, fix-and-hold 
  2. GLONASS AR off, continuous
  3. GLONASS AR on, fix-and-hold
  4. GLONASS AR on, continuous



As you would expect, the best results occurred when both GLONASS AR and fix-and-hold were enabled (case 3). However, I would be very careful enabling fix-and-hold in any real application without some significant testing and probably some adjustment of the input parameters to match your particular environment.