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,177 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ostk.physics.time import DateTime
|
|
8
|
+
from ostk.physics.time import Duration
|
|
9
|
+
from ostk.physics.time import Instant
|
|
10
|
+
from ostk.physics.time import Scale
|
|
11
|
+
from ostk.physics.unit import Angle
|
|
12
|
+
from ostk.physics.coordinate import Frame
|
|
13
|
+
|
|
14
|
+
from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
|
|
15
|
+
from ostk.astrodynamics.trajectory import LocalOrbitalFrameDirection
|
|
16
|
+
|
|
17
|
+
from ostk.astrodynamics import GuidanceLaw
|
|
18
|
+
from ostk.astrodynamics.flight import Maneuver
|
|
19
|
+
from ostk.astrodynamics.guidance_law import ConstantThrust
|
|
20
|
+
from ostk.astrodynamics.trajectory import State
|
|
21
|
+
from ostk.astrodynamics.trajectory.state import CoordinateSubset
|
|
22
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianPosition
|
|
23
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianVelocity
|
|
24
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianAcceleration
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def local_orbital_frame_direction() -> LocalOrbitalFrameDirection:
|
|
29
|
+
return LocalOrbitalFrameDirection(
|
|
30
|
+
vector=[1.0, 0.0, 0.0],
|
|
31
|
+
local_orbital_frame_factory=LocalOrbitalFrameFactory.VNC(Frame.GCRF()),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def guidance_law(
|
|
37
|
+
local_orbital_frame_direction: LocalOrbitalFrameDirection,
|
|
38
|
+
) -> ConstantThrust:
|
|
39
|
+
return ConstantThrust(thrust_direction=local_orbital_frame_direction)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def instant() -> Instant:
|
|
44
|
+
return Instant.date_time(DateTime(2021, 3, 20, 12, 0, 0), Scale.UTC)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.fixture
|
|
48
|
+
def position_coordinates() -> list[float]:
|
|
49
|
+
return [7000000.0, 0.0, 0.0]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture
|
|
53
|
+
def velocity_coordinates() -> list[float]:
|
|
54
|
+
return [0.0, 7546.05329, 0.0]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.fixture
|
|
58
|
+
def thrust_acceleration() -> float:
|
|
59
|
+
return 1.0 / 105.0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture
|
|
63
|
+
def frame() -> Frame:
|
|
64
|
+
return Frame.GCRF()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.fixture
|
|
68
|
+
def instants() -> list[Instant]:
|
|
69
|
+
return [
|
|
70
|
+
Instant.J2000(),
|
|
71
|
+
Instant.J2000() + Duration.seconds(30.0),
|
|
72
|
+
Instant.J2000() + Duration.seconds(35.0),
|
|
73
|
+
Instant.J2000() + Duration.seconds(37.0),
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def acceleration_profile() -> list[np.ndarray]:
|
|
79
|
+
return [
|
|
80
|
+
np.array([1.0e-3, 0.0e-3, 0.0e-3]),
|
|
81
|
+
np.array([0.0e-3, 1.0e-3, 0.0e-3]),
|
|
82
|
+
np.array([0.0e-3, 0.0e-3, 1.0e-3]),
|
|
83
|
+
np.array([1.0e-3, 1.0e-3, 1.0e-3]),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pytest.fixture
|
|
88
|
+
def mass_flow_rate_profile() -> list[float]:
|
|
89
|
+
return [-1.0e-5, -1.1e-5, -0.9e-5, -1.0e-5]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@pytest.fixture
|
|
93
|
+
def coordinate_subsets() -> list[CoordinateSubset]:
|
|
94
|
+
return [
|
|
95
|
+
CartesianPosition.default(),
|
|
96
|
+
CartesianVelocity.default(),
|
|
97
|
+
CartesianAcceleration.thrust_acceleration(),
|
|
98
|
+
CoordinateSubset.mass_flow_rate(),
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@pytest.fixture
|
|
103
|
+
def maneuver(
|
|
104
|
+
instants: list[Instant],
|
|
105
|
+
acceleration_profile: list[np.ndarray],
|
|
106
|
+
mass_flow_rate_profile: list[float],
|
|
107
|
+
frame: Frame,
|
|
108
|
+
coordinate_subsets: list[CoordinateSubset],
|
|
109
|
+
) -> Maneuver:
|
|
110
|
+
states = []
|
|
111
|
+
for instant, acceleration, mass_flow_rate in zip(
|
|
112
|
+
instants, acceleration_profile, mass_flow_rate_profile
|
|
113
|
+
):
|
|
114
|
+
states.append(
|
|
115
|
+
State(
|
|
116
|
+
instant,
|
|
117
|
+
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, *acceleration, mass_flow_rate],
|
|
118
|
+
frame,
|
|
119
|
+
coordinate_subsets,
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
return Maneuver(states)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestConstantThrust:
|
|
126
|
+
def test_constructors(self, guidance_law: ConstantThrust):
|
|
127
|
+
assert guidance_law is not None
|
|
128
|
+
assert isinstance(guidance_law, ConstantThrust)
|
|
129
|
+
assert isinstance(guidance_law, GuidanceLaw)
|
|
130
|
+
|
|
131
|
+
def test_getters(self, guidance_law: ConstantThrust):
|
|
132
|
+
assert guidance_law.get_local_thrust_direction() is not None
|
|
133
|
+
|
|
134
|
+
def test_static_constructors(self):
|
|
135
|
+
assert ConstantThrust.intrack() is not None
|
|
136
|
+
|
|
137
|
+
assert ConstantThrust.intrack(velocity_direction=False) is not None
|
|
138
|
+
|
|
139
|
+
assert ConstantThrust.intrack(velocity_direction=True) is not None
|
|
140
|
+
|
|
141
|
+
def test_compute_acceleration_success(
|
|
142
|
+
self,
|
|
143
|
+
guidance_law: ConstantThrust,
|
|
144
|
+
instant: Instant,
|
|
145
|
+
position_coordinates: list[float],
|
|
146
|
+
velocity_coordinates: list[float],
|
|
147
|
+
thrust_acceleration: float,
|
|
148
|
+
frame: Frame,
|
|
149
|
+
):
|
|
150
|
+
contribution = guidance_law.calculate_thrust_acceleration_at(
|
|
151
|
+
instant=instant,
|
|
152
|
+
position_coordinates=position_coordinates,
|
|
153
|
+
velocity_coordinates=velocity_coordinates,
|
|
154
|
+
thrust_acceleration=thrust_acceleration,
|
|
155
|
+
output_frame=frame,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
assert len(contribution) == 3
|
|
159
|
+
assert contribution == pytest.approx([0.0, 0.009523809523809525, 0.0], abs=5e-11)
|
|
160
|
+
|
|
161
|
+
def test_from_maneuver(self, maneuver: Maneuver):
|
|
162
|
+
constant_thrust = ConstantThrust.from_maneuver(
|
|
163
|
+
maneuver=maneuver,
|
|
164
|
+
local_orbital_frame_factory=LocalOrbitalFrameFactory.TNW(Frame.GCRF()),
|
|
165
|
+
)
|
|
166
|
+
assert isinstance(constant_thrust, ConstantThrust)
|
|
167
|
+
|
|
168
|
+
constant_thrust_with_maximum_allowed_angular_offset = (
|
|
169
|
+
ConstantThrust.from_maneuver(
|
|
170
|
+
maneuver=maneuver,
|
|
171
|
+
local_orbital_frame_factory=LocalOrbitalFrameFactory.TNW(Frame.GCRF()),
|
|
172
|
+
maximum_allowed_angular_offset=Angle.degrees(180.0),
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
assert isinstance(
|
|
176
|
+
constant_thrust_with_maximum_allowed_angular_offset, ConstantThrust
|
|
177
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from ostk.physics.time import Instant
|
|
8
|
+
from ostk.physics.coordinate import Frame
|
|
9
|
+
from ostk.astrodynamics import GuidanceLaw
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def guidance_law() -> GuidanceLaw:
|
|
14
|
+
class MyGuidanceLaw(GuidanceLaw):
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
name: str,
|
|
19
|
+
):
|
|
20
|
+
super().__init__(name)
|
|
21
|
+
|
|
22
|
+
def calculate_thrust_acceleration_at(
|
|
23
|
+
self,
|
|
24
|
+
instant: Instant,
|
|
25
|
+
position_coordinates: np.array,
|
|
26
|
+
velocity_coordinates: np.array,
|
|
27
|
+
thrust_acceleration: float,
|
|
28
|
+
output_frame: Frame,
|
|
29
|
+
) -> np.array:
|
|
30
|
+
return np.array([0.0, 0.0, 0.0])
|
|
31
|
+
|
|
32
|
+
return MyGuidanceLaw("My Guidance Law")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestGuidanceLaw:
|
|
36
|
+
def test_subclass(
|
|
37
|
+
self,
|
|
38
|
+
guidance_law: GuidanceLaw,
|
|
39
|
+
):
|
|
40
|
+
assert isinstance(guidance_law, GuidanceLaw)
|
|
41
|
+
|
|
42
|
+
def test_get_name(
|
|
43
|
+
self,
|
|
44
|
+
guidance_law: GuidanceLaw,
|
|
45
|
+
):
|
|
46
|
+
assert guidance_law.get_name() == "My Guidance Law"
|
|
47
|
+
|
|
48
|
+
def test_calculate_thrust_acceleration_at(
|
|
49
|
+
self,
|
|
50
|
+
guidance_law: GuidanceLaw,
|
|
51
|
+
):
|
|
52
|
+
thrust_acceleration: np.array = guidance_law.calculate_thrust_acceleration_at(
|
|
53
|
+
instant=Instant.J2000(),
|
|
54
|
+
position_coordinates=np.array([0.0, 0.0, 0.0]),
|
|
55
|
+
velocity_coordinates=np.array([0.0, 0.0, 0.0]),
|
|
56
|
+
thrust_acceleration=1.0,
|
|
57
|
+
output_frame=Frame.GCRF(),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
assert np.array_equal(thrust_acceleration, np.array([0.0, 0.0, 0.0]))
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from ostk.physics.coordinate import Frame
|
|
8
|
+
from ostk.physics.time import Instant
|
|
9
|
+
from ostk.physics.time import Duration
|
|
10
|
+
from ostk.physics.time import Interval
|
|
11
|
+
from ostk.astrodynamics import GuidanceLaw
|
|
12
|
+
from ostk.astrodynamics.guidance_law import HeterogeneousGuidanceLaw
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def interval_1() -> Interval:
|
|
17
|
+
return Interval.closed(
|
|
18
|
+
start_instant=Instant.J2000(),
|
|
19
|
+
end_instant=Instant.J2000() + Duration.seconds(100.0),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def guidance_law_1() -> GuidanceLaw:
|
|
25
|
+
class GuidanceLaw1(GuidanceLaw):
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
name: str,
|
|
30
|
+
):
|
|
31
|
+
super().__init__(name)
|
|
32
|
+
|
|
33
|
+
def calculate_thrust_acceleration_at(
|
|
34
|
+
self,
|
|
35
|
+
instant: Instant,
|
|
36
|
+
position_coordinates: np.array,
|
|
37
|
+
velocity_coordinates: np.array,
|
|
38
|
+
thrust_acceleration: float,
|
|
39
|
+
output_frame: Frame,
|
|
40
|
+
) -> np.array:
|
|
41
|
+
return np.array([1.0, 2.0, 3.0])
|
|
42
|
+
|
|
43
|
+
return GuidanceLaw1("My Guidance Law 1")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.fixture
|
|
47
|
+
def interval_2() -> Interval:
|
|
48
|
+
return Interval.closed(
|
|
49
|
+
start_instant=Instant.J2000() + Duration.seconds(200.0),
|
|
50
|
+
end_instant=Instant.J2000() + Duration.seconds(300.0),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def guidance_law_2() -> GuidanceLaw:
|
|
56
|
+
class GuidanceLaw2(GuidanceLaw):
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
name: str,
|
|
61
|
+
):
|
|
62
|
+
super().__init__(name)
|
|
63
|
+
|
|
64
|
+
def calculate_thrust_acceleration_at(
|
|
65
|
+
self,
|
|
66
|
+
instant: Instant,
|
|
67
|
+
position_coordinates: np.array,
|
|
68
|
+
velocity_coordinates: np.array,
|
|
69
|
+
thrust_acceleration: float,
|
|
70
|
+
output_frame: Frame,
|
|
71
|
+
) -> np.array:
|
|
72
|
+
return np.array([4.0, 5.0, 6.0])
|
|
73
|
+
|
|
74
|
+
return GuidanceLaw2("My Guidance Law 2")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def heterogeneous_guidance_law(
|
|
79
|
+
interval_1: Interval,
|
|
80
|
+
guidance_law_1: GuidanceLaw,
|
|
81
|
+
interval_2: Interval,
|
|
82
|
+
guidance_law_2: GuidanceLaw,
|
|
83
|
+
) -> HeterogeneousGuidanceLaw:
|
|
84
|
+
return HeterogeneousGuidanceLaw(
|
|
85
|
+
guidance_laws_with_intervals=[
|
|
86
|
+
(guidance_law_1, interval_1),
|
|
87
|
+
(guidance_law_2, interval_2),
|
|
88
|
+
],
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TestHeterogeneousGuidanceLaw:
|
|
93
|
+
def test_constructor_and_getters(
|
|
94
|
+
self,
|
|
95
|
+
interval_1: Interval,
|
|
96
|
+
guidance_law_1: GuidanceLaw,
|
|
97
|
+
interval_2: Interval,
|
|
98
|
+
guidance_law_2: GuidanceLaw,
|
|
99
|
+
):
|
|
100
|
+
heterogeneous_guidance_law = HeterogeneousGuidanceLaw(
|
|
101
|
+
guidance_laws_with_intervals=[
|
|
102
|
+
(guidance_law_1, interval_1),
|
|
103
|
+
(guidance_law_2, interval_2),
|
|
104
|
+
],
|
|
105
|
+
)
|
|
106
|
+
assert heterogeneous_guidance_law is not None
|
|
107
|
+
assert isinstance(heterogeneous_guidance_law, HeterogeneousGuidanceLaw)
|
|
108
|
+
assert heterogeneous_guidance_law.get_guidance_laws_with_intervals() == [
|
|
109
|
+
(guidance_law_1, interval_1),
|
|
110
|
+
(guidance_law_2, interval_2),
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
def test_add_guidance_law(
|
|
114
|
+
self,
|
|
115
|
+
interval_1: Interval,
|
|
116
|
+
guidance_law_1: GuidanceLaw,
|
|
117
|
+
interval_2: Interval,
|
|
118
|
+
guidance_law_2: GuidanceLaw,
|
|
119
|
+
):
|
|
120
|
+
heterogeneous_guidance_law = HeterogeneousGuidanceLaw()
|
|
121
|
+
|
|
122
|
+
assert isinstance(heterogeneous_guidance_law, HeterogeneousGuidanceLaw)
|
|
123
|
+
assert heterogeneous_guidance_law.get_guidance_laws_with_intervals() == []
|
|
124
|
+
|
|
125
|
+
heterogeneous_guidance_law.add_guidance_law(guidance_law_1, interval_1)
|
|
126
|
+
assert heterogeneous_guidance_law.get_guidance_laws_with_intervals() == [
|
|
127
|
+
(guidance_law_1, interval_1),
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
heterogeneous_guidance_law.add_guidance_law(guidance_law_2, interval_2)
|
|
131
|
+
assert heterogeneous_guidance_law.get_guidance_laws_with_intervals() == [
|
|
132
|
+
(guidance_law_1, interval_1),
|
|
133
|
+
(guidance_law_2, interval_2),
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
@pytest.mark.parametrize(
|
|
137
|
+
(
|
|
138
|
+
"instant",
|
|
139
|
+
"expected_thrust_acceleration",
|
|
140
|
+
),
|
|
141
|
+
[
|
|
142
|
+
(Instant.J2000() - Duration.seconds(50.0), np.array([0.0, 0.0, 0.0])),
|
|
143
|
+
(Instant.J2000() + Duration.seconds(50.0), np.array([1.0, 2.0, 3.0])),
|
|
144
|
+
(Instant.J2000() + Duration.seconds(150.0), np.array([0.0, 0.0, 0.0])),
|
|
145
|
+
(Instant.J2000() + Duration.seconds(250.0), np.array([4.0, 5.0, 6.0])),
|
|
146
|
+
(Instant.J2000() + Duration.seconds(350.0), np.array([0.0, 0.0, 0.0])),
|
|
147
|
+
],
|
|
148
|
+
)
|
|
149
|
+
def test_calculate_thrust_acceleration_at(
|
|
150
|
+
self,
|
|
151
|
+
heterogeneous_guidance_law: HeterogeneousGuidanceLaw,
|
|
152
|
+
instant: Instant,
|
|
153
|
+
expected_thrust_acceleration: np.array,
|
|
154
|
+
):
|
|
155
|
+
assert np.array_equal(
|
|
156
|
+
heterogeneous_guidance_law.calculate_thrust_acceleration_at(
|
|
157
|
+
instant=instant,
|
|
158
|
+
position_coordinates=np.array([0.0, 0.0, 0.0]),
|
|
159
|
+
velocity_coordinates=np.array([0.0, 0.0, 0.0]),
|
|
160
|
+
thrust_acceleration=1.0,
|
|
161
|
+
output_frame=Frame.GCRF(),
|
|
162
|
+
),
|
|
163
|
+
expected_thrust_acceleration,
|
|
164
|
+
)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ostk.physics.time import Instant
|
|
8
|
+
from ostk.physics.coordinate import Frame
|
|
9
|
+
from ostk.physics.coordinate import Position
|
|
10
|
+
from ostk.physics.coordinate import Velocity
|
|
11
|
+
from ostk.physics.unit import Derived
|
|
12
|
+
from ostk.physics.environment.gravitational import Earth as EarthGravitationalModel
|
|
13
|
+
from ostk.physics.time import Instant
|
|
14
|
+
from ostk.physics.unit import Length
|
|
15
|
+
from ostk.physics.unit import Angle
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from ostk.astrodynamics.trajectory.orbit.model.kepler import COE
|
|
19
|
+
from ostk.astrodynamics import GuidanceLaw
|
|
20
|
+
from ostk.astrodynamics.guidance_law import QLaw
|
|
21
|
+
from ostk.astrodynamics.trajectory import State
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def target_COE() -> COE:
|
|
26
|
+
return COE(
|
|
27
|
+
Length.meters(42000.0e3),
|
|
28
|
+
0.01,
|
|
29
|
+
Angle.degrees(0.05),
|
|
30
|
+
Angle.degrees(0.0),
|
|
31
|
+
Angle.degrees(0.0),
|
|
32
|
+
Angle.degrees(0.0),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def gravitational_parameter() -> Derived:
|
|
38
|
+
return Derived(
|
|
39
|
+
3.986004418e14,
|
|
40
|
+
EarthGravitationalModel.EGM2008.gravitational_parameter.get_unit(),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def parameters() -> QLaw.Parameters:
|
|
46
|
+
return QLaw.Parameters(
|
|
47
|
+
element_weights={
|
|
48
|
+
COE.Element.SemiMajorAxis: (1.0, 100.0),
|
|
49
|
+
COE.Element.Eccentricity: (1.0, 1e-3),
|
|
50
|
+
},
|
|
51
|
+
m=5,
|
|
52
|
+
n=6,
|
|
53
|
+
r=7,
|
|
54
|
+
b=0.08,
|
|
55
|
+
k=9,
|
|
56
|
+
periapsis_weight=0.1,
|
|
57
|
+
minimum_periapsis_radius=Length.kilometers(7000.0),
|
|
58
|
+
absolute_effectivity_threshold=0.2,
|
|
59
|
+
relative_effectivity_threshold=0.3,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@pytest.fixture
|
|
64
|
+
def gradient_strategy() -> QLaw.GradientStrategy:
|
|
65
|
+
return QLaw.GradientStrategy.FiniteDifference
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.fixture
|
|
69
|
+
def q_law(
|
|
70
|
+
target_COE: COE,
|
|
71
|
+
gravitational_parameter: Derived,
|
|
72
|
+
parameters: QLaw.Parameters,
|
|
73
|
+
gradient_strategy: QLaw.GradientStrategy,
|
|
74
|
+
) -> QLaw:
|
|
75
|
+
return QLaw(
|
|
76
|
+
target_coe=target_COE,
|
|
77
|
+
gravitational_parameter=gravitational_parameter,
|
|
78
|
+
parameters=parameters,
|
|
79
|
+
coe_domain=QLaw.COEDomain.Osculating,
|
|
80
|
+
gradient_strategy=gradient_strategy,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@pytest.fixture
|
|
85
|
+
def thrust_acceleration() -> float:
|
|
86
|
+
return 1.0 / 300.0
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.fixture
|
|
90
|
+
def frame() -> Frame:
|
|
91
|
+
return Frame.GCRF()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.fixture
|
|
95
|
+
def position_coordinates() -> list[float]:
|
|
96
|
+
return [6930000.0, 0.0, 0.0]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@pytest.fixture
|
|
100
|
+
def velocity_coordinates() -> list[float]:
|
|
101
|
+
return [0.0, 7621.89248591193, 6.65135764404186]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@pytest.fixture
|
|
105
|
+
def instant() -> Instant:
|
|
106
|
+
return Instant.J2000()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@pytest.fixture
|
|
110
|
+
def position(frame: Frame, position_coordinates: list[float]) -> Position:
|
|
111
|
+
return Position.meters(position_coordinates, frame)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@pytest.fixture
|
|
115
|
+
def velocity(frame: Frame, velocity_coordinates: list[float]) -> Velocity:
|
|
116
|
+
return Velocity.meters_per_second(velocity_coordinates, frame)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@pytest.fixture
|
|
120
|
+
def state(instant: Instant, position: Position, velocity: Velocity) -> State:
|
|
121
|
+
return State(instant=instant, position=position, velocity=velocity)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class TestQLawParameters:
|
|
125
|
+
def test_constructors(self, parameters: QLaw.Parameters):
|
|
126
|
+
assert parameters is not None
|
|
127
|
+
assert isinstance(parameters, QLaw.Parameters)
|
|
128
|
+
|
|
129
|
+
def test_getters(self, parameters: QLaw.Parameters):
|
|
130
|
+
assert parameters.get_control_weights() is not None
|
|
131
|
+
assert parameters.get_convergence_thresholds() is not None
|
|
132
|
+
assert parameters.m == 5
|
|
133
|
+
assert parameters.n == 6
|
|
134
|
+
assert parameters.r == 7
|
|
135
|
+
assert parameters.b == 0.08
|
|
136
|
+
assert parameters.k == 9
|
|
137
|
+
assert parameters.periapsis_weight == 0.1
|
|
138
|
+
assert parameters.get_minimum_periapsis_radius() == Length.kilometers(7000.0)
|
|
139
|
+
assert parameters.absolute_effectivity_threshold == 0.2
|
|
140
|
+
assert parameters.relative_effectivity_threshold == 0.3
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class TestQLaw:
|
|
144
|
+
def test_constructors(
|
|
145
|
+
self,
|
|
146
|
+
target_COE: COE,
|
|
147
|
+
gravitational_parameter: Derived,
|
|
148
|
+
parameters: QLaw.Parameters,
|
|
149
|
+
gradient_strategy: QLaw.GradientStrategy,
|
|
150
|
+
):
|
|
151
|
+
qlaw: QLaw = QLaw(
|
|
152
|
+
target_coe=target_COE,
|
|
153
|
+
gravitational_parameter=gravitational_parameter,
|
|
154
|
+
parameters=parameters,
|
|
155
|
+
coe_domain=QLaw.COEDomain.BrouwerLyddaneMeanLong,
|
|
156
|
+
gradient_strategy=gradient_strategy,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
assert qlaw is not None
|
|
160
|
+
assert isinstance(qlaw, QLaw)
|
|
161
|
+
assert isinstance(qlaw, GuidanceLaw)
|
|
162
|
+
|
|
163
|
+
def test_getters(self, q_law: QLaw):
|
|
164
|
+
assert q_law.get_parameters() is not None
|
|
165
|
+
assert q_law.get_target_coe() is not None
|
|
166
|
+
assert q_law.get_gradient_strategy() is not None
|
|
167
|
+
assert q_law.get_coe_domain() is not None
|
|
168
|
+
|
|
169
|
+
def test_calculate_thrust_acceleration_at(
|
|
170
|
+
self,
|
|
171
|
+
q_law: QLaw,
|
|
172
|
+
position_coordinates: list[float],
|
|
173
|
+
velocity_coordinates: list[float],
|
|
174
|
+
thrust_acceleration: float,
|
|
175
|
+
instant: Instant,
|
|
176
|
+
frame: Frame,
|
|
177
|
+
):
|
|
178
|
+
assert pytest.approx(
|
|
179
|
+
q_law.calculate_thrust_acceleration_at(
|
|
180
|
+
instant=instant,
|
|
181
|
+
position_coordinates=position_coordinates,
|
|
182
|
+
velocity_coordinates=velocity_coordinates,
|
|
183
|
+
thrust_acceleration=thrust_acceleration,
|
|
184
|
+
output_frame=frame,
|
|
185
|
+
)
|
|
186
|
+
) == np.array([0.0, 0.0033333320640941645, 2.9088817174504986e-06])
|
|
187
|
+
|
|
188
|
+
def test_compute_effectivity(
|
|
189
|
+
self,
|
|
190
|
+
q_law: QLaw,
|
|
191
|
+
state: State,
|
|
192
|
+
thrust_acceleration: float,
|
|
193
|
+
):
|
|
194
|
+
assert (
|
|
195
|
+
q_law.compute_effectivity(
|
|
196
|
+
state=state,
|
|
197
|
+
thrust_acceleration=thrust_acceleration,
|
|
198
|
+
)
|
|
199
|
+
is not None
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
assert (
|
|
203
|
+
q_law.compute_effectivity(
|
|
204
|
+
state=state,
|
|
205
|
+
thrust_acceleration=thrust_acceleration,
|
|
206
|
+
discretization_step_count=15,
|
|
207
|
+
)
|
|
208
|
+
is not None
|
|
209
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Apache License 2.0
|