cssrlib 1.0.0__tar.gz → 1.1.0__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.0.0/src/cssrlib.egg-info → cssrlib-1.1.0}/PKG-INFO +3 -10
- {cssrlib-1.0.0 → cssrlib-1.1.0}/README.md +2 -9
- {cssrlib-1.0.0 → cssrlib-1.1.0}/setup.cfg +1 -1
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/cssr_bds.py +25 -13
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/cssr_has.py +10 -3
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/cssrlib.py +33 -20
- cssrlib-1.1.0/src/cssrlib/dgps.py +289 -0
- cssrlib-1.1.0/src/cssrlib/ephemeris.py +894 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/gnss.py +100 -41
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/peph.py +28 -15
- cssrlib-1.1.0/src/cssrlib/pntpos.py +546 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/pppssr.py +43 -14
- cssrlib-1.1.0/src/cssrlib/rawnav.py +1662 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/rinex.py +168 -49
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/rtcm.py +110 -79
- cssrlib-1.1.0/src/cssrlib/sbas.py +1073 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/test/test_peph.py +14 -15
- {cssrlib-1.0.0 → cssrlib-1.1.0/src/cssrlib.egg-info}/PKG-INFO +3 -10
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib.egg-info/SOURCES.txt +2 -0
- cssrlib-1.0.0/src/cssrlib/ephemeris.py +0 -435
- cssrlib-1.0.0/src/cssrlib/pntpos.py +0 -125
- cssrlib-1.0.0/src/cssrlib/rawnav.py +0 -522
- {cssrlib-1.0.0 → cssrlib-1.1.0}/LICENSE +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/MANIFEST.in +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/pyproject.toml +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/__init__.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/cssr_pvs.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/data/30340780.21q +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/data/3034078M1.21O +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/data/SEPT078M.21P +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/data/SEPT078M1.21O +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/mlambda.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/plot.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/ppp.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/ppprtk.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/rtk.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/test/test_eph.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/test/test_gnss.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/test/test_rnx.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/test/test_rtk.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib/tlesim.py +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib.egg-info/dependency_links.txt +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib.egg-info/not-zip-safe +0 -0
- {cssrlib-1.0.0 → cssrlib-1.1.0}/src/cssrlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cssrlib
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Python Toolkit for PPP/PPP-RTK positioning
|
|
5
5
|
Home-page: https://github.com/hirokawa/cssrlib
|
|
6
6
|
Author: Rui Hirokawa
|
|
@@ -38,17 +38,10 @@ Click this button for a quick demo in Google Colab
|
|
|
38
38
|
|
|
39
39
|
Prerequisites
|
|
40
40
|
=============
|
|
41
|
-
Additional python packages are required as prerequisites and can be installed via the following
|
|
41
|
+
Additional python packages are required as prerequisites and can be installed via the following command
|
|
42
42
|
|
|
43
43
|
```
|
|
44
|
-
pip install
|
|
45
|
-
pip install notebook numpy matplotlib
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Optionally, on linux, users can install the `cartopy` package and the `PySolid` package
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
pip install cartopy pysolid
|
|
44
|
+
pip install -r requirements.txt
|
|
52
45
|
```
|
|
53
46
|
|
|
54
47
|
If the installation of `cartopy` fails, try installing `libgeos++-dev` first.
|
|
@@ -23,17 +23,10 @@ Click this button for a quick demo in Google Colab
|
|
|
23
23
|
|
|
24
24
|
Prerequisites
|
|
25
25
|
=============
|
|
26
|
-
Additional python packages are required as prerequisites and can be installed via the following
|
|
26
|
+
Additional python packages are required as prerequisites and can be installed via the following command
|
|
27
27
|
|
|
28
28
|
```
|
|
29
|
-
pip install
|
|
30
|
-
pip install notebook numpy matplotlib
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Optionally, on linux, users can install the `cartopy` package and the `PySolid` package
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
pip install cartopy pysolid
|
|
29
|
+
pip install -r requirements.txt
|
|
37
30
|
```
|
|
38
31
|
|
|
39
32
|
If the installation of `cartopy` fails, try installing `libgeos++-dev` first.
|
|
@@ -19,6 +19,8 @@ class cssr_bds(cssr):
|
|
|
19
19
|
self.nsig_max = 8
|
|
20
20
|
self.iodp = -1
|
|
21
21
|
self.iodp_p = -1
|
|
22
|
+
self.cb_blen = 12
|
|
23
|
+
self.cb_scl = 0.017
|
|
22
24
|
|
|
23
25
|
def ssig2rsig(self, sys: sGNSS, utyp: uTYP, ssig):
|
|
24
26
|
gps_tbl = {
|
|
@@ -177,9 +179,16 @@ class cssr_bds(cssr):
|
|
|
177
179
|
return i
|
|
178
180
|
|
|
179
181
|
def decode_cssr_orb_sat(self, msg, i, inet, sat_n):
|
|
180
|
-
slot, iodn, iodc
|
|
181
|
-
|
|
182
|
-
|
|
182
|
+
slot, iodn, iodc = bs.unpack_from('u9u10u3', msg, i)
|
|
183
|
+
i += 22
|
|
184
|
+
|
|
185
|
+
dx, dy, dz = bs.unpack_from('s{:d}s{:d}s{:d}'.format(
|
|
186
|
+
self.dorb_blen[0], self.dorb_blen[1], self.dorb_blen[2]), msg, i)
|
|
187
|
+
i += self.dorb_blen[0] + self.dorb_blen[1] + self.dorb_blen[2]
|
|
188
|
+
|
|
189
|
+
ucls, uval = bs.unpack_from('u3u3', msg, i)
|
|
190
|
+
i += 6
|
|
191
|
+
|
|
183
192
|
sys, prn = self.slot2prn(slot)
|
|
184
193
|
if sys == uGNSS.NONE:
|
|
185
194
|
return i
|
|
@@ -191,9 +200,9 @@ class cssr_bds(cssr):
|
|
|
191
200
|
iodn = iodn & 0xff # IODC -> IODE
|
|
192
201
|
|
|
193
202
|
dorb = np.zeros(3)
|
|
194
|
-
dorb[0] = self.sval(dx,
|
|
195
|
-
dorb[1] = self.sval(dy,
|
|
196
|
-
dorb[2] = self.sval(dz,
|
|
203
|
+
dorb[0] = self.sval(dx, self.dorb_blen[0], self.dorb_scl[0])
|
|
204
|
+
dorb[1] = self.sval(dy, self.dorb_blen[1], self.dorb_scl[1])
|
|
205
|
+
dorb[2] = self.sval(dz, self.dorb_blen[2], self.dorb_scl[2])
|
|
197
206
|
|
|
198
207
|
self.lc[inet].iode[sat] = iodn
|
|
199
208
|
self.lc[inet].iodc[sat] = iodc
|
|
@@ -220,7 +229,7 @@ class cssr_bds(cssr):
|
|
|
220
229
|
self.iodssr_c[sCType.ORBIT] = head['iodssr']
|
|
221
230
|
self.lc[inet].cstat |= (1 << sCType.ORBIT)
|
|
222
231
|
|
|
223
|
-
i += 19
|
|
232
|
+
i += 19 # reserve
|
|
224
233
|
return i
|
|
225
234
|
|
|
226
235
|
def decode_cssr_cbias(self, msg, i, inet=0):
|
|
@@ -248,10 +257,12 @@ class cssr_bds(cssr):
|
|
|
248
257
|
|
|
249
258
|
self.lc[inet].cbias[sat] = {}
|
|
250
259
|
for j in range(0, nsig):
|
|
251
|
-
sig, cb = bs.unpack_from(
|
|
252
|
-
|
|
260
|
+
sig, cb = bs.unpack_from(
|
|
261
|
+
'u4s{:d}'.format(self.cb_blen), msg, i)
|
|
262
|
+
i += 4+self.cb_blen
|
|
253
263
|
sig_ = self.ssig2rsig(sys, uTYP.C, sig)
|
|
254
|
-
self.lc[inet].cbias[sat][sig_] = self.sval(
|
|
264
|
+
self.lc[inet].cbias[sat][sig_] = self.sval(
|
|
265
|
+
cb, self.cb_blen, self.cb_scl)
|
|
255
266
|
|
|
256
267
|
self.iodssr_c[sCType.CBIAS] = head['iodssr']
|
|
257
268
|
self.lc[inet].cstat |= (1 << sCType.CBIAS)
|
|
@@ -260,8 +271,8 @@ class cssr_bds(cssr):
|
|
|
260
271
|
|
|
261
272
|
def decode_cssr_clk_sat(self, msg, i, inet, sat):
|
|
262
273
|
""" decode clock correction for satellite """
|
|
263
|
-
iodc, dclk = bs.unpack_from('
|
|
264
|
-
i +=
|
|
274
|
+
iodc, dclk = bs.unpack_from('u3s{:d}'.format(self.dclk_blen), msg, i)
|
|
275
|
+
i += 3+self.dclk_blen
|
|
265
276
|
|
|
266
277
|
if sat in self.lc[inet].iodc_c.keys() and \
|
|
267
278
|
iodc != self.lc[inet].iodc_c[sat]:
|
|
@@ -269,7 +280,8 @@ class cssr_bds(cssr):
|
|
|
269
280
|
self.lc[inet].dclk_p[sat] = self.lc[inet].dclk[sat]
|
|
270
281
|
self.lc[inet].iodc_c[sat] = iodc
|
|
271
282
|
# note: the sign of the clock correction reversed
|
|
272
|
-
self.lc[inet].dclk[sat] = -
|
|
283
|
+
self.lc[inet].dclk[sat] = - \
|
|
284
|
+
self.sval(dclk, self.dclk_blen, self.dclk_scl)
|
|
273
285
|
return i
|
|
274
286
|
|
|
275
287
|
def decode_cssr_clk(self, msg, i, inet=0):
|
|
@@ -75,13 +75,20 @@ class cssr_has(cssr):
|
|
|
75
75
|
return head, i
|
|
76
76
|
|
|
77
77
|
def decode_cssr(self, msg, i=0):
|
|
78
|
-
|
|
78
|
+
# Galileo HAS-SIS only defines MT=1, MT=4073 is CSSR message used in the
|
|
79
|
+
# Galileo HAS test dataset
|
|
80
|
+
#
|
|
81
|
+
if self.msgtype != 1 and self.msgtype != 4073:
|
|
79
82
|
print(f"invalid MT={self.msgtype}")
|
|
80
83
|
return False
|
|
81
84
|
# time of hour
|
|
82
85
|
# flags: mask,orbit,clock,clock subset,cbias,pbias,mask_id,iodset_id
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
try:
|
|
87
|
+
self.toh, flags, res, mask_id, self.iodssr = \
|
|
88
|
+
bs.unpack_from('u12u6u4u5u5', msg, i)
|
|
89
|
+
except:
|
|
90
|
+
print(f"invalid content={self.msgtype}")
|
|
91
|
+
return False
|
|
85
92
|
i += 32
|
|
86
93
|
|
|
87
94
|
if self.monlevel > 0 and self.fh is not None:
|
|
@@ -18,6 +18,10 @@ class sCSSRTYPE(IntEnum):
|
|
|
18
18
|
IGS_SSR = 5
|
|
19
19
|
RTCM3_SSR = 6
|
|
20
20
|
PVS_PPP = 7 # PPP via SouthPAN
|
|
21
|
+
SBAS_L1 = 8 # L1 SBAS
|
|
22
|
+
SBAS_L5 = 9 # L5 SBAS (DFMC)
|
|
23
|
+
DGPS = 10 # DGPS (QZSS SLAS)
|
|
24
|
+
STDPOS = 11
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class sGNSS(IntEnum):
|
|
@@ -61,7 +65,7 @@ class sCType(IntEnum):
|
|
|
61
65
|
TROP = 6
|
|
62
66
|
URA = 7
|
|
63
67
|
AUTH = 8
|
|
64
|
-
HCLOCK =
|
|
68
|
+
HCLOCK = 9
|
|
65
69
|
VTEC = 10
|
|
66
70
|
MAX = 11
|
|
67
71
|
|
|
@@ -206,11 +210,12 @@ class local_corr:
|
|
|
206
210
|
self.inet = -1
|
|
207
211
|
self.inet_ref = -1
|
|
208
212
|
self.ng = -1
|
|
209
|
-
self.pbias =
|
|
210
|
-
self.cbias =
|
|
213
|
+
self.pbias = {}
|
|
214
|
+
self.cbias = {}
|
|
211
215
|
self.iode = None
|
|
212
216
|
self.dorb = None
|
|
213
217
|
self.dclk = None
|
|
218
|
+
self.hclk = None
|
|
214
219
|
self.stec = None
|
|
215
220
|
self.trph = None
|
|
216
221
|
self.trpw = None
|
|
@@ -218,10 +223,14 @@ class local_corr:
|
|
|
218
223
|
self.ct = None
|
|
219
224
|
self.quality_trp = None
|
|
220
225
|
self.quality_stec = None
|
|
221
|
-
self.
|
|
222
|
-
|
|
223
|
-
self.t0.append(gtime_t())
|
|
226
|
+
self.sat_n = []
|
|
227
|
+
self.t0 = {}
|
|
224
228
|
self.cstat = 0 # status for receiving CSSR message
|
|
229
|
+
self.t0s = {}
|
|
230
|
+
sc_t = [sCType.CLOCK, sCType.ORBIT, sCType.CBIAS, sCType.PBIAS,
|
|
231
|
+
sCType.HCLOCK]
|
|
232
|
+
for sc in sc_t:
|
|
233
|
+
self.t0s[sc] = gtime_t()
|
|
225
234
|
|
|
226
235
|
|
|
227
236
|
class cssr:
|
|
@@ -272,7 +281,7 @@ class cssr:
|
|
|
272
281
|
self.lc = []
|
|
273
282
|
self.fcnt = -1
|
|
274
283
|
self.flg_net = False
|
|
275
|
-
self.time =
|
|
284
|
+
self.time = gtime_t()
|
|
276
285
|
self.nsig_max = 0
|
|
277
286
|
self.ngrid = 0
|
|
278
287
|
self.grid_index = []
|
|
@@ -440,9 +449,15 @@ class cssr:
|
|
|
440
449
|
return False
|
|
441
450
|
|
|
442
451
|
def set_t0(self, inet=0, sat=0, ctype=0, t=gtime_t()):
|
|
443
|
-
""" set reference time for
|
|
452
|
+
""" set reference time for correction to check validity time """
|
|
453
|
+
sc_t = [sCType.CLOCK, sCType.ORBIT, sCType.CBIAS, sCType.PBIAS,
|
|
454
|
+
sCType.HCLOCK]
|
|
455
|
+
|
|
444
456
|
if sat not in self.lc[inet].t0:
|
|
445
457
|
self.lc[inet].t0[sat] = {}
|
|
458
|
+
for sc in sc_t:
|
|
459
|
+
self.lc[inet].t0[sat][sc] = gtime_t()
|
|
460
|
+
|
|
446
461
|
self.lc[inet].t0[sat][ctype] = t
|
|
447
462
|
|
|
448
463
|
def quality_idx(self, cl, val):
|
|
@@ -682,7 +697,6 @@ class cssr:
|
|
|
682
697
|
self.lc[inet].cbias = {}
|
|
683
698
|
for k in range(nsat):
|
|
684
699
|
sat = self.sat_n[k]
|
|
685
|
-
sys, _ = sat2prn(sat)
|
|
686
700
|
self.lc[inet].cbias[sat] = {}
|
|
687
701
|
for j in range(len(self.sig_n[sat])):
|
|
688
702
|
rsig = self.sig_n[sat][j].toTyp(uTYP.C)
|
|
@@ -703,7 +717,6 @@ class cssr:
|
|
|
703
717
|
self.lc[inet].di = {}
|
|
704
718
|
for k in range(nsat):
|
|
705
719
|
sat = self.sat_n[k]
|
|
706
|
-
sys, _ = sat2prn(sat)
|
|
707
720
|
self.lc[inet].pbias[sat] = {}
|
|
708
721
|
self.lc[inet].di[sat] = {}
|
|
709
722
|
for j in range(len(self.sig_n[sat])):
|
|
@@ -904,8 +917,8 @@ class cssr:
|
|
|
904
917
|
def decode_cssr_comb(self, msg, i, inet=0):
|
|
905
918
|
"""decode MT4073,11 Orbit,Clock Combined Correction message """
|
|
906
919
|
head, i = self.decode_head(msg, i)
|
|
907
|
-
|
|
908
|
-
|
|
920
|
+
if self.iodssr != head['iodssr']:
|
|
921
|
+
return -1
|
|
909
922
|
dfm = bs.unpack_from_dict('b1b1b1', ['orb', 'clk', 'net'], msg, i)
|
|
910
923
|
i += 3
|
|
911
924
|
self.flg_net = dfm['net']
|
|
@@ -1122,7 +1135,7 @@ class cssr:
|
|
|
1122
1135
|
|
|
1123
1136
|
if self.subtype == sCSSR.CLOCK:
|
|
1124
1137
|
self.fh.write(" {:s}\t{:s}\n".format("SatID", "dclk [m]"))
|
|
1125
|
-
for
|
|
1138
|
+
for sat_ in self.lc[0].dclk.keys():
|
|
1126
1139
|
if np.isnan(self.lc[0].dclk[sat_]):
|
|
1127
1140
|
continue
|
|
1128
1141
|
self.fh.write(" {:s}\t{:8.4f}\n"
|
|
@@ -1133,7 +1146,7 @@ class cssr:
|
|
|
1133
1146
|
self.fh.write(" {:s}\t{:s}\t{:s}\t{:s}\t{:s}\n"
|
|
1134
1147
|
.format("SatID", "IODE", "Radial[m]",
|
|
1135
1148
|
"Along[m]", "Cross[m]"))
|
|
1136
|
-
for
|
|
1149
|
+
for sat_ in self.lc[0].dorb.keys():
|
|
1137
1150
|
if np.isnan(self.lc[0].dorb[sat_][0]):
|
|
1138
1151
|
continue
|
|
1139
1152
|
self.fh.write(" {:s}\t{:3d}\t{:6.3f}\t{:6.3f}\t{:6.3f}\n"
|
|
@@ -1147,12 +1160,12 @@ class cssr:
|
|
|
1147
1160
|
self.fh.write(" {:s}\t{:s}\t{:s}\t{:s}\t{:s}\t{:s}\n"
|
|
1148
1161
|
.format("SatID", "IODE", "Radial[m]",
|
|
1149
1162
|
"Along[m]", "Cross[m]", "dclk[m]"))
|
|
1150
|
-
for
|
|
1163
|
+
for sat_ in self.lc[0].dorb.keys():
|
|
1151
1164
|
if np.isnan(self.lc[0].dorb[sat_][0]) or \
|
|
1152
1165
|
np.isnan(self.lc[0].dclk[sat_]):
|
|
1153
1166
|
continue
|
|
1154
1167
|
self.fh.write(
|
|
1155
|
-
" {:s}\t{:3d}\t{:6.3f}\t{:6.3f}\t{:6.3f}\t{:
|
|
1168
|
+
" {:s}\t{:3d}\t{:6.3f}\t{:6.3f}\t{:6.3f}\t{:8.4f}\n"
|
|
1156
1169
|
.format(sat2id(sat_),
|
|
1157
1170
|
self.lc[0].iode[sat_],
|
|
1158
1171
|
self.lc[0].dorb[sat_][0],
|
|
@@ -1163,9 +1176,9 @@ class cssr:
|
|
|
1163
1176
|
elif self.subtype == sCSSR.CBIAS:
|
|
1164
1177
|
self.fh.write(" {:s}\t{:s}\t{:s}\t{:s}\n"
|
|
1165
1178
|
.format("SatID", "SigID", "Code Bias[m]", "..."))
|
|
1166
|
-
for
|
|
1179
|
+
for sat_ in self.lc[0].cbias.keys():
|
|
1167
1180
|
self.fh.write(" {:s}\t".format(sat2id(sat_)))
|
|
1168
|
-
for sig_ in
|
|
1181
|
+
for sig_ in self.lc[0].cbias[sat_].keys():
|
|
1169
1182
|
self.fh.write("{:s}\t{:5.2f}\t"
|
|
1170
1183
|
.format(sig_.str(),
|
|
1171
1184
|
self.lc[0].cbias[sat_][sig_]))
|
|
@@ -1174,9 +1187,9 @@ class cssr:
|
|
|
1174
1187
|
elif self.subtype == sCSSR.PBIAS:
|
|
1175
1188
|
self.fh.write(" {:s}\t{:s}\t{:s}\t{:s}\n"
|
|
1176
1189
|
.format("SatID", "SigID", "Phase Bias[m]", "..."))
|
|
1177
|
-
for
|
|
1190
|
+
for sat_ in self.lc[0].pbias.keys():
|
|
1178
1191
|
self.fh.write(" {:s}\t".format(sat2id(sat_)))
|
|
1179
|
-
for sig_ in
|
|
1192
|
+
for sig_ in self.lc[0].pbias[sat_].keys():
|
|
1180
1193
|
self.fh.write("{:s}\t{:5.2f}\t"
|
|
1181
1194
|
.format(sig_.str(),
|
|
1182
1195
|
self.lc[0].pbias[sat_][sig_]))
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DGPS (QZSS SLAS) correction data decoder
|
|
3
|
+
|
|
4
|
+
[1] Quasi-Zenith Satellite System Interface Specification
|
|
5
|
+
Sub-meter Level Augmentation Service (IS-QZSS-L1S-006), 2023
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import bitstruct as bs
|
|
11
|
+
from cssrlib.cssrlib import cssr, sCSSRTYPE, prn2sat, sCType
|
|
12
|
+
from cssrlib.gnss import uGNSS, rCST, timediff, time2str, \
|
|
13
|
+
ecef2pos
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def vardgps(el, nav):
|
|
17
|
+
""" measurement error varianvce for DGPS [1] """
|
|
18
|
+
c_el = np.cos(el)
|
|
19
|
+
pos = ecef2pos(nav.x[0:3])
|
|
20
|
+
Fpp = 1/np.sqrt(1-(rCST.RE_WGS84*c_el/(rCST.RE_WGS84+pos[2]))**2)
|
|
21
|
+
s_iono = Fpp*0.004*(nav.baseline+2*100*0.07)
|
|
22
|
+
s_mp = 0.13+0.53*np.exp(-el/0.1745)
|
|
23
|
+
v_air = 0.11**2 + s_mp**2
|
|
24
|
+
v_pr = (0.16+0.107*np.exp(-el/0.271))**2/1+0.08**2
|
|
25
|
+
v_sig = v_pr + v_air + s_iono**2
|
|
26
|
+
return v_sig
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class dgpsDec(cssr):
|
|
30
|
+
MAX_ST = 64
|
|
31
|
+
MAX_SAT = 23
|
|
32
|
+
|
|
33
|
+
def __init__(self, foutname=None):
|
|
34
|
+
super().__init__(foutname)
|
|
35
|
+
self.MAXNET = 1
|
|
36
|
+
self.cssrmode = sCSSRTYPE.DGPS
|
|
37
|
+
self.nsig_max = 0
|
|
38
|
+
self.sat_n = []
|
|
39
|
+
|
|
40
|
+
self.sat = []
|
|
41
|
+
|
|
42
|
+
self.lc[0].dclk = {}
|
|
43
|
+
self.lc[0].ddft = {}
|
|
44
|
+
self.lc[0].dorb = {}
|
|
45
|
+
self.lc[0].dvel = {}
|
|
46
|
+
self.lc[0].iode = {}
|
|
47
|
+
self.lc[0].t0 = {}
|
|
48
|
+
|
|
49
|
+
self.tmax = {sCType.CLOCK: 120.0, sCType.ORBIT: 120.0}
|
|
50
|
+
|
|
51
|
+
# GPS/QZS LNAV, Galileo F/NAV
|
|
52
|
+
self.nav_mode = {uGNSS.GPS: 0, uGNSS.GAL: 1, uGNSS.QZS: 0,
|
|
53
|
+
uGNSS.GLO: 0, uGNSS.BDS: 0}
|
|
54
|
+
|
|
55
|
+
self.iodp = -1
|
|
56
|
+
self.iodi = -1
|
|
57
|
+
self.iodm = -1
|
|
58
|
+
self.iodg = -1
|
|
59
|
+
|
|
60
|
+
self.iodssr = -1
|
|
61
|
+
self.iodp_c = {}
|
|
62
|
+
|
|
63
|
+
self.baselen = 0 # baseline length [km]
|
|
64
|
+
|
|
65
|
+
self.posr = np.zeros((self.MAX_ST, 3))
|
|
66
|
+
self.posr[0, :] = [43.150, 141.220, 50]
|
|
67
|
+
self.posr[1, :] = [38.270, 140.740, 200]
|
|
68
|
+
self.posr[3, :] = [36.580, 140.550, 150]
|
|
69
|
+
self.posr[5, :] = [36.400, 136.410, 50]
|
|
70
|
+
self.posr[6, :] = [34.710, 135.040, 200]
|
|
71
|
+
self.posr[7, :] = [34.350, 132.450, 50]
|
|
72
|
+
self.posr[8, :] = [33.600, 130.230, 50]
|
|
73
|
+
self.posr[9, :] = [30.550, 130.940, 100]
|
|
74
|
+
self.posr[10, :] = [28.420, 129.690, 50]
|
|
75
|
+
self.posr[11, :] = [26.150, 127.690, 100]
|
|
76
|
+
self.posr[12, :] = [24.730, 125.350, 100]
|
|
77
|
+
self.posr[13, :] = [24.370, 124.130, 100]
|
|
78
|
+
self.posr[14, :] = [27.090, 142.190, 100]
|
|
79
|
+
|
|
80
|
+
self.mlen = {uGNSS.GPS: 64, uGNSS.QZS: 9, uGNSS.GLO: 36, uGNSS.GAL: 36,
|
|
81
|
+
uGNSS.BDS: 36}
|
|
82
|
+
self.prn_ofst = {uGNSS.GPS: 0, uGNSS.QZS: 192, uGNSS.GLO: 0,
|
|
83
|
+
uGNSS.GAL: 0, uGNSS.BDS: 0}
|
|
84
|
+
|
|
85
|
+
def sval(self, u, n, scl):
|
|
86
|
+
""" calculate signed value based on n-bit int, lsb """
|
|
87
|
+
invalid = 2**(n-1)-1
|
|
88
|
+
y = np.nan if u == invalid else u*scl
|
|
89
|
+
return y
|
|
90
|
+
|
|
91
|
+
def check_validity(self, time):
|
|
92
|
+
for sat in self.sat_n:
|
|
93
|
+
if timediff(time, self.lc[0].t0[sat][sCType.CLOCK]) > \
|
|
94
|
+
self.tmax[sCType.CLOCK]:
|
|
95
|
+
self.lc[0].dclk[sat] = 0.0
|
|
96
|
+
if timediff(time, self.lc[0].t0[sat][sCType.ORBIT]) > \
|
|
97
|
+
self.tmax[sCType.ORBIT]:
|
|
98
|
+
self.lc[0].iode[sat] = -1
|
|
99
|
+
self.lc[0].dorb[sat] = np.zeros(3)
|
|
100
|
+
|
|
101
|
+
def decode_mt43(self, msg, i):
|
|
102
|
+
""" decode DC report by JMA (TBD) """
|
|
103
|
+
# i = self.dcr.decode_jma(msg)
|
|
104
|
+
return i
|
|
105
|
+
|
|
106
|
+
def decode_mt44(self, msg, i):
|
|
107
|
+
""" decode DC report by other organization (TBD) """
|
|
108
|
+
# i = self.dcr.decode_ews(msg)
|
|
109
|
+
return i
|
|
110
|
+
|
|
111
|
+
def decode_mt47(self, msg, i):
|
|
112
|
+
""" decode location of reference station """
|
|
113
|
+
i = 14
|
|
114
|
+
for k in range(5):
|
|
115
|
+
code, lat, lon, alt = bs.unpack_from('u6s15s15u6', msg, i)
|
|
116
|
+
if code == 63:
|
|
117
|
+
continue
|
|
118
|
+
self.posr[code, 0] = lat*0.005
|
|
119
|
+
self.posr[code, 1] = lon*0.005+115
|
|
120
|
+
self.posr[code, 2] = alt*50.0-100
|
|
121
|
+
|
|
122
|
+
i += 42
|
|
123
|
+
return 0
|
|
124
|
+
|
|
125
|
+
def decode_mt48(self, msg, i):
|
|
126
|
+
""" decode satellite mask """
|
|
127
|
+
self.iodssr_p = self.iodp
|
|
128
|
+
self.sat_n_p = self.sat_n
|
|
129
|
+
|
|
130
|
+
i = 14
|
|
131
|
+
self.nsat = 0
|
|
132
|
+
v = bs.unpack_from('u2u64u9u36u36u36', msg, i)
|
|
133
|
+
|
|
134
|
+
self.sat_n = []
|
|
135
|
+
self.iodp = v[0]
|
|
136
|
+
sys_t = [uGNSS.GPS, uGNSS.QZS, uGNSS.GLO, uGNSS.GAL, uGNSS.BDS]
|
|
137
|
+
for k, sys in enumerate(sys_t):
|
|
138
|
+
prn, nsat_s = self.decode_mask(v[k+1], self.mlen[sys])
|
|
139
|
+
for j in range(nsat_s):
|
|
140
|
+
self.sat_n.append(prn2sat(sys, prn[j]+self.prn_ofst[sys]))
|
|
141
|
+
self.nsat += nsat_s
|
|
142
|
+
|
|
143
|
+
self.iodssr = self.iodp
|
|
144
|
+
|
|
145
|
+
self.lc[0].cstat |= (1 << sCType.MASK)
|
|
146
|
+
self.set_t0(ctype=sCType.MASK, t=self.time)
|
|
147
|
+
|
|
148
|
+
self.sat = self.sat_n
|
|
149
|
+
|
|
150
|
+
return i
|
|
151
|
+
|
|
152
|
+
def decode_mt49(self, msg, i):
|
|
153
|
+
""" decode issue of data """
|
|
154
|
+
iodp = bs.unpack_from('u2', msg, 223)[0]
|
|
155
|
+
if iodp != self.iodp:
|
|
156
|
+
return -1
|
|
157
|
+
i = 14
|
|
158
|
+
iodi, mask = bs.unpack_from('u2u23', msg, i)
|
|
159
|
+
i += 25
|
|
160
|
+
|
|
161
|
+
self.iodn = {}
|
|
162
|
+
|
|
163
|
+
self.iodi = iodi # issue of data
|
|
164
|
+
for k in range(23):
|
|
165
|
+
if (mask >> (23-k-1)) & 1 == 0 or k >= self.nsat:
|
|
166
|
+
continue
|
|
167
|
+
iodn = bs.unpack_from('u8', msg, i)[0]
|
|
168
|
+
i += 8
|
|
169
|
+
|
|
170
|
+
sat = self.sat[k]
|
|
171
|
+
self.iodn[sat] = iodn
|
|
172
|
+
|
|
173
|
+
return i
|
|
174
|
+
|
|
175
|
+
def decode_mt50(self, msg, i):
|
|
176
|
+
""" decode DGPS correction """
|
|
177
|
+
iodp, iodi, code, h, mask_s = bs.unpack_from('u2u2u6u1u23', msg, i)
|
|
178
|
+
i += 34
|
|
179
|
+
if iodp != self.iodp or iodi != self.iodi or h == 1:
|
|
180
|
+
return i
|
|
181
|
+
|
|
182
|
+
nsat = 0
|
|
183
|
+
inet = code+1
|
|
184
|
+
|
|
185
|
+
self.lc[inet].iode = {}
|
|
186
|
+
self.lc[inet].dclk = {}
|
|
187
|
+
self.lc[inet].dorb = {}
|
|
188
|
+
self.lc[inet].sat_n = []
|
|
189
|
+
|
|
190
|
+
for k in range(23):
|
|
191
|
+
if k >= self.nsat:
|
|
192
|
+
continue
|
|
193
|
+
sat = self.sat[k]
|
|
194
|
+
self.lc[inet].dorb[sat] = np.zeros(3)
|
|
195
|
+
|
|
196
|
+
if (mask_s >> (23-k-1)) & 1 == 0:
|
|
197
|
+
# self.lc[inet].iode[sat] = -1
|
|
198
|
+
# self.lc[inet].dclk[sat] = 0.0
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
prc = bs.unpack_from('s12', msg, i)[0]*0.04
|
|
202
|
+
i += 12
|
|
203
|
+
|
|
204
|
+
self.lc[inet].sat_n.append(sat)
|
|
205
|
+
self.lc[inet].iode[sat] = self.iodn[sat]
|
|
206
|
+
self.lc[inet].dclk[sat] = prc
|
|
207
|
+
|
|
208
|
+
self.set_t0(ctype=sCType.CLOCK, sat=sat, inet=inet, t=self.time)
|
|
209
|
+
self.set_t0(ctype=sCType.ORBIT, sat=sat, inet=inet, t=self.time)
|
|
210
|
+
|
|
211
|
+
nsat += 1
|
|
212
|
+
if nsat > 14:
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
self.iodp_c[inet] = iodp
|
|
216
|
+
|
|
217
|
+
self.lc[0].cstat |= (1 << sCType.CLOCK)
|
|
218
|
+
self.lc[0].cstat |= (1 << sCType.ORBIT)
|
|
219
|
+
|
|
220
|
+
return i
|
|
221
|
+
|
|
222
|
+
def decode_mt51(self, msg, i):
|
|
223
|
+
""" decode satellite health """
|
|
224
|
+
v = bs.unpack_from('u64u9u36u36u36', msg, i)
|
|
225
|
+
i += 181
|
|
226
|
+
self.svh[uGNSS.GPS] = v[0]
|
|
227
|
+
self.svh[uGNSS.QZS] = v[1]
|
|
228
|
+
self.svh[uGNSS.GLO] = v[2]
|
|
229
|
+
self.svh[uGNSS.GAL] = v[3]
|
|
230
|
+
self.svh[uGNSS.BDS] = v[4]
|
|
231
|
+
return i
|
|
232
|
+
|
|
233
|
+
def decode_cssr(self, msg, i=0):
|
|
234
|
+
""" decode DGPS messages """
|
|
235
|
+
|
|
236
|
+
_, mt = bs.unpack_from('u8u6', msg, i)
|
|
237
|
+
i += 14
|
|
238
|
+
|
|
239
|
+
self.msgtype = mt
|
|
240
|
+
|
|
241
|
+
if mt == 43: # DC report (JMA)
|
|
242
|
+
i = self.decode_mt43(msg, i)
|
|
243
|
+
elif mt == 44: # DC report (other source)
|
|
244
|
+
i = self.decode_mt44(msg, i)
|
|
245
|
+
elif mt == 47: #
|
|
246
|
+
i = self.decode_mt47(msg, i)
|
|
247
|
+
elif mt == 48: #
|
|
248
|
+
i = self.decode_mt48(msg, i)
|
|
249
|
+
elif mt == 49: #
|
|
250
|
+
i = self.decode_mt49(msg, i)
|
|
251
|
+
elif mt == 50: #
|
|
252
|
+
i = self.decode_mt50(msg, i)
|
|
253
|
+
elif mt == 51: #
|
|
254
|
+
i = self.decode_mt51(msg, i)
|
|
255
|
+
elif mt == 63: # Null
|
|
256
|
+
None
|
|
257
|
+
|
|
258
|
+
if self.monlevel > 3:
|
|
259
|
+
self.fh.write("{:s} mt={:2d} \n".format(time2str(self.time), mt))
|
|
260
|
+
|
|
261
|
+
def get_station(self, r):
|
|
262
|
+
""" get the nearest referece station """
|
|
263
|
+
pos = ecef2pos(r)
|
|
264
|
+
c_lat = np.cos(pos[0])
|
|
265
|
+
idx = np.where(self.posr[:, 0]**2+self.posr[:, 1]**2 > 0)[0]
|
|
266
|
+
if len(idx) == 0:
|
|
267
|
+
return -1, -1
|
|
268
|
+
dpos = np.deg2rad(self.posr[idx, 0:2])-pos[0:2]
|
|
269
|
+
rng = np.sqrt(dpos[:, 0]**2+(dpos[:, 1]*c_lat)**2)*rCST.RE_WGS84
|
|
270
|
+
kmin = np.argmin(rng)
|
|
271
|
+
refid = idx[kmin]
|
|
272
|
+
return refid, rng[kmin]
|
|
273
|
+
|
|
274
|
+
def set_dgps_corr(self, rr):
|
|
275
|
+
""" get DGPS correction """
|
|
276
|
+
if self.iodp < 0 or self.iodi < 0:
|
|
277
|
+
return -1
|
|
278
|
+
refid, rmin = self.get_station(rr)
|
|
279
|
+
baselen = rmin*1e-3 # baseline length [km]
|
|
280
|
+
self.inet = refid+1
|
|
281
|
+
if len(self.lc[self.inet].sat_n) > 0:
|
|
282
|
+
self.sat_n = self.lc[self.inet].sat_n
|
|
283
|
+
self.iodssr_c[sCType.ORBIT] = self.iodp_c[self.inet]
|
|
284
|
+
self.iodssr_c[sCType.CLOCK] = self.iodp_c[self.inet]
|
|
285
|
+
self.lc[0].t0 = self.lc[self.inet].t0
|
|
286
|
+
self.lc[0].iode = self.lc[self.inet].iode
|
|
287
|
+
self.lc[0].dclk = self.lc[self.inet].dclk
|
|
288
|
+
self.lc[0].dorb = self.lc[self.inet].dorb
|
|
289
|
+
return baselen
|