1212from numpy .random import default_rng
1313
1414from gnss_lib_py .parsers .navdata import NavData
15- from gnss_lib_py .parsers .android import AndroidDerived2021
15+ from gnss_lib_py .parsers .android import AndroidDerived2021 , AndroidDerived2022
1616from gnss_lib_py .algorithms .gnss_filters import GNSSEKF , solve_gnss_ekf
1717
1818@pytest .fixture (name = 'init_dict' )
@@ -35,7 +35,8 @@ def gnss_init_params():
3535 'state_0' : state_0 ,
3636 'sigma_0' : 5 * np .eye (state_dim ),
3737 'Q' : Q ,
38- 'R' : R }
38+ 'R' : R ,
39+ 'use_tx_time' : True }
3940 return init_dict
4041
4142
@@ -159,17 +160,83 @@ def fixture_load_derived(derived_path):
159160 derived = AndroidDerived2021 (derived_path )
160161 return derived
161162
162- def test_solve_gnss_ekf (derived ):
163+
164+ @pytest .fixture (name = "derived_2022_path" )
165+ def fixture_derived_2022_path (root_path ):
166+ """Filepath of Android Derived 2022 measurements
167+
168+ Returns
169+ -------
170+ derived_2022_path : string
171+ Location for the unit_test Android 2022 derived measurements
172+
173+ Notes
174+ -----
175+ Test data is a subset of the Android Raw Measurement Dataset [3]_,
176+ from the 2022 Decimeter Challenge. Particularly, the
177+ train/2021-04-29-MTV-2/SamsungGalaxyS20Ultra trace. The dataset
178+ was retrieved from
179+ https://www.kaggle.com/competitions/smartphone-decimeter-2022/data
180+
181+ References
182+ ----------
183+ .. [3] Fu, Guoyu Michael, Mohammed Khider, and Frank van Diggelen.
184+ "Android Raw GNSS Measurement Datasets for Precise Positioning."
185+ Proceedings of the 33rd International Technical Meeting of the
186+ Satellite Division of The Institute of Navigation (ION GNSS+
187+ 2020). 2020.
188+ """
189+ derived_2022_path = os .path .join (root_path , '../android_2022/device_gnss.csv' )
190+ return derived_2022_path
191+
192+
193+ @pytest .fixture (name = "derived_2022" )
194+ def fixture_load_derived_2022 (derived_2022_path ):
195+ """Load instance of AndroidDerived2021
196+
197+ Parameters
198+ ----------
199+ derived_2022_path : pytest.fixture
200+ String with location of Android derived 2022 measurement file
201+
202+ Returns
203+ -------
204+ derived_2022 : AndroidDerived2021
205+ Instance of AndroidDerived2022 for testing
206+ """
207+ derived_2022 = AndroidDerived2022 (derived_2022_path )
208+ return derived_2022
209+
210+
211+ @pytest .fixture (name = "noise_tx_init_dict" )
212+ def fixture_android_init_dict ():
213+ """Define dictionary containing identity process and measure noises.
214+
215+ Returns
216+ -------
217+ init_dict : dict
218+ Dictionary of initialization parameters, in this case, containing
219+ just the process and measurement noise covariance matrices.
220+ """
221+ init_dict = {}
222+ init_dict ['Q' ] = np .eye (7 )
223+ init_dict ['R' ] = np .eye (1 )
224+ init_dict ['use_tx_time' ] = False
225+ return init_dict
226+
227+ def test_solve_gnss_ekf (derived , noise_tx_init_dict ):
163228 """Test that solving for GNSS EKF doesn't fail
164229
165230 Parameters
166231 ----------
167232 derived : AndroidDerived2021
168233 Instance of AndroidDerived2021 for testing.
234+ init_dict : dict
235+ Dictionary of initialization parameters, in this case, containing
236+ just the process and measurement noise covariance matrices.
169237
170238 """
171- state_estimate = solve_gnss_ekf (derived )
172-
239+ state_estimate = solve_gnss_ekf (derived , noise_tx_init_dict )
173240 # result should be a NavData Class instance
174241 assert isinstance (state_estimate ,type (NavData ()))
175242
@@ -202,23 +269,76 @@ def test_solve_gnss_ekf(derived):
202269 assert row_index in str (excinfo .value )
203270
204271
205- def test_solve_gnss_ekf_fails (derived ):
272+
273+ def test_solve_gnss_ekf_fails (derived , noise_tx_init_dict ):
206274 """Test expected fails for the GNSS EKF.
207275
208276 Parameters
209277 ----------
210278 derived : AndroidDerived2021
211279 Instance of AndroidDerived2021 for testing
280+ init_dict : dict
281+ Dictionary of initialization parameters, in this case, containing
282+ just the process and measurement noise covariance matrices.
212283
213284 """
214285
215286 navdata = derived .remove (cols = list (range (len (derived ))))
216287
217288 with pytest .warns (RuntimeWarning ) as warns :
218- solve_gnss_ekf (navdata )
289+ solve_gnss_ekf (navdata , noise_tx_init_dict )
219290
220291 # verify RuntimeWarning
221292 assert len (warns ) == 1
222293 warn = warns [0 ]
223294 assert issubclass (warn .category , RuntimeWarning )
224295 assert "No valid state" in str (warn .message )
296+
297+
298+ # Test that RuntimeError is raised if no measurment noise is provided
299+ with pytest .raises (RuntimeError ):
300+ del (noise_tx_init_dict ['R' ])
301+ solve_gnss_ekf (derived , noise_tx_init_dict )
302+ # Test that RuntimeError is raised if no process noise is provided
303+ with pytest .raises (RuntimeError ):
304+ del (noise_tx_init_dict ['Q' ])
305+ solve_gnss_ekf (derived , noise_tx_init_dict )
306+ # Test that RuntimeError is raised if no initial dictionary is provided
307+ with pytest .raises (RuntimeError ):
308+ solve_gnss_ekf (derived )
309+
310+
311+ def test_solve_gnss_ekf_initializations (derived_2022 ):
312+ """Tests that different initial state cases run without error.
313+
314+ Parameters
315+ ----------
316+ derived_2022 : AndroidDerived2022
317+ Instance of AndroidDerived2022 for testing
318+ init_dict : dict
319+ Dictionary of initialization parameters, in this case, containing
320+ just the process and measurement noise covariance matrices.
321+ """
322+ # GNSS EKF solution when initial states and biases are given
323+ derived_2022 ['b_rx_m' ] = 0
324+ # Reinitializing the initial dictionary because other functions might
325+ # have added to this.
326+ reset_init_dict = {}
327+ reset_init_dict ['Q' ] = np .eye (7 )
328+ reset_init_dict ['R' ] = np .eye (1 )
329+ reset_init_dict ['use_tx_time' ] = True
330+ _ = solve_gnss_ekf (derived_2022 , reset_init_dict )
331+ # GNSS EKF solution when initial positions are given
332+ derived_2022 .remove (rows = ['b_rx_m' ], inplace = True )
333+ reset_init_dict = {}
334+ reset_init_dict ['Q' ] = np .eye (7 )
335+ reset_init_dict ['R' ] = np .eye (1 )
336+ reset_init_dict ['use_tx_time' ] = True
337+ _ = solve_gnss_ekf (derived_2022 , reset_init_dict )
338+ # GNSS EKF solution when no initial states are given
339+ derived_no_rx_rows = derived_2022 .remove (rows = ['x_rx_m' , 'y_rx_m' , 'z_rx_m' ])
340+ reset_init_dict = {}
341+ reset_init_dict ['Q' ] = np .eye (7 )
342+ reset_init_dict ['R' ] = np .eye (1 )
343+ reset_init_dict ['use_tx_time' ] = True
344+ _ = solve_gnss_ekf (derived_no_rx_rows , reset_init_dict )
0 commit comments