Skip to content

L1C (CNAV-2) TOW is 7200 s short in the last frame of each ITOW interval — L1CD loses TOW every 2 hours #90

Description

@tomojitakasu

Summary

In decode_CNV2() (src/sdr_nav.c) the CNAV-2 TOW is computed as

update_tow(ch, getbitu(data, 22, 8) * 7200.0 + (toi - 1) * 18.0 + TOFF_L1CD);

which assumes TOI counts 1...400. The TOI actually carried in subframe 1 is
(frame index + 1) mod 400, so the last frame of every ITOW interval carries
TOI = 0, not 400
. (toi - 1) * 18.0 then evaluates to -18 and the resulting
TOW is one ITOW interval (7200 s) short. Every L1C channel therefore fails the
TOW consistency check and loses its TOW every 2 hours.

Observed

TOW MISMATCH <propagated> -> <decoded> at each 2-hour boundary
(pocket_web continuous log, 2026-08-16, QZSS):

pocket_20260816_0200.log  J03/J04/J07/J08 L1CD  TOW MISMATCH  7200.520 ->     0.520
pocket_20260816_0400.log  J02/J03/J04/J07/J08  14400.520 ->  7200.520
pocket_20260816_0600.log  J02/J03/J04/J07/J08  21600.520 -> 14400.520

The propagated value on the left is the correct one. ch->tow is invalidated
and all L1CD observations disappear until the TOW is re-latched and confirmed -
about 37 s (two CNAV-2 frames) each time:

155477.540  J04 1S present    <- last epoch before the ITOW boundary
155478.540  J04 1S gone       <- TOW MISMATCH
155514.540  J04 1S present    <- back after ~37 s

L1CP (1L) is unaffected because the pilot uses the tow_v == 2 path.

Evidence for the TOI convention

Decoding the raw $NAV frames of J04 L1CD around the 2026-08-16 week boundary
(WN = bits 9-21, ITOW = bits 22-29, TOI = bits 0-8):

frame start (GPST) WN ITOW TOI
604782 of week 2431 (last frame of the week) 2431 83 0
0 of week 2432 2432 0 1
18 of week 2432 2432 0 2

So WN / ITOW describe the current frame, and TOI is the index of the next
frame within its interval, wrapping to 0 at the interval end.

Suggested fix

// TOI = 0 means the next frame is in the next ITOW interval
double tow = getbitu(data, 22, 8) * 7200.0 +
    (toi > 0 ? toi - 1 : 399) * 18.0 + TOFF_L1CD;
update_tow(ch, tow);

At the end of the week this yields 604800.520, which has to be wrapped to
0.520 with the week number incremented.

Note that the TOI of NavIC L1-SPS in decode_IRNV1() uses a different, 0-based
convention and is correct as written (ITOW * 7200 + toi * 18 + TOFF_I1SD, no
mismatch at 2-hour boundaries in the same logs). The two should not be unified.

I have this implemented and tested locally and can open a PR if useful.

Environment

PocketSDR library 0.20 (SDR_LIB_VER), master at 03787da, Windows 11 /
MSYS2 UCRT64 gcc 15.2.0, 8 ch front end, QZSS L1CD/L1CP.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions