Sub-meter fleet tracking without a local base station¶
Use this route when the application needs better-than-standalone accuracy but a private RTK base is not an option: fleet telematics, insurance telematics, agricultural guidance previews, or asset tracking over wide areas. QZSS CLAS (or MADOCA via L6E/L6D) delivers satellite-delivered corrections, so one L6-capable rover receiver replaces the base-station link.
This page is the application framing. The decode smoke test and full option surface live in QZSS L6, CLAS, and MADOCA; read that route first if you have never decoded a capture here.
What you need¶
| Item | Notes |
|---|---|
| Rover observations | RINEX from any multi-frequency receiver; raw UBX/SBF converts via gnss convert |
| Navigation file | Matching broadcast RINEX |
| L6 capture | Raw 250-byte frames logged by an L6-capable receiver; Japan-only coverage for CLAS |
| Reference (optional) | A surveyed point or independent solution to score against |
Without a reference the route still produces artifacts, but "sub-meter" remains a claim you cannot check. Plan at least one scored run.
One scored run¶
The frozen, public PPC Tokyo run1 decision route downloads the corresponding QZSS archive hours, decodes Compact SSR, runs the complete interval, scores against the independent PPC Applanix trajectory, and emits one manifest:
python3 apps/gnss.py clas-application-decision \
--dataset-root data/PPC-Dataset \
--output-dir output/use_cases/clas_decision/run1 \
--l6-cache output/use_cases/clas_decision/l6_cache
The two hourly inputs are pinned as 2024205D.l6 and 2024205E.l6 (900,000
bytes each) with SHA-256 values in the manifest. The archive path is
https://sys.qzss.go.jp/archives/l6/{year}/{YYYYDOY}{slot}.l6; the files are
materialized from the QZSS public archive rather than copied into this
repository. summary.json separates FIX RMS2D, whole-route RMS2D, solution
availability, FIX rate, correction-time coverage, fallback epochs, first
correction, and first valid position. The manifest also hashes the POS,
scorecard, decode inventory/logs, KML, plot, and summary; missing or
non-finite products fail closed. Correction coverage is the union of
30-second Compact SSR intervals clipped to the solution POS time window, so a
valid-looking correction file outside the scored run is not counted. Missing,
entirely out-of-window, or explicitly lost corrections produce a non-zero exit and
unusable (or degraded when some in-window corrections remain), never a
silent success.
The frozen Tokyo run1 full replay on 2026-08-24 found 100% correction-time
coverage and 99.28% solution availability. FIX RMS2D was 0.352 m, but only
10.704% (1,270/11,865) of scored epochs were FIX, 2,884 epochs used the
standalone fallback state, and whole-route RMS2D was 41.862 m. The application
decision is therefore degraded and the continuous-sub-meter gate fails.
“Sub-meter” applies only to the explicitly counted FIX population, not the
whole route. With correction availability injected to zero, the same result
becomes unusable with correction_unavailable; fallback never masks the
loss.
For the fail-closed loss check, a test-only switch removes correction availability from the decision (it never turns fallback into success):
python3 apps/gnss.py clas-application-decision \
--dataset-root data/PPC-Dataset \
--output-dir output/use_cases/clas_decision/run1 \
--l6-cache output/use_cases/clas_decision/l6_cache \
--reuse --inject-correction-loss
This intentionally exits non-zero with state=unusable. Do it only in a
copy of a result directory because it rewrites the decision summary.
mkdir -p output/use_cases/clas_submeter
python3 apps/gnss.py clas-ppp \
--profile clas \
--obs <rover.obs> \
--nav <navigation.nav> \
--qzss-l6 <qzss-l6-capture.bin> \
--qzss-gps-week <week-of-capture> \
--out output/use_cases/clas_submeter/clas_solution.pos \
--summary-json output/use_cases/clas_submeter/clas_summary.json
The summary keys to archive are epochs, ppp_fixed_epochs,
ppp_float_epochs, fallback_epochs, and ppp_solution_rate_pct. Score
against your reference with the same matching conventions used by the
repository's moving-data gate (see docs/ppc_clas_validation.md) so results
stay comparable across runs.
For MADOCA L6E/L6D inputs use the native path instead:
python3 apps/gnss.py ppp \
--obs <rover.obs> \
--nav <navigation.nav> \
--madoca-l6 <madoca-l6e-file> \
--ar-method per-freq \
--out output/use_cases/clas_submeter/madoca_solution.pos \
--summary-json output/use_cases/clas_submeter/madoca_summary.json
CLAS, MADOCA L6E/L6D, and RTCM SSR are separate variants in the decision
table. Only CLAS is truth-scored by the frozen capture above. MADOCA depends
on its service/receiver signal and uses --profile madoca; RTCM SSR depends
on an IP caster and uses --ssr-rtcm. A CLAS score is never presented as
evidence for either alternative.
Interpreting for an application decision¶
Published moving-data evidence for this correction path is in the README "Moving CLAS PPP vs MRTKLIB" section: six urban runs with FIX RMS2D of 0.19-0.63 m on FIX epochs, but FIX rates of 9-38% — corrections help precision when they hold, not availability everywhere. Translate that into your application honestly:
- Guidance/telematics that tolerate float gaps: usually viable.
- Continuous cm-level control (machine guidance, lane keeping): not this route alone; combine with IMU fusion or add RTK.
- Outside Japan or without L6 reception: no CLAS; SSR over IP (
--ssr, RTCM SSR) is the repository's alternative input.
First artifacts and exit criteria¶
test -s output/use_cases/clas_submeter/clas_solution.pos
grep -q '^% LibGNSS++ Position Solution' output/use_cases/clas_submeter/clas_solution.pos
python3 -c "import json;d=json.load(open('output/use_cases/clas_submeter/clas_summary.json'));print(d['epochs'],d.get('ppp_solution_rate_pct'))"
Boundary and next step¶
Coverage, facility selection, and message-subtype support are bounded as documented in QZSS L6, CLAS, and MADOCA. This route adds no new decoder capability; it packages the existing one into an application decision workflow.
Next step: log one day of paired rover + L6 captures on a vehicle that matches your deployment, score them against the best available reference, and only then commit to a correction service contract.