keplemon 3.1.1__cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- keplemon/.DS_Store +0 -0
- keplemon/._.DS_Store +0 -0
- keplemon/._arm +0 -0
- keplemon/._libastrofunc.so +0 -0
- keplemon/._libdllmain.so +0 -0
- keplemon/._libelops.so +0 -0
- keplemon/._libenvconst.so +0 -0
- keplemon/._libextephem.so +0 -0
- keplemon/._libobs.so +0 -0
- keplemon/._libsatstate.so +0 -0
- keplemon/._libsensor.so +0 -0
- keplemon/._libsgp4prop.so +0 -0
- keplemon/._libspvec.so +0 -0
- keplemon/._libtimefunc.so +0 -0
- keplemon/._libtle.so +0 -0
- keplemon/._libvcm.so +0 -0
- keplemon/EGM-2008.GEO +2563 -0
- keplemon/EGM-96.GEO +2563 -0
- keplemon/JPLcon_1950_2050.405 +392370 -0
- keplemon/SGP4_Open_License.txt +186 -0
- keplemon/WGS84-70.GEO +2563 -0
- keplemon/__init__.py +33 -0
- keplemon/__init__.pyi +54 -0
- keplemon/__main__.py +20 -0
- keplemon/_keplemon.abi3.so +0 -0
- keplemon/bodies.py +8 -0
- keplemon/bodies.pyi +367 -0
- keplemon/catalogs.py +5 -0
- keplemon/catalogs.pyi +19 -0
- keplemon/elements.py +39 -0
- keplemon/elements.pyi +521 -0
- keplemon/enums.py +21 -0
- keplemon/enums.pyi +120 -0
- keplemon/estimation.py +9 -0
- keplemon/estimation.pyi +200 -0
- keplemon/events.py +17 -0
- keplemon/events.pyi +103 -0
- keplemon/exceptions.py +5 -0
- keplemon/libastrofunc.so +0 -0
- keplemon/libdllmain.so +0 -0
- keplemon/libelops.so +0 -0
- keplemon/libenvconst.so +0 -0
- keplemon/libextephem.so +0 -0
- keplemon/libobs.so +0 -0
- keplemon/libsatstate.so +0 -0
- keplemon/libsensor.so +0 -0
- keplemon/libsgp4prop.so +0 -0
- keplemon/libspvec.so +0 -0
- keplemon/libtimefunc.so +0 -0
- keplemon/libtle.so +0 -0
- keplemon/libvcm.so +0 -0
- keplemon/propagation.py +15 -0
- keplemon/propagation.pyi +50 -0
- keplemon/py.typed +0 -0
- keplemon/time.py +96 -0
- keplemon/time.pyi +293 -0
- keplemon/time_constants.dat +19472 -0
- keplemon-3.1.1.dist-info/METADATA +21 -0
- keplemon-3.1.1.dist-info/RECORD +76 -0
- keplemon-3.1.1.dist-info/WHEEL +5 -0
- keplemon-3.1.1.dist-info/entry_points.txt +2 -0
- keplemon.libs/libastrofunc-d5d29f1a.so +0 -0
- keplemon.libs/libdllmain-83b073db.so +0 -0
- keplemon.libs/libelops-d6961cbd.so +0 -0
- keplemon.libs/libenvconst-5ff8e89b.so +0 -0
- keplemon.libs/libextephem-9ddad493.so +0 -0
- keplemon.libs/libgfortran-daac5196.so.5 +0 -0
- keplemon.libs/libgomp-d22c30c5.so.1 +0 -0
- keplemon.libs/libobs-acba28cb.so +0 -0
- keplemon.libs/libsatstate-a0706992.so +0 -0
- keplemon.libs/libsensor-15ffa85c.so +0 -0
- keplemon.libs/libsgp4prop-8300f9d3.so +0 -0
- keplemon.libs/libspvec-b3cef8a2.so +0 -0
- keplemon.libs/libtimefunc-d4915652.so +0 -0
- keplemon.libs/libtle-72004375.so +0 -0
- keplemon.libs/libvcm-460d66c8.so +0 -0
keplemon/estimation.pyi
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from keplemon.elements import TopocentricElements, CartesianVector
|
|
5
|
+
from keplemon.time import Epoch
|
|
6
|
+
from keplemon.bodies import Satellite, Sensor, Constellation
|
|
7
|
+
from keplemon.enums import KeplerianType, AssociationConfidence
|
|
8
|
+
|
|
9
|
+
class Covariance:
|
|
10
|
+
sigmas: list[float]
|
|
11
|
+
""""""
|
|
12
|
+
|
|
13
|
+
class ObservationAssociation:
|
|
14
|
+
observation_id: str
|
|
15
|
+
satellite_id: str
|
|
16
|
+
residual: "ObservationResidual"
|
|
17
|
+
confidence: "AssociationConfidence"
|
|
18
|
+
|
|
19
|
+
class Observation:
|
|
20
|
+
"""
|
|
21
|
+
Args:
|
|
22
|
+
sensor: Sensor that made the observation
|
|
23
|
+
epoch: Time of the observation
|
|
24
|
+
observed_teme_topocentric: Topocentric elements of the satellite at the time of observation
|
|
25
|
+
observer_teme_position: Position of the observer in TEME coordinates
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
id: str
|
|
29
|
+
"""Unique identifier for the observation"""
|
|
30
|
+
|
|
31
|
+
sensor: Sensor
|
|
32
|
+
"""Sensor which produced the observation"""
|
|
33
|
+
|
|
34
|
+
epoch: Epoch
|
|
35
|
+
"""Time the measurement was observed"""
|
|
36
|
+
|
|
37
|
+
range: Optional[float]
|
|
38
|
+
"""Observed range from the sensor to the satellite in **_kilometers_**"""
|
|
39
|
+
|
|
40
|
+
range_rate: Optional[float]
|
|
41
|
+
"""Observed range rate from the sensor to the satellite in **_kilometers per second_**"""
|
|
42
|
+
|
|
43
|
+
right_ascension: float
|
|
44
|
+
"""Observed TEME right ascension in **_degrees_**"""
|
|
45
|
+
|
|
46
|
+
declination: float
|
|
47
|
+
"""Observed TEME declination in **_degrees_**"""
|
|
48
|
+
|
|
49
|
+
right_ascension_rate: Optional[float]
|
|
50
|
+
"""Observed right ascension rate in **_degrees per second_**"""
|
|
51
|
+
|
|
52
|
+
declination_rate: Optional[float]
|
|
53
|
+
"""Observed declination rate in **_degrees per second_**"""
|
|
54
|
+
|
|
55
|
+
observed_satellite_id: Optional[str]
|
|
56
|
+
"""Tagged satellite ID of the observation"""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
sensor: Sensor,
|
|
61
|
+
epoch: Epoch,
|
|
62
|
+
observed_teme_topocentric: TopocentricElements,
|
|
63
|
+
observer_teme_position: CartesianVector,
|
|
64
|
+
) -> None: ...
|
|
65
|
+
@staticmethod
|
|
66
|
+
def from_saal_files(sensor_file: str, observation_file: str) -> list["Observation"]: ...
|
|
67
|
+
def get_residual(self, sat: Satellite) -> Optional[ObservationResidual]:
|
|
68
|
+
"""
|
|
69
|
+
Calculate the residual of the observation with respect to a given satellite state.
|
|
70
|
+
|
|
71
|
+
!!! note
|
|
72
|
+
If an error occurs during propagation of the satellite state, this method will return None.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
sat: Expected satellite state
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Calculated residual
|
|
79
|
+
"""
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
def get_associations(self, sats: Constellation) -> list[ObservationAssociation]:
|
|
83
|
+
"""
|
|
84
|
+
Calculate the associations of the observation with respect to a given constellation of satellites.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
sats: Constellation of satellites to compare against
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
List of possible observation associations
|
|
91
|
+
"""
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
class ObservationResidual:
|
|
95
|
+
range: float
|
|
96
|
+
"""Euclidean distance between the observed and expected state in **_kilometers_**"""
|
|
97
|
+
|
|
98
|
+
radial: float
|
|
99
|
+
"""Radial distance between the observed and expected state in **_kilometers_**"""
|
|
100
|
+
|
|
101
|
+
in_track: float
|
|
102
|
+
"""In-track distance between the observed and expected state in **_kilometers_**"""
|
|
103
|
+
|
|
104
|
+
cross_track: float
|
|
105
|
+
"""Cross-track distance between the observed and expected state in **_kilometers_**"""
|
|
106
|
+
|
|
107
|
+
velocity: float
|
|
108
|
+
"""Velocity magnitude difference between the observed and expected state in **_kilometers per second_**"""
|
|
109
|
+
|
|
110
|
+
radial_velocity: float
|
|
111
|
+
"""Radial velocity difference between the observed and expected state in **_kilometers per second_**"""
|
|
112
|
+
|
|
113
|
+
in_track_velocity: float
|
|
114
|
+
"""In-track velocity difference between the observed and expected state in **_kilometers per second_**"""
|
|
115
|
+
|
|
116
|
+
cross_track_velocity: float
|
|
117
|
+
"""Cross-track velocity difference between the observed and expected state in **_kilometers per second_**"""
|
|
118
|
+
|
|
119
|
+
time: float
|
|
120
|
+
"""Time difference between the observed and expected state in **_seconds_**"""
|
|
121
|
+
|
|
122
|
+
beta: float
|
|
123
|
+
"""Out-of-plane difference between the observed and expected state in **_degrees_**"""
|
|
124
|
+
|
|
125
|
+
height: float
|
|
126
|
+
"""Height difference between the observed and expected state in **_kilometers_**"""
|
|
127
|
+
|
|
128
|
+
class BatchLeastSquares:
|
|
129
|
+
"""
|
|
130
|
+
Args:
|
|
131
|
+
obs: List of observations to be used in the estimation
|
|
132
|
+
a_priori: A priori satellite state
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
converged: bool
|
|
136
|
+
"""Indicates if the solution meets the tolerance criteria"""
|
|
137
|
+
|
|
138
|
+
max_iterations: int
|
|
139
|
+
"""Maximum number of iterations to perform when solving if the tolerance is not met"""
|
|
140
|
+
|
|
141
|
+
iteration_count: int
|
|
142
|
+
"""Number of iterations performed to reach the solution"""
|
|
143
|
+
|
|
144
|
+
current_estimate: Satellite
|
|
145
|
+
"""Current estimate of the satellite state after iterating or solving"""
|
|
146
|
+
|
|
147
|
+
rms: Optional[float]
|
|
148
|
+
"""Root mean square of the residuals in **_kilometers_**"""
|
|
149
|
+
|
|
150
|
+
weighted_rms: Optional[float]
|
|
151
|
+
"""Unitless weighted root mean square of the residuals"""
|
|
152
|
+
|
|
153
|
+
estimate_srp: bool
|
|
154
|
+
"""Flag to indicate if solar radiation pressure should be estimated
|
|
155
|
+
|
|
156
|
+
!!! warning
|
|
157
|
+
This currently has unexpected behavior if solving for output_types other than XP
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
estimate_drag: bool
|
|
161
|
+
"""Flag to indicate if atmospheric drag should be estimated
|
|
162
|
+
|
|
163
|
+
!!! warning
|
|
164
|
+
This currently has unexpected behavior if solving for output_types other than XP
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
a_priori: Satellite
|
|
168
|
+
"""A priori satellite state used to initialize the estimation"""
|
|
169
|
+
|
|
170
|
+
observations: list[Observation]
|
|
171
|
+
"""List of observations used in the estimation"""
|
|
172
|
+
|
|
173
|
+
residuals: list[tuple[Epoch, ObservationResidual]]
|
|
174
|
+
"""List of residuals for each observation compared to the current estimate"""
|
|
175
|
+
|
|
176
|
+
covariance: Optional[Covariance]
|
|
177
|
+
"""UVW covariance matrix of the current estimate in **_kilometers_** and **_kilometers per second_**"""
|
|
178
|
+
|
|
179
|
+
output_type: KeplerianType
|
|
180
|
+
"""Type of Keplerian elements to be used in the output state"""
|
|
181
|
+
|
|
182
|
+
eccentricity_constraint_weight: Optional[float]
|
|
183
|
+
"""Tikhonov weight that keeps equinoctial a_f/a_g (eccentricity) near the a priori state"""
|
|
184
|
+
|
|
185
|
+
def __init__(
|
|
186
|
+
self,
|
|
187
|
+
obs: list[Observation],
|
|
188
|
+
a_priori: Satellite,
|
|
189
|
+
) -> None: ...
|
|
190
|
+
def solve(self) -> None:
|
|
191
|
+
"""Iterate until the solution converges or the maximum number of iterations is reached."""
|
|
192
|
+
...
|
|
193
|
+
|
|
194
|
+
def iterate(self) -> None:
|
|
195
|
+
"""Perform a single iteration of the estimation process."""
|
|
196
|
+
...
|
|
197
|
+
|
|
198
|
+
def reset(self) -> None:
|
|
199
|
+
"""Reset the estimation process to the initial state."""
|
|
200
|
+
...
|
keplemon/events.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from keplemon._keplemon.events import ( # type: ignore
|
|
2
|
+
CloseApproach,
|
|
3
|
+
CloseApproachReport,
|
|
4
|
+
HorizonAccess,
|
|
5
|
+
HorizonAccessReport,
|
|
6
|
+
FieldOfViewCandidate,
|
|
7
|
+
FieldOfViewReport,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"CloseApproach",
|
|
12
|
+
"CloseApproachReport",
|
|
13
|
+
"HorizonAccess",
|
|
14
|
+
"HorizonAccessReport",
|
|
15
|
+
"FieldOfViewCandidate",
|
|
16
|
+
"FieldOfViewReport",
|
|
17
|
+
]
|
keplemon/events.pyi
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
from keplemon.time import Epoch, TimeSpan
|
|
3
|
+
from keplemon.elements import HorizonState, CartesianVector, TopocentricElements
|
|
4
|
+
from keplemon.enums import ReferenceFrame
|
|
5
|
+
|
|
6
|
+
class FieldOfViewCandidate:
|
|
7
|
+
satellite_id: str
|
|
8
|
+
"""ID of the candidate satellite"""
|
|
9
|
+
|
|
10
|
+
direction: TopocentricElements
|
|
11
|
+
"""Measured direction to the candidate satellite in the sensor's topocentric frame"""
|
|
12
|
+
|
|
13
|
+
class FieldOfViewReport:
|
|
14
|
+
epoch: Epoch
|
|
15
|
+
"""UTC epoch of the field of view report"""
|
|
16
|
+
|
|
17
|
+
sensor_position: CartesianVector
|
|
18
|
+
"""TEME position of the sensor in the observatory's topocentric frame in **_kilometers_**"""
|
|
19
|
+
|
|
20
|
+
sensor_direction: TopocentricElements
|
|
21
|
+
"""Direction of the sensor in the observatory's topocentric frame"""
|
|
22
|
+
|
|
23
|
+
fov_angle: float
|
|
24
|
+
"""Field of view angle of the sensor in **_degrees_**"""
|
|
25
|
+
|
|
26
|
+
candidates: list[FieldOfViewCandidate]
|
|
27
|
+
"""List of candidate satellites within the field of view"""
|
|
28
|
+
|
|
29
|
+
reference_frame: ReferenceFrame
|
|
30
|
+
"""Reference frame of the output direction elements"""
|
|
31
|
+
|
|
32
|
+
class CloseApproach:
|
|
33
|
+
epoch: Epoch
|
|
34
|
+
"""UTC epoch of the close approach"""
|
|
35
|
+
|
|
36
|
+
primary_id: str
|
|
37
|
+
"""Satellite ID of the primary body in the close approach"""
|
|
38
|
+
|
|
39
|
+
secondary_id: str
|
|
40
|
+
"""Satellite ID of the secondary body in the close approach"""
|
|
41
|
+
|
|
42
|
+
distance: float
|
|
43
|
+
"""Distance between the two bodies in **_kilometers_**"""
|
|
44
|
+
|
|
45
|
+
class CloseApproachReport:
|
|
46
|
+
"""
|
|
47
|
+
Args:
|
|
48
|
+
start: CA screening start time
|
|
49
|
+
end: CA screening end time
|
|
50
|
+
distance_threshold: Distance threshold for CA screening in **_kilometers_**
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
close_approaches: list[CloseApproach]
|
|
54
|
+
"""List of close approaches found during the screening"""
|
|
55
|
+
|
|
56
|
+
distance_threshold: float
|
|
57
|
+
def __init__(self, start: Epoch, end: Epoch, distance_threshold: float) -> None: ...
|
|
58
|
+
|
|
59
|
+
class HorizonAccess:
|
|
60
|
+
|
|
61
|
+
satellite_id: str
|
|
62
|
+
"""ID of the satellite for which the access is calculated"""
|
|
63
|
+
|
|
64
|
+
observatory_id: str
|
|
65
|
+
"""ID of the observatory for which the access is calculated"""
|
|
66
|
+
|
|
67
|
+
start: HorizonState
|
|
68
|
+
"""State of the satellite at the start of the access period"""
|
|
69
|
+
|
|
70
|
+
end: HorizonState
|
|
71
|
+
"""State of the satellite at the end of the access period"""
|
|
72
|
+
|
|
73
|
+
class HorizonAccessReport:
|
|
74
|
+
"""
|
|
75
|
+
Args:
|
|
76
|
+
start: UTC epoch of the start of the access report
|
|
77
|
+
end: UTC epoch of the end of the access report
|
|
78
|
+
min_elevation: Minimum elevation angle for access in **_degrees_**
|
|
79
|
+
min_duration: Minimum duration of access
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
accesses: list[HorizonAccess]
|
|
83
|
+
"""List of horizon accesses found during the screening"""
|
|
84
|
+
|
|
85
|
+
elevation_threshold: float
|
|
86
|
+
"""Minimum elevation angle for access in **_degrees_**"""
|
|
87
|
+
|
|
88
|
+
start: Epoch
|
|
89
|
+
"""UTC epoch of the start of the access report"""
|
|
90
|
+
|
|
91
|
+
end: Epoch
|
|
92
|
+
"""UTC epoch of the end of the access report"""
|
|
93
|
+
|
|
94
|
+
duration_threshold: TimeSpan
|
|
95
|
+
"""Minimum duration of a valid access"""
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
start: Epoch,
|
|
100
|
+
end: Epoch,
|
|
101
|
+
min_elevation: float,
|
|
102
|
+
min_duration: TimeSpan,
|
|
103
|
+
) -> None: ...
|
keplemon/exceptions.py
ADDED
keplemon/libastrofunc.so
ADDED
|
Binary file
|
keplemon/libdllmain.so
ADDED
|
Binary file
|
keplemon/libelops.so
ADDED
|
Binary file
|
keplemon/libenvconst.so
ADDED
|
Binary file
|
keplemon/libextephem.so
ADDED
|
Binary file
|
keplemon/libobs.so
ADDED
|
Binary file
|
keplemon/libsatstate.so
ADDED
|
Binary file
|
keplemon/libsensor.so
ADDED
|
Binary file
|
keplemon/libsgp4prop.so
ADDED
|
Binary file
|
keplemon/libspvec.so
ADDED
|
Binary file
|
keplemon/libtimefunc.so
ADDED
|
Binary file
|
keplemon/libtle.so
ADDED
|
Binary file
|
keplemon/libvcm.so
ADDED
|
Binary file
|
keplemon/propagation.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from keplemon._keplemon.propagation import ( # type: ignore
|
|
2
|
+
ForceProperties,
|
|
3
|
+
InertialPropagator,
|
|
4
|
+
SGP4Output,
|
|
5
|
+
b_star_to_drag_coefficient,
|
|
6
|
+
drag_coefficient_to_b_star,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ForceProperties",
|
|
11
|
+
"InertialPropagator",
|
|
12
|
+
"SGP4Output",
|
|
13
|
+
"b_star_to_drag_coefficient",
|
|
14
|
+
"drag_coefficient_to_b_star",
|
|
15
|
+
]
|
keplemon/propagation.pyi
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from keplemon.elements import CartesianState, GeodeticPosition, KeplerianElements, KeplerianState, TLE
|
|
7
|
+
from keplemon.time import Epoch
|
|
8
|
+
|
|
9
|
+
class ForceProperties:
|
|
10
|
+
srp_coefficient: float
|
|
11
|
+
drag_coefficient: float
|
|
12
|
+
mass: float
|
|
13
|
+
srp_area: float
|
|
14
|
+
drag_area: float
|
|
15
|
+
mean_motion_dot: float
|
|
16
|
+
mean_motion_dot_dot: float
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
srp_coefficient: float,
|
|
20
|
+
srp_area: float,
|
|
21
|
+
drag_coefficient: float,
|
|
22
|
+
drag_area: float,
|
|
23
|
+
mass: float,
|
|
24
|
+
mean_motion_dot: float,
|
|
25
|
+
mean_motion_dot_dot: float,
|
|
26
|
+
) -> None: ...
|
|
27
|
+
|
|
28
|
+
class InertialPropagator:
|
|
29
|
+
@staticmethod
|
|
30
|
+
def from_tle(tle: TLE) -> InertialPropagator: ...
|
|
31
|
+
|
|
32
|
+
def get_cartesian_state_at_epoch(self, epoch: Epoch) -> Optional[CartesianState]: ...
|
|
33
|
+
def get_keplerian_state_at_epoch(self, epoch: Epoch) -> Optional[KeplerianState]: ...
|
|
34
|
+
|
|
35
|
+
keplerian_state: KeplerianState
|
|
36
|
+
force_properties: ForceProperties
|
|
37
|
+
|
|
38
|
+
class SGP4Output:
|
|
39
|
+
cartesian_state: CartesianState
|
|
40
|
+
mean_elements: KeplerianElements
|
|
41
|
+
osculating_elements: KeplerianElements
|
|
42
|
+
geodetic_position: GeodeticPosition
|
|
43
|
+
|
|
44
|
+
def b_star_to_drag_coefficient(b_star: float) -> float:
|
|
45
|
+
"""Convert B* to drag coefficient."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
def drag_coefficient_to_b_star(drag_coefficient: float) -> float:
|
|
49
|
+
"""Convert drag coefficient to B*."""
|
|
50
|
+
...
|
keplemon/py.typed
ADDED
|
File without changes
|
keplemon/time.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from keplemon._keplemon.time import ( # type: ignore
|
|
2
|
+
TimeSpan,
|
|
3
|
+
TimeComponents,
|
|
4
|
+
Epoch,
|
|
5
|
+
)
|
|
6
|
+
import requests # type: ignore
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from keplemon._keplemon.enums import TimeSystem # type: ignore
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"TimeSpan",
|
|
12
|
+
"TimeComponents",
|
|
13
|
+
"Epoch",
|
|
14
|
+
"request_time_constants_update",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def request_time_constants_update(output_path: str) -> None:
|
|
19
|
+
finals = requests.get("https://maia.usno.navy.mil/ser7/finals.all").text.splitlines()
|
|
20
|
+
|
|
21
|
+
leap_seconds = requests.get("https://maia.usno.navy.mil/ser7/tai-utc.dat").text.splitlines()
|
|
22
|
+
|
|
23
|
+
month_map = {
|
|
24
|
+
"JAN": 1,
|
|
25
|
+
"FEB": 2,
|
|
26
|
+
"MAR": 3,
|
|
27
|
+
"APR": 4,
|
|
28
|
+
"MAY": 5,
|
|
29
|
+
"JUN": 6,
|
|
30
|
+
"JUL": 7,
|
|
31
|
+
"AUG": 8,
|
|
32
|
+
"SEP": 9,
|
|
33
|
+
"OCT": 10,
|
|
34
|
+
"NOV": 11,
|
|
35
|
+
"DEC": 12,
|
|
36
|
+
}
|
|
37
|
+
leap_second_map = {}
|
|
38
|
+
for line in leap_seconds:
|
|
39
|
+
yy = int(line[3:5].strip())
|
|
40
|
+
mm = month_map[line[6:9]]
|
|
41
|
+
dd = int(line[10:12].strip())
|
|
42
|
+
time_comps = TimeComponents(yy, mm, dd, 0, 0, 0)
|
|
43
|
+
current_epoch = Epoch.from_time_components(time_comps, TimeSystem.UTC)
|
|
44
|
+
ds50 = int(current_epoch.days_since_1950)
|
|
45
|
+
leap = float(line[38:48].strip())
|
|
46
|
+
leap_second_map[ds50] = leap
|
|
47
|
+
|
|
48
|
+
time_constant_lines: list[str] = []
|
|
49
|
+
sorted_leap_seconds = sorted(leap_second_map, reverse=True)
|
|
50
|
+
ut1 = 0.0
|
|
51
|
+
prev_ut1_utc = 0.0
|
|
52
|
+
prev_time = 0
|
|
53
|
+
prev_leap = 0.0
|
|
54
|
+
for line in finals:
|
|
55
|
+
|
|
56
|
+
if len(line.strip()) < 68:
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
yy = int(line[0:2].strip())
|
|
60
|
+
mm = int(line[2:4].strip())
|
|
61
|
+
dd = int(line[4:6].strip())
|
|
62
|
+
if yy < 50:
|
|
63
|
+
yyyy = 2000 + yy
|
|
64
|
+
else:
|
|
65
|
+
yyyy = 1900 + yy
|
|
66
|
+
ymd = datetime(yyyy, mm, dd).strftime("%d-%b-%y")
|
|
67
|
+
|
|
68
|
+
time_comps = TimeComponents(yy, mm, dd, 0, 0, 0)
|
|
69
|
+
current_epoch = Epoch.from_time_components(time_comps, TimeSystem.UTC)
|
|
70
|
+
ds50 = int(current_epoch.days_since_1950)
|
|
71
|
+
leap = 0.0
|
|
72
|
+
for leap_ds50 in sorted_leap_seconds:
|
|
73
|
+
if ds50 >= leap_ds50:
|
|
74
|
+
leap = leap_second_map[leap_ds50]
|
|
75
|
+
break
|
|
76
|
+
|
|
77
|
+
ut1 = float(line[58:68].strip())
|
|
78
|
+
if prev_time == 0:
|
|
79
|
+
ut1_r = 0.0
|
|
80
|
+
else:
|
|
81
|
+
ut1_r = (ut1 - prev_ut1_utc) / (ds50 - prev_time)
|
|
82
|
+
ut1_r = (ut1_r - (leap - prev_leap)) * 1e3
|
|
83
|
+
|
|
84
|
+
p_x = float(line[18:27].strip())
|
|
85
|
+
p_y = float(line[37:46].strip())
|
|
86
|
+
|
|
87
|
+
doy = current_epoch.day_of_year
|
|
88
|
+
time_constant_lines.append(
|
|
89
|
+
f" {yy:02d} {doy:03.0f} {ymd} {leap:3.0f} {ut1:8.5f} {ut1_r:6.3f} {p_x:7.4f} {p_y:7.4f}\n"
|
|
90
|
+
)
|
|
91
|
+
prev_time = ds50
|
|
92
|
+
prev_ut1_utc = ut1
|
|
93
|
+
prev_leap = leap
|
|
94
|
+
|
|
95
|
+
with open(output_path, "w") as f:
|
|
96
|
+
f.writelines(time_constant_lines)
|