@@ -119,7 +119,7 @@ def get_dop(navdata, **which_dop):
119119
120120
121121def calculate_dop (derived ):
122- """Calculate DOP from state estimate .
122+ """Calculate DOP from elevation and azimuth (ENU) .
123123
124124 Parameters
125125 ----------
@@ -135,24 +135,90 @@ def calculate_dop(derived):
135135 "TDOP", "PDOP", "GDOP".
136136 """
137137
138+ # Use the elevation and azimuth angles to get the ENU and Time matrix
139+ # Each row is [d_e, d_n, d_u, 1] for each satellite.
140+ enut_matrix = calculate_enut_matrix (derived )
141+ enut_gram_matrix = enut_matrix .T @ enut_matrix
142+
143+ try :
144+ dop_matrix = np .linalg .inv (enut_gram_matrix )
145+
146+ # Calculate the DOP
147+ dop = {}
148+ dop ["dop_matrix" ] = dop_matrix
149+ dop ["GDOP" ] = np .sqrt (np .trace (dop_matrix ))
150+ dop ["HDOP" ] = np .sqrt (dop_matrix [0 , 0 ] + dop_matrix [1 , 1 ])
151+ dop ["VDOP" ] = np .sqrt (dop_matrix [2 , 2 ])
152+ dop ["PDOP" ] = np .sqrt (dop_matrix [0 , 0 ] + \
153+ dop_matrix [1 , 1 ] + \
154+ dop_matrix [2 , 2 ])
155+ dop ["TDOP" ] = np .sqrt (dop_matrix [3 , 3 ])
156+
157+ except np .linalg .LinAlgError :
158+ # If the matrix is singular, return NaNs for the DOP
159+ dop = {}
160+ dop ["dop_matrix" ] = np .nan * np .ones ((4 , 4 ))
161+ dop ["GDOP" ] = np .nan
162+ dop ["HDOP" ] = np .nan
163+ dop ["VDOP" ] = np .nan
164+ dop ["PDOP" ] = np .nan
165+ dop ["TDOP" ] = np .nan
166+
167+ return dop
168+
169+
170+ def calculate_enu_unit_vectors (derived ):
171+ """
172+ Calculate the ENU unit vectors from elevation and azimuth.
173+ Each row is [d_e, d_n, d_u] for each satellite, where d is a unit
174+ line-of-sight vector in the ENU frame.
175+
176+ Parameters
177+ ----------
178+ derived : gnss_lib_py.navdata.navdata.NavData
179+ NavData instance containing received GNSS measurements for a
180+ particular time instance, contains elevation and azimuth angle
181+ information for an estimated location.
182+
183+ Returns
184+ -------
185+ unit_dir_mat : np.ndarray (num_satellites, 3)
186+ Matrix of ENU unit vectors.
187+ """
188+
138189 # Get the elevation and azimuth angles
139190 sv_el_az_rad = np .deg2rad (derived ['el_sv_deg' , 'az_sv_deg' ])
140191
141192 # Important: This matrix is in ENU coordinates, not NED.
142193 unit_dir_mat = np .vstack (
143194 (np .atleast_2d (np .cos (sv_el_az_rad [0 ,:]) * np .sin (sv_el_az_rad [1 ,:])),
144195 np .atleast_2d (np .cos (sv_el_az_rad [0 ,:]) * np .cos (sv_el_az_rad [1 ,:])),
145- np .atleast_2d (np .sin (sv_el_az_rad [0 ,:])),
146- np .ones ((1 , sv_el_az_rad .shape [1 ])))).T
147- dop_matrix = np .linalg .inv (np .matmul (unit_dir_mat .T , unit_dir_mat ))
148-
149- # Calculate the DOP
150- dop = {}
151- dop ["dop_matrix" ] = dop_matrix
152- dop ["GDOP" ] = np .sqrt (np .trace (dop_matrix ))
153- dop ["HDOP" ] = np .sqrt (dop_matrix [0 , 0 ] + dop_matrix [1 , 1 ])
154- dop ["VDOP" ] = np .sqrt (dop_matrix [2 , 2 ])
155- dop ["PDOP" ] = np .sqrt (dop_matrix [0 , 0 ] + dop_matrix [1 , 1 ] + dop_matrix [2 , 2 ])
156- dop ["TDOP" ] = np .sqrt (dop_matrix [3 , 3 ])
196+ np .atleast_2d (np .sin (sv_el_az_rad [0 ,:]))
197+ )).T
157198
158- return dop
199+ return unit_dir_mat
200+
201+
202+ def calculate_enut_matrix (derived ):
203+ """
204+ Calculate the ENU and Time Matrix from elevation and azimuth.
205+ Each row is [d_e, d_n, d_u, 1] for each satellite.
206+
207+ Parameters
208+ ----------
209+ derived : gnss_lib_py.navdata.navdata.NavData
210+ NavData instance containing received GNSS measurements for a
211+ particular time instance, contains elevation and azimuth angle
212+ information for an estimated location.
213+
214+ Returns
215+ -------
216+ enut_matrix : np.ndarray (num_satellites, 4)
217+ Matrix of ENU and Time vectors.
218+
219+ """
220+ unit_dir_mat = calculate_enu_unit_vectors (derived )
221+ enut_matrix = np .hstack ((unit_dir_mat ,
222+ np .ones ((unit_dir_mat .shape [0 ], 1 ))))
223+
224+ return enut_matrix
0 commit comments