GNSS carrier phase from Nexus 9

GNSS carrier phase from Nexus 9

As it is known, there is an active development in using Android ranges for PPP 1 2 and RTK, but these require the phase observables, which, as of the time of writing this post, only few devices provide. Even if they are provided, obtaining the carrier phase might not be as straightforward as in commercial GNSS receivers.

In order to make our first tests with GNSS carrier-phase measurements obtained from an Android device, Rokubun has acquired a non-cellular Nexus 9 tablet. This device is one of the few that has the duty-cycle deactivated, which allows for a continuous tracking of the phase, without a cycle slip at every second.

How to obtain carrier-phase measurements

Even though the Android API seems to have dedicated accessors to the carrier phase (getCarrierPhase() and getCarrierCycles()), these methods usually report 0.0. The user has to rely on the getAccumulatedDeltaRange() method instead, which is defined as a constant (i.e. the wavelength) that multiplies the carrier-phase (expressed in cycles).

A note of caution raised by Google at Innovate UK event “The Future of Mobile Sat Nav” (held in London on July 10th 2017) is that the carrier phase measurements might require a careful processing in order to be reconstructed due to the different implementations of the duty cycling for each manufacturer.

For this work, the Android app gps-measurements-tool available at GitHub has been used to log GNSS data.

Using the phase

In order to process the phase with GNSS data processing software (such as e.g. RTKlib), we have used a Python script that converts from the GPS logger app to a more standard RINEX format. This script is available here in case you are interested in using it or contributing to it. Please note that this is in active development and the code is very preliminary, use it at your own risk.

In the case of the Nexus 9 tablet, both the time tags of the measurements and the pseudoranges are computed using the smartphone clock and satellite transmission time information and the carrier-phase has been obtained as is (see e.g. this post or the upcoming white paper under preparation by the GSA Task Force on this matter). With this approach, if one plots the pseudorange and the carrier phase against time, for a satellite (see the following example for the GPS satellite “PRN20”), one will see that the pseudorange has a series of periodic jumps that are not present in the phase, which is much more smooth. This leads to a code-phase divergence that increases with time.

Range and phase using instantaneous FullBiasNanos

These jumps are due to the fact that the clock parameter FullBiasNanos (used to construct both the time tags and the pseudorange) show a periodic jump of 256 nanoseconds (ca. 77m) each 3 seconds. This jump in the FullBiasNanos is the culprit of the discontinuities of the pseudoranges shown above because this parameter is also needed to construct the range. Since this is a ‘clock-like’ feature (i.e. is a feature of the receiver that affects all observations), this would not pose a problem if the carrier-phase would show these jumps as well (i.e. the clock parameter when estimating the position would ‘absorb’ these jumps). The problem is that, in this context, the carrier phase is not “consistent” with the pseudorange measurements. The effect of this is that, when processing the data, while the post-fit residuals show a Gaussian distribution for the range, the carrier phase post-fit residuals show regular jumps whose size are around 77meters (the size of the jumps of the FullBiasNanos, see last plot of this post).

This feature is specially critical if the analyst is interested in using smartphone data for e.g. ionospheric studies, that need the code-minus-phase divergence combination.

As pointed out by several colleagues, a possible means to mitigate this issue would be to assume a constant FullBiasNanos (taking for instance only the first value), and let the receiver clock (in the estimation process) assume this clock drift. If one does that, the code-phase divergence of the previous plots disappears (see following plot)

Using constant FullBiasNanos mitigates the code/phase divergence due to the receiver clock
Kinematic positioning using phase

In order to test the RINEX converter and check the effect of the FullBiasNanos in navigation, RTKlib has been used to perform PPP-like processing using precise orbits (rapid IGS orbits and clocks) as well as ionospheric data from IONEX files. Since there was no ground control point to refer the results to, a static solution using precise orbits and IONEX files was computed. This was used as the ground truth to refer the other results. These first results are shown in the following figure:

Horizontal deviation relative to static solution (precise + IONEX)

The horizontal deviations (relative to the ground truth) of the static solution (using broadcast ephemeris) show deviations less than 0.5m at the terminal epoch, while the kinematic solutions show a substantial difference. Using a constant FullBiasNanos (red dots) seem to improve the solution a bit but the error is still large (6.5 +/- 3.3 m when using constant FullBiasNanos and 8.7 +/- 5.1m with instantaneous FullBiasNanos). This is consistent with the post-fit residuals of the phase (see plot below). Note that, as far as the carrier phase post-fit residuals are concerned, despite the fact that the jumps have now disappeared, the residuals are in the range of meters. This large residuals might be in part due to the ionospheric model (IONEX), which has errors on the order of 5 TECU (which is equivalent to ca. 80 cm in GPS L1 frequency).


Post-fit residuals of the carrier-phase measurements

These results indicate that, on top of the fact that the antenna in smartphone is critical to achieve a good carrier-phase, the smartphone GNSS carrier-phase measurements might not be used as is. Careful attention is required to reconstruct those measurements in order to be used in PPP as well as for ionospheric monitoring applications. This treatment might be even different for each GNSS chipset manufacturer.


Thanks to Moises Navarro (Airbus & GSA) for his valuable contribution on the FullBiasNanos treatment of the smartphone GNSS receiver clock



Miquel Garcia

  • Miquel Garcia

    Thanks for your comment. The best way to approach this is to follow the tutorial from the Android Developers web page. unfortunately with the generic comment I cannot offer any useful help. Please. try to be more specific.
    Good luck!

  • ZhangShuwei

    Hello,I’ve been trying to debug the code in android studio, but I always run into link error, when I’m building a Android studio project. Can you give me some advice?

  • Miquel Garcia

    Thanks for the useful info! We will have a look and see if we can change it in our Nexus9.

  • galileo_fan

    The webform has stripped the XML “gll” tag. Its attribute was

  • galileo_fan

    Looking at the samsung S8 gpsd daemon, there are 2 possible duty-cycle configuration parameters in the GLL API:
    GlMeSrdAsicConfig::SetConfigParameters:SetDutyCycle(Min %lu,Max %lu,Sats %lu,PwrdBHzBlk %lu)
    GlMeSrdAsicConfig::SetConfigParameters:SetForcedDutyCycle(DcStart %lu ms, DcOn %lu ms, DcOff %lu ms, DcStop %lu ms)
    On a rooted smartphone with the BCM475x GPS chipset you can set them in the gps.xml as

    The default values are i1=2 and i2=5 (don’t know about the others).
    Can you check what are the settings for your Nexus9 ?

  • Miquel Garcia

    Hi Erza,

    Thanks for your comments.

    The results are with GPS only, because the Nexus 9 tablet only support this constellation. Newer smartphones such as Huawei P10 or Samsung S8 support multiconstellation. Have a look at this web page:

    Regarding your second question, I assume RTD stands for Real-Time Differential isn’t it? Please notice that RTK with smartphones are not yet fully possible as the carrier phases present some issues. They do not have the same quality as GNSS receivers due to the phone’s hardware. Expect accuracies between 0.5m and 1m, but this highly depends on the environment (e.g. multipath) and the processing type (static, kinematic, …)

    Please post your questions in this forum.

    Hope this help.


  • Erza

    Dear Miquel:
    I am so sorry to bother you again, I would like to ask you some questions.
    first: you get above results by using GPS system, but not with other systems such as GLONASS system.
    second: At present, what precision can you achieve by using RTD positioning mode and RTK positioning mode repectively?
    I am looking forward to your reply at your convenience as soon as possible.

    Yours sincerely,

  • Erza

    Hello, I am a master student from Southeast University, Nanjing, China. I major in GNSS positioning. Now I would like to learn more about GNSS positioning using mobile phone raw observations. Can you consult with you? This is my email– .I hope you can get your email, so that we can better communicate

  • Miquel Garcia

    Thanks Denis for your comment!

    Thanks for noticing the typo in tne code! It has been corrected as per the indications in the API:


  • Denis Laurichesse

    Thank you for the FullBiasNanos constant trick !
    According to me, as BiasNanos comes with FullBiasNanos, it should be taken as a constant as well.
    Another comment: in line 404, I think that there is a sign error on BiasNanos (in the Android API, it is added to FullBiasNanos).

  • Miquel Garcia

    Hi Simon, thanks for your reply!

    I agree with your statement of the IONEX and the ionospheric errors, we still have to dig more on the phase residuals to clarify this. Following your suggestion, I prepared a plot showing the range rate computed with different methods (range differences with instantaneous FullBiasNanos, carrierphase differences and Doppler values as reported by the PseudoRangeRateMetersPerSecond getter of the Android API). Both the Doppler and the range rate computed using the carrier phase seem reasonably similar…

    I will keep you posted!

    Range rate measurements from Nexus 9

  • Simon Banville

    If I remember correctly, the tutorial taught by Frank Van Diggelen and his colleagues from Google suggested to use a constant FullBiasNanos as well. The phase residuals still look puzzling to me: the ionospheric errors caused by the IONEX map should vary slowly and not be as noisy. Did you collect Doppler measurements as well? Could you validate the carrier-phase against the Doppler observations? Keep us updated!

    p.s. Thanks for the links to blackdotgnss!

Leave a Reply

Your email address will not be published. Required fields are marked *