Skip to content

Commit e4c58f5

Browse files
committed
add_sv_states from precise
1 parent 1261fed commit e4c58f5

3 files changed

Lines changed: 161 additions & 79 deletions

File tree

gnss_lib_py/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
from gnss_lib_py.utils.coordinates import *
2020
from gnss_lib_py.utils.ephemeris_downloader import *
2121
from gnss_lib_py.utils.filters import *
22-
from gnss_lib_py.utils.sv_models import *
2322
from gnss_lib_py.utils.gnss_models import *
23+
from gnss_lib_py.utils.sv_models import *
2424
from gnss_lib_py.utils.time_conversions import *
2525
from gnss_lib_py.utils.visualizations import *
2626

gnss_lib_py/utils/sv_models.py

Lines changed: 77 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,100 @@
2222
from gnss_lib_py.utils.ephemeris_downloader import DEFAULT_EPHEM_PATH, load_ephemeris
2323

2424

25-
def add_sv_states(measurements, source = 'precise', file_paths = None,
25+
def add_sv_states(navdata, source = 'precise', file_paths = None,
2626
download_directory = DEFAULT_EPHEM_PATH,
27-
constellations = None, delta_t_dec = -2,
2827
verbose = True):
2928
"""Add SV states to measurements using SP3 and CLK or Rinex files.
29+
30+
If source is 'precise' then will use SP3 and CLK files.
31+
32+
Parameters
33+
----------
34+
navdata : gnss_lib_py.parsers.navdata.NavData
35+
Instance of the NavData class that must include rows for
36+
``gps_millis``, ``gnss_id``, ``sv_id``, and ``raw_pr_m``.
37+
source : string
38+
The method used to compute SV states. If 'precise', then will
39+
use SP3 and CLK precise files.
40+
file_paths : list, string or path-like
41+
Paths to existing ephemeris files if they exist.
42+
download_directory : string or path-like
43+
Directory where ephemeris files are downloaded if necessary.
44+
verbose : bool
45+
Prints extra debugging statements if true.
46+
47+
Returns
48+
-------
49+
navdata_w_sv_states : gnss_lib_py.parsers.navdata.NavData
50+
Updated NavData class with satellite information computed.
51+
3052
"""
3153
if source == 'precise':
32-
measurements_w_sv_states = add_sv_states_precise(measurements,
33-
sp3_clk_paths = file_paths,
34-
download_directory = download_directory,
35-
constellations = constellations,
36-
delta_t_dec = delta_t_dec,
37-
verbose = verbose)
54+
navdata_w_sv_states = add_sv_states_precise(navdata,
55+
file_paths = file_paths,
56+
download_directory = download_directory,
57+
verbose = verbose)
3858
else:
3959
raise RuntimeError('Only Precise SV state estimation supported')
40-
return measurements_w_sv_states
41-
60+
return navdata_w_sv_states
4261

4362

44-
def add_sv_states_precise(measurements, sp3_clk_paths = None,
63+
def add_sv_states_precise(navdata, file_paths = None,
4564
download_directory = DEFAULT_EPHEM_PATH,
46-
constellations=None, delta_t_dec=-2,
4765
verbose=True):
4866
"""Add SV states to measurements using SP3 and CLK files.
4967
50-
Given received measurements, add SV states for measurements corresponding
51-
to received time and SV ID using SP3 and CLK files. If receiver
52-
position is given, that position is used to calculate the difference
53-
between signal transmission and reception to find the SV states
54-
corresponding to the time at which the signal was transmitted.
55-
5668
Parameters
5769
----------
58-
"""
59-
return measurements
70+
navdata : gnss_lib_py.parsers.navdata.NavData
71+
Instance of the NavData class that must include rows for
72+
``gps_millis``, ``gnss_id``, ``sv_id``, and ``raw_pr_m``.
73+
source : string
74+
The method used to compute SV states. If 'precise', then will
75+
use SP3 and CLK precise files.
76+
file_paths : list, string or path-like
77+
Paths to existing SP3 or CLK files if they exist.
78+
download_directory : string or path-like
79+
Directory where ephemeris files are downloaded if necessary.
80+
verbose : bool
81+
Prints extra debugging statements if true.
6082
83+
Returns
84+
-------
85+
navdata_w_sv_states : gnss_lib_py.parsers.navdata.NavData
86+
Updated NavData class with satellite information computed.
6187
88+
"""
89+
90+
# get unique gps_millis and constellations for ephemeris loader
91+
unique_gps_millis = np.unique(navdata["gps_millis"])
92+
constellations = np.unique(navdata["gnss_id"])
93+
94+
# load sp3 files
95+
sp3_paths = load_ephemeris("sp3", gps_millis = unique_gps_millis,
96+
constellations=constellations,
97+
file_paths = file_paths,
98+
download_directory=download_directory,
99+
verbose=verbose
100+
)
101+
sp3 = Sp3(sp3_paths)
102+
103+
# load clk files
104+
clk_paths = load_ephemeris("clk", gps_millis = unique_gps_millis,
105+
constellations=constellations,
106+
file_paths = file_paths,
107+
download_directory=download_directory,
108+
verbose=verbose
109+
)
110+
clk = Clk(clk_paths)
111+
112+
# add SV states using sp3 and clk
113+
navdata_w_sv_states = single_gnss_from_precise_eph(navdata,
114+
sp3,
115+
clk,
116+
verbose=verbose)
117+
118+
return navdata_w_sv_states
62119

63120
def add_sv_states_rinex(measurements, ephemeris_path= DEFAULT_EPHEM_PATH,
64121
constellations=['gps'], delta_t_dec = -2):
@@ -709,9 +766,6 @@ def _find_delxyz_range(sv_posvel, rx_ecef):
709766
true_range = np.linalg.norm(del_pos, axis=0)
710767
return del_pos, true_range
711768

712-
713-
714-
715769
def single_gnss_from_precise_eph(navdata, sp3_parsed_file,
716770
clk_parsed_file, inplace=False,
717771
verbose = False):
@@ -862,39 +916,3 @@ def single_gnss_from_precise_eph(navdata, sp3_parsed_file,
862916
if inplace:
863917
return None
864918
return new_navdata
865-
866-
def add_sv_states_sp3_and_clk(navdata, sp3_path, clk_path,
867-
inplace=False, verbose = False):
868-
"""Compute satellite information using .sp3 and .clk for multiple GNSS
869-
870-
Parameters
871-
----------
872-
navdata : gnss_lib_py.parsers.navdata.NavData
873-
Instance of the NavData class that depicts android derived dataset
874-
sp3_path : path
875-
File path for .sp3 file to extract precise ephemerides
876-
clk_path : path
877-
File path for .clk file to extract precise ephemerides
878-
inplace : bool
879-
If true, adds satellite positions and clock bias to the input
880-
navdata object, otherwise returns a new NavData object with the
881-
satellite rows added.
882-
verbose : bool
883-
Flag for whether to print intermediate steps useful
884-
for debugging/reviewing (the default is False)
885-
886-
Returns
887-
-------
888-
navdata : gnss_lib_py.parsers.navdata.NavData
889-
Updated NavData class with satellite information computed using
890-
precise ephemerides from .sp3 and .clk files
891-
"""
892-
sp3_parsed_gnss = Sp3(sp3_path)
893-
clk_parsed_gnss = Clk(clk_path)
894-
precise_navdata = single_gnss_from_precise_eph(navdata,
895-
sp3_parsed_gnss,
896-
clk_parsed_gnss,
897-
inplace = inplace,
898-
verbose = verbose)
899-
900-
return precise_navdata

tests/utils/test_sv_models.py

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
__date__ = "21 Mar 2023"
77

88
import os
9+
from datetime import datetime, timezone
910

1011
import pytest
1112
import numpy as np
@@ -16,6 +17,7 @@
1617
from gnss_lib_py.parsers.sp3 import Sp3
1718
from gnss_lib_py.parsers.navdata import NavData
1819
import gnss_lib_py.utils.sv_models as sv_models
20+
import gnss_lib_py.utils.time_conversions as tc
1921
from gnss_lib_py.parsers.android import AndroidDerived2021
2022
# pylint: disable=protected-access
2123

@@ -452,22 +454,6 @@ def test_add_visible_svs_for_trajectory(android_gps_l1, ephemeris_path,
452454
measure_frame_sv[row],
453455
decimal=error_tol_dec['brd_eph'])
454456

455-
@pytest.fixture(name="root_path")
456-
def fixture_root_path():
457-
"""Location of measurements for unit test
458-
459-
Returns
460-
-------
461-
root_path : string
462-
Folder location containing measurements
463-
"""
464-
root_path = os.path.dirname(
465-
os.path.dirname(
466-
os.path.dirname(
467-
os.path.realpath(__file__))))
468-
root_path = os.path.join(root_path, 'data/unit_test/')
469-
return root_path
470-
471457
@pytest.fixture(name="sp3_path")
472458
def fixture_sp3_path(root_path):
473459
"""Filepath of valid .sp3 measurements
@@ -873,7 +859,7 @@ def test_gpscheck_sp3_eph(navdata_gpsl1, sp3data, clkdata, ephemeris_path):
873859

874860

875861
def test_compute_concat_precise_eph(navdata, sp3_path, clk_path):
876-
"""Tests that add_sv_states_sp3_and_clk does not fail for multi-GNSS
862+
"""Tests that single_gnss_from_precise_eph does not fail for multi-GNSS
877863
878864
Notes
879865
-----
@@ -895,8 +881,11 @@ def test_compute_concat_precise_eph(navdata, sp3_path, clk_path):
895881
navdata_merged = NavData()
896882
navdata_merged = navdata.where('gnss_id',gnss_consts)
897883

898-
navdata_prcs_merged = sv_models.add_sv_states_sp3_and_clk(navdata, sp3_path,
899-
clk_path, verbose = True)
884+
sp3 = Sp3(sp3_path)
885+
clk = Clk(clk_path)
886+
887+
navdata_prcs_merged = sv_models.single_gnss_from_precise_eph(navdata,
888+
sp3, clk, verbose=True)
900889

901890
navdata_prcs_merged = navdata_prcs_merged.where("gnss_id",gnss_consts)
902891

@@ -993,3 +982,78 @@ def test_compute_gps_brdcst_eph(navdata_gpsl1, navdata, navdata_glonassg1,
993982
pd.testing.assert_frame_equal(navdata_gpsl1_df.sort_index(axis=1),
994983
navdata_gpsl1_eph_df.sort_index(axis=1),
995984
check_dtype=False, check_names=True)
985+
986+
@pytest.fixture(name="all_ephem_paths")
987+
def fixture_all_ephem_paths(root_path):
988+
"""Location of ephemeris files for unit test
989+
990+
Parameters
991+
----------
992+
root_path : string
993+
Location where ephemeris files are stored/to be downloaded.
994+
995+
Returns
996+
-------
997+
all_ephem_paths : string
998+
Location of all unit test ephemeris files.
999+
1000+
"""
1001+
1002+
all_ephem_paths = []
1003+
1004+
ephem_dirs = [
1005+
os.path.join(root_path,"rinex","nav"),
1006+
os.path.join(root_path,"sp3"),
1007+
os.path.join(root_path,"clk"),
1008+
]
1009+
for ephem_dir in ephem_dirs:
1010+
all_ephem_paths += [os.path.join(ephem_dir,file) \
1011+
for file in os.listdir(ephem_dir)]
1012+
1013+
return all_ephem_paths
1014+
1015+
def test_add_sv_states_precise(all_ephem_paths):
1016+
"""Test adding SV states
1017+
1018+
Parameters
1019+
----------
1020+
all_ephem_paths : string
1021+
Location of all unit test ephemeris files.
1022+
1023+
"""
1024+
1025+
# create minimal test inputs
1026+
navdata = NavData()
1027+
1028+
datetimes = np.array([
1029+
datetime(2020, 5, 17, 11, tzinfo=timezone.utc),
1030+
datetime(2021, 4, 28, 12, tzinfo=timezone.utc),
1031+
datetime(2023, 3, 14, 11, tzinfo=timezone.utc),
1032+
])
1033+
gps_millis = tc.datetime_to_gps_millis(datetimes)
1034+
1035+
navdata["gps_millis"] = gps_millis
1036+
navdata["gnss_id"] = np.array(["gps","glonass","qzss"])
1037+
navdata["sv_id"] = np.array([2,1,1])
1038+
navdata["raw_pr_m"] = np.array([26E3]*3)
1039+
1040+
sv_states = sv_models.add_sv_states(navdata,"precise",
1041+
file_paths=all_ephem_paths,
1042+
verbose=True)
1043+
1044+
assert not np.isnan(sv_states[["x_sv_m","y_sv_m","z_sv_m"]]).any()
1045+
1046+
# test minimal inputs
1047+
1048+
def test_add_sv_states_fails():
1049+
"""Test options which should fail.
1050+
1051+
"""
1052+
1053+
navdata = NavData()
1054+
1055+
with pytest.raises(RuntimeError) as excinfo:
1056+
sv_models.add_sv_states(navdata, source="broadcast")
1057+
1058+
with pytest.raises(RuntimeError) as excinfo:
1059+
sv_models.add_sv_states(navdata, source="rinex")

0 commit comments

Comments
 (0)