pygnssutils 1.2.2__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pygnssutils-1.2.2/src/pygnssutils.egg-info → pygnssutils-1.2.3}/PKG-INFO +4 -6
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/README.md +2 -4
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/pyproject.toml +1 -1
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/_version.py +1 -1
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/globals.py +1 -1
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rawnav.py +135 -61
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_conv.py +23 -2
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_conv_cli.py +36 -1
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_conv_met.py +2 -2
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_conv_nav.py +146 -121
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_conv_obs.py +15 -10
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_globals.py +14 -12
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_helpers.py +40 -33
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_subframes_bds.py +18 -12
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_subframes_gal.py +4 -3
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/rinex_subframes_gps.py +11 -8
- {pygnssutils-1.2.2 → pygnssutils-1.2.3/src/pygnssutils.egg-info}/PKG-INFO +4 -6
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils.egg-info/SOURCES.txt +1 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils.egg-info/requires.txt +1 -1
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_rinex.py +21 -1
- pygnssutils-1.2.3/tests/test_rinex_defs.py +136 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/LICENSE +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/setup.cfg +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/__init__.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/exceptions.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssmqttclient.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssmqttclient_cli.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssntripclient.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssntripclient_cli.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssreader.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssserver.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssserver_cli.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssstreamer.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/gnssstreamer_cli.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/helpers.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/mqttmessage.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils/socket_server.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils.egg-info/dependency_links.txt +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils.egg-info/entry_points.txt +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/src/pygnssutils.egg-info/top_level.txt +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_cli.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_gnssstreamer.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_rawnav.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_socketwrapper.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_sourcetable.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_static.py +0 -0
- {pygnssutils-1.2.2 → pygnssutils-1.2.3}/tests/test_stream.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygnssutils
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: GNSS Command Line Utilities
|
|
5
5
|
Author-email: Steve Smith <semuadmin@semuconsulting.com>
|
|
6
6
|
Maintainer-email: Steve Smith <semuadmin@semuconsulting.com>
|
|
@@ -34,7 +34,7 @@ Requires-Dist: certifi>=2025.0.0
|
|
|
34
34
|
Requires-Dist: paho-mqtt>=2.1.0
|
|
35
35
|
Requires-Dist: pyserial>=3.5
|
|
36
36
|
Requires-Dist: pyspartn>=1.0.8
|
|
37
|
-
Requires-Dist: pyubx2>=1.3.
|
|
37
|
+
Requires-Dist: pyubx2>=1.3.3
|
|
38
38
|
Requires-Dist: pynmeagps>=1.1.4
|
|
39
39
|
Requires-Dist: pysbf2>=1.0.4
|
|
40
40
|
Requires-Dist: pyubxutils>=1.0.6
|
|
@@ -543,18 +543,16 @@ class pygnssutils.rinex_conv.RinexConvertor(app, rinex_version, rinex_type, gnss
|
|
|
543
543
|
|
|
544
544
|
A command line utility and Python class `RinexConverter` to convert binary GNSS data logs to RINEX text file format.
|
|
545
545
|
|
|
546
|
-
**NB:
|
|
546
|
+
**NB: The current ALPHA release implements the following functionality:**
|
|
547
547
|
|
|
548
548
|
1. RINEX versions 3.05 and 4.02.
|
|
549
549
|
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.
|
|
550
|
-
1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently supports GPS LNAV
|
|
550
|
+
1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently supports GPS LNAV/CNAV, GAL FNAV/INAV, BDS D1/D2**, but the underlying `RinexConverterNavigation` class will be enhanced in future releases.
|
|
551
551
|
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.
|
|
552
552
|
1. Convert NMEA MWD (wind speed and direction) and XDR (temperature and pressure) sensor data to RINEX Meteorology file format.
|
|
553
553
|
|
|
554
554
|
A Graphical User Interface for this utility will be added to [PyGPSClient](https://github.com/semuconsulting/PyGPSClient).
|
|
555
555
|
|
|
556
|
-
The intention behind this preview release is to **gauge the wider appetite for further development** of a cross-platform Python RINEX conversion utility and enhance functionality in a future release, as and when time permits. **CONTRIBUTORS WELCOME**.
|
|
557
|
-
|
|
558
556
|
Assuming the u-blox receiver is already configured to output raw observation (UBX-RXM-RAWX) and navigation subframe (UBX-RXM-SFRBX) data, a suitable input log file can be created using the pygnssutils `gnssstreamer` CLI utility e.g. ...
|
|
559
557
|
|
|
560
558
|
```
|
|
@@ -499,18 +499,16 @@ class pygnssutils.rinex_conv.RinexConvertor(app, rinex_version, rinex_type, gnss
|
|
|
499
499
|
|
|
500
500
|
A command line utility and Python class `RinexConverter` to convert binary GNSS data logs to RINEX text file format.
|
|
501
501
|
|
|
502
|
-
**NB:
|
|
502
|
+
**NB: The current ALPHA release implements the following functionality:**
|
|
503
503
|
|
|
504
504
|
1. RINEX versions 3.05 and 4.02.
|
|
505
505
|
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 supports GPS LNAV
|
|
506
|
+
1. Convert binary RXM-SFRBX (navigation subframe) data from u-blox receivers to RINEX Navigation file format. **Currently supports GPS LNAV/CNAV, GAL FNAV/INAV, BDS D1/D2**, but the underlying `RinexConverterNavigation` class will be enhanced in future releases.
|
|
507
507
|
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.
|
|
508
508
|
1. Convert NMEA MWD (wind speed and direction) and XDR (temperature and pressure) sensor data to RINEX Meteorology file format.
|
|
509
509
|
|
|
510
510
|
A Graphical User Interface for this utility will be added to [PyGPSClient](https://github.com/semuconsulting/PyGPSClient).
|
|
511
511
|
|
|
512
|
-
The intention behind this preview release is to **gauge the wider appetite for further development** of a cross-platform Python RINEX conversion utility and enhance functionality in a future release, as and when time permits. **CONTRIBUTORS WELCOME**.
|
|
513
|
-
|
|
514
512
|
Assuming the u-blox receiver is already configured to output raw observation (UBX-RXM-RAWX) and navigation subframe (UBX-RXM-SFRBX) data, a suitable input log file can be created using the pygnssutils `gnssstreamer` CLI utility e.g. ...
|
|
515
513
|
|
|
516
514
|
```
|
|
@@ -121,7 +121,7 @@ LOGLIMIT = 10485760 # max size of logfile in bytes
|
|
|
121
121
|
NOGGA = -1
|
|
122
122
|
"""No GGA sentence to be sent (for NTRIP caster)"""
|
|
123
123
|
EPILOG = (
|
|
124
|
-
"© 2022 semuadmin (Steve Smith) BSD 3-Clause license"
|
|
124
|
+
"© 2022-2026 semuadmin (Steve Smith) BSD 3-Clause license"
|
|
125
125
|
" - https://github.com/semuconsulting/pygnssutils/"
|
|
126
126
|
)
|
|
127
127
|
"""CLI argument parser epilog"""
|
|
@@ -60,7 +60,7 @@ Created on 20 Apr 2026
|
|
|
60
60
|
:license: BSD 3-Clause
|
|
61
61
|
"""
|
|
62
62
|
|
|
63
|
-
# pylint: disable=
|
|
63
|
+
# pylint: disable=unused-argument, unused-variable, too-many-arguments, too-many-positional-arguments
|
|
64
64
|
|
|
65
65
|
import struct
|
|
66
66
|
from logging import getLogger
|
|
@@ -79,8 +79,8 @@ from pygnssutils.rinex_globals import (
|
|
|
79
79
|
QZS,
|
|
80
80
|
SBA,
|
|
81
81
|
UBXRINEXGNSS,
|
|
82
|
-
UBXRINEXOBSCODE,
|
|
83
82
|
)
|
|
83
|
+
from pygnssutils.rinex_helpers import get_obscode_ubx
|
|
84
84
|
|
|
85
85
|
IS1 = "_is1"
|
|
86
86
|
"""IS1 field name suffix (between MSB and ISB)"""
|
|
@@ -120,7 +120,7 @@ class RawNav:
|
|
|
120
120
|
self,
|
|
121
121
|
gnss: Literal["G", "R", "E", "C", "J", "S", "I"],
|
|
122
122
|
svid: int,
|
|
123
|
-
|
|
123
|
+
sigcode: str,
|
|
124
124
|
**kwargs, # pylint: disable=unused-argument
|
|
125
125
|
):
|
|
126
126
|
"""
|
|
@@ -128,14 +128,14 @@ class RawNav:
|
|
|
128
128
|
|
|
129
129
|
:param Literal["G","R","E","C","J","S","I"] gnss: GNSS code
|
|
130
130
|
:param int svid: RINEX SV id e.g. 14
|
|
131
|
-
:param str
|
|
131
|
+
:param str sigcode: RINEX signal code e.g. "1C"
|
|
132
132
|
:param dict kwargs: optional keyword arguments
|
|
133
133
|
"""
|
|
134
134
|
|
|
135
135
|
self._logger = getLogger(__name__)
|
|
136
136
|
self._gnss = gnss
|
|
137
137
|
self._svid = svid
|
|
138
|
-
self.
|
|
138
|
+
self._sigcode = sigcode
|
|
139
139
|
self.wn = -1
|
|
140
140
|
self.toc = -1
|
|
141
141
|
self.tow = -1
|
|
@@ -290,7 +290,7 @@ class RawNav:
|
|
|
290
290
|
|
|
291
291
|
stg = (
|
|
292
292
|
f"<RAWNAV({self.identity}, gnss={self._gnss}, svid={self._svid}, "
|
|
293
|
-
f"sigid={self.
|
|
293
|
+
f"sigid={self._sigcode}, sfracq={self._subframeacq}, "
|
|
294
294
|
)
|
|
295
295
|
for i, att in enumerate(self.__dict__):
|
|
296
296
|
if att[0] != "_": # only show public attributes
|
|
@@ -310,7 +310,7 @@ class RawNav:
|
|
|
310
310
|
:rtype: str
|
|
311
311
|
"""
|
|
312
312
|
|
|
313
|
-
return f"{self._gnss}{self._svid:02d}{self.
|
|
313
|
+
return f"{self._gnss}{self._svid:02d}{self._sigcode}"
|
|
314
314
|
|
|
315
315
|
@property
|
|
316
316
|
def gnss(self) -> str:
|
|
@@ -343,18 +343,18 @@ class RawNav:
|
|
|
343
343
|
:rtype: str
|
|
344
344
|
"""
|
|
345
345
|
|
|
346
|
-
return f"{self._gnss}{self._svid
|
|
346
|
+
return f"{self._gnss}{self._svid:>2}" # no leading zero
|
|
347
347
|
|
|
348
348
|
@property
|
|
349
|
-
def
|
|
349
|
+
def sigcode(self) -> str:
|
|
350
350
|
"""
|
|
351
|
-
Getter for signal
|
|
351
|
+
Getter for signal code in RINEX format.
|
|
352
352
|
|
|
353
|
-
:return: signal
|
|
353
|
+
:return: signal code e.g. '1C'
|
|
354
354
|
:rtype: str
|
|
355
355
|
"""
|
|
356
356
|
|
|
357
|
-
return self.
|
|
357
|
+
return self._sigcode
|
|
358
358
|
|
|
359
359
|
@property
|
|
360
360
|
def subframeacq(self) -> int:
|
|
@@ -411,37 +411,37 @@ class RawNavReader:
|
|
|
411
411
|
gnss = UBXRINEXGNSS[data.gnssId]
|
|
412
412
|
svid = data.svId
|
|
413
413
|
numw = data.numWords
|
|
414
|
-
|
|
414
|
+
sigcode = get_obscode_ubx(data.gnssId, data.sigId)
|
|
415
415
|
except KeyError as err:
|
|
416
416
|
raise RINEXProcessingError(
|
|
417
417
|
f"Unrecognised GNSS or Signal code: {data.gnssId=}, {data.sigId=}"
|
|
418
418
|
) from err
|
|
419
419
|
|
|
420
420
|
if gnss == GPS:
|
|
421
|
-
sfrdata = self._process_rxm_sfrbx_gps(gnss, svid,
|
|
421
|
+
sfrdata = self._process_rxm_sfrbx_gps(gnss, svid, sigcode, numw, data)
|
|
422
422
|
elif gnss == GAL:
|
|
423
|
-
sfrdata = self._process_rxm_sfrbx_gal(gnss, svid,
|
|
423
|
+
sfrdata = self._process_rxm_sfrbx_gal(gnss, svid, sigcode, numw, data)
|
|
424
424
|
elif gnss == BDS:
|
|
425
|
-
sfrdata = self._process_rxm_sfrbx_bds(gnss, svid,
|
|
425
|
+
sfrdata = self._process_rxm_sfrbx_bds(gnss, svid, sigcode, numw, data)
|
|
426
426
|
elif gnss == GLO:
|
|
427
|
-
sfrdata = self._process_rxm_sfrbx_glo(gnss, svid,
|
|
427
|
+
sfrdata = self._process_rxm_sfrbx_glo(gnss, svid, sigcode, numw, data)
|
|
428
428
|
elif gnss == SBA:
|
|
429
|
-
sfrdata = self._process_rxm_sfrbx_sba(gnss, svid,
|
|
429
|
+
sfrdata = self._process_rxm_sfrbx_sba(gnss, svid, sigcode, numw, data)
|
|
430
430
|
elif gnss == QZS:
|
|
431
|
-
sfrdata = self._process_rxm_sfrbx_qzs(gnss, svid,
|
|
431
|
+
sfrdata = self._process_rxm_sfrbx_qzs(gnss, svid, sigcode, numw, data)
|
|
432
432
|
elif gnss == IRN:
|
|
433
|
-
sfrdata = self._process_rxm_sfrbx_irn(gnss, svid,
|
|
433
|
+
sfrdata = self._process_rxm_sfrbx_irn(gnss, svid, sigcode, numw, data)
|
|
434
434
|
return sfrdata
|
|
435
435
|
|
|
436
436
|
def _process_rxm_sfrbx_gps(
|
|
437
|
-
self, gnss: str, svid: int,
|
|
437
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
438
438
|
) -> dict[str, str | int | float | NoneType]:
|
|
439
439
|
"""
|
|
440
440
|
Reassemble GPS subframe from individual UBX RXM-SFRBX dwrds.
|
|
441
441
|
|
|
442
442
|
:param str gnss: RINEX gnss code
|
|
443
443
|
:param int svid: SV
|
|
444
|
-
:param str
|
|
444
|
+
:param str sigcode: RINEX sig code e.g. '1C'
|
|
445
445
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
446
446
|
:return: dict of subframe attributes
|
|
447
447
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -450,21 +450,19 @@ class RawNavReader:
|
|
|
450
450
|
|
|
451
451
|
subframe = 0
|
|
452
452
|
subframeid = 0
|
|
453
|
-
# dataid = 0
|
|
454
453
|
subframepageid = 0
|
|
455
454
|
|
|
456
455
|
# for GPS LNAV, subframe = 10 * 30 bits, with each 32-bit dwrd padded with 2 bits at end
|
|
457
|
-
if
|
|
456
|
+
if sigcode == "1C": # GPS LNAV
|
|
458
457
|
for i in range(numw):
|
|
459
458
|
wrd = getattr(data, f"dwrd_{i+1:02d}") & 0xFFFFFFFC >> 2
|
|
460
459
|
subframe += wrd << (30 * (numw - 1 - i))
|
|
461
460
|
subframeid = (subframe >> 248) & 0b111
|
|
462
|
-
# dataid = subframe >> 234 & 0b11
|
|
463
461
|
if subframeid in (4, 5):
|
|
464
462
|
subframepageid = subframe >> 232 & 0b111111
|
|
465
463
|
|
|
466
464
|
# for GPS CNAV, subframe = 3 * 100 bits, final 20 bits of 320 bit dwrd is padding
|
|
467
|
-
elif
|
|
465
|
+
elif sigcode in ("2L", "2S", "5I", "5Q"): # GPS CNAV
|
|
468
466
|
for i in range(numw):
|
|
469
467
|
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
470
468
|
subframe += wrd << (32 * (numw - 1 - i))
|
|
@@ -477,22 +475,21 @@ class RawNavReader:
|
|
|
477
475
|
return {
|
|
478
476
|
"gnss": gnss,
|
|
479
477
|
"svid": svid,
|
|
480
|
-
"
|
|
481
|
-
# "dataid": dataid,
|
|
478
|
+
"sigcode": sigcode,
|
|
482
479
|
"subframeid": subframeid,
|
|
483
480
|
"subframepageid": subframepageid,
|
|
484
481
|
"subframe": subframe,
|
|
485
482
|
}
|
|
486
483
|
|
|
487
484
|
def _process_rxm_sfrbx_gal(
|
|
488
|
-
self, gnss: str, svid: int,
|
|
485
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
489
486
|
) -> dict[str, str | int | float | NoneType]:
|
|
490
487
|
"""
|
|
491
488
|
Reassemble GALILEO subframe from individual UBX RXM-SFRBX dwrds.
|
|
492
489
|
|
|
493
490
|
:param str gnss: RINEX gnss code
|
|
494
491
|
:param int svid: SV
|
|
495
|
-
:param str
|
|
492
|
+
:param str sigcode: RINEX sigid e.g. '5I'
|
|
496
493
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
497
494
|
:return: dict of subframe attributes
|
|
498
495
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -505,7 +502,7 @@ class RawNavReader:
|
|
|
505
502
|
|
|
506
503
|
# for GAL FNAV, subframe = 244 bits,
|
|
507
504
|
# 8 * 32 bit dwrds with 12 bits padding at end
|
|
508
|
-
if
|
|
505
|
+
if sigcode == "5I": # GAL FNAV
|
|
509
506
|
for i in range(numw):
|
|
510
507
|
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
511
508
|
subframe += wrd << (32 * (numw - 1 - i))
|
|
@@ -517,7 +514,7 @@ class RawNavReader:
|
|
|
517
514
|
# for GAL INAV, subframe = 256 bits, 8 * 32 bit dwrds,
|
|
518
515
|
# with word data separated into 112 msb and 16 lsb
|
|
519
516
|
# (see GAL_INAV_SUBFRAME)
|
|
520
|
-
elif
|
|
517
|
+
elif sigcode in ("1B", "7I"): # GAL INAV
|
|
521
518
|
supsubframe = 0
|
|
522
519
|
for i in range(numw):
|
|
523
520
|
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
@@ -532,21 +529,21 @@ class RawNavReader:
|
|
|
532
529
|
return {
|
|
533
530
|
"gnss": gnss,
|
|
534
531
|
"svid": svid,
|
|
535
|
-
"
|
|
532
|
+
"sigcode": sigcode,
|
|
536
533
|
"subframeid": subframeid,
|
|
537
534
|
"subframepageid": subframepageid,
|
|
538
535
|
"subframe": subframe,
|
|
539
536
|
}
|
|
540
537
|
|
|
541
538
|
def _process_rxm_sfrbx_bds(
|
|
542
|
-
self, gnss: str, svid: int,
|
|
539
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
543
540
|
) -> dict[str, str | int | float | NoneType]:
|
|
544
541
|
"""
|
|
545
542
|
Reassemble BEIDOU subframe from individual UBX RXM-SFRBX dwrds.
|
|
546
543
|
|
|
547
544
|
:param str gnss: RINEX gnss code
|
|
548
545
|
:param int svid: SV
|
|
549
|
-
:param str
|
|
546
|
+
:param str sigcode: RINEX sig code e.g. '2I'
|
|
550
547
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
551
548
|
:return: dict of subframe attributes
|
|
552
549
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -558,7 +555,7 @@ class RawNavReader:
|
|
|
558
555
|
subframepageid = 0
|
|
559
556
|
d1d2 = 0
|
|
560
557
|
|
|
561
|
-
if
|
|
558
|
+
if sigcode in ("2I", "6I", "7I"): # BDS D1/D2
|
|
562
559
|
if data.sigId in (1, 3, 10): # D2
|
|
563
560
|
d1d2 = 2
|
|
564
561
|
else: # D1
|
|
@@ -572,16 +569,16 @@ class RawNavReader:
|
|
|
572
569
|
elif d1d2 == 2 and subframeid in (1,):
|
|
573
570
|
subframepageid = subframe >> 254 & 0b1111
|
|
574
571
|
|
|
575
|
-
elif
|
|
572
|
+
elif sigcode == "1D": # BDS CNV1
|
|
576
573
|
pass # TODO
|
|
577
574
|
|
|
578
|
-
elif
|
|
575
|
+
elif sigcode == "5D": # BDS CNV2
|
|
579
576
|
pass # TODO
|
|
580
577
|
|
|
581
578
|
return {
|
|
582
579
|
"gnss": gnss,
|
|
583
580
|
"svid": svid,
|
|
584
|
-
"
|
|
581
|
+
"sigcode": sigcode,
|
|
585
582
|
"d1d2": d1d2,
|
|
586
583
|
"subframeid": subframeid,
|
|
587
584
|
"subframepageid": subframepageid,
|
|
@@ -589,14 +586,14 @@ class RawNavReader:
|
|
|
589
586
|
}
|
|
590
587
|
|
|
591
588
|
def _process_rxm_sfrbx_glo(
|
|
592
|
-
self, gnss: str, svid: int,
|
|
589
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
593
590
|
) -> dict[str, str | int | float | NoneType]:
|
|
594
591
|
"""
|
|
595
592
|
Reassemble GLONASS subframe from individual UBX RXM-SFRBX dwrds.
|
|
596
593
|
|
|
597
594
|
:param str gnss: RINEX gnss code
|
|
598
595
|
:param int svid: SV
|
|
599
|
-
:param str
|
|
596
|
+
:param str sigcode: RINEX sigid e.g. '1C'
|
|
600
597
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
601
598
|
:return: dict of subframe attributes
|
|
602
599
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -609,7 +606,7 @@ class RawNavReader:
|
|
|
609
606
|
|
|
610
607
|
# for GLO, subframe = 85 bits, 3 * 32 bit dwrds, plus
|
|
611
608
|
# a receiver-generated 4th 32 dwrd containing subframe and page ids
|
|
612
|
-
if
|
|
609
|
+
if sigcode in ("1C", "2C"): # GLO L1,L2
|
|
613
610
|
for i in range(numw):
|
|
614
611
|
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
615
612
|
subframe += wrd << (32 * (numw - 1 - i))
|
|
@@ -620,21 +617,21 @@ class RawNavReader:
|
|
|
620
617
|
return {
|
|
621
618
|
"gnss": gnss,
|
|
622
619
|
"svid": svid,
|
|
623
|
-
"
|
|
620
|
+
"sigcode": sigcode,
|
|
624
621
|
"subframeid": subframeid,
|
|
625
622
|
"subframepageid": subframepageid,
|
|
626
623
|
"subframe": subframe,
|
|
627
624
|
}
|
|
628
625
|
|
|
629
626
|
def _process_rxm_sfrbx_sba(
|
|
630
|
-
self, gnss: str, svid: int,
|
|
627
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
631
628
|
) -> dict[str, str | int | float | NoneType]:
|
|
632
629
|
"""
|
|
633
630
|
Reassemble SBAS subframe from individual UBX RXM-SFRBX dwrds.
|
|
634
631
|
|
|
635
632
|
:param str gnss: RINEX gnss code
|
|
636
633
|
:param int svid: SV
|
|
637
|
-
:param str
|
|
634
|
+
:param str sigcode: RINEX sigcode e.g. '1C'
|
|
638
635
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
639
636
|
:return: dict of subframe attributes
|
|
640
637
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -642,22 +639,39 @@ class RawNavReader:
|
|
|
642
639
|
"""
|
|
643
640
|
|
|
644
641
|
subframe = 0
|
|
645
|
-
tow = 0
|
|
646
642
|
subframeid = 0
|
|
647
643
|
subframepageid = 0
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
644
|
+
svid -= 100 # adjust SV ID range
|
|
645
|
+
|
|
646
|
+
# for SBAS, subframe = 250 bits,
|
|
647
|
+
# 8 * 32 bit dwrds with 6 bits padding at end
|
|
648
|
+
if sigcode == "1C": # SBAS L1C/A
|
|
649
|
+
for i in range(numw):
|
|
650
|
+
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
651
|
+
subframe += wrd << (32 * (numw - 1 - i))
|
|
652
|
+
subframe = (
|
|
653
|
+
subframe >> 12
|
|
654
|
+
) & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF # (2**250 - 1)
|
|
655
|
+
subframeid = (subframe >> 236) & 0b111111
|
|
656
|
+
|
|
657
|
+
return {
|
|
658
|
+
"gnss": gnss,
|
|
659
|
+
"svid": svid,
|
|
660
|
+
"sigcode": sigcode,
|
|
661
|
+
"subframeid": subframeid,
|
|
662
|
+
"subframepageid": subframepageid,
|
|
663
|
+
"subframe": subframe,
|
|
664
|
+
}
|
|
651
665
|
|
|
652
666
|
def _process_rxm_sfrbx_qzs(
|
|
653
|
-
self, gnss: str, svid: int,
|
|
667
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
654
668
|
) -> dict[str, str | int | float | NoneType]:
|
|
655
669
|
"""
|
|
656
670
|
Reassemble QZSS subframe from individual UBX RXM-SFRBX dwrds.
|
|
657
671
|
|
|
658
672
|
:param str gnss: RINEX gnss code
|
|
659
673
|
:param int svid: SV
|
|
660
|
-
:param str
|
|
674
|
+
:param str sigcode: RINEX sigcode e.g. '1C'
|
|
661
675
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
662
676
|
:return: dict of subframe attributes
|
|
663
677
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -665,22 +679,65 @@ class RawNavReader:
|
|
|
665
679
|
"""
|
|
666
680
|
|
|
667
681
|
subframe = 0
|
|
668
|
-
tow = 0
|
|
669
682
|
subframeid = 0
|
|
670
683
|
subframepageid = 0
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
684
|
+
svid -= 192 # adjust SV ID range
|
|
685
|
+
|
|
686
|
+
# for QZSS L1C/A, subframe = 10 * 30 bits, with each 32-bit dwrd padded with 2 bits at end
|
|
687
|
+
# same as GPS LNAV
|
|
688
|
+
if sigcode == "1C": # QZSS L1C/A
|
|
689
|
+
for i in range(numw):
|
|
690
|
+
wrd = getattr(data, f"dwrd_{i+1:02d}") & 0xFFFFFFFC >> 2
|
|
691
|
+
subframe += wrd << (30 * (numw - 1 - i))
|
|
692
|
+
subframeid = (subframe >> 248) & 0b111
|
|
693
|
+
if subframeid in (4, 5):
|
|
694
|
+
subframepageid = subframe >> 232 & 0b111111
|
|
695
|
+
|
|
696
|
+
# for QZSS L1S, subframe = 250 bits, 8 * 32 bit dwrds with 6 bits padding at end
|
|
697
|
+
# same as SBAS L1C/A
|
|
698
|
+
if sigcode == "1Z": # QZSS L1S
|
|
699
|
+
for i in range(numw):
|
|
700
|
+
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
701
|
+
subframe += wrd << (32 * (numw - 1 - i))
|
|
702
|
+
subframe = (
|
|
703
|
+
subframe >> 12
|
|
704
|
+
) & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF # (2**250 - 1)
|
|
705
|
+
subframeid = (subframe >> 236) & 0b111111
|
|
706
|
+
|
|
707
|
+
# for QZSS L2C, L5I, subframe = 3 * 100 bits, final 20 bits of 320 bit dwrd is padding
|
|
708
|
+
# same as GPS CNAV
|
|
709
|
+
elif sigcode in (
|
|
710
|
+
"2L",
|
|
711
|
+
"2S",
|
|
712
|
+
"5I",
|
|
713
|
+
): # QZSS L2C, L5I
|
|
714
|
+
for i in range(numw):
|
|
715
|
+
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
716
|
+
subframe += wrd << (32 * (numw - 1 - i))
|
|
717
|
+
subframe = (
|
|
718
|
+
(subframe >> 20)
|
|
719
|
+
& 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
720
|
+
) # (2**300 - 1)
|
|
721
|
+
subframeid = (subframe >> 280) & 0b111111
|
|
722
|
+
|
|
723
|
+
return {
|
|
724
|
+
"gnss": gnss,
|
|
725
|
+
"svid": svid,
|
|
726
|
+
"sigcode": sigcode,
|
|
727
|
+
"subframeid": subframeid,
|
|
728
|
+
"subframepageid": subframepageid,
|
|
729
|
+
"subframe": subframe,
|
|
730
|
+
}
|
|
674
731
|
|
|
675
732
|
def _process_rxm_sfrbx_irn(
|
|
676
|
-
self, gnss: str, svid: int,
|
|
733
|
+
self, gnss: str, svid: int, sigcode: str, numw: int, data: UBXMessage
|
|
677
734
|
) -> dict[str, str | int | float | NoneType]:
|
|
678
735
|
"""
|
|
679
736
|
Reassemble IRNSS (NAVIC) subframe from individual UBX RXM-SFRBX dwrds.
|
|
680
737
|
|
|
681
738
|
:param str gnss: RINEX gnss code
|
|
682
739
|
:param int svid: SV
|
|
683
|
-
:param str
|
|
740
|
+
:param str sigcode: RINEX sigcode e.g. '5A'
|
|
684
741
|
:param UBXMessage data: parsed UBX RXM-SFRBX message
|
|
685
742
|
:return: dict of subframe attributes
|
|
686
743
|
:rtype: dict[str, str | int | float | NoneType]
|
|
@@ -688,9 +745,26 @@ class RawNavReader:
|
|
|
688
745
|
"""
|
|
689
746
|
|
|
690
747
|
subframe = 0
|
|
691
|
-
tow = 0
|
|
692
748
|
subframeid = 0
|
|
693
749
|
subframepageid = 0
|
|
694
|
-
|
|
695
|
-
#
|
|
696
|
-
|
|
750
|
+
|
|
751
|
+
# for IRN L5A, subframe = 3 * 100 bits, final 20 bits of 320 bit dwrd is padding
|
|
752
|
+
# same as GPS CNAV
|
|
753
|
+
if sigcode in ("5A",): # IRN L5A
|
|
754
|
+
for i in range(numw):
|
|
755
|
+
wrd = getattr(data, f"dwrd_{i+1:02d}")
|
|
756
|
+
subframe += wrd << (32 * (numw - 1 - i))
|
|
757
|
+
subframe = (
|
|
758
|
+
(subframe >> 20)
|
|
759
|
+
& 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
760
|
+
) # (2**300 - 1)
|
|
761
|
+
subframeid = (subframe >> 280) & 0b111111
|
|
762
|
+
|
|
763
|
+
return {
|
|
764
|
+
"gnss": gnss,
|
|
765
|
+
"svid": svid,
|
|
766
|
+
"sigcode": sigcode,
|
|
767
|
+
"subframeid": subframeid,
|
|
768
|
+
"subframepageid": subframepageid,
|
|
769
|
+
"subframe": subframe,
|
|
770
|
+
}
|
|
@@ -89,11 +89,15 @@ class RinexConverter:
|
|
|
89
89
|
rinex_types: list[str],
|
|
90
90
|
gnssfilter: list[str],
|
|
91
91
|
obsfilter: list[str],
|
|
92
|
+
timecorr: bool,
|
|
93
|
+
ionocorr: bool,
|
|
94
|
+
eopcorr: bool,
|
|
92
95
|
datasource: list[str],
|
|
93
96
|
starttime: datetime | str,
|
|
94
97
|
minobs: int,
|
|
95
98
|
marker: list[str],
|
|
96
99
|
antenna: list[str],
|
|
100
|
+
antennahed: list[float | str],
|
|
97
101
|
receiver: list[str],
|
|
98
102
|
observer: str,
|
|
99
103
|
comments: list[str],
|
|
@@ -112,6 +116,9 @@ class RinexConverter:
|
|
|
112
116
|
(or None for all) e.g. [GPS,GAL]
|
|
113
117
|
:param list[str] obsfilter: List of observation codes to process \
|
|
114
118
|
(or None for all) e.g. ["1C","2B"]
|
|
119
|
+
:param bool timecorr: Include time (clock) corrections
|
|
120
|
+
:param bool ionocorr: Include ionospheric corrections
|
|
121
|
+
:param bool eopcorr: Include earth orientation corrections
|
|
115
122
|
:param list[str] datasource: List of datasources for each rinex \
|
|
116
123
|
type e.g. ["R","R","R"]
|
|
117
124
|
:param datetime | str starttime: Approximate start time of RTCM3 (e.g. NTRIP) data \
|
|
@@ -120,6 +127,7 @@ class RinexConverter:
|
|
|
120
127
|
:param int minobs: Minimum observations per observation type (0)
|
|
121
128
|
:param list[str] marker: marker details (name, number, type)
|
|
122
129
|
:param list[str] antenna: antenna details (number, type)
|
|
130
|
+
:param list[float | str] antennahed: antenna delta H,E,D
|
|
123
131
|
:param list[str] | receiver: receiver details (number, type, version)
|
|
124
132
|
:param str observer: observer details
|
|
125
133
|
:param list[str] comments: user comments
|
|
@@ -137,6 +145,9 @@ class RinexConverter:
|
|
|
137
145
|
self._rinex_types = ALLOBS if rinex_types == [""] else rinex_types
|
|
138
146
|
self._gnssfilter = ALLGNSS if gnssfilter == [""] else gnssfilter
|
|
139
147
|
self._obsfilter = obsfilter
|
|
148
|
+
self._timecorrflag = timecorr
|
|
149
|
+
self._ionocorrflag = ionocorr
|
|
150
|
+
self._eopcorrflag = eopcorr
|
|
140
151
|
while len(datasource) < 3: # OBS, NAV, MET
|
|
141
152
|
datasource.append("R")
|
|
142
153
|
self._datasource = ["R", "R", "R"] if datasource == [""] else datasource
|
|
@@ -149,6 +160,7 @@ class RinexConverter:
|
|
|
149
160
|
self._minobs = minobs
|
|
150
161
|
self._marker = marker
|
|
151
162
|
self._antenna = antenna
|
|
163
|
+
self._antennahed = antennahed
|
|
152
164
|
self._receiver = receiver
|
|
153
165
|
self._observer = observer
|
|
154
166
|
self.user_comments = comments
|
|
@@ -163,6 +175,7 @@ class RinexConverter:
|
|
|
163
175
|
self._station = kwargs.get("station", "")
|
|
164
176
|
self.verbosity = int(verbosity)
|
|
165
177
|
self.logtofile = logtofile
|
|
178
|
+
self._logfile = ""
|
|
166
179
|
|
|
167
180
|
self._outputs = {}
|
|
168
181
|
self._tot = 0
|
|
@@ -179,10 +192,14 @@ class RinexConverter:
|
|
|
179
192
|
rinex_version=self._rinex_version,
|
|
180
193
|
gnssfilter=self._gnssfilter,
|
|
181
194
|
obsfilter=self._obsfilter,
|
|
195
|
+
timecorr=self._timecorrflag,
|
|
196
|
+
ionocorr=self._ionocorrflag,
|
|
197
|
+
eopcorr=self._eopcorrflag,
|
|
182
198
|
datasource=self._datasource[{OBS: 0, NAV: 1, MET: 2}[rt]],
|
|
183
199
|
minobs=self._minobs,
|
|
184
200
|
marker=self._marker,
|
|
185
201
|
antenna=self._antenna,
|
|
202
|
+
antennahed=self._antennahed,
|
|
186
203
|
receiver=self._receiver,
|
|
187
204
|
observer=self._observer,
|
|
188
205
|
**kwargs,
|
|
@@ -210,6 +227,7 @@ class RinexConverter:
|
|
|
210
227
|
if isinstance(infile, str):
|
|
211
228
|
infile = Path(infile)
|
|
212
229
|
|
|
230
|
+
self._logfile = infile
|
|
213
231
|
outputpath = infile.parent
|
|
214
232
|
|
|
215
233
|
# check total number of raw messages in file
|
|
@@ -308,8 +326,8 @@ class RinexConverter:
|
|
|
308
326
|
RINEXProcessingError,
|
|
309
327
|
TypeError,
|
|
310
328
|
ValueError,
|
|
311
|
-
)
|
|
312
|
-
self.logger.
|
|
329
|
+
):
|
|
330
|
+
self.logger.exception(f"RINEX NAV Conversion error")
|
|
313
331
|
res = RINEX_ERROR
|
|
314
332
|
except KeyboardInterrupt:
|
|
315
333
|
self.logger.warning("Terminated by user")
|
|
@@ -346,9 +364,12 @@ class RinexConverter:
|
|
|
346
364
|
:rtype: str
|
|
347
365
|
"""
|
|
348
366
|
|
|
367
|
+
datasource = self._datasource[{"O": 0, "N": 1, "M": 2}[rinextype]]
|
|
349
368
|
hdr = (
|
|
350
369
|
format_version(self._rinex_version, rinextype, self._gnssfilter)
|
|
351
370
|
+ format_runby()
|
|
371
|
+
+ format_comments(f"log: {self._logfile}")
|
|
372
|
+
+ format_comments(f"format: {datasource}")
|
|
352
373
|
+ format_comments(self.user_comments)
|
|
353
374
|
)
|
|
354
375
|
if self._rinex_version >= RINEX4:
|