Skip to content

Commit 1b46920

Browse files
committed
- added SBAS DFMC signal selection
- added partial AR (experimental)
1 parent 9158649 commit 1b46920

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

src/cssrlib/mlambda.py

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"""
1212

1313
import numpy as np
14+
from scipy.stats import norm
15+
from numpy.linalg import inv
1416

1517

1618
def ldldecom(Q):
@@ -66,6 +68,12 @@ def reduction(L, d):
6668
return L, d, Z
6769

6870

71+
def sr_boost(d):
72+
""" Compute the bootstrapped success rate """
73+
Ps = np.prod(2*norm.cdf(0.5/np.sqrt(d))-1)
74+
return Ps
75+
76+
6977
def msearch(L, d, zs, m=2):
7078
n = len(d)
7179
nn = 0
@@ -129,14 +137,67 @@ def msearch(L, d, zs, m=2):
129137
return zn, s
130138

131139

132-
def mlambda(a, Q, m=2):
133-
L, d = ldldecom(Q)
140+
def parsearch(zhat, Qzhat, Z, L, d, P0=0.995, ncands=2):
141+
""" Partial Ambiguity Resolution """
142+
n = len(Qzhat)
143+
Ps = sr_boost(d)
144+
145+
k = 0
146+
while Ps < P0 and k < (n-1):
147+
k += 1
148+
149+
# Compute the bootstrapped success rate if the last n-k+1 ambiguities
150+
# would be fixed
151+
Ps = sr_boost(d[k:])
152+
153+
if Ps > P0:
154+
155+
zpar, sqnorm = msearch(L[k:, k:], d[k:], zhat[k:], ncands)
156+
157+
Qzpar = Qzhat[k:, k:]
158+
Zpar = Z[:, k:]
159+
160+
# First k-1 ambiguities are adjusted based on correlation with the
161+
# fixed ambiguities
162+
QP = Qzhat[:k, k:]@inv(Qzhat[k:, k:])
163+
164+
zfix = np.zeros((k, ncands))
165+
for i in range(ncands):
166+
zfix[:, i] = zhat[:k] - QP@(zhat[k:]-zpar[:, i])
167+
168+
zfix = np.concatenate((zfix, zpar), axis=0)
169+
nfix = n-k
170+
171+
else:
172+
173+
zpar = []
174+
Qzpar = []
175+
Zpar = []
176+
sqnorm = []
177+
Ps = np.nan
178+
zfix = zhat
179+
nfix = 0
180+
181+
return zpar, sqnorm, Qzpar, Zpar, Ps, nfix, zfix
182+
183+
184+
def mlambda(ahat, Qahat, ncands=2, armode=1, P0=0.995):
185+
""" modified LAMBDA method for ambiguity resolution """
186+
L, d = ldldecom(Qahat)
134187
L, d, Z = reduction(L, d)
135-
invZt = np.round(np.linalg.inv(Z.T))
136-
z = Z.T@a
137-
E, s = msearch(L, d, z, m)
138-
afix_ = invZt@E
139-
return afix_, s
188+
iZt = np.round(inv(Z.T))
189+
zhat = Z.T@ahat
190+
191+
if armode == 1:
192+
zfix, s = msearch(L, d, zhat, ncands)
193+
Ps, nfix = np.nan, len(zhat)
194+
elif armode == 2: # PAR
195+
Qzhat = Z.T@Qahat@Z
196+
zpar, s, Qzpar, Zpar, Ps, nfix, zfix = parsearch(zhat, Qzhat, Z, L, d,
197+
P0, ncands)
198+
199+
afix_ = iZt@zfix
200+
return afix_, s, nfix, Ps
140201

141202

142203
if __name__ == '__main__':

src/cssrlib/pppssr.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ def __init__(self, nav, pos0=np.zeros(3),
121121
self.nav.elmaskar = np.deg2rad(20.0) # elevation mask for AR
122122
self.nav.elmin = np.deg2rad(15.0)
123123

124+
self.nav.parmode = 2 # 1: normal, 2: PAR
125+
self.nav.par_P0 = 0.995 # probability of sussefull AR
126+
124127
# Initial state vector
125128
#
126129
self.nav.x[0:3] = pos0
@@ -657,11 +660,13 @@ def zdres(self, obs, cs, bsx, rs, vs, dts, rr, rtype=1):
657660
elif sys == uGNSS.BDS:
658661
sig0 = (rSigRnx("CC6I"),)
659662

660-
elif cs.cssrmode == sc.PVS_PPP:
663+
elif cs.cssrmode in (sc.PVS_PPP, sc.SBAS_L1, sc.SBAS_L5):
661664
if sys == uGNSS.GPS:
662665
sig0 = (rSigRnx("GC1C"), rSigRnx("GC5Q"))
663666
elif sys == uGNSS.GAL:
664667
sig0 = (rSigRnx("EC1C"), rSigRnx("EC5Q"))
668+
elif sys == uGNSS.SBS:
669+
sig0 = (rSigRnx("SC1C"), rSigRnx("SC5Q"))
665670

666671
# Receiver/satellite antenna offset
667672
#
@@ -1054,7 +1059,7 @@ def ddidx(self, nav, sat):
10541059
ix = np.resize(ix, (nb, 2))
10551060
return ix
10561061

1057-
def resamb_lambda(self, sat):
1062+
def resamb_lambda(self, sat, armode=1, P0=0.995):
10581063
""" resolve integer ambiguity using LAMBDA method """
10591064
nx = self.nav.nx
10601065
na = self.nav.na
@@ -1072,8 +1077,9 @@ def resamb_lambda(self, sat):
10721077
Qab = self.nav.P[0:na, ix[:, 0]]-self.nav.P[0:na, ix[:, 1]]
10731078

10741079
# MLAMBDA ILS
1075-
b, s = mlambda(y, Qb)
1076-
if s[0] <= 0.0 or s[1]/s[0] >= self.nav.thresar:
1080+
b, s, nfix, Ps = mlambda(y, Qb, armode=armode, P0=P0)
1081+
if s[0] <= 0.0 or s[1]/s[0] >= self.nav.thresar \
1082+
or (armode == 2 and nfix > 0):
10771083
self.nav.xa = self.nav.x[0:na].copy()
10781084
self.nav.Pa = self.nav.P[0:na, 0:na].copy()
10791085
bias = b[:, 0]
@@ -1084,6 +1090,13 @@ def resamb_lambda(self, sat):
10841090

10851091
# restore SD ambiguity
10861092
xa = self.restamb(bias, nb)
1093+
1094+
elif armode == 2 and nfix == 0:
1095+
nb = 0
1096+
if self.nav.monlevel > 0:
1097+
self.nav.fout.write(
1098+
"{:s} Ps={:3.2f} nfix={:d}\n".
1099+
format(time2str(self.time), Ps, nfix))
10871100
else:
10881101
nb = 0
10891102

@@ -1404,7 +1417,7 @@ def process(self, obs, cs=None, orb=None, bsx=None, obsb=None):
14041417
self.nav.smode = 5 # 4: fixed ambiguities, 5: float ambiguities
14051418

14061419
if self.nav.armode > 0:
1407-
nb, xa = self.resamb_lambda(sat)
1420+
nb, xa = self.resamb_lambda(sat, self.nav.parmode, self.nav.par_P0)
14081421
if nb > 0:
14091422
# Use position with fixed ambiguities xa
14101423
yu, eu, elu = self.zdres(obs, cs, bsx, rs, vs, dts, xa[0:3])
@@ -1416,6 +1429,10 @@ def process(self, obs, cs=None, orb=None, bsx=None, obsb=None):
14161429
if self.nav.armode == 3: # fix and hold
14171430
self.holdamb(xa) # hold fixed ambiguity
14181431
self.nav.smode = 4 # fix
1432+
else:
1433+
pass
1434+
else:
1435+
pass
14191436

14201437
# Store epoch for solution
14211438
#

0 commit comments

Comments
 (0)