Skip to content

Commit 986a7cf

Browse files
committed
NPI-4377 various clarity and robustness improvements to NANU utility functions
1 parent 0fa9d8d commit 986a7cf

File tree

1 file changed

+48
-16
lines changed

1 file changed

+48
-16
lines changed

gnssanalysis/gn_io/nanu.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,46 @@
11
import glob
22
import logging as _logging
33
import os as _os
4-
from typing import Union as _Union
5-
from datetime import datetime
4+
from datetime import datetime, date as dt_date
5+
import warnings
66

77
import numpy as _np
88
import pandas as _pd
99

1010
from .. import gn_io as _gn_io
1111

1212

13-
def nanu_path_to_id(nanu_path: str) -> str:
14-
# TODO some examples would be good here.
13+
def nanu_path_to_id(nanu_path: str, reject_old_format: bool = True) -> str:
14+
"""
15+
Extracts a NANU ID from a NANU path or filename.
16+
E.g.
17+
- 2022001.nnu: standard naming convention, first NANU of 2022
18+
- nanu.2022001.txt: CelesTrak convention, first NANU of 2022
19+
- (rejected by default!) nanu.001-96003.txt: CelesTrak convention, first NANU of 1996, occurring on DOY 3 (?)
20+
Note: the numbering is sequential, not day-of-year.
21+
22+
Beginning 1997111, the format appears to change. This is the beginning of a machine readable format for
23+
message block 1.
24+
25+
CelesTrak archive can be found here:
26+
https://celestrak.org/GPS/NANU/2019/ (cert alt name is broken on www.celestrak.org)
27+
28+
:param str nanu_path: path or filename of a NANU file, e.g. nanu/2022/2022001.nnu or nanu/2022/nanu.2022001.txt
29+
:param bool reject_old_format: (on by default) raise exception if old NANU encountered (not machine readable)
30+
:returns str: the NANU ID, e.g 2022001
31+
:raises ValueError: if reject_old_format is True and a NANU < 25th Nov 1997 is encountered (not machine readable)
32+
"""
1533

1634
dir, _, filename = nanu_path.rpartition(_os.sep)
17-
nanu_id, _, extension = filename.partition(".") # get filename without extension
18-
if nanu_id == "nanu": # celestrak naming convention
19-
nanu_id, _, extension = extension.partition(".")
20-
if "-" in nanu_id: # 199X file
35+
nanu_id, _, extension = filename.partition(".") # get name (no extension) e.g. 2022001 or nanu.2022001)
36+
if nanu_id == "nanu": # celestrak naming convention E.g. 'nanu.2022001.txt': the bit we want was in the 'extension'
37+
nanu_id, _, extension = extension.partition(".") # E.g. 2022001.txt -> 2022001, txt
38+
if "-" in nanu_id: # 199X file. E.g. 001-91002: first NANU of 1991 regarding?/published? DOY 2 (2nd Jan)
39+
# While we can determine the ID of this file, the content is not machine readable!
40+
if reject_old_format: # Below date inferred from 'DTG: 250256Z NOV 97'
41+
raise ValueError(f"NANUs prior to 1997111 (25th Nov 1997) are not machine readable. Got: {filename}")
2142
nanu_id = nanu_id[4:6] + nanu_id[:3] # last one might be a letter but we skip for id
43+
# Recombine short year '91' with sequence number '001'. TODO shouldn't we be padding that with '19'?
2244
return nanu_id
2345

2446

@@ -48,30 +70,40 @@ def parse_nanu(nanu_bytes: bytes) -> dict:
4870
return output_dict
4971

5072

51-
def read_nanu(path: str) -> dict:
73+
def read_nanu(path: str, reject_old_format: bool = True) -> dict:
5274
"""A parser for Notice Advisory to Navstar Users (NANU) files.
5375
Assumes there is only one message per file, that starts with '1.'
5476
55-
:param _Union[str, bytes] path_or_bytes: path to nanu file or a bytes object
77+
NOTE: machine readable NANUs started on 25th Nov 1997. NANUs prior to this
78+
are by default rejected by nanu_path_to_id(): a ValueError is raised.
79+
80+
:param str path: path to nanu file
81+
:param bool reject_old_format: (on by default) raise exception if old NANU encountered (not machine readable)
5682
:return dict: nanu values with parameter names as keys
83+
:raises ValueError: if an old NANU is encountered which is not machine readable (prior to 1997-11-25)
5784
"""
5885
nanu_bytes = _gn_io.common.path2bytes(path)
5986
output_dict = {}
6087
output_dict["FILEPATH"] = path # TODO change to pathlib
61-
output_dict["NANU ID"] = nanu_path_to_id(path)
88+
output_dict["NANU ID"] = nanu_path_to_id(path, reject_old_format=reject_old_format)
6289
output_dict["CONTENT"] = nanu_bytes
6390
output_dict.update(parse_nanu(nanu_bytes))
6491
return output_dict
6592

6693

67-
def collect_nanus_to_df(glob_expr: str) -> _pd.DataFrame:
68-
"""Parses all the globbed files
94+
def collect_nanus_to_df(glob_expr: str, reject_old_format: bool = True) -> _pd.DataFrame:
95+
"""Runs the provided glob expression, parsing all the files it matches as NANUs, and loading them into a
96+
Pandas DataFrame ready for further processing.
6997
70-
:param str glob_expr: a glob expression
98+
:param str glob_expr: a glob expression to match NANU files, e.g. 'nanu/**/*.nnu' or
99+
'nanu/**/*.{nnu,txt}' or 'nanu/**/nanu.*.txt'
100+
:param bool reject_old_format: (on by default) raise exception if old NANU encountered (not machine readable)
71101
:return _pd.DataFrame: a dataframe of NANU data
102+
:raises ValueError: if an old NANU is encountered which is not machine readable (prior to 1997-11-25). Depends on
103+
reject_old_format=True.
72104
"""
73-
nanus_list = sorted(glob.glob(glob_expr))
74-
return _pd.DataFrame(read_nanu(n) for n in nanus_list if n is not None)
105+
nanu_file_paths = sorted(glob.glob(glob_expr))
106+
return _pd.DataFrame(read_nanu(n, reject_old_format=reject_old_format) for n in nanu_file_paths if n is not None)
75107

76108

77109
def get_bad_sv_from_nanu_df(

0 commit comments

Comments
 (0)