Skip to content

Commit 9d2a5e0

Browse files
committed
Added tests for AndroidDerived2022 and GT loaders
1 parent 9303bec commit 9d2a5e0

10 files changed

Lines changed: 8336 additions & 23 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
MessageType,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps,AccuracyMeters,BearingDegrees,UnixTimeMillis
2+
Fix,GT,37.4166186,-122.082065,,0.002044282,0.1,92.96875,1.58957E+12
3+
Fix,GT,37.4166186,-122.082065,,0.002198359,0.1,92.969666,1.58957E+12
4+
Fix,GT,37.4166186,-122.082065,,0.001414214,0.1,92.96985,1.58957E+12

data/unit_test/android_2022/device_gnss.csv

Lines changed: 7906 additions & 0 deletions
Large diffs are not rendered by default.

data/unit_test/android_2022/ground_truth.csv

Lines changed: 201 additions & 0 deletions
Large diffs are not rendered by default.

gnss_lib_py/parsers/android.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
__authors__ = "Shubh Gupta, Adam Dai, Ashwin Kanhere"
66
__date__ = "02 Nov 2021"
77

8-
from distutils.log import warn
8+
99
import os
1010
import csv
1111
import warnings
@@ -22,7 +22,7 @@ class AndroidDerived2021(NavData):
2222
2323
Inherits from NavData().
2424
"""
25-
def __init__(self, input_path):
25+
def __init__(self, input_path, remove_bad_measures=True):
2626
"""Android specific loading and preprocessing
2727
2828
Parameters
@@ -47,9 +47,10 @@ def __init__(self, input_path):
4747

4848

4949
# Correction 5 implemented verbatim from competition tips
50-
delta_millis = pd_df['millisSinceGpsEpoch'] - pd_df['receivedSvTimeInGpsNanos'] / 1e6
51-
where_good_signals = (delta_millis > 0) & (delta_millis < 300)
52-
pd_df = pd_df[where_good_signals].copy()
50+
if remove_bad_measures:
51+
delta_millis = pd_df['millisSinceGpsEpoch'] - pd_df['receivedSvTimeInGpsNanos'] / 1e6
52+
where_good_signals = (delta_millis > 0) & (delta_millis < 300)
53+
pd_df = pd_df[where_good_signals].copy()
5354

5455
super().__init__(pandas_df=pd_df)
5556

@@ -101,14 +102,40 @@ def _row_map():
101102
return row_map
102103

103104

104-
class AndroidDerived2022(AndroidDerived2021):
105+
class AndroidDerived2022(NavData):
105106
"""Class handling derived measurements from Android dataset.
106107
107-
Inherits from AndroidDerived2021().
108-
The row nomenclature for the new derived dataset changed. We reflect
109-
this changed nomenclature in the _row_map() method.
108+
Inherits from NavData().
109+
The row nomenclature for the new derived dataset has changed.
110+
We reflect this changed nomenclature in the _row_map() method.
110111
"""
111112

113+
def __init__(self, input_path):
114+
"""Android specific loading and preprocessing
115+
116+
Parameters
117+
----------
118+
input_path : string
119+
Path to measurement csv file
120+
"""
121+
super().__init__(csv_path=input_path)
122+
123+
def postprocess(self):
124+
"""Android derived specific postprocessing
125+
126+
Notes
127+
-----
128+
Adds corrected pseudoranges to measurements. Time step corrections
129+
implemented from https://www.kaggle.com/c/google-smartphone-decimeter-challenge/data
130+
retrieved on 10 August, 2022
131+
"""
132+
pr_corrected = self['raw_pr_m', :] \
133+
+ self['b_sv_m', :] \
134+
- self['intersignal_bias_m', :] \
135+
- self['tropo_delay_m', :] \
136+
- self['iono_delay_m', :]
137+
self['corr_pr_m'] = pr_corrected
138+
112139
@staticmethod
113140
def _row_map():
114141
"""Map of row names from loaded to gnss_lib_py standard
@@ -207,7 +234,7 @@ def postprocess(self):
207234
"""
208235
if np.any(np.isnan(self['alt_gt_m'])):
209236
warnings.warn("Some altitude values were missing, using 0m ", RuntimeWarning)
210-
self['alt_gt_m'] = np.np.nan_to_num(self['alt_gt_m'])
237+
self['alt_gt_m'] = np.nan_to_num(self['alt_gt_m'])
211238
gt_lla = np.transpose(np.vstack([self['lat_gt_deg'], self['long_gt_deg'], self['alt_gt_m']]))
212239
gt_ecef = geodetic_to_ecef(gt_lla)
213240
self["x_gt_m"] = gt_ecef[:,0]
@@ -225,9 +252,9 @@ def _row_map():
225252
Dictionary of the form {old_name : new_name}
226253
"""
227254
row_map = {'LatitudeDegrees' : 'lat_gt_deg',
228-
'LongitudeDegrees' : 'long_gt_deg',
229-
'AltitudeMeters' : 'alt_gt_m',
230-
'UnixTimeMillis' : 'unix_millis'
255+
'LongitudeDegrees' : 'long_gt_deg',
256+
'AltitudeMeters' : 'alt_gt_m',
257+
'UnixTimeMillis' : 'unix_millis'
231258
}
232259
return row_map
233260

@@ -358,7 +385,7 @@ def make_csv(input_path, output_directory, field, show_path=False):
358385
with MakeCsv() in opensource/ReadGnssLogger.m
359386
360387
"""
361-
if not os.path.isdir(output_directory):
388+
if not os.path.isdir(output_directory): #pragma: no cover
362389
os.makedirs(output_directory)
363390
output_path = os.path.join(output_directory, field + ".csv")
364391
with open(output_path, 'w', encoding="utf8") as out_csv:
@@ -378,7 +405,7 @@ def make_csv(input_path, output_directory, field, show_path=False):
378405
line_data = line.rstrip('\n').replace(" ","").split(",")
379406
if line_data[0] == field:
380407
writer.writerow(line_data[1:])
381-
if show_path:
408+
if show_path: #pragma: no cover
382409
print(output_path)
383410

384411
return output_path

gnss_lib_py/utils/time_conversions.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,16 @@ def gps_to_unix_millis(gps_millis, rem_leap_secs=True):
379379
"""
380380
#NOTE: Ensure that one of these methods is always adding/removing
381381
# leap seconds here
382-
t_utc = gps_millis_to_datetime(gps_millis, rem_leap_secs=rem_leap_secs)
383-
unix_millis = datetime_to_unix_millis(t_utc)
382+
if isinstance(gps_millis, np.ndarray) and len(gps_millis) > 1:
383+
unix_millis = np.zeros_like(gps_millis)
384+
for t_idx, gps in enumerate(gps_millis):
385+
t_utc = gps_millis_to_datetime(gps, rem_leap_secs=rem_leap_secs)
386+
unix_millis[t_idx] = datetime_to_unix_millis(t_utc)
387+
else:
388+
t_utc = gps_millis_to_datetime(gps_millis, rem_leap_secs=rem_leap_secs)
389+
unix_millis = datetime_to_unix_millis(t_utc)
384390
return unix_millis
385391

386-
387392
def _check_tzinfo(t_datetime):
388393
"""Raises warning if time doesn't have timezone and converts to UTC.
389394

notebooks/tutorials/algorithms.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"source": [
3333
"# load Android Google Challenge data\n",
3434
"!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/Pixel4XL_derived.csv --quiet -O \"Pixel4XL_derived.csv\"\n",
35-
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\")"
35+
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\", remove_bad_measures=False)"
3636
]
3737
},
3838
{

notebooks/tutorials/parsers.ipynb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@
4545
"Loading the data into an instance of `NavData` is as easy as creating an instance of `AndroidDerived2021` with the relevant file path."
4646
]
4747
},
48+
{
49+
"cell_type": "markdown",
50+
"id": "0e7c9e45",
51+
"metadata": {},
52+
"source": [
53+
"**Note:**\n",
54+
"\n",
55+
"In this case, the data is filtered to be seconds apart, in the regular\n",
56+
"setting, such measurements would be removed. To prevent this from happening,\n",
57+
"we use the remove_bad_measures flag here. For the full dataset, set this flag to True"
58+
]
59+
},
4860
{
4961
"cell_type": "code",
5062
"execution_count": null,
@@ -55,7 +67,7 @@
5567
"# download Android data file\n",
5668
"!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/Pixel4XL_derived.csv --quiet -O \"Pixel4XL_derived.csv\"\n",
5769
"# load Android Google Challenge data\n",
58-
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\")"
70+
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\", remove_bad_measures=False)"
5971
]
6072
},
6173
{

notebooks/tutorials/utilities.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
"\n",
9797
"# load Android Google Challenge data\n",
9898
"!wget https://raw.githubusercontent.com/Stanford-NavLab/gnss_lib_py/main/data/unit_test/Pixel4XL_derived.csv --quiet -O \"Pixel4XL_derived.csv\"\n",
99-
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\")"
99+
"derived_data = AndroidDerived2021(\"Pixel4XL_derived.csv\", remove_bad_measures=False)"
100100
]
101101
},
102102
{

tests/parsers/test_android.py

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pytest
1313

1414
from gnss_lib_py.parsers.android import AndroidDerived2021, AndroidRawFixes, AndroidRawImu, AndroidGroundTruth2021
15+
from gnss_lib_py.parsers.android import AndroidDerived2022, AndroidGroundTruth2022
1516
from gnss_lib_py.parsers.navdata import NavData
1617
from gnss_lib_py.parsers.android import make_csv
1718

@@ -37,6 +38,11 @@ def fixture_root_path():
3738
def fixture_derived_path(root_path):
3839
"""Filepath of Android Derived measurements
3940
41+
Parameters
42+
----------
43+
root_path : string
44+
Path of testing dataset root path
45+
4046
Returns
4147
-------
4248
derived_path : string
@@ -65,6 +71,11 @@ def fixture_derived_path(root_path):
6571
def fixture_raw_path(root_path):
6672
"""Filepath of Android Raw measurements
6773
74+
Parameters
75+
----------
76+
root_path : string
77+
Path of testing dataset root path
78+
6879
Returns
6980
-------
7081
raw_path : string
@@ -352,14 +363,14 @@ def fixture_gtruth_path(root_path):
352363
353364
Notes
354365
-----
355-
Test data is a subset of the Android Ground Truth Dataset [2]_,
366+
Test data is a subset of the Android Ground Truth Dataset [3]_,
356367
particularly the train/2020-05-14-US-MTV-1/Pixel4 trace. The dataset
357368
was retrieved from
358369
https://www.kaggle.com/c/google-smartphone-decimeter-challenge/data
359370
360371
References
361372
----------
362-
.. [2] Fu, Guoyu Michael, Mohammed Khider, and Frank van Diggelen.
373+
.. [3] Fu, Guoyu Michael, Mohammed Khider, and Frank van Diggelen.
363374
"Android Raw GNSS Measurement Datasets for Precise Positioning."
364375
Proceedings of the 33rd International Technical Meeting of the
365376
Satellite Division of The Institute of Navigation (ION GNSS+
@@ -397,3 +408,132 @@ def test_android_gtruth(android_gtruth_path):
397408
isinstance(test_gtruth, NavData)
398409

399410

411+
def test_gt_2022(root_path):
412+
"""Testing that Android ground truth 2022 is created without errors.
413+
414+
Parameters
415+
----------
416+
gt_2022_path : string
417+
Location for the unit_test Android ground truth 2022 measurements
418+
"""
419+
gt_path = os.path.join(root_path, 'ground_truth.csv')
420+
gt_2021 = AndroidGroundTruth2021(gt_path)
421+
assert isinstance(gt_2021, NavData)
422+
423+
424+
######################################################################
425+
#### Android Derived 2022 Dataset tests
426+
######################################################################
427+
428+
@pytest.fixture(name="root_path_2022")
429+
def fixture_root_path_2022():
430+
"""Location of measurements for unit test
431+
432+
Returns
433+
-------
434+
root_path : string
435+
Folder location containing measurements
436+
"""
437+
root_path = os.path.dirname(
438+
os.path.dirname(
439+
os.path.dirname(
440+
os.path.realpath(__file__))))
441+
root_path = os.path.join(root_path, 'data/unit_test/android_2022')
442+
return root_path
443+
444+
445+
@pytest.fixture(name="derived_2022_path")
446+
def fixture_derived_2022_path(root_path_2022):
447+
"""Filepath of Android Derived measurements
448+
449+
Returns
450+
-------
451+
derived_path : string
452+
Location for the unit_test Android derived 2022 measurements
453+
454+
Notes
455+
-----
456+
Test data is a subset of the Android Raw Measurement Dataset [4]_,
457+
from the 2022 Decimeter Challenge. Particularly, the
458+
train/2021-04-29-MTV-2/SamsungGalaxyS20Ultra trace. The dataset
459+
was retrieved from
460+
https://www.kaggle.com/competitions/smartphone-decimeter-2022/data
461+
462+
References
463+
----------
464+
.. [4] Fu, Guoyu Michael, Mohammed Khider, and Frank van Diggelen.
465+
"Android Raw GNSS Measurement Datasets for Precise Positioning."
466+
Proceedings of the 33rd International Technical Meeting of the
467+
Satellite Division of The Institute of Navigation (ION GNSS+
468+
2020). 2020.
469+
"""
470+
derived_path = os.path.join(root_path_2022, 'device_gnss.csv')
471+
return derived_path
472+
473+
474+
@pytest.fixture(name="gt_2022_path")
475+
def fixture_gt_2022_path(root_path_2022):
476+
"""Filepath of Android ground truth estimates
477+
478+
Returns
479+
-------
480+
derived_path : string
481+
Location for the unit_test Android ground truth estimates
482+
483+
Notes
484+
-----
485+
Test data is a subset of the Android Raw Measurement Dataset [5]_,
486+
from the 2022 Decimeter Challenge. Particularly, the
487+
train/2021-04-29-MTV-2/SamsungGalaxyS20Ultra trace. The dataset
488+
was retrieved from
489+
https://www.kaggle.com/competitions/smartphone-decimeter-2022/data
490+
491+
References
492+
----------
493+
.. [5] Fu, Guoyu Michael, Mohammed Khider, and Frank van Diggelen.
494+
"Android Raw GNSS Measurement Datasets for Precise Positioning."
495+
Proceedings of the 33rd International Technical Meeting of the
496+
Satellite Division of The Institute of Navigation (ION GNSS+
497+
2020). 2020.
498+
"""
499+
gt_path = os.path.join(root_path_2022, 'ground_truth.csv')
500+
return gt_path
501+
502+
503+
def test_derived_2022(derived_2022_path):
504+
"""Testing that Android Derived 2022 is created without errors.
505+
506+
Parameters
507+
----------
508+
derived_2022_path : string
509+
Location for the unit_test Android derived 2022 measurements
510+
"""
511+
derived_2022 = AndroidDerived2022(derived_2022_path)
512+
assert isinstance(derived_2022, NavData)
513+
514+
515+
def test_gt_2022(gt_2022_path):
516+
"""Testing that Android ground truth 2022 is created without errors.
517+
518+
Parameters
519+
----------
520+
gt_2022_path : string
521+
Location for the unit_test Android ground truth 2022 measurements
522+
"""
523+
gt_2022 = AndroidGroundTruth2022(gt_2022_path)
524+
assert isinstance(gt_2022, NavData)
525+
526+
527+
def test_gt_alt_nan(root_path_2022):
528+
"""Testing that Android Ground Truth Loader sets blank altitudes to 0.
529+
530+
Parameters
531+
----------
532+
root_path_2022 : string
533+
Location for the files with missing altitude, including the file
534+
with missing altitude
535+
"""
536+
gt_2022_nan = os.path.join(root_path_2022, 'alt_nan_ground_truth.csv')
537+
with pytest.warns(RuntimeWarning):
538+
gt_2022 = AndroidGroundTruth2022(gt_2022_nan)
539+
np.testing.assert_almost_equal(gt_2022['alt_gt_m'], np.zeros(len(gt_2022)))

tests/utils/test_time_conversions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,24 @@ def test_gps_unix_millis():
251251
assert unix_millis == rev_unix_millis
252252

253253

254+
def test_gps_unix_millis_vect():
255+
"""Test vectorized version of unix_to_gps_millis and gps_to_unix_millis.
256+
257+
Notes
258+
-----
259+
Test based on the test implemented in test_gps_unix_millis
260+
"""
261+
262+
delta_times = np.arange(10)
263+
unix_millis_vect = 1660161069000. + delta_times
264+
exp_gps_millis_vect = 1344196287000. + delta_times
265+
out_gps_millis_vect = tc.unix_to_gps_millis(unix_millis_vect)
266+
np.testing.assert_almost_equal(exp_gps_millis_vect, out_gps_millis_vect)
267+
# Testing reverse conversion
268+
rev_unix_millis_vect = tc.gps_to_unix_millis(exp_gps_millis_vect)
269+
np.testing.assert_almost_equal(unix_millis_vect, rev_unix_millis_vect)
270+
271+
254272
def test_tz_conversion():
255273
"""Checking internal timezone conversions to UTC
256274

0 commit comments

Comments
 (0)