Skip to content

Commit ff60bc0

Browse files
committed
move kaggle funcs to android.py and test
1 parent 91756cd commit ff60bc0

7 files changed

Lines changed: 145 additions & 89 deletions

File tree

gnss_lib_py/parsers/android.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
from gnss_lib_py.parsers.navdata import NavData
1717
from gnss_lib_py.utils.coordinates import geodetic_to_ecef
18+
from gnss_lib_py.utils.coordinates import ecef_to_geodetic
1819
from gnss_lib_py.utils.time_conversions import unix_to_gps_millis
20+
from gnss_lib_py.utils.time_conversions import gps_to_unix_millis
1921

2022
class AndroidDerived2021(NavData):
2123
"""Class handling derived measurements from Android dataset.
@@ -491,3 +493,71 @@ def make_csv(input_path, output_directory, field, show_path=False):
491493
print(output_path)
492494

493495
return output_path
496+
497+
def solve_kaggle_baseline(navdata):
498+
"""Convert Decimeter challenge baseline into state_estimate.
499+
500+
The baseline solution was provided in 2022, but not in 2021.
501+
502+
Parameters
503+
----------
504+
navdata : gnss_lib_py.parsers.android.AndroidDerived2022
505+
Instance of the AndroidDerived2022 class.
506+
507+
"""
508+
509+
columns = ["unix_millis",
510+
"x_rx_m",
511+
"y_rx_m",
512+
"z_rx_m",
513+
]
514+
data_df = (navdata.pandas_df().drop_duplicates(subset='unix_millis')[columns]
515+
.reset_index(drop=True))
516+
lat,lon,alt = ecef_to_geodetic(data_df[["x_rx_m",
517+
"y_rx_m",
518+
"z_rx_m",
519+
]].to_numpy().T)
520+
521+
state_estimate = NavData()
522+
state_estimate["gps_millis"] = unix_to_gps_millis(
523+
data_df["unix_millis"].to_numpy())
524+
state_estimate["lat_rx_deg"] = lat
525+
state_estimate["lon_rx_deg"] = lon
526+
state_estimate["alt_rx_deg"] = alt
527+
528+
return state_estimate
529+
530+
def prepare_kaggle_submission(state_wls, trip_id):
531+
"""Converts from gnss_lib_py receiver state to Kaggle submission.
532+
533+
534+
receiver_state : gnss_lib_py.parsers.navdata.NavData
535+
Estimated receiver position in latitude and longitude as an
536+
instance of the NavData class with the following
537+
rows: ``lat_*_deg``, ``lon_*_deg``.
538+
tripId : string
539+
Value for the tripId column in kaggle submission which is a
540+
fusion of the data and phone type
541+
542+
Returns
543+
-------
544+
output : gnss_lib_py.parsers.navdata.NavData
545+
NavData structure ready for Kaggle submission
546+
547+
"""
548+
549+
state_wls.in_rows("gps_millis")
550+
wildcards = state_wls.find_wildcard_indexes(["lat_*_deg",
551+
"lon_*_deg"],max_allow = 1)
552+
553+
output = NavData()
554+
output["tripId"] = np.array([trip_id] * state_wls.shape[1])
555+
output["UnixTimeMillis"] = gps_to_unix_millis(state_wls["gps_millis"])
556+
output.orig_dtypes["UnixTimeMillis"] = np.int64
557+
output["LatitudeDegrees"] = state_wls[wildcards["lat_*_deg"]]
558+
output["LongitudeDegrees"] = state_wls[wildcards["lon_*_deg"]]
559+
560+
output.interpolate("UnixTimeMillis",["LatitudeDegrees",
561+
"LongitudeDegrees"])
562+
563+
return output

gnss_lib_py/parsers/kaggle.py

Lines changed: 0 additions & 74 deletions
This file was deleted.

gnss_lib_py/parsers/navdata.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ def interpolate(self, x_row, y_rows, inplace=False, *args):
695695
new_navdata = self.copy()
696696
for y_row in y_rows:
697697
nan_idxs = self.argwhere(y_row,np.nan)
698+
if len(nan_idxs) == 0:
699+
continue
698700
not_nan_idxs = self.argwhere(y_row,np.nan,"neq")
699701
x_vals = self[x_row,nan_idxs]
700702
xp_vals = self[x_row,not_nan_idxs]

gnss_lib_py/utils/time_conversions.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,6 @@ def datetime_to_gps_millis(t_datetime, add_leap_secs=True):
261261
gps_millis = tow_to_gps_millis(gps_week, tow)
262262
return gps_millis
263263

264-
265264
def unix_millis_to_datetime(unix_millis):
266265
"""Convert milliseconds since UNIX epoch (1/1/1970) to UTC datetime.
267266
@@ -275,7 +274,9 @@ def unix_millis_to_datetime(unix_millis):
275274
t_utc : datetime.datetime
276275
UTC time as a datetime object.
277276
"""
278-
t_utc = UNIX_EPOCH_0 + timedelta(milliseconds=float(unix_millis))
277+
if np.issubdtype(type(unix_millis),int):
278+
unix_millis = float(unix_millis)
279+
t_utc = UNIX_EPOCH_0 + timedelta(milliseconds=unix_millis)
279280
t_utc = t_utc.replace(tzinfo=timezone.utc)
280281
return t_utc
281282

@@ -318,7 +319,7 @@ def unix_to_gps_millis(unix_millis, add_leap_secs=True):
318319
319320
Returns
320321
-------
321-
gps_millis : float
322+
gps_millis : int
322323
Milliseconds since GPS Epoch (6th January 1980 GPS).
323324
"""
324325
# Add leapseconds should always be true here
@@ -327,9 +328,10 @@ def unix_to_gps_millis(unix_millis, add_leap_secs=True):
327328
for t_idx, unix in enumerate(unix_millis):
328329
t_utc = unix_millis_to_datetime(unix)
329330
gps_millis[t_idx] = datetime_to_gps_millis(t_utc, add_leap_secs=add_leap_secs)
331+
gps_millis = gps_millis.astype(int)
330332
else:
331333
t_utc = unix_millis_to_datetime(unix_millis)
332-
gps_millis = datetime_to_gps_millis(t_utc, add_leap_secs=add_leap_secs)
334+
gps_millis = int(datetime_to_gps_millis(t_utc, add_leap_secs=add_leap_secs))
333335
return gps_millis
334336

335337

@@ -373,7 +375,7 @@ def gps_to_unix_millis(gps_millis, rem_leap_secs=True):
373375
374376
Returns
375377
-------
376-
unix_millis : float
378+
unix_millis : int
377379
Milliseconds since UNIX Epoch (1/1/1970 UTC)
378380
379381
"""
@@ -384,9 +386,10 @@ def gps_to_unix_millis(gps_millis, rem_leap_secs=True):
384386
for t_idx, gps in enumerate(gps_millis):
385387
t_utc = gps_millis_to_datetime(gps, rem_leap_secs=rem_leap_secs)
386388
unix_millis[t_idx] = datetime_to_unix_millis(t_utc)
389+
gps_millis = gps_millis.astype(int)
387390
else:
388391
t_utc = gps_millis_to_datetime(gps_millis, rem_leap_secs=rem_leap_secs)
389-
unix_millis = datetime_to_unix_millis(t_utc)
392+
unix_millis = int(datetime_to_unix_millis(t_utc))
390393
return unix_millis
391394

392395
def _check_tzinfo(t_datetime):

tests/parsers/test_android.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,17 +588,23 @@ def fixture_gt_2022_path(root_path_2022):
588588
gt_path = os.path.join(root_path_2022, 'ground_truth.csv')
589589
return gt_path
590590

591-
591+
@pytest.fixture(name="derived_2022")
592592
def test_derived_2022(derived_2022_path):
593593
"""Testing that Android Derived 2022 is created without errors.
594594
595595
Parameters
596596
----------
597597
derived_2022_path : string
598598
Location for the unit_test Android derived 2022 measurements
599+
600+
Returns
601+
-------
602+
derived_2022 :
603+
599604
"""
600605
derived_2022 = android.AndroidDerived2022(derived_2022_path)
601606
assert isinstance(derived_2022, NavData)
607+
return derived_2022
602608

603609

604610
def test_gt_2022(gt_2022_path):
@@ -643,3 +649,52 @@ def test_remove_all_data(derived_path_xl):
643649
remove_timing_outliers=True)
644650

645651
assert derived.shape[1] == 0
652+
653+
@pytest.fixture(name="state_estimate")
654+
def test_solve_kaggle_baseline(derived_2022):
655+
"""Testing Kaggle baseline solution.
656+
657+
Parameters
658+
----------
659+
derived_2022 : gnss_lib_py.parsers.android.AndroidDerived2022
660+
Android derived 2022 measurements
661+
662+
Returns
663+
-------
664+
state_estimate : gnss_lib_py.parsers.navdata.NavData
665+
Baseline state estimate.
666+
"""
667+
668+
state_estimate = android.solve_kaggle_baseline(derived_2022)
669+
670+
state_estimate.in_rows(["gps_millis","lat_rx_deg",
671+
"lon_rx_deg","alt_rx_deg"])
672+
673+
assert state_estimate.shape[1] == 6
674+
675+
expected = np.array([1303770943999,1303770944999,1303770945999,
676+
1303770946999,1303770947999,1303770948999])
677+
np.testing.assert_array_equal(state_estimate["gps_millis"],expected)
678+
679+
return state_estimate
680+
681+
def test_prepare_kaggle_submission(state_estimate):
682+
"""Prepare Kaggle baseline solution.
683+
684+
Parameters
685+
----------
686+
state_estimate : gnss_lib_py.parsers.navdata.NavData
687+
Baseline state estimate.
688+
689+
"""
690+
691+
output = android.prepare_kaggle_submission(state_estimate,"test")
692+
693+
output.in_rows(["tripId","UnixTimeMillis",
694+
"LatitudeDegrees","LongitudeDegrees"])
695+
696+
assert output.shape[1] == 6
697+
698+
expected = np.array([1619735725999,1619735726999,1619735727999,
699+
1619735728999,1619735729999,1619735730999])
700+
np.testing.assert_array_equal(output["UnixTimeMillis"], expected)

tests/parsers/test_kaggle.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/parsers/test_navdata.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,14 @@ def test_interpolate():
21722172
"""Test inerpolate nan function.
21732173
21742174
"""
2175+
2176+
data = NavData()
2177+
data["ints"] = [1,2]
2178+
data["floats"] = [1.,2.]
2179+
new_data = data.interpolate("ints","floats")
2180+
new_data["ints"] = np.array([1,2])
2181+
new_data["floats"] = np.array([1.,2.])
2182+
21752183
data = NavData()
21762184
data["UnixTimeMillis"] = [0,1,2,3,4,5,6,7,8,9,10]
21772185
data["LatitudeDegrees"] = [0., np.nan, np.nan, np.nan, np.nan, 50.,

0 commit comments

Comments
 (0)