cssrlib 1.2.0__tar.gz → 1.3.2__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.
- {cssrlib-1.2.0/src/cssrlib.egg-info → cssrlib-1.3.2}/PKG-INFO +2 -2
- {cssrlib-1.2.0 → cssrlib-1.3.2}/pyproject.toml +2 -2
- {cssrlib-1.2.0 → cssrlib-1.3.2}/setup.cfg +1 -1
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/__init__.py +2 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_bds.py +21 -13
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_has.py +24 -17
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_mdc.py +126 -48
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_pvs.py +16 -11
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssrlib.py +811 -107
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/dgps.py +41 -22
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ephemeris.py +96 -60
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ewss.py +270 -91
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/gnss.py +590 -334
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/mlambda.py +174 -100
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/osnma.py +74 -54
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/peph.py +219 -117
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/plot.py +41 -16
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/pntpos.py +66 -34
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ppp.py +97 -117
- cssrlib-1.3.2/src/cssrlib/ppprtk.py +23 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/pppssr.py +315 -176
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/qznma.py +49 -32
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rawnav.py +97 -89
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rinex.py +545 -519
- cssrlib-1.3.2/src/cssrlib/rtcm.py +4974 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rtk.py +6 -10
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/sbas.py +213 -106
- cssrlib-1.3.2/src/cssrlib/test/test_eph.py +75 -0
- cssrlib-1.3.2/src/cssrlib/test/test_rnx.py +81 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/tlesim.py +4 -6
- cssrlib-1.3.2/src/cssrlib/utils.py +258 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2/src/cssrlib.egg-info}/PKG-INFO +2 -2
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/SOURCES.txt +1 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/requires.txt +1 -1
- cssrlib-1.2.0/src/cssrlib/ppprtk.py +0 -24
- cssrlib-1.2.0/src/cssrlib/rtcm.py +0 -2758
- cssrlib-1.2.0/src/cssrlib/test/test_eph.py +0 -50
- cssrlib-1.2.0/src/cssrlib/test/test_rnx.py +0 -59
- {cssrlib-1.2.0 → cssrlib-1.3.2}/LICENSE +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/MANIFEST.in +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/README.md +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/30340780.21q +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/3034078M1.21O +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/SEPT078M.21P +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/SEPT078M1.21O +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_gnss.py +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_peph.py +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_rtk.py +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/dependency_links.txt +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/not-zip-safe +0 -0
- {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cssrlib
|
|
3
|
-
Version: 1.2
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Python Toolkit for PPP/PPP-RTK positioning
|
|
5
5
|
Home-page: https://github.com/hirokawa/cssrlib
|
|
6
6
|
Author: Rui Hirokawa
|
|
@@ -16,7 +16,7 @@ Requires-Dist: notebook
|
|
|
16
16
|
Requires-Dist: numpy
|
|
17
17
|
Requires-Dist: matplotlib
|
|
18
18
|
Requires-Dist: cartopy
|
|
19
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: cryptography
|
|
20
20
|
Dynamic: license-file
|
|
21
21
|
|
|
22
22
|
CSSRlib - Toolkit for PPP-RTK/RTK in Python using Compact SSR
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "cssrlib"
|
|
10
|
-
version = "1.2
|
|
10
|
+
version = "1.3.2"
|
|
11
11
|
description = "Python Toolkit for PPP/PPP-RTK positioning"
|
|
12
12
|
authors = [
|
|
13
13
|
{name="Rui Hirokawa", email="rui.hirokawa@gmail.com"},
|
|
@@ -23,5 +23,5 @@ dependencies = [
|
|
|
23
23
|
"numpy",
|
|
24
24
|
"matplotlib",
|
|
25
25
|
"cartopy",
|
|
26
|
-
"
|
|
26
|
+
"cryptography",
|
|
27
27
|
]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
"""
|
|
2
|
-
BDS PPP correction data decoder
|
|
1
|
+
"""BDS PPP correction data decoder.
|
|
3
2
|
|
|
4
|
-
[1] BeiDou Navigation Satellite System Signal In Space
|
|
3
|
+
[1] BeiDou Navigation Satellite System Signal In Space ICD
|
|
5
4
|
Precise Point Positioning Service Signal PPP-B2b (Version 1.0), 2020
|
|
6
5
|
"""
|
|
7
6
|
|
|
@@ -12,7 +11,10 @@ from cssrlib.gnss import bdt2time, bdt2gpst, uGNSS, uSIG, uTYP, rSigRnx
|
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class cssr_bds(cssr):
|
|
14
|
+
"""Class to decode BDS PPP (B2b) Compact SSR messages."""
|
|
15
|
+
|
|
15
16
|
def __init__(self, foutname=None):
|
|
17
|
+
"""Initialize BDS PPP SSR decoder."""
|
|
16
18
|
super().__init__(foutname)
|
|
17
19
|
self.MAXNET = 1
|
|
18
20
|
self.cssrmode = sCSSRTYPE.BDS_PPP
|
|
@@ -23,6 +25,7 @@ class cssr_bds(cssr):
|
|
|
23
25
|
self.cb_scl = 0.017
|
|
24
26
|
|
|
25
27
|
def ssig2rsig(self, sys: sGNSS, utyp: uTYP, ssig):
|
|
28
|
+
"""Convert SSR signal index to RINEX signal code."""
|
|
26
29
|
gps_tbl = {
|
|
27
30
|
0: uSIG.L1C,
|
|
28
31
|
1: uSIG.L1P,
|
|
@@ -72,13 +75,14 @@ class cssr_bds(cssr):
|
|
|
72
75
|
return rSigRnx(sys, utyp, usig_tbl[ssig])
|
|
73
76
|
|
|
74
77
|
def sval(self, u, n, scl):
|
|
75
|
-
"""
|
|
78
|
+
"""Calculate signed value based on n-bit int, lsb."""
|
|
76
79
|
invalid = -2**(n-1)
|
|
77
80
|
dnu = -(2**(n-1)-1) # this value seems to be invalid
|
|
78
81
|
y = np.nan if u == invalid or u == dnu else u*scl
|
|
79
82
|
return y
|
|
80
83
|
|
|
81
84
|
def slot2prn(self, slot):
|
|
85
|
+
"""Convert BDS B2b satellite slot index to system and PRN."""
|
|
82
86
|
prn = 0
|
|
83
87
|
sys = uGNSS.NONE
|
|
84
88
|
if slot >= 1 and slot <= 63:
|
|
@@ -96,6 +100,7 @@ class cssr_bds(cssr):
|
|
|
96
100
|
return sys, prn
|
|
97
101
|
|
|
98
102
|
def decode_head(self, msg, i, st=-1):
|
|
103
|
+
"""Decode BDS PPP message header."""
|
|
99
104
|
self.tod, _, iodssr = bs.unpack_from('u17u4u2', msg, i)
|
|
100
105
|
i += 23
|
|
101
106
|
|
|
@@ -107,10 +112,11 @@ class cssr_bds(cssr):
|
|
|
107
112
|
if self.week >= 0:
|
|
108
113
|
self.time = bdt2gpst(bdt2time(self.week, self.tow))
|
|
109
114
|
|
|
110
|
-
head = {'
|
|
115
|
+
head = {'udi': 0, 'mi': 0, 'iodssr': iodssr}
|
|
111
116
|
return head, i
|
|
112
117
|
|
|
113
118
|
def add_gnss(self, mask, blen, gnss):
|
|
119
|
+
"""Add decoded GNSS satellite mask entries."""
|
|
114
120
|
prn, nsat = self.decode_mask(mask, blen)
|
|
115
121
|
self.nsat_g[gnss] = nsat
|
|
116
122
|
self.nsat_n += nsat
|
|
@@ -124,7 +130,7 @@ class cssr_bds(cssr):
|
|
|
124
130
|
self.gnss_n.append(gnss)
|
|
125
131
|
|
|
126
132
|
def decode_cssr_mask(self, msg, i):
|
|
127
|
-
"""
|
|
133
|
+
"""Decode MT1 Mask message."""
|
|
128
134
|
head, i = self.decode_head(msg, i, sCSSR.MASK)
|
|
129
135
|
|
|
130
136
|
self.iodp = bs.unpack_from('u4', msg, i)[0]
|
|
@@ -179,6 +185,7 @@ class cssr_bds(cssr):
|
|
|
179
185
|
return i
|
|
180
186
|
|
|
181
187
|
def decode_cssr_orb_sat(self, msg, i, inet, sat_n):
|
|
188
|
+
"""Decode satellite orbit correction for BDS PPP."""
|
|
182
189
|
slot, iodn, iodc = bs.unpack_from('u9u10u3', msg, i)
|
|
183
190
|
i += 22
|
|
184
191
|
|
|
@@ -216,7 +223,7 @@ class cssr_bds(cssr):
|
|
|
216
223
|
return i
|
|
217
224
|
|
|
218
225
|
def decode_cssr_orb(self, msg, i, inet=0):
|
|
219
|
-
"""
|
|
226
|
+
"""Decode MT2 orbit + URA message."""
|
|
220
227
|
head, i = self.decode_head(msg, i)
|
|
221
228
|
sat_n = np.array(self.sat_n)
|
|
222
229
|
|
|
@@ -233,7 +240,7 @@ class cssr_bds(cssr):
|
|
|
233
240
|
return i
|
|
234
241
|
|
|
235
242
|
def decode_cssr_cbias(self, msg, i, inet=0):
|
|
236
|
-
"""
|
|
243
|
+
"""Decode MT3 Code Bias Correction message."""
|
|
237
244
|
head, i = self.decode_head(msg, i)
|
|
238
245
|
nsat = self.nsat_n
|
|
239
246
|
self.flg_net = False
|
|
@@ -270,7 +277,7 @@ class cssr_bds(cssr):
|
|
|
270
277
|
return i
|
|
271
278
|
|
|
272
279
|
def decode_cssr_clk_sat(self, msg, i, inet, sat):
|
|
273
|
-
"""
|
|
280
|
+
"""Decode clock correction for satellite."""
|
|
274
281
|
iodc, dclk = bs.unpack_from('u3s{:d}'.format(self.dclk_blen), msg, i)
|
|
275
282
|
i += 3+self.dclk_blen
|
|
276
283
|
|
|
@@ -285,7 +292,7 @@ class cssr_bds(cssr):
|
|
|
285
292
|
return i
|
|
286
293
|
|
|
287
294
|
def decode_cssr_clk(self, msg, i, inet=0):
|
|
288
|
-
"""
|
|
295
|
+
"""Decode MT4 Clock Correction message."""
|
|
289
296
|
head, i = self.decode_head(msg, i)
|
|
290
297
|
if self.iodssr != head['iodssr']:
|
|
291
298
|
return -1
|
|
@@ -311,7 +318,7 @@ class cssr_bds(cssr):
|
|
|
311
318
|
return i
|
|
312
319
|
|
|
313
320
|
def decode_cssr_ura(self, msg, i):
|
|
314
|
-
"""
|
|
321
|
+
"""Decode MT5 URA message."""
|
|
315
322
|
head, i = self.decode_head(msg, i)
|
|
316
323
|
if self.iodssr != head['iodssr']:
|
|
317
324
|
return -1
|
|
@@ -332,7 +339,7 @@ class cssr_bds(cssr):
|
|
|
332
339
|
return i
|
|
333
340
|
|
|
334
341
|
def decode_cssr_comb1(self, msg, i, inet=0):
|
|
335
|
-
"""
|
|
342
|
+
"""Decode MT6 combined message #1."""
|
|
336
343
|
numc, numo = bs.unpack_from('u5u3', msg, i)
|
|
337
344
|
sat_n = np.array(self.sat_n)
|
|
338
345
|
|
|
@@ -354,7 +361,7 @@ class cssr_bds(cssr):
|
|
|
354
361
|
return i
|
|
355
362
|
|
|
356
363
|
def decode_cssr_comb2(self, msg, i, inet=0):
|
|
357
|
-
"""
|
|
364
|
+
"""Decode MT7 combined message #2."""
|
|
358
365
|
numc, numo = bs.unpack_from('u5u3', msg, i)
|
|
359
366
|
sat_n = np.array(self.sat_n)
|
|
360
367
|
|
|
@@ -377,6 +384,7 @@ class cssr_bds(cssr):
|
|
|
377
384
|
return i
|
|
378
385
|
|
|
379
386
|
def decode_cssr(self, msg, i=0):
|
|
387
|
+
"""Decode BDS PPP B2b message."""
|
|
380
388
|
mt = bs.unpack_from('u6', msg, i)[0]
|
|
381
389
|
i += 6
|
|
382
390
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Galileo HAS correction data decoder
|
|
1
|
+
"""Galileo HAS correction data decoder.
|
|
3
2
|
|
|
4
3
|
[1] Galileo High Accuracy Service Signal-in-Space
|
|
5
4
|
Interface Control Document (HAS SIS ICD), Issue 1.0, May 2022
|
|
@@ -15,7 +14,10 @@ from binascii import unhexlify
|
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class cssr_has(cssr):
|
|
17
|
+
"""Class to decode Galileo HAS Compact SSR messages."""
|
|
18
|
+
|
|
18
19
|
def __init__(self, foutname=None):
|
|
20
|
+
"""Initialize Galileo HAS SSR decoder."""
|
|
19
21
|
super().__init__(foutname)
|
|
20
22
|
self.MAXNET = 1
|
|
21
23
|
self.cssrmode = sCSSRTYPE.GAL_HAS_SIS
|
|
@@ -29,13 +31,14 @@ class cssr_has(cssr):
|
|
|
29
31
|
self.pb_scl = 0.01 # cycles
|
|
30
32
|
|
|
31
33
|
def sval(self, u, n, scl):
|
|
32
|
-
"""
|
|
34
|
+
"""Calculate signed value based on n-bit int, lsb."""
|
|
33
35
|
invalid = -2**(n-1)
|
|
34
36
|
dnu = 2**(n-1)-1
|
|
35
37
|
y = np.nan if u == invalid or u == dnu else u*scl
|
|
36
38
|
return y
|
|
37
39
|
|
|
38
40
|
def decode_cssr_clk_sub(self, msg, i=0):
|
|
41
|
+
"""Decode Galileo HAS clock subset correction message."""
|
|
39
42
|
head, i = self.decode_head(msg, i)
|
|
40
43
|
self.flg_net = False
|
|
41
44
|
if self.iodssr != head['iodssr']:
|
|
@@ -58,12 +61,11 @@ class cssr_has(cssr):
|
|
|
58
61
|
return i
|
|
59
62
|
|
|
60
63
|
def decode_head(self, msg, i, st=-1):
|
|
61
|
-
"""
|
|
62
|
-
|
|
64
|
+
"""Decode header part of HAS messages."""
|
|
63
65
|
if st == sCSSR.MASK:
|
|
64
|
-
|
|
66
|
+
udi = 0
|
|
65
67
|
else:
|
|
66
|
-
|
|
68
|
+
udi = bs.unpack_from('u4', msg, i)[0]
|
|
67
69
|
i += 4
|
|
68
70
|
|
|
69
71
|
if self.tow0 >= 0:
|
|
@@ -71,13 +73,12 @@ class cssr_has(cssr):
|
|
|
71
73
|
if self.week >= 0:
|
|
72
74
|
self.time = gpst2time(self.week, self.tow)
|
|
73
75
|
|
|
74
|
-
head = {'
|
|
76
|
+
head = {'udi': udi, 'mi': 0, 'iodssr': self.iodssr}
|
|
75
77
|
return head, i
|
|
76
78
|
|
|
77
79
|
def decode_cssr(self, msg, i=0):
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
# Galileo HAS-SIS only defines MT=1, MT=4073 is CSSR message used in the
|
|
80
|
+
"""Decode HAS messages."""
|
|
81
|
+
# Galileo HAS-SIS only defines MT=1; MT=4073 is CSSR used in the
|
|
81
82
|
# Galileo HAS test dataset
|
|
82
83
|
#
|
|
83
84
|
if self.msgtype != 1 and self.msgtype != 4073:
|
|
@@ -131,9 +132,10 @@ class cssr_has(cssr):
|
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
class cnav_msg():
|
|
134
|
-
"""
|
|
135
|
+
"""Class to handle Galileo E6 (CNAV) message."""
|
|
135
136
|
|
|
136
137
|
def __init__(self):
|
|
138
|
+
"""Initialize Galileo C/NAV HAS message decoder."""
|
|
137
139
|
self.mid_decoded = []
|
|
138
140
|
self.mid_ = -1
|
|
139
141
|
self.ms_ = -1
|
|
@@ -148,10 +150,11 @@ class cnav_msg():
|
|
|
148
150
|
self.monlevel = 0
|
|
149
151
|
|
|
150
152
|
def load_gmat(self, file_gm):
|
|
153
|
+
"""Load Reed-Solomon generator matrix for Galileo HAS decoding."""
|
|
151
154
|
self.gMat = np.genfromtxt(file_gm, dtype="u1", delimiter=",")
|
|
152
155
|
|
|
153
156
|
def decode_has_header(self, buff, i):
|
|
154
|
-
"""
|
|
157
|
+
"""Decode header of HAS pages (obsoleted)."""
|
|
155
158
|
if bs.unpack_from('u24', buff, i)[0] == 0xaf3bc3:
|
|
156
159
|
return 0, 0, 0, 0, 0
|
|
157
160
|
|
|
@@ -160,7 +163,7 @@ class cnav_msg():
|
|
|
160
163
|
return hass, mt, mid, ms, pid
|
|
161
164
|
|
|
162
165
|
def decode_has_page(self, idx, has_pages, gMat, ms):
|
|
163
|
-
""" HPVRS
|
|
166
|
+
"""Decode HPVRS Reed-Solomon RS(255,32,224) page."""
|
|
164
167
|
HASmsg = bytes()
|
|
165
168
|
k = len(idx)
|
|
166
169
|
if k >= ms:
|
|
@@ -172,8 +175,7 @@ class cnav_msg():
|
|
|
172
175
|
return HASmsg
|
|
173
176
|
|
|
174
177
|
def decode_cnav(self, tow, vi):
|
|
175
|
-
"""
|
|
176
|
-
|
|
178
|
+
"""Decode Galileo CNAV message."""
|
|
177
179
|
HASmsg = None
|
|
178
180
|
|
|
179
181
|
for vn in vi:
|
|
@@ -183,8 +185,13 @@ class cnav_msg():
|
|
|
183
185
|
continue
|
|
184
186
|
hass, res = bs.unpack_from('u2u2', buff, i)
|
|
185
187
|
i += 4
|
|
188
|
+
# HAS status
|
|
186
189
|
if hass >= 2: # 0:test,1:operational,2:res,3:dnu
|
|
187
190
|
continue
|
|
191
|
+
# mt: type of message
|
|
192
|
+
# mid: id of the message
|
|
193
|
+
# ms: size of non-encoded message in number of pages 0:1,...
|
|
194
|
+
# pid: id of the transmitted HAS encoded page
|
|
188
195
|
mt, mid, ms, pid = bs.unpack_from('u2u5u5u8', buff, i)
|
|
189
196
|
|
|
190
197
|
self.msgtype = mt
|
|
@@ -202,7 +209,7 @@ class cnav_msg():
|
|
|
202
209
|
if self.monlevel >= 2:
|
|
203
210
|
print(f"{mt} {mid} {ms} {pid}")
|
|
204
211
|
|
|
205
|
-
if len(self.rec) >= self.ms_:
|
|
212
|
+
if self.ms_ > 0 and len(self.rec) >= self.ms_:
|
|
206
213
|
if self.monlevel >= 2:
|
|
207
214
|
print(" data collected mid={:2d} ms={:2d} tow={:.0f}"
|
|
208
215
|
.format(self.mid_, self.ms_, tow))
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
"""
|
|
2
|
-
QZSS MADOCA-PPP correction data decoder
|
|
1
|
+
"""QZSS MADOCA-PPP correction data decoder.
|
|
3
2
|
|
|
4
3
|
[1] Quasi-Zenith Satellite System Interface Specification Multi-GNSS
|
|
5
4
|
Advanced Orbit and Clock Augmentation - Precise Point Positioning
|
|
6
|
-
(IS-QZSS-MDC-
|
|
5
|
+
(IS-QZSS-MDC-005draft), October, 2026
|
|
7
6
|
|
|
8
7
|
"""
|
|
9
8
|
|
|
10
9
|
import numpy as np
|
|
11
10
|
import bitstruct as bs
|
|
12
11
|
from cssrlib.cssrlib import cssr, sCSSRTYPE, sCSSR, local_corr, sCType
|
|
13
|
-
from cssrlib.gnss import gpst2time, uGNSS, prn2sat, rCST
|
|
12
|
+
from cssrlib.gnss import gpst2time, time2str, uGNSS, prn2sat, rCST, sat2id
|
|
13
|
+
from cssrlib.gnss import pos2ecef, gtime_t
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class areaInfo():
|
|
17
|
+
"""Class to store MADOCA-PPP service area information."""
|
|
18
|
+
|
|
17
19
|
def __init__(self, sid, latr, lonr, p1=0, p2=0):
|
|
20
|
+
"""Initialize MADOCA-PPP area information."""
|
|
18
21
|
self.sid = sid
|
|
19
22
|
self.latr = latr
|
|
20
23
|
self.lonr = lonr
|
|
@@ -26,7 +29,10 @@ class areaInfo():
|
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
class ionoCorr():
|
|
32
|
+
"""Class to store MADOCA-PPP regional ionospheric corrections."""
|
|
33
|
+
|
|
29
34
|
def __init__(self):
|
|
35
|
+
"""Initialize MADOCA-PPP ionospheric correction data."""
|
|
30
36
|
self.t0 = None
|
|
31
37
|
self.qi = []
|
|
32
38
|
self.iodssr = 0
|
|
@@ -36,7 +42,10 @@ class ionoCorr():
|
|
|
36
42
|
|
|
37
43
|
|
|
38
44
|
class cssr_mdc(cssr):
|
|
45
|
+
"""Class to decode QZSS MADOCA-PPP L6D/L6E messages."""
|
|
46
|
+
|
|
39
47
|
def __init__(self, foutname=None):
|
|
48
|
+
"""Initialize MADOCA-PPP L6 message decoder."""
|
|
40
49
|
super().__init__(foutname)
|
|
41
50
|
|
|
42
51
|
self.cssrmode = sCSSRTYPE.QZS_MADOCA
|
|
@@ -44,11 +53,19 @@ class cssr_mdc(cssr):
|
|
|
44
53
|
|
|
45
54
|
self.pnt = {}
|
|
46
55
|
self.ci = {}
|
|
56
|
+
self.reg_alrt = {}
|
|
57
|
+
self.reg_iod = {}
|
|
47
58
|
|
|
48
59
|
self.area = -1
|
|
60
|
+
self.reg = -1
|
|
61
|
+
self.alrt = 0
|
|
49
62
|
self.narea_t = {1: 8, 2: 16, 3: 5, 4: 1, 5: 8}
|
|
50
63
|
self.MAXNET = np.sum(list(self.narea_t.values()))
|
|
51
64
|
|
|
65
|
+
self.tmax = {sCType.CLOCK: 60.0, sCType.ORBIT: 60.0,
|
|
66
|
+
sCType.CBIAS: 60.0, sCType.PBIAS: 60.0,
|
|
67
|
+
sCType.TROP: 120.0, sCType.STEC: 300.0}
|
|
68
|
+
|
|
52
69
|
for inet in range(self.MAXNET+1):
|
|
53
70
|
self.lc.append(local_corr())
|
|
54
71
|
self.lc[inet].inet = inet
|
|
@@ -58,35 +75,40 @@ class cssr_mdc(cssr):
|
|
|
58
75
|
self.lc[inet].t0 = {}
|
|
59
76
|
|
|
60
77
|
def find_grid_index(self, pos):
|
|
61
|
-
"""
|
|
62
|
-
|
|
78
|
+
"""Find region/area."""
|
|
63
79
|
latd, lond = np.rad2deg(pos[0:2])
|
|
80
|
+
rr = pos2ecef(pos)
|
|
64
81
|
self.reg = self.area = -1
|
|
82
|
+
min_dist = 1e5
|
|
65
83
|
|
|
66
|
-
for reg in self.pnt.
|
|
67
|
-
|
|
84
|
+
for reg in self.pnt.keys():
|
|
85
|
+
if self.reg_alrt.get(reg, 0) != 0:
|
|
86
|
+
continue
|
|
87
|
+
for area in self.pnt[reg].keys():
|
|
68
88
|
p = self.pnt[reg][area]
|
|
89
|
+
ref_ecef = pos2ecef(
|
|
90
|
+
np.array([p.latr*rCST.D2R, p.lonr*rCST.D2R, 0.0]))
|
|
91
|
+
dist = np.linalg.norm(rr - ref_ecef)*1e-3 # [km]
|
|
92
|
+
if dist > min_dist:
|
|
93
|
+
continue
|
|
69
94
|
if p.sid == 0: # rectangle shape:
|
|
70
95
|
if p.latr-p.lats <= latd and latd <= p.latr+p.lats and \
|
|
71
96
|
p.lonr-p.lons <= lond and lond <= p.lonr+p.lons:
|
|
72
97
|
self.reg = reg
|
|
73
98
|
self.area = area
|
|
74
|
-
|
|
99
|
+
min_dist = dist
|
|
75
100
|
elif p.sid == 1: # circle
|
|
76
|
-
|
|
77
|
-
de = (lond - p.lonr)*rCST.D2R * \
|
|
78
|
-
rCST.RE_WGS84*np.cos(p.lonr*rCST.D2R)
|
|
79
|
-
r = np.sqrt(dn**2+de**2)
|
|
80
|
-
if r <= p.rng:
|
|
101
|
+
if dist <= p.rng:
|
|
81
102
|
self.reg = reg
|
|
82
103
|
self.area = area
|
|
83
|
-
|
|
104
|
+
min_dist = dist
|
|
84
105
|
|
|
85
106
|
inet = self.get_inet(self.reg, self.area)
|
|
107
|
+
self.inet = inet
|
|
86
108
|
return inet
|
|
87
109
|
|
|
88
110
|
def get_dpos(self, pos):
|
|
89
|
-
"""
|
|
111
|
+
"""Calculate position offset from reference."""
|
|
90
112
|
if self.reg < 0 or self.area < 0:
|
|
91
113
|
print("get_dpos: region, area not defined.")
|
|
92
114
|
return 0, 0
|
|
@@ -99,28 +121,37 @@ class cssr_mdc(cssr):
|
|
|
99
121
|
return dlat, dlon
|
|
100
122
|
|
|
101
123
|
def get_stec(self, dlat=0.0, dlon=0.0):
|
|
102
|
-
"""
|
|
124
|
+
"""Calculate STEC correction by interporation."""
|
|
103
125
|
if self.inet < 0:
|
|
104
126
|
print("get_stec: region, area not defined.")
|
|
105
|
-
return
|
|
127
|
+
return np.zeros(self.nsat_n)
|
|
106
128
|
|
|
107
129
|
p = self.lc[self.inet]
|
|
108
130
|
# if p.inet_ref != self.iodssr:
|
|
109
131
|
# return 0.0
|
|
110
|
-
stec = np.zeros(
|
|
132
|
+
stec = np.zeros(p.nsat_n)
|
|
133
|
+
v = np.array([1, dlat, dlon, dlat*dlon, dlat**2, dlon**2])
|
|
111
134
|
|
|
112
|
-
for i, sat in enumerate(
|
|
113
|
-
stec[i] =
|
|
135
|
+
for i, sat in enumerate(p.sat_n):
|
|
136
|
+
stec[i] = v@p.ci[sat]
|
|
114
137
|
|
|
115
138
|
return stec
|
|
116
139
|
|
|
117
140
|
def decode_mdc_stec_area(self, buff, i=0):
|
|
118
|
-
"""
|
|
141
|
+
"""Decode MT1 STEC coverage message."""
|
|
119
142
|
tow, uid, mi, iodssr = bs.unpack_from('u20u4u1u4', buff, i)
|
|
120
143
|
i += 29
|
|
144
|
+
self.tow = tow
|
|
121
145
|
self.tow0 = tow//3600*3600
|
|
146
|
+
if self.week >= 0:
|
|
147
|
+
self.time = gpst2time(self.week, self.tow)
|
|
122
148
|
reg, alrt, len_, narea = bs.unpack_from('u8u1u16u5', buff, i)
|
|
123
149
|
i += 30
|
|
150
|
+
self.reg = reg
|
|
151
|
+
self.alrt = alrt
|
|
152
|
+
self.reg_alrt[reg] = alrt
|
|
153
|
+
self.reg_iod[reg] = iodssr
|
|
154
|
+
|
|
124
155
|
if reg not in self.pnt:
|
|
125
156
|
self.pnt[reg] = {}
|
|
126
157
|
|
|
@@ -130,14 +161,14 @@ class cssr_mdc(cssr):
|
|
|
130
161
|
|
|
131
162
|
if sid == 0: # rectangle shape
|
|
132
163
|
latr, lonr, lats, lons = bs.unpack_from('s11u12u8u8', buff, i)
|
|
133
|
-
if self.monlevel
|
|
164
|
+
if self.monlevel >= 2:
|
|
134
165
|
print(f"{reg} {area:2d} {sid} {latr*0.1:5.1f} "
|
|
135
166
|
f"{lonr*0.1:5.1f} {lats*0.1:3.1f} {lons*0.1:3.1f}")
|
|
136
167
|
self.pnt[reg][area] = areaInfo(
|
|
137
168
|
sid, latr*0.1, lonr*0.1, lats*0.1, lons*0.1)
|
|
138
169
|
else: # circle range
|
|
139
170
|
latr, lonr, rng = bs.unpack_from('s15u16u8', buff, i)
|
|
140
|
-
if self.monlevel
|
|
171
|
+
if self.monlevel >= 2:
|
|
141
172
|
print(f"{reg} {area:2d} {sid} {latr*0.01:6.2f} "
|
|
142
173
|
f"{lonr*0.01:6.2f} {rng*10}")
|
|
143
174
|
self.pnt[reg][area] = areaInfo(
|
|
@@ -146,7 +177,9 @@ class cssr_mdc(cssr):
|
|
|
146
177
|
return i
|
|
147
178
|
|
|
148
179
|
def get_inet(self, reg, area):
|
|
149
|
-
""" region
|
|
180
|
+
"""Convert region and area ID to network index."""
|
|
181
|
+
if reg < 0 or area < 0:
|
|
182
|
+
return -1
|
|
150
183
|
|
|
151
184
|
inet = 0
|
|
152
185
|
for r in self.narea_t.keys():
|
|
@@ -159,12 +192,23 @@ class cssr_mdc(cssr):
|
|
|
159
192
|
return inet
|
|
160
193
|
|
|
161
194
|
def decode_mdc_stec_corr(self, buff, i=0):
|
|
162
|
-
"""
|
|
195
|
+
"""Decode MT2 STEC correction message."""
|
|
163
196
|
dtow, uid, mi, iodssr = bs.unpack_from('u12u4u1u4', buff, i)
|
|
164
197
|
i += 21
|
|
198
|
+
if self.tow0 >= 0:
|
|
199
|
+
tow = self.tow0 + dtow
|
|
200
|
+
if self.tow >= 0 and tow < self.tow - 1800:
|
|
201
|
+
tow += 3600
|
|
202
|
+
self.tow = tow
|
|
203
|
+
t0 = gpst2time(self.week, self.tow) if self.week >= 0 else gtime_t()
|
|
204
|
+
if self.week >= 0:
|
|
205
|
+
self.time = t0
|
|
165
206
|
reg, area, stype_ = bs.unpack_from('u8u5u2', buff, i)
|
|
166
207
|
i += 15
|
|
167
208
|
|
|
209
|
+
self.reg = reg
|
|
210
|
+
self.area = area
|
|
211
|
+
|
|
168
212
|
nsat = bs.unpack_from('u5u5u5u5u5', buff, i)
|
|
169
213
|
i += 25
|
|
170
214
|
# gps, glo, gal, bds, qzss
|
|
@@ -172,7 +216,6 @@ class cssr_mdc(cssr):
|
|
|
172
216
|
|
|
173
217
|
inet = self.get_inet(reg, area)
|
|
174
218
|
|
|
175
|
-
self.lc[inet].nsat_n = np.sum(nsat)
|
|
176
219
|
ci = {}
|
|
177
220
|
qi = {}
|
|
178
221
|
stype = {}
|
|
@@ -181,39 +224,29 @@ class cssr_mdc(cssr):
|
|
|
181
224
|
for gnss in range(5):
|
|
182
225
|
sys = sys_t[gnss]
|
|
183
226
|
for k in range(nsat[gnss]):
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
prn, qi_, c00 = bs.unpack_from('u6u6s14', buff, i)
|
|
187
|
-
i += 26
|
|
227
|
+
prn, cls_, val = bs.unpack_from('u6u3u3', buff, i)
|
|
228
|
+
i += 12
|
|
188
229
|
|
|
189
230
|
if sys == uGNSS.QZS:
|
|
190
231
|
prn += 192
|
|
191
232
|
sat = prn2sat(sys, prn)
|
|
192
|
-
|
|
233
|
+
ci_sat, i = self.decode_cssr_stec_coeff(buff, stype_, i)
|
|
234
|
+
if np.isnan(ci_sat).any():
|
|
235
|
+
continue
|
|
236
|
+
qi[sat] = self.quality_idx(cls_, val)
|
|
193
237
|
stype[sat] = stype_
|
|
194
|
-
|
|
195
|
-
if stype_ > 0:
|
|
196
|
-
c01, c10 = bs.unpack_from('s12s12', buff, i)
|
|
197
|
-
i += 24
|
|
198
|
-
if stype_ > 1:
|
|
199
|
-
c11 = bs.unpack_from('s10', buff, i)[0]
|
|
200
|
-
i += 10
|
|
201
|
-
if stype_ > 2:
|
|
202
|
-
c02, c20 = bs.unpack_from('s8s8', buff, i)
|
|
203
|
-
i += 16
|
|
204
|
-
|
|
205
238
|
sat_ += [sat]
|
|
206
|
-
ci[sat] =
|
|
207
|
-
|
|
208
|
-
c02*5e-3, c20*5e-3])
|
|
239
|
+
ci[sat] = ci_sat
|
|
240
|
+
self.set_t0(inet, sat, sCType.STEC, t0)
|
|
209
241
|
j += 1
|
|
210
242
|
|
|
243
|
+
self.lc[inet].nsat_n = len(sat_)
|
|
244
|
+
self.lc[inet].flg_stec = 2
|
|
211
245
|
self.lc[inet].stype = stype
|
|
212
246
|
self.lc[inet].sat_n = sat_
|
|
213
247
|
self.lc[inet].ci = ci
|
|
214
248
|
self.lc[inet].stec_quality = qi
|
|
215
249
|
|
|
216
|
-
t0 = gpst2time(self.week, self.tow0+dtow)
|
|
217
250
|
self.set_t0(inet, 0, sCType.STEC, t0)
|
|
218
251
|
self.lc[inet].cstat |= (1 << sCType.STEC)
|
|
219
252
|
|
|
@@ -221,15 +254,60 @@ class cssr_mdc(cssr):
|
|
|
221
254
|
|
|
222
255
|
return i
|
|
223
256
|
|
|
257
|
+
def out_log(self):
|
|
258
|
+
# if self.msgtype not in (1, 2):
|
|
259
|
+
# return super(cssr_mdc, self).out_log()
|
|
260
|
+
"""Write decoded MADOCA-PPP STEC messages to log file."""
|
|
261
|
+
sz_t = [1, 3, 4, 6]
|
|
262
|
+
|
|
263
|
+
if self.time == -1:
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
self.fh.write("{:4d}\t{:s}\n".format(self.msgtype,
|
|
267
|
+
time2str(self.time)))
|
|
268
|
+
|
|
269
|
+
if self.msgtype == 1:
|
|
270
|
+
|
|
271
|
+
self.fh.write(f"Reg\tArea\tsid\t"
|
|
272
|
+
f"latr\tlonr\tlats\tlons\n")
|
|
273
|
+
|
|
274
|
+
for area in self.pnt[self.reg].keys():
|
|
275
|
+
p = self.pnt[self.reg][area]
|
|
276
|
+
self.fh.write(f"{self.reg}\t{area:2d}\t{p.sid}\t"
|
|
277
|
+
f"{p.latr:3.1f}\t{p.lonr:4.1f}\t")
|
|
278
|
+
|
|
279
|
+
if p.sid == 0:
|
|
280
|
+
self.fh.write(f"{p.lats:3.1f}\t{p.lons:3.1f}\n")
|
|
281
|
+
else:
|
|
282
|
+
self.fh.write(f"{p.rng:3.1f}\n")
|
|
283
|
+
|
|
284
|
+
elif self.msgtype == 2:
|
|
285
|
+
inet = self.get_inet(self.reg, self.area)
|
|
286
|
+
|
|
287
|
+
self.fh.write(f"Reg:{self.reg}\tArea:{self.area:2d}\n")
|
|
288
|
+
self.fh.write("Sat,stype,c00,c01,c10,c11,c20,c02\n")
|
|
289
|
+
|
|
290
|
+
for sat in self.lc[inet].sat_n:
|
|
291
|
+
stype = self.lc[inet].stype[sat]
|
|
292
|
+
ci = self.lc[inet].ci[sat]
|
|
293
|
+
self.fh.write(f"{sat2id(sat)}\t{stype}")
|
|
294
|
+
for k in range(sz_t[stype]):
|
|
295
|
+
self.fh.write(f"\t{ci[k]:6.2f}")
|
|
296
|
+
self.fh.write("\n")
|
|
297
|
+
self.fh.flush()
|
|
298
|
+
|
|
224
299
|
def decode_cssr(self, msg, i=0):
|
|
225
|
-
"""
|
|
300
|
+
"""Decode Compact SSR message with MADOCA-PPP extension."""
|
|
226
301
|
df = {'msgtype': 4073}
|
|
227
302
|
while df['msgtype'] in [1, 2, 4073]:
|
|
303
|
+
if len(msg)*8 < i + 16:
|
|
304
|
+
return 0
|
|
228
305
|
df = bs.unpack_from_dict('u12u4', ['msgtype', 'subtype'], msg, i)
|
|
229
306
|
i += 16
|
|
230
307
|
if df['msgtype'] not in [1, 2, 4073]:
|
|
231
308
|
return -1
|
|
232
309
|
|
|
310
|
+
self.msgtype = df['msgtype']
|
|
233
311
|
self.subtype = df['subtype']
|
|
234
312
|
if df['msgtype'] == 4073: # Compact SSR
|
|
235
313
|
if self.subtype == sCSSR.MASK:
|