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.
Files changed (51) hide show
  1. {cssrlib-1.2.0/src/cssrlib.egg-info → cssrlib-1.3.2}/PKG-INFO +2 -2
  2. {cssrlib-1.2.0 → cssrlib-1.3.2}/pyproject.toml +2 -2
  3. {cssrlib-1.2.0 → cssrlib-1.3.2}/setup.cfg +1 -1
  4. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/__init__.py +2 -0
  5. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_bds.py +21 -13
  6. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_has.py +24 -17
  7. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_mdc.py +126 -48
  8. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssr_pvs.py +16 -11
  9. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/cssrlib.py +811 -107
  10. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/dgps.py +41 -22
  11. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ephemeris.py +96 -60
  12. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ewss.py +270 -91
  13. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/gnss.py +590 -334
  14. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/mlambda.py +174 -100
  15. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/osnma.py +74 -54
  16. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/peph.py +219 -117
  17. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/plot.py +41 -16
  18. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/pntpos.py +66 -34
  19. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/ppp.py +97 -117
  20. cssrlib-1.3.2/src/cssrlib/ppprtk.py +23 -0
  21. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/pppssr.py +315 -176
  22. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/qznma.py +49 -32
  23. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rawnav.py +97 -89
  24. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rinex.py +545 -519
  25. cssrlib-1.3.2/src/cssrlib/rtcm.py +4974 -0
  26. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/rtk.py +6 -10
  27. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/sbas.py +213 -106
  28. cssrlib-1.3.2/src/cssrlib/test/test_eph.py +75 -0
  29. cssrlib-1.3.2/src/cssrlib/test/test_rnx.py +81 -0
  30. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/tlesim.py +4 -6
  31. cssrlib-1.3.2/src/cssrlib/utils.py +258 -0
  32. {cssrlib-1.2.0 → cssrlib-1.3.2/src/cssrlib.egg-info}/PKG-INFO +2 -2
  33. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/SOURCES.txt +1 -0
  34. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/requires.txt +1 -1
  35. cssrlib-1.2.0/src/cssrlib/ppprtk.py +0 -24
  36. cssrlib-1.2.0/src/cssrlib/rtcm.py +0 -2758
  37. cssrlib-1.2.0/src/cssrlib/test/test_eph.py +0 -50
  38. cssrlib-1.2.0/src/cssrlib/test/test_rnx.py +0 -59
  39. {cssrlib-1.2.0 → cssrlib-1.3.2}/LICENSE +0 -0
  40. {cssrlib-1.2.0 → cssrlib-1.3.2}/MANIFEST.in +0 -0
  41. {cssrlib-1.2.0 → cssrlib-1.3.2}/README.md +0 -0
  42. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/30340780.21q +0 -0
  43. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/3034078M1.21O +0 -0
  44. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/SEPT078M.21P +0 -0
  45. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/data/SEPT078M1.21O +0 -0
  46. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_gnss.py +0 -0
  47. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_peph.py +0 -0
  48. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib/test/test_rtk.py +0 -0
  49. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/dependency_links.txt +0 -0
  50. {cssrlib-1.2.0 → cssrlib-1.3.2}/src/cssrlib.egg-info/not-zip-safe +0 -0
  51. {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.0
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: pysolid
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.0"
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
- "pysolid",
26
+ "cryptography",
27
27
  ]
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = cssrlib
3
- version = 1.2.0
3
+ version = 1.3.2
4
4
  author = Rui Hirokawa
5
5
  author_email = rui.hirokawa@gmail.com
6
6
  description = Python Toolkit for PPP/PPP-RTK positioning
@@ -1,3 +1,5 @@
1
+ """CSSRLIB package for GNSS SSR and PPP/PPP-RTK processing."""
2
+
1
3
 
2
4
  from cssrlib.gnss import (gpst2time,epoch2time,ecef2pos,
3
5
  prn2sat)
@@ -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 Interface Control Document
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
- """ calculate signed value based on n-bit int, lsb """
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 = {'uint': 0, 'mi': 0, 'iodssr': iodssr}
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
- """decode MT1 Mask message """
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
- """decode MT2 orbit + URA message """
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
- """decode MT3 Code Bias Correction message """
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
- """ decode clock correction for satellite """
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
- """decode MT4 Clock Correction message """
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
- """decode MT5 URA message """
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
- """decode MT6 combined message #1 """
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
- """decode MT7 combined message #2 """
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
- """ calculate signed value based on n-bit int, lsb """
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
- """ decode header part of HAS messages """
62
-
64
+ """Decode header part of HAS messages."""
63
65
  if st == sCSSR.MASK:
64
- ui = 0
66
+ udi = 0
65
67
  else:
66
- ui = bs.unpack_from('u4', msg, i)[0]
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 = {'uint': ui, 'mi': 0, 'iodssr': self.iodssr}
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
- """ decode HAS messages """
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
- """ class to handle Galileo E6 (CNAV) message """
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
- """ decode header of HAS pages (obsoleted) """
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 decoding for RS(255,32,224) """
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
- """ decode Galileo CNAV message """
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-004), 2025
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
- """ find region/area """
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.key():
67
- for area in self.pnt[reg].key():
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
- break
99
+ min_dist = dist
75
100
  elif p.sid == 1: # circle
76
- dn = (latd - p.latr)*rCST.D2R*rCST.RE_WGS84
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
- break
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
- """ calculate position offset from reference """
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
- """ calculate STEC correction by interporation """
124
+ """Calculate STEC correction by interporation."""
103
125
  if self.inet < 0:
104
126
  print("get_stec: region, area not defined.")
105
- return 0.0
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(self.nsat_n)
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(self.sat_n):
113
- stec[i] = [1, dlat, dlon, dlat*dlon, dlat**2, dlon**2]@p.ci[sat]
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
- """ decoder for MT1 - STEC Coverage Message """
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 > 2:
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 > 2:
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, area to inet conversion """
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
- """ decoder for MT2 - STEC Correction Message """
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
- c01 = c10 = c11 = c02 = c20 = 0.0
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
- qi[sat] = qi_
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] = np.array(
207
- [c00*0.05, c01*0.02, c10*0.02, c11*0.02,
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
- """decode Compact SSR message with MADOCA-PPP extension """
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: