Skip to content

Commit 52a8973

Browse files
committed
update rinexconv
1 parent aa98caf commit 52a8973

7 files changed

Lines changed: 200 additions & 72 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,9 +501,9 @@ A command line utility and Python class `RinexConverter` to convert binary GNSS
501501

502502
**NB: This ALPHA preview release is limited to the following experimental functionality:**
503503

504-
1. [RINEX version 3.05](https://files.igs.org/pub/data/format/rinex305.pdf).
504+
1. RINEX versions 3.04 and 4.02.
505505
1. Convert binary UBX RXM-RAW or RXM-RAWX (raw observation) data from u-blox receivers (e.g. ZED-F9P) to RINEX Observation file format.
506-
1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently only GPS LNAV data is supported**, but the underlying `RinexConverterNavigation` class is readily extensible.
506+
1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently only GPS LNAV and CNAV data is supported**, but the underlying `RinexConverterNavigation` class is readily extensible.
507507
1. Convert RTCM3 Ephemerides messages (1019, 1020, 1041-1046) from any source (including NTRIP caster or RTK base station receiver) to RINEX Navigation file format.
508508
1. Convert NMEA MWD (wind speed and direction) and XDR (temperature and pressure) sensor data to RINEX Meteorology file format.
509509

src/pygnssutils/rawnav.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@
88
etc.) of one or more raw GNSS NAV subframe messages, as a
99
precursor to RINEX conversion.
1010
11+
Once a RawNav object is instantiated, the `parse` function can
12+
be invoked repeatedly to collate data from separate sequential
13+
subframes e.g. for GPS LNAV, subframe 1 contains clock corrections,
14+
subframes 2 & 3 contain ephemerides and subframe 4 page 18 contains
15+
ionospheric corrections.
16+
17+
An `sfracq` bitfield signifies which subframe IDs have been acquired,
18+
and hence whether or not the RawNav object contains sufficient
19+
information to be converted to a NAV record.
20+
21+
A boolean `sequence` argument determines whether subframes are
22+
processed as a sequence e.g. for GNSS where MSB and LSB attributes
23+
are in separate, sequential (but not necessarily contiguous) subframes.
24+
25+
Static methods are provided to facilitate acquisition of NAV subframe data
26+
from UBX RXM-SFRBX messages.
27+
1128
The objective is to handle any GNSS subframe format for which:
1229
1330
- data is available as a raw, unpadded little-endian integer.
@@ -18,13 +35,6 @@
1835
signed int and IEEE 754 float) have been defined and implemented
1936
in `bits2val`.
2037
21-
Once a RawNav object is instantiated, the `parse` function can
22-
be invoked repeatedly to collate data from separate sequential
23-
subframes e.g. for GPS LNAV, subframe 1 contains clock corrections,
24-
subframes 2 & 3 contain ephemerides and subframe 4 page 18 contains
25-
ionospheric corrections. An `sfracq` bitfield signifies which
26-
subframe IDs have been acquired.
27-
2838
Format of data definition dictionary::
2939
3040
dict[field_name, tuple[offset, length, encoding, scaling]
@@ -35,13 +45,6 @@
3545
MSB and LSB field names MUST be suffixed "_msb" and "_lsb"
3646
respectively - the `parse` function will automatically combine them.
3747
38-
A boolean `sequence` argument determines whether subframes are
39-
processed as a sequence e.g. for GNSS where MSB and LSB attributes
40-
are in separate, sequential (but not necessarily contiguous) subframes.
41-
42-
Static methods are provided to facilitate acquisition of NAV subframe data
43-
from UBX RXM-SFRBX messages (currently for GPS LNAV only).
44-
4548
Created on 20 Apr 2026
4649
4750
:author: semuadmin (Steve Smith)
@@ -122,7 +125,7 @@ def parse(
122125
self,
123126
data: int,
124127
definition: dict[str, tuple[int, int, str, int]],
125-
sfrmap: dict = {},
128+
sfrmap: dict | NoneType = None,
126129
sequence: bool = False,
127130
):
128131
"""
@@ -131,14 +134,16 @@ def parse(
131134
:param int data: raw, unpadded input data
132135
:param dict[str, tuple[int, int, str, int]] def: subframe definition dictionary \
133136
(from GNSS ICD)
134-
:param dict sfrmap: map of subframe ids to sfracq bitmask ({})
137+
:param dict | NoneType sfrmap: map of subframe ids to sfracq bitmask (None)
135138
:param bool sequence: process subframe as part of a contiguous sequence (False)
136139
:raises: RINEXProcessingError
137140
"""
138141
# pylint: disable=too-many-locals
139142

140143
try:
141144

145+
if sfrmap is None:
146+
sfrmap = {}
142147
# get exemplary preamble value if one is available
143148
valpre = definition.pop(VALPREAMBLE, 0)
144149

@@ -186,9 +191,6 @@ def parse(
186191

187192
# update epoch with last acquisition timestamp
188193
# TODO is toc the correction value to use here?
189-
# doesn't seem to reflect actual UTC time and
190-
# doesn't appear to increment by seconds like
191-
# the tow in HOW???
192194
self._epoch = wnotow2utc(
193195
wno=int(getattr(self, WN)),
194196
tow=int(getattr(self, TOC) * 1000),
@@ -354,6 +356,9 @@ def process_rxm_sfrbx(data: UBXMessage) -> dict[str, str | int | float | NoneTyp
354356
"""
355357
Reassemble individual subframe from UBX RXM-SFRBX dwrds.
356358
359+
CURRENTLY ONLY GPS LNAV & CNAV IMPLEMENTED BUT METHOD
360+
READILY EXTENSIBLE.
361+
357362
:param UBXMessage data: parsed UBX RXM-SFRBX message
358363
:return: dict of subframe attributes
359364
:rtype: dict[str, str | int | float | NoneType]
@@ -402,7 +407,7 @@ def process_rxm_sfrbx(data: UBXMessage) -> dict[str, str | int | float | NoneTyp
402407
if subframeid in (4, 5):
403408
output["dataid"] = subframe >> 234 & 0x3
404409
output["svcode"] = subframe >> 232 & 0x3F
405-
# for GPS LNAV, subframe = 3 * 100 bits, final 20 bits of 320 bit dwrd is padding
410+
# for GPS CNAV, subframe = 3 * 100 bits, final 20 bits of 320 bit dwrd is padding
406411
elif gnss == GPS and sigid in ("2L", "2S", "5I", "5Q"): # GPS CNAV
407412
for i in range(numw):
408413
wrd = getattr(data, f"dwrd_{i+1:02d}")

src/pygnssutils/rinex_conv_cli.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,7 @@ def main():
4545

4646
ap = ArgumentParser(
4747
epilog=EPILOG,
48-
description=(
49-
"NB: %(prog)s is currently an experimental facility with "
50-
"limited functionality. NOT FOR PRODUCTION USE."
51-
),
48+
description=("NB: %(prog)s is currently an experimental facility."),
5249
formatter_class=ArgumentDefaultsHelpFormatter,
5350
)
5451
ap.add_argument(
@@ -95,7 +92,7 @@ def main():
9592
ap.add_argument(
9693
"--obsfilter",
9794
required=False,
98-
help="Comma-separated list of observation codes to process, or blank for all e.g '1C,2B'",
95+
help="Comma-separated list of observation codes to process, or blank for all e.g '1C,2S'",
9996
type=str,
10097
default="",
10198
)

0 commit comments

Comments
 (0)