Ublox M8N vs M8T: Part 3


This is the third part in a series of posts comparing data from a pair of Ublox M8T receivers with data from a pair of Ublox M8N receivers. In the first post I identified a problem with erroneous fixes in the RTKLIB solution for the M8T data. In the second post I found that the source of the problem appeared to be in the handling of cycle slips in the translation from the receiver binary output to the text input used by RTKLIB. I also showed that adopting an algorithm more similar to the one used to translate the M8N binary improved but did not entirely fix the problem. In this post I will show that if the cycle slip translation is more precisely adapted to the differences in binary output between the M8N and the M8T then we can virtually eliminate the erroneous fixes and get an M8T solution that is now slightly more accurate than the M8N solution.

One thing I may not have made clear in the previous posts is the way I am collecting and processing the data from the Emlid Reach M8T receivers. I am using their ReachView software to collect the raw GPS data but all the processing is done afterwards using my own demo4 version of RTKLIB. I don’t have access to Emlid’s RTKLIB source code and don’t know if they have made any changes that might have improved this issue in their own real-time version of RTKLIB. So this is more a comparison between the M8N and the M8T receivers using my version of RTKLIB and not an evaluation of anything specific to the RTKLIB version of Reach.

Last post I finished with this plot showing the difference between the M8N solution and the M8T. For reasons I’ve explained before, we know this should be a perfect circle with a radius equal to the distance between the receivers.


By looking at spikes in the z-axis accelerations we were able to show that the deviations from the circle in the above plot were due to errors in the M8T solution and not the M8N solution. This plot was taken after I had modified the binary to text translation in RTKCONV to make the M8T translation more similar to the M8N translation. Before that, the errors were much larger.

Let’s start by taking a closer look at the binary outputs of the two receivers. The details for the M8T are available in the M8 receiver spec and for the M8N in this document from Tomoji Takasu but I will summarize them here.

Both receivers provide three values for each satellite output sample that can be used to evaluate the quality of the carrier phase measurement. The first is the carrier-phase valid bit. Both receivers provide this in the tracking status byte. It indicates that the receiver is currently locked to the carrier-phase for this satellite. Note that it does not tell us if the receiver has been continuously locked since the previous output sample and it also does not indicate anything about the quality of the measurement.

The second output (locktime or lock2) indicates how long the receiver has been locked to the carrier-phase for this satellite. If this count is lower than the count for the previous sample, then an unlock, i.e. cycle-slip, has occurred. Both receivers also provide this value, and this is what RTKCONV uses to detect a cycle-slip.

The third value (mesQI or cpStdev) is a quality indicator and this is where the receivers differ. On the M8N this appears to be more of a state indicator than a true quality indicator. The comments indicate that it’s value corresponds to:


For the M8N, the RTKCONV code throws out any phase measurement for which this quality indicator is not between 4 and 7.

On the M8T, the quality indicator is actually a numeric estimate of the standard deviation of the carrier phase measurement. If the value is between 1 and 7, then the estimate of standard deviation is this value multiplied by 0.004 meters. If this value is 15, then there is no valid estimate. This value is currently ignored by the RTKCONV code and that is the root of the problem.

Before discussing how to modify the code to incorporate this information, we need to understand exactly how the cycle-slip bit is interpreted by RTKLIB. On a sample for which this bit is set, RTKLIB will reset the phase-bias state for that satellite based on that carrier-phase measurement. Note that the reset is done using the measurement from the current sample, not the following sample. What this means is that the cycle-slip bit should not be used to indicate that there is a cycle-slip on the current sample. Rather it should indicate that there has been a cycle-slip since the last good measurement and that the quality of the current sample is now high enough to use it to reset the phase-bias state.

So how high should the quality indicator be before resetting the phase-bias? It will be a trade-off between time and accuracy. I chose the value of four since it’s in the middle of the scale and somewhat equivalent to what is used on the M8N, but it could be argued that this value should be higher or lower. Forcing the cycle-slip to be set on a good sample also eliminated the problem we previously saw with samples subsequent to the cycle-slip not being flagged, so I was able to remove the code I added in the previous post.

Here are the changes I made to the original code for the M8T receiver. The new variable cpstd is the standard deviation of the carrier phase measurement as described above. The constant STD_SLIP is the quality threshold described above and is set to 4.


Here is the position solution calculated with the above code change.


Here is the difference in position between the two solutions. As you can see, the deviations from the circle have been significantly reduced.


The noise in the z-axis accelerations has also been significantly reduced and is now slightly lower than in the M8N data.

       M8N                                                                           Reach M8Twalker16

I have posted the raw data and config files to my data set library in the niwot2_car folder and the code changes to my Github page.


11 thoughts on “Ublox M8N vs M8T: Part 3”

  1. Hello,
    sorry for posting so long after the initial article.
    When looking on the M8N – what would be a good way to substitute the MESQI 0-7 indicator, as this is not implemented in versions >=3.0 .
    I am currently using the lock1 & lock2 (code & carrier lock count) e.g. if both are larger than 10, but this seems to result in jumping results of the AR values and frequent slips – compared to an U-blox Neo 7 with the TRK-D5 method.




    1. How are you enabling the trk-meas message? Custom firmware 3.0.? or some magic command.
      I use just lock2 >80 and get good results in an open sky environment. Haven’t done much testing in anything else yet, but my M8N’s work well compared to my M8T’s both FW >3.0. I haven’t tried a lock1 & lock2 solution as yet.


      1. Hi,
        thanks for sharing your experience. I will start playing with that .
        to enable TRK-MEAS I use a custom firmware – as my devices where shipped with 3.01 in ROM. I am using RXM-SFRBX and TRK-MEAS.


        1. Hi Urs,
          I’m really looking for raw data on M8N. In a few months I will switch to M8T but I have to work with what I have right now. What approach did you take to customize the firmware?


      2. One thing, I didn’t realize, I left the var “qi=U1(p+1)” as it was, resulting into permanent “0”. I only replaced “qi” in the queries. The “qi=0” seems to have no noticable effect on RTKNAVI, but makes a big difference when converting with STRSVR to RTCM3. The “float” is very unstable and has errors of +/- 100+ m.
        Now I just set “qi=7 ” when lock2 is >10. Voila – now it works even with RTCM3 messages like a charm.

        best regards,



  2. Hi Tim,

    Things are starting to look pretty good here, many thanks to your great work!

    I have a question that I hope you might be able to answer:
    I’m using rtkrcv on a rover unit combined with ntrip. The results stream is read by a client application (tcpsrv option) and all this works very well. I’m getting good fixes and tests point out that the measured positions are generally correct within a few centimeters. I would, however, like to give the user an idea of the position accuracy, roughly (e.g. <10cm or <50cm). Is there any way I can get such accuracy/quality information from rtkrcv? Or is there a way to add some information to the output stream (I already added some stuff to the solution output format for my specific needs)?



    1. Hi Dimitri. I’m not that familiar with RTKRCV but it looks like the standard deviations are output as part of the solution. They are the smaller numbers at the end of each solution line, one for each axis. These are only estimates of the accuracy though, made by the kalman filter, based on the input values you have chosen on the statistics page in the configuration options. How accurate the standard deviations will be will depend on how accurate your estimates of the errors are on this page. Of course, it is also possible for the estimates to be very wrong, even if the configuration estimates are good, for example in the case of a false fix.


      1. Hi Tim,

        I am not sure I fully understand you. In the status page of rtkrcv (via the telnet interface) I am getting “pos xyz float std (m) rover” and “pos xyz fixed std (m) rover” values. But they seem unrealistically low. In float mode the values are e.g. 0.026 0.029 0.026 which I can hardly believe. In my experience the solution is somewhere in 50 – 100 cm accurate in float mode.

        The output contains a covariance matrix, with 3 ‘normal’ and 3 ‘tangent’ values. Is this something I can use to deduce accuracy from? I don’t fully understand between which sets of values this covariance is.

        I am thinking about a rough estimate, a bit like the blue circle you get in google maps when showing the gps position on a mobile device like an iPhone. Perhaps I should simply show 3m for single, 0.5m for float and 0.05m for fixed? Or is that too simple…?



        1. Hi Dimitri. I don’t think the covariance matrix is going to help you, the diagonal elements are just the squares of the stdevs and the off-diagonal elements represent correlation between states, not what you’re interested in. I’m not sure how good an answer you are going to get when the result is float. I suspect the stdevs are more meaningful in fix mode, when there are fewer uncertainties. If you want to summarize the uncertainty with a single number, the stdevs can be combined in a root mean square sense, i.e. sqrt(stdevx^2+stdevy^2) for just the horizontal components, or sqrt(stdevx^2+stdevy^2+stdevz^2) for all 3 axes. That will give you the one sigma number which means the result should be within +/- that value 68% of the time. The result should be within +/- two times that value (2 sigma) 95% of the time and three times (3 sigma) 99.7% of the time.

          There are at least three reasons why the stdevs will not be entirely accurate. First of all, the statistical inputs in your config file (all the “stats-xxxx” parameters) may not accurately represent the reality of your system. Second, those inputs assume the error distributions are gaussian, or bell-curve shaped, which of course they never are in the real-world, and third, there may be errors in the RTKLIB code/model, either actual mistakes, or more likely, simplifications that add error.

          It’s possible in the end that you will find simple constants based on the solution mode may be more meaningful, especially for single and float solutions.


  3. Tested latest RTKLIBEXPLORER version in PostProcessing M8T data from Emild Reach and in Emlid ReachView v0.4.7 release with some upgrades based on your work here.

    Initial impression is good. Better realtime fixes and more stable coordinates.

    Appears to be significant improvement.

    Richard Johnson


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 )

Google+ photo

You are commenting using your Google+ 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.