Skip to content

Commit 54ba202

Browse files
committed
- added cssr decoder for mdc
- added plot utility for circle and rectangle with Cartopy
1 parent 1755932 commit 54ba202

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

src/cssrlib/cssr_mdc.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"""
2+
QZSS MADOCA-PPP correction data decoder
3+
4+
[1] Quasi-Zenith Satellite System Interface Specification Multi-GNSS
5+
Advanced Orbit and Clock Augmentation - Precise Point Positioning
6+
(IS-QZSS-MDC-003), 2024
7+
8+
"""
9+
10+
import numpy as np
11+
import bitstruct as bs
12+
from cssrlib.cssrlib import cssr, sCSSRTYPE
13+
from cssrlib.gnss import gpst2time, uGNSS, prn2sat
14+
15+
16+
class areaInfo():
17+
def __init__(self, sid, latr, lonr, p1=0, p2=0):
18+
self.sid = sid
19+
self.latr = latr
20+
self.lonr = lonr
21+
if sid == 0:
22+
self.lats = p1
23+
self.lons = p2
24+
elif sid == 1:
25+
self.rng = p1
26+
27+
28+
class ionoCorr():
29+
def __init__(self):
30+
self.t0 = None
31+
self.qi = []
32+
self.iodssr = 0
33+
self.ct = 0
34+
self.sat = []
35+
self.c = np.zeros((6))
36+
37+
38+
class cssr_mdc(cssr):
39+
def __init__(self, foutname=None):
40+
super().__init__(foutname)
41+
self.MAXNET = 1
42+
self.cssrmode = sCSSRTYPE.QZS_MADOCA
43+
self.buff = bytearray(250*10)
44+
45+
self.pnt = {}
46+
self.ci = {}
47+
48+
def decode_mdc_stec_area(self, buff, i=0):
49+
""" decoder for MT1 - STEC Coverage Message """
50+
msgtype, subtype = bs.unpack_from('u12u4', buff, i)
51+
i += 16
52+
tow, uid, mi, iodssr = bs.unpack_from('u20u4u1u4', buff, i)
53+
i += 29
54+
self.tow0 = tow//3600*3600
55+
reg, alrt, len_, narea = bs.unpack_from('u8u1u16u5', buff, i)
56+
i += 30
57+
if reg not in self.pnt:
58+
self.pnt[reg] = {}
59+
60+
for k in range(narea):
61+
area, sid = bs.unpack_from('u5u1', buff, i)
62+
i += 6
63+
64+
if sid == 0:
65+
latr, lonr, lats, lons = bs.unpack_from('s11u12u8u8', buff, i)
66+
if self.monlevel > 2:
67+
print(f"{reg} {area:2d} {sid} {latr*0.1:5.1f} "
68+
f"{lonr*0.1:5.1f} {lats*0.1:3.1f} {lons*0.1:3.1f}")
69+
self.pnt[reg][area] = areaInfo(
70+
sid, latr*0.1, lonr*0.1, lats*0.1, lons*0.1)
71+
else:
72+
latr, lonr, rng = bs.unpack_from('s15u16u8', buff, i)
73+
if self.monlevel > 2:
74+
print(f"{reg} {area:2d} {sid} {latr*0.01:6.2f} "
75+
f"{lonr*0.01:6.2f} {rng*10}")
76+
self.pnt[reg][area] = areaInfo(
77+
sid, latr*0.01, lonr*0.01, rng*10.0)
78+
i += 39
79+
return i
80+
81+
def decode_mdc_stec_corr(self, buff, i=0):
82+
""" decoder for MT2 - STEC Correction Message """
83+
msgtype, subtype = bs.unpack_from('u12u4', buff, i)
84+
i += 16
85+
dtow, uid, mi, iodssr = bs.unpack_from('u12u4u1u4', buff, i)
86+
i += 21
87+
reg, area, ct = bs.unpack_from('u8u5u2', buff, i)
88+
i += 15
89+
90+
nsat = bs.unpack_from('u5u5u5u5u5', buff, i)
91+
i += 25
92+
# gps, glo, gal, bds, qzss
93+
94+
sys_t = [uGNSS.GPS, uGNSS.GLO, uGNSS.GAL, uGNSS.BDS, uGNSS.QZS]
95+
96+
if reg not in self.ci:
97+
self.ci[reg] = {}
98+
if area not in self.ci[reg]:
99+
self.ci[reg][area] = ionoCorr()
100+
101+
c01 = c10 = c11 = c02 = c20 = 0
102+
nsat_total = np.sum(nsat)
103+
c = np.zeros((nsat_total, 6))
104+
qi = np.zeros((nsat_total), dtype=int)
105+
sat_ = []
106+
j = 0
107+
for gnss in range(5):
108+
sys = sys_t[gnss]
109+
for k in range(nsat[gnss]):
110+
prn, qi[j], c00 = bs.unpack_from('u6u6s14', buff, i)
111+
if sys == uGNSS.QZS:
112+
prn += 192
113+
sat = prn2sat(sys, prn)
114+
115+
i += 26
116+
if ct > 0:
117+
c01, c10 = bs.unpack_from('s12s12', buff, i)
118+
i += 24
119+
if ct > 1:
120+
c11 = bs.unpack_from('s10', buff, i)[0]
121+
i += 10
122+
if ct > 2:
123+
c02, c20 = bs.unpack_from('s8s8', buff, i)
124+
i += 16
125+
126+
sat_ += [sat]
127+
c[j, :] = [c00*0.05, c01*0.02, c10*0.02, c11*0.02,
128+
c02*5e-3, c20*5e-3]
129+
j += 1
130+
131+
self.ci[reg][area].t0 = gpst2time(self.week, self.tow0+dtow)
132+
self.ci[reg][area].iodssr = iodssr
133+
self.ci[reg][area].sat = sat_
134+
self.ci[reg][area].qi = qi
135+
self.ci[reg][area].ct = ct
136+
self.ci[reg][area].c = c
137+
return i

src/cssrlib/plot.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import matplotlib.pyplot as plt
77
import matplotlib.ticker as mticker
88
from cssrlib.gnss import uGNSS, sat2prn, sat2id
9+
from cssrlib.gnss import rCST
910

1011

1112
def plot_nsat(t, nsat):
@@ -85,3 +86,28 @@ def skyplot(azm, elv, elmask=0, satlist=None):
8586
nsat += 1
8687
plt.show()
8788
return nsat
89+
90+
91+
def draw_rect(ax, ccrs, p, col, alpha=0.5):
92+
""" draw rectangle centered on [latr, lonr] """
93+
94+
lonr_ = [p.lonr-p.lons, p.lonr+p.lons, p.lonr +
95+
p.lons, p.lonr-p.lons, p.lonr-p.lons]
96+
latr_ = [p.latr+p.lats, p.latr+p.lats, p.latr -
97+
p.lats, p.latr-p.lats, p.latr+p.lats]
98+
99+
ax.fill(lonr_, latr_, color=col, alpha=alpha,
100+
transform=ccrs)
101+
102+
103+
def draw_circle(ax, ccrs, p, col, nc=10, alpha=0.5):
104+
""" draw circle centered on [latr, lonr] with radius rng """
105+
r_ = p.rng/(rCST.RE_WGS84*1e-3)*rCST.R2D
106+
107+
the_ = np.linspace(0, 2*np.pi, nc)
108+
109+
lonr_ = p.lonr + r_/np.cos(p.latr*rCST.D2R)*np.cos(the_)
110+
latr_ = p.latr + r_*np.sin(the_)
111+
112+
ax.fill(lonr_, latr_, color=col, alpha=alpha,
113+
transform=ccrs)

0 commit comments

Comments
 (0)