open-space-toolkit-astrodynamics 17.2.0__py312-none-manylinux2014_x86_64.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.
- open_space_toolkit_astrodynamics-17.2.0.dist-info/METADATA +30 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/RECORD +151 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/WHEEL +5 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/top_level.txt +1 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/zip-safe +1 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/__init__.py +11 -0
- ostk/astrodynamics/__init__.pyi +720 -0
- ostk/astrodynamics/access.pyi +577 -0
- ostk/astrodynamics/conjunction/__init__.pyi +121 -0
- ostk/astrodynamics/conjunction/close_approach.pyi +89 -0
- ostk/astrodynamics/conjunction/message/__init__.pyi +3 -0
- ostk/astrodynamics/conjunction/message/ccsds.pyi +705 -0
- ostk/astrodynamics/converters.py +130 -0
- ostk/astrodynamics/converters.pyi +58 -0
- ostk/astrodynamics/data/__init__.pyi +3 -0
- ostk/astrodynamics/data/provider.pyi +22 -0
- ostk/astrodynamics/dataframe.py +597 -0
- ostk/astrodynamics/display.py +281 -0
- ostk/astrodynamics/dynamics.pyi +311 -0
- ostk/astrodynamics/eclipse.pyi +70 -0
- ostk/astrodynamics/estimator.pyi +268 -0
- ostk/astrodynamics/event_condition.pyi +910 -0
- ostk/astrodynamics/flight/__init__.pyi +626 -0
- ostk/astrodynamics/flight/profile/__init__.pyi +99 -0
- ostk/astrodynamics/flight/profile/model.pyi +179 -0
- ostk/astrodynamics/flight/system.pyi +268 -0
- ostk/astrodynamics/guidance_law.pyi +416 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.17 +0 -0
- ostk/astrodynamics/pytrajectory/__init__.py +1 -0
- ostk/astrodynamics/pytrajectory/__init__.pyi +3 -0
- ostk/astrodynamics/pytrajectory/pystate.py +263 -0
- ostk/astrodynamics/pytrajectory/pystate.pyi +66 -0
- ostk/astrodynamics/solver.pyi +432 -0
- ostk/astrodynamics/test/__init__.py +1 -0
- ostk/astrodynamics/test/access/__init__.py +1 -0
- ostk/astrodynamics/test/access/test_generator.py +319 -0
- ostk/astrodynamics/test/access/test_visibility_criterion.py +201 -0
- ostk/astrodynamics/test/conftest.py +119 -0
- ostk/astrodynamics/test/conjunction/close_approach/__init__.py +0 -0
- ostk/astrodynamics/test/conjunction/close_approach/test_generator.py +228 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
- ostk/astrodynamics/test/conjunction/test_close_approach.py +244 -0
- ostk/astrodynamics/test/data/provider/test_off_nadir.py +58 -0
- ostk/astrodynamics/test/dynamics/__init__.py +1 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
- ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
- ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
- ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
- ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
- ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
- ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
- ostk/astrodynamics/test/dynamics/test_thruster.py +157 -0
- ostk/astrodynamics/test/eclipse/__init__.py +1 -0
- ostk/astrodynamics/test/eclipse/test_generator.py +138 -0
- ostk/astrodynamics/test/estimator/test_orbit_determination_solver.py +261 -0
- ostk/astrodynamics/test/estimator/test_tle_solver.py +216 -0
- ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
- ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
- ostk/astrodynamics/test/event_condition/test_brouwer_lyddane_mean_long_condition.py +135 -0
- ostk/astrodynamics/test/event_condition/test_coe_condition.py +135 -0
- ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
- ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
- ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
- ostk/astrodynamics/test/flight/__init__.py +1 -0
- ostk/astrodynamics/test/flight/profile/model/test_tabulated_profile.py +115 -0
- ostk/astrodynamics/test/flight/system/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/test_propulsion_system.py +64 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system.py +83 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
- ostk/astrodynamics/test/flight/test_maneuver.py +231 -0
- ostk/astrodynamics/test/flight/test_profile.py +293 -0
- ostk/astrodynamics/test/flight/test_system.py +45 -0
- ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +177 -0
- ostk/astrodynamics/test/guidance_law/test_guidance_law.py +60 -0
- ostk/astrodynamics/test/guidance_law/test_heterogeneous_guidance_law.py +164 -0
- ostk/astrodynamics/test/guidance_law/test_qlaw.py +209 -0
- ostk/astrodynamics/test/solvers/__init__.py +1 -0
- ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +196 -0
- ostk/astrodynamics/test/solvers/test_least_squares_solver.py +334 -0
- ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +161 -0
- ostk/astrodynamics/test/test_access.py +128 -0
- ostk/astrodynamics/test/test_converters.py +290 -0
- ostk/astrodynamics/test/test_dataframe.py +1355 -0
- ostk/astrodynamics/test/test_display.py +184 -0
- ostk/astrodynamics/test/test_event_condition.py +80 -0
- ostk/astrodynamics/test/test_import.py +26 -0
- ostk/astrodynamics/test/test_root_solver.py +70 -0
- ostk/astrodynamics/test/test_trajectory.py +126 -0
- ostk/astrodynamics/test/test_utilities.py +338 -0
- ostk/astrodynamics/test/test_viewer.py +318 -0
- ostk/astrodynamics/test/trajectory/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/model/test_nadir_trajectory.py +87 -0
- ostk/astrodynamics/test/trajectory/model/test_tabulated_trajectory.py +303 -0
- ostk/astrodynamics/test/trajectory/model/test_target_scan_trajectory.py +126 -0
- ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
- ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +305 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +337 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_modified_equinoctial.py +142 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
- ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_acceleration.py +136 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +58 -0
- ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +316 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +119 -0
- ostk/astrodynamics/test/trajectory/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/test_orbit.py +212 -0
- ostk/astrodynamics/test/trajectory/test_propagator.py +452 -0
- ostk/astrodynamics/test/trajectory/test_segment.py +694 -0
- ostk/astrodynamics/test/trajectory/test_sequence.py +550 -0
- ostk/astrodynamics/test/trajectory/test_state.py +629 -0
- ostk/astrodynamics/test/trajectory/test_state_builder.py +172 -0
- ostk/astrodynamics/trajectory/__init__.pyi +1982 -0
- ostk/astrodynamics/trajectory/model.pyi +259 -0
- ostk/astrodynamics/trajectory/orbit/__init__.pyi +349 -0
- ostk/astrodynamics/trajectory/orbit/message/__init__.pyi +3 -0
- ostk/astrodynamics/trajectory/orbit/message/spacex.pyi +264 -0
- ostk/astrodynamics/trajectory/orbit/model/__init__.pyi +648 -0
- ostk/astrodynamics/trajectory/orbit/model/brouwerLyddaneMean.pyi +121 -0
- ostk/astrodynamics/trajectory/orbit/model/kepler.pyi +709 -0
- ostk/astrodynamics/trajectory/orbit/model/sgp4.pyi +330 -0
- ostk/astrodynamics/trajectory/state/__init__.pyi +402 -0
- ostk/astrodynamics/trajectory/state/coordinate_subset.pyi +208 -0
- ostk/astrodynamics/utilities.py +396 -0
- ostk/astrodynamics/viewer.py +851 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ostk.mathematics.geometry.d3.object import Cuboid
|
|
8
|
+
from ostk.mathematics.geometry.d3.object import Composite
|
|
9
|
+
from ostk.mathematics.geometry.d3.object import Point
|
|
10
|
+
|
|
11
|
+
from ostk.physics.unit import Mass
|
|
12
|
+
from ostk.physics.time import Instant
|
|
13
|
+
from ostk.physics.time import DateTime
|
|
14
|
+
from ostk.physics.time import Scale
|
|
15
|
+
from ostk.physics.coordinate import Frame
|
|
16
|
+
|
|
17
|
+
from ostk.astrodynamics.trajectory.state import CoordinateSubset
|
|
18
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianPosition
|
|
19
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianVelocity
|
|
20
|
+
from ostk.astrodynamics.trajectory.state import CoordinateBroker
|
|
21
|
+
|
|
22
|
+
from ostk.astrodynamics.trajectory import State
|
|
23
|
+
from ostk.astrodynamics.flight.system import PropulsionSystem
|
|
24
|
+
from ostk.astrodynamics.flight.system import SatelliteSystem
|
|
25
|
+
from ostk.astrodynamics.dynamics import Thruster
|
|
26
|
+
from ostk.astrodynamics.guidance_law import ConstantThrust
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def guidance_law() -> ConstantThrust:
|
|
31
|
+
return ConstantThrust.intrack(True)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def propulsion_system() -> PropulsionSystem:
|
|
36
|
+
return PropulsionSystem(
|
|
37
|
+
1.0,
|
|
38
|
+
150.0,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def satellite_system(propulsion_system: PropulsionSystem) -> SatelliteSystem:
|
|
44
|
+
mass = Mass(100.0, Mass.Unit.Kilogram)
|
|
45
|
+
satellite_geometry = Composite(
|
|
46
|
+
Cuboid(
|
|
47
|
+
Point(0.0, 0.0, 0.0),
|
|
48
|
+
[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
|
49
|
+
[1.0, 0.0, 0.0],
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
inertia_tensor = np.ndarray(shape=(3, 3))
|
|
53
|
+
surface_area = 0.8
|
|
54
|
+
drag_coefficient = 2.1
|
|
55
|
+
|
|
56
|
+
return SatelliteSystem(
|
|
57
|
+
mass,
|
|
58
|
+
satellite_geometry,
|
|
59
|
+
inertia_tensor,
|
|
60
|
+
surface_area,
|
|
61
|
+
drag_coefficient,
|
|
62
|
+
propulsion_system,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@pytest.fixture
|
|
67
|
+
def dynamics(
|
|
68
|
+
satellite_system: SatelliteSystem,
|
|
69
|
+
guidance_law: ConstantThrust,
|
|
70
|
+
) -> Thruster:
|
|
71
|
+
return Thruster(
|
|
72
|
+
satellite_system=satellite_system,
|
|
73
|
+
guidance_law=guidance_law,
|
|
74
|
+
name="Constant Thrust Thruster Dynamics",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.fixture
|
|
79
|
+
def coordinate_broker() -> CoordinateBroker:
|
|
80
|
+
return CoordinateBroker(
|
|
81
|
+
[
|
|
82
|
+
CartesianPosition.default(),
|
|
83
|
+
CartesianVelocity.default(),
|
|
84
|
+
CoordinateSubset.mass(),
|
|
85
|
+
]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.fixture
|
|
90
|
+
def state(coordinate_broker: CoordinateBroker) -> State:
|
|
91
|
+
instant: Instant = Instant.date_time(DateTime(2021, 3, 20, 12, 0, 0), Scale.UTC)
|
|
92
|
+
coordinates: list = [7000000.0, 0.0, 0.0, 0.0, 7546.05329, 0.0, 105.0]
|
|
93
|
+
|
|
94
|
+
return State(instant, coordinates, Frame.GCRF(), coordinate_broker)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestThruster:
|
|
98
|
+
def test_constructors(
|
|
99
|
+
self,
|
|
100
|
+
guidance_law: ConstantThrust,
|
|
101
|
+
satellite_system: SatelliteSystem,
|
|
102
|
+
):
|
|
103
|
+
thrusters = [
|
|
104
|
+
Thruster(
|
|
105
|
+
satellite_system=satellite_system,
|
|
106
|
+
guidance_law=guidance_law,
|
|
107
|
+
),
|
|
108
|
+
Thruster(
|
|
109
|
+
satellite_system=satellite_system,
|
|
110
|
+
guidance_law=guidance_law,
|
|
111
|
+
name="A name",
|
|
112
|
+
),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
for thruster in thrusters:
|
|
116
|
+
assert thruster is not None
|
|
117
|
+
assert isinstance(thruster, Thruster)
|
|
118
|
+
assert thruster.is_defined()
|
|
119
|
+
|
|
120
|
+
def test_getters(self, dynamics: Thruster):
|
|
121
|
+
assert dynamics.get_satellite_system() is not None
|
|
122
|
+
assert dynamics.get_guidance_law() is not None
|
|
123
|
+
assert dynamics.get_read_coordinate_subsets() is not None
|
|
124
|
+
assert dynamics.get_write_coordinate_subsets() is not None
|
|
125
|
+
|
|
126
|
+
def test_compute_contribution_success(self, dynamics: Thruster, state: State):
|
|
127
|
+
contribution = dynamics.compute_contribution(
|
|
128
|
+
state.get_instant(), state.get_coordinates(), state.get_frame()
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
assert len(contribution) == 4
|
|
132
|
+
assert contribution == pytest.approx(
|
|
133
|
+
[0.0, 0.009523809523809525, 0.0, -0.0006798108086519521], abs=5e-11
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def test_compute_contribution_failure_out_of_fuel(
|
|
137
|
+
self,
|
|
138
|
+
satellite_system: SatelliteSystem,
|
|
139
|
+
coordinate_broker: CoordinateBroker,
|
|
140
|
+
dynamics: Thruster,
|
|
141
|
+
):
|
|
142
|
+
instant: Instant = Instant.date_time(DateTime(2021, 3, 20, 12, 0, 0), Scale.UTC)
|
|
143
|
+
coordinates: list = [
|
|
144
|
+
7000000.0,
|
|
145
|
+
0.0,
|
|
146
|
+
0.0,
|
|
147
|
+
0.0,
|
|
148
|
+
7546.05329,
|
|
149
|
+
0.0,
|
|
150
|
+
satellite_system.get_mass().in_kilograms(),
|
|
151
|
+
]
|
|
152
|
+
state = State(instant, coordinates, Frame.GCRF(), coordinate_broker)
|
|
153
|
+
|
|
154
|
+
with pytest.raises(RuntimeError):
|
|
155
|
+
contribution = dynamics.compute_contribution(
|
|
156
|
+
state.get_instant(), state.get_coordinates(), state.get_frame()
|
|
157
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.unit import Length
|
|
6
|
+
from ostk.physics.unit import Angle
|
|
7
|
+
from ostk.physics.time import DateTime
|
|
8
|
+
from ostk.physics.time import Scale
|
|
9
|
+
from ostk.physics.time import Duration
|
|
10
|
+
from ostk.physics.time import Instant
|
|
11
|
+
from ostk.physics.time import Interval
|
|
12
|
+
from ostk.physics import Environment
|
|
13
|
+
from ostk.physics.environment.object import Celestial
|
|
14
|
+
from ostk.physics.environment.utility import Eclipse
|
|
15
|
+
from ostk.physics.environment.utility import EclipsePhase
|
|
16
|
+
|
|
17
|
+
from ostk.astrodynamics import Trajectory
|
|
18
|
+
from ostk.astrodynamics.trajectory import Orbit
|
|
19
|
+
from ostk.astrodynamics.trajectory.orbit.model import Kepler
|
|
20
|
+
from ostk.astrodynamics.trajectory.orbit.model.kepler import COE
|
|
21
|
+
from ostk.astrodynamics.eclipse import Generator
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def environment() -> Environment:
|
|
26
|
+
return Environment.default()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def earth(environment: Environment) -> Celestial:
|
|
31
|
+
return environment.access_celestial_object_with_name("Earth")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def search_step_size() -> Duration:
|
|
36
|
+
return Duration.seconds(30.0)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@pytest.fixture
|
|
40
|
+
def search_tolerance() -> Duration:
|
|
41
|
+
return Duration.milliseconds(10.0)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def generator(
|
|
46
|
+
environment: Environment,
|
|
47
|
+
search_step_size: Duration,
|
|
48
|
+
search_tolerance: Duration,
|
|
49
|
+
) -> Generator:
|
|
50
|
+
return Generator(
|
|
51
|
+
environment=environment,
|
|
52
|
+
search_step_size=search_step_size,
|
|
53
|
+
search_tolerance=search_tolerance,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.fixture
|
|
58
|
+
def trajectory(earth: Celestial) -> Trajectory:
|
|
59
|
+
return Orbit(
|
|
60
|
+
model=Kepler(
|
|
61
|
+
coe=COE(
|
|
62
|
+
semi_major_axis=Length.kilometers(6700.0),
|
|
63
|
+
eccentricity=0.0,
|
|
64
|
+
inclination=Angle.degrees(0.0),
|
|
65
|
+
raan=Angle.degrees(0.0),
|
|
66
|
+
aop=Angle.degrees(0.0),
|
|
67
|
+
true_anomaly=Angle.degrees(0.0),
|
|
68
|
+
),
|
|
69
|
+
epoch=Instant.date_time(DateTime(2000, 1, 1, 0, 0, 0), Scale.UTC),
|
|
70
|
+
celestial_object=earth,
|
|
71
|
+
perturbation_type=Kepler.PerturbationType.No,
|
|
72
|
+
),
|
|
73
|
+
celestial_object=earth,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def analysis_interval() -> Interval:
|
|
79
|
+
return Interval.closed(
|
|
80
|
+
Instant.date_time(DateTime(2000, 1, 1, 14, 0, 0), Scale.UTC),
|
|
81
|
+
Instant.date_time(DateTime(2000, 1, 1, 17, 0, 0), Scale.UTC),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class TestGenerator:
|
|
86
|
+
def test_constructor_and_properties_success(
|
|
87
|
+
self,
|
|
88
|
+
environment: Environment,
|
|
89
|
+
search_step_size: Duration,
|
|
90
|
+
search_tolerance: Duration,
|
|
91
|
+
):
|
|
92
|
+
generator: Generator = Generator(
|
|
93
|
+
environment=environment,
|
|
94
|
+
search_step_size=search_step_size,
|
|
95
|
+
search_tolerance=search_tolerance,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
assert generator is not None
|
|
99
|
+
assert isinstance(generator, Generator)
|
|
100
|
+
assert generator.is_defined() is True
|
|
101
|
+
assert generator.get_environment().is_defined()
|
|
102
|
+
assert generator.get_search_step_size() == search_step_size
|
|
103
|
+
assert generator.get_search_tolerance() == search_tolerance
|
|
104
|
+
|
|
105
|
+
def test_default_constructor_and_properties_success(self):
|
|
106
|
+
generator: Generator = Generator()
|
|
107
|
+
assert generator is not None
|
|
108
|
+
assert isinstance(generator, Generator)
|
|
109
|
+
assert generator.is_defined() is True
|
|
110
|
+
|
|
111
|
+
def test_generate_success(
|
|
112
|
+
self,
|
|
113
|
+
generator: Generator,
|
|
114
|
+
trajectory: Trajectory,
|
|
115
|
+
analysis_interval: Interval,
|
|
116
|
+
):
|
|
117
|
+
eclipses: list[Eclipse] = generator.generate(
|
|
118
|
+
trajectory=trajectory,
|
|
119
|
+
analysis_interval=analysis_interval,
|
|
120
|
+
occulted_celestial_object_name="Sun",
|
|
121
|
+
occulting_celestial_object_name="Earth",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
assert eclipses is not None
|
|
125
|
+
assert isinstance(eclipses, list)
|
|
126
|
+
assert len(eclipses) > 0
|
|
127
|
+
|
|
128
|
+
# Check that all returned objects are Eclipse instances
|
|
129
|
+
for eclipse in eclipses:
|
|
130
|
+
assert isinstance(eclipse, Eclipse)
|
|
131
|
+
|
|
132
|
+
# Check eclipse phases
|
|
133
|
+
phases: list[EclipsePhase] = eclipse.get_phases()
|
|
134
|
+
assert isinstance(phases, list)
|
|
135
|
+
assert len(phases) > 0
|
|
136
|
+
|
|
137
|
+
for phase in phases:
|
|
138
|
+
assert isinstance(phase, EclipsePhase)
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from ostk.physics import Environment
|
|
10
|
+
from ostk.physics.time import Instant
|
|
11
|
+
from ostk.physics.coordinate import Frame
|
|
12
|
+
from ostk.physics.environment.object.celestial import Earth
|
|
13
|
+
|
|
14
|
+
from ostk.astrodynamics.solver import LeastSquaresSolver
|
|
15
|
+
from ostk.astrodynamics.trajectory import State
|
|
16
|
+
from ostk.astrodynamics.trajectory import Orbit
|
|
17
|
+
from ostk.astrodynamics.trajectory import Propagator
|
|
18
|
+
from ostk.astrodynamics.trajectory.state import NumericalSolver
|
|
19
|
+
from ostk.astrodynamics.trajectory.state import CoordinateSubset
|
|
20
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianPosition
|
|
21
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianVelocity
|
|
22
|
+
from ostk.astrodynamics.estimator import OrbitDeterminationSolver
|
|
23
|
+
from ostk.astrodynamics.dataframe import generate_states_from_dataframe
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def environment() -> Environment:
|
|
28
|
+
return Environment(central_celestial_object=Earth.EGM96(10, 10), objects=[])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def numerical_solver() -> NumericalSolver:
|
|
33
|
+
return NumericalSolver.default()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def least_squares_solver() -> LeastSquaresSolver:
|
|
38
|
+
return LeastSquaresSolver.default()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def orbit_determination_solver(
|
|
43
|
+
environment: Environment,
|
|
44
|
+
numerical_solver: NumericalSolver,
|
|
45
|
+
least_squares_solver: LeastSquaresSolver,
|
|
46
|
+
) -> OrbitDeterminationSolver:
|
|
47
|
+
return OrbitDeterminationSolver(
|
|
48
|
+
environment=environment,
|
|
49
|
+
numerical_solver=numerical_solver,
|
|
50
|
+
solver=least_squares_solver,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def coordinate_subsets() -> list[CoordinateSubset]:
|
|
56
|
+
return [
|
|
57
|
+
CartesianPosition.default(),
|
|
58
|
+
CartesianVelocity.default(),
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture
|
|
63
|
+
def initial_guess(
|
|
64
|
+
observations: list[State],
|
|
65
|
+
) -> State:
|
|
66
|
+
return observations[0]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.fixture
|
|
70
|
+
def observations() -> list[State]:
|
|
71
|
+
return generate_states_from_dataframe(
|
|
72
|
+
pd.read_csv(
|
|
73
|
+
"/app/test/OpenSpaceToolkit/Astrodynamics/Estimator/OrbitDeterminationSolverData/gnss_data.csv"
|
|
74
|
+
),
|
|
75
|
+
reference_frame=Frame.ITRF(),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.fixture
|
|
80
|
+
def initial_guess_sigmas(
|
|
81
|
+
coordinate_subsets: list[CoordinateSubset],
|
|
82
|
+
) -> dict[CoordinateSubset, list[float]]:
|
|
83
|
+
return {
|
|
84
|
+
coordinate_subsets[0]: [1e-1, 1e-1, 1e-1],
|
|
85
|
+
coordinate_subsets[1]: [1e-2, 1e-2, 1e-2],
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.fixture
|
|
90
|
+
def observation_sigmas(
|
|
91
|
+
coordinate_subsets: list[CoordinateSubset],
|
|
92
|
+
) -> dict[CoordinateSubset, list[float]]:
|
|
93
|
+
return {
|
|
94
|
+
coordinate_subsets[0]: [1e-1, 1e-1, 1e-1],
|
|
95
|
+
coordinate_subsets[1]: [1e-2, 1e-2, 1e-2],
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@pytest.fixture
|
|
100
|
+
def rms_error() -> float:
|
|
101
|
+
return 1.0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@pytest.fixture
|
|
105
|
+
def x_hat() -> np.ndarray:
|
|
106
|
+
return np.array([1.0, 0.0])
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@pytest.fixture
|
|
110
|
+
def step(
|
|
111
|
+
rms_error: float,
|
|
112
|
+
x_hat: np.ndarray,
|
|
113
|
+
) -> LeastSquaresSolver.Step:
|
|
114
|
+
return LeastSquaresSolver.Step(
|
|
115
|
+
rms_error=rms_error,
|
|
116
|
+
x_hat=x_hat,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.fixture
|
|
121
|
+
def observation_count() -> int:
|
|
122
|
+
return 5
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@pytest.fixture
|
|
126
|
+
def termination_criteria() -> str:
|
|
127
|
+
return "RMS Update Threshold"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@pytest.fixture
|
|
131
|
+
def estimated_state() -> State:
|
|
132
|
+
return State(
|
|
133
|
+
Instant.J2000(),
|
|
134
|
+
[1.0, 0.0],
|
|
135
|
+
Frame.GCRF(),
|
|
136
|
+
[CoordinateSubset("Position", 1), CoordinateSubset("Velocity", 1)],
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@pytest.fixture
|
|
141
|
+
def estimated_covariance() -> np.ndarray:
|
|
142
|
+
return np.array([[1.0, 0.0], [0.0, 1.0]])
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@pytest.fixture
|
|
146
|
+
def estimated_frisbee_covariance() -> np.ndarray:
|
|
147
|
+
return np.array([[1.0, 0.0], [0.0, 1.0]])
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@pytest.fixture
|
|
151
|
+
def computed_observations(
|
|
152
|
+
observations: list[State],
|
|
153
|
+
) -> list[State]:
|
|
154
|
+
return observations
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@pytest.fixture
|
|
158
|
+
def steps(step: LeastSquaresSolver.Step) -> list[LeastSquaresSolver.Step]:
|
|
159
|
+
return [step]
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@pytest.fixture
|
|
163
|
+
def solver_analysis(
|
|
164
|
+
termination_criteria: str,
|
|
165
|
+
estimated_state: State,
|
|
166
|
+
estimated_covariance: np.ndarray,
|
|
167
|
+
estimated_frisbee_covariance: np.ndarray,
|
|
168
|
+
computed_observations: list[State],
|
|
169
|
+
steps: list[LeastSquaresSolver.Step],
|
|
170
|
+
) -> LeastSquaresSolver.Analysis:
|
|
171
|
+
return LeastSquaresSolver.Analysis(
|
|
172
|
+
termination_criteria=termination_criteria,
|
|
173
|
+
estimated_state=estimated_state,
|
|
174
|
+
estimated_covariance=estimated_covariance,
|
|
175
|
+
estimated_frisbee_covariance=estimated_frisbee_covariance,
|
|
176
|
+
computed_observations=computed_observations,
|
|
177
|
+
steps=steps,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@pytest.fixture
|
|
182
|
+
def analysis(
|
|
183
|
+
initial_guess: State,
|
|
184
|
+
solver_analysis: LeastSquaresSolver.Analysis,
|
|
185
|
+
) -> OrbitDeterminationSolver.Analysis:
|
|
186
|
+
return OrbitDeterminationSolver.Analysis(
|
|
187
|
+
estimated_state=initial_guess,
|
|
188
|
+
solver_analysis=solver_analysis,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class TestOrbitDeterminationSolverAnalysis:
|
|
193
|
+
def test_constructor(
|
|
194
|
+
self,
|
|
195
|
+
analysis: OrbitDeterminationSolver.Analysis,
|
|
196
|
+
):
|
|
197
|
+
assert isinstance(analysis, OrbitDeterminationSolver.Analysis)
|
|
198
|
+
|
|
199
|
+
def test_properties(
|
|
200
|
+
self,
|
|
201
|
+
analysis: OrbitDeterminationSolver.Analysis,
|
|
202
|
+
):
|
|
203
|
+
assert isinstance(analysis.estimated_state, State)
|
|
204
|
+
assert isinstance(analysis.solver_analysis, LeastSquaresSolver.Analysis)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class TestOrbitDeterminationSolver:
|
|
208
|
+
def test_constructor(
|
|
209
|
+
self,
|
|
210
|
+
orbit_determination_solver: OrbitDeterminationSolver,
|
|
211
|
+
):
|
|
212
|
+
assert isinstance(orbit_determination_solver, OrbitDeterminationSolver)
|
|
213
|
+
|
|
214
|
+
def test_access_methods(
|
|
215
|
+
self,
|
|
216
|
+
orbit_determination_solver: OrbitDeterminationSolver,
|
|
217
|
+
):
|
|
218
|
+
assert isinstance(orbit_determination_solver.access_environment(), Environment)
|
|
219
|
+
assert isinstance(orbit_determination_solver.access_propagator(), Propagator)
|
|
220
|
+
assert isinstance(orbit_determination_solver.access_solver(), LeastSquaresSolver)
|
|
221
|
+
assert isinstance(orbit_determination_solver.access_estimation_frame(), Frame)
|
|
222
|
+
|
|
223
|
+
def test_estimate(
|
|
224
|
+
self,
|
|
225
|
+
orbit_determination_solver: OrbitDeterminationSolver,
|
|
226
|
+
initial_guess: State,
|
|
227
|
+
observations: list[State],
|
|
228
|
+
coordinate_subsets: list[CoordinateSubset],
|
|
229
|
+
initial_guess_sigmas: dict[CoordinateSubset, list[float]],
|
|
230
|
+
observation_sigmas: dict[CoordinateSubset, list[float]],
|
|
231
|
+
):
|
|
232
|
+
analysis: OrbitDeterminationSolver.Analysis = orbit_determination_solver.estimate(
|
|
233
|
+
initial_guess=initial_guess,
|
|
234
|
+
observations=observations,
|
|
235
|
+
estimation_coordinate_subsets=coordinate_subsets,
|
|
236
|
+
initial_guess_sigmas=initial_guess_sigmas,
|
|
237
|
+
observation_sigmas=observation_sigmas,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
assert isinstance(analysis, OrbitDeterminationSolver.Analysis)
|
|
241
|
+
assert isinstance(analysis.estimated_state, State)
|
|
242
|
+
assert isinstance(analysis.solver_analysis, LeastSquaresSolver.Analysis)
|
|
243
|
+
|
|
244
|
+
def test_estimate_orbit(
|
|
245
|
+
self,
|
|
246
|
+
orbit_determination_solver: OrbitDeterminationSolver,
|
|
247
|
+
initial_guess: State,
|
|
248
|
+
observations: list[State],
|
|
249
|
+
coordinate_subsets: list[CoordinateSubset],
|
|
250
|
+
initial_guess_sigmas: dict[CoordinateSubset, list[float]],
|
|
251
|
+
observation_sigmas: dict[CoordinateSubset, list[float]],
|
|
252
|
+
):
|
|
253
|
+
orbit: Orbit = orbit_determination_solver.estimate_orbit(
|
|
254
|
+
initial_guess=initial_guess,
|
|
255
|
+
observations=observations,
|
|
256
|
+
estimation_coordinate_subsets=coordinate_subsets,
|
|
257
|
+
initial_guess_sigmas=initial_guess_sigmas,
|
|
258
|
+
observation_sigmas=observation_sigmas,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
assert isinstance(orbit, Orbit)
|