open-space-toolkit-astrodynamics 9.1.6__py39-none-manylinux2014_aarch64.whl → 13.0.2__py39-none-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.
- {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/METADATA +5 -5
- {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/RECORD +29 -27
- {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/WHEEL +1 -1
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-39-aarch64-linux-gnu.so +0 -0
- ostk/astrodynamics/converters.py +35 -90
- ostk/astrodynamics/dataframe.py +479 -0
- ostk/astrodynamics/display.py +2 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.13 +0 -0
- ostk/astrodynamics/pytrajectory/pystate.py +216 -1
- ostk/astrodynamics/test/conftest.py +2 -2
- ostk/astrodynamics/test/flight/test_profile.py +155 -55
- ostk/astrodynamics/test/test_converters.py +43 -140
- ostk/astrodynamics/test/test_dataframe.py +875 -0
- ostk/astrodynamics/test/test_display.py +2 -3
- ostk/astrodynamics/test/test_event_condition.py +27 -7
- ostk/astrodynamics/test/test_trajectory.py +116 -38
- ostk/astrodynamics/test/test_utilities.py +31 -46
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +13 -0
- ostk/astrodynamics/test/trajectory/orbit/test_pass.py +9 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +3 -0
- ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +2 -2
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +34 -2
- ostk/astrodynamics/test/trajectory/test_orbit.py +26 -2
- ostk/astrodynamics/test/trajectory/test_segment.py +99 -1
- ostk/astrodynamics/test/trajectory/test_sequence.py +53 -0
- ostk/astrodynamics/test/trajectory/test_state.py +306 -0
- ostk/astrodynamics/utilities.py +125 -36
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.9 +0 -0
- {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/top_level.txt +0 -0
- {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/zip-safe +0 -0
@@ -1,13 +1,24 @@
|
|
1
1
|
# Apache License 2.0
|
2
2
|
|
3
|
-
|
4
3
|
# Python-only State functionality
|
4
|
+
import re
|
5
|
+
|
5
6
|
import numpy as np
|
6
7
|
|
7
8
|
from ostk.physics.coordinate import Frame
|
8
9
|
from ostk.physics.time import Instant
|
9
10
|
|
10
11
|
from ostk.astrodynamics.trajectory import State, StateBuilder
|
12
|
+
from ostk.astrodynamics.trajectory.state import CoordinateSubset
|
13
|
+
from ostk.astrodynamics.converters import coerce_to_instant
|
14
|
+
from ostk.astrodynamics.trajectory.state.coordinate_subset import (
|
15
|
+
CartesianPosition,
|
16
|
+
CartesianVelocity,
|
17
|
+
AttitudeQuaternion,
|
18
|
+
AngularVelocity,
|
19
|
+
)
|
20
|
+
|
21
|
+
CANONICAL_FORMAT: str = r"(r|v)_(.*?)_(x|y|z)"
|
11
22
|
|
12
23
|
|
13
24
|
@staticmethod
|
@@ -33,4 +44,208 @@ def custom_class_generator(frame: Frame, coordinate_subsets: list) -> type:
|
|
33
44
|
return StateTemplateType
|
34
45
|
|
35
46
|
|
47
|
+
@staticmethod
|
48
|
+
def from_dict(data: dict) -> State:
|
49
|
+
"""
|
50
|
+
Create a State from a dictionary.
|
51
|
+
|
52
|
+
Note: Implicit assumption that ECEF = ITRF, and ECI = GCRF.
|
53
|
+
|
54
|
+
The dictionary must contain the following:
|
55
|
+
- 'timestamp': The timestamp of the state.
|
56
|
+
- 'r_ITRF_x'/'rx'/'rx_eci'/'rx_ecef': The x-coordinate of the position.
|
57
|
+
- 'r_ITRF_y'/'ry'/'ry_eci'/'ry_ecef': The y-coordinate of the position.
|
58
|
+
- 'r_ITRF_z'/'rz'/'rz_eci'/'rz_ecef': The z-coordinate of the position.
|
59
|
+
- 'v_ITRF_x'/'vx'/'vx_eci'/'vx_ecef': The x-coordinate of the velocity.
|
60
|
+
- 'v_ITRF_y'/'vy'/'vy_eci'/'vy_ecef': The y-coordinate of the velocity.
|
61
|
+
- 'v_ITRF_z'/'vz'/'vz_eci'/'vz_ecef': The z-coordinate of the velocity.
|
62
|
+
- 'frame': The frame of the state. Required if 'rx', 'ry', 'rz', 'vx', 'vy', 'vz' are provided.
|
63
|
+
- 'q_B_ECI_x': The x-coordinate of the quaternion. Optional.
|
64
|
+
- 'q_B_ECI_y': The y-coordinate of the quaternion. Optional.
|
65
|
+
- 'q_B_ECI_z': The z-coordinate of the quaternion. Optional.
|
66
|
+
- 'q_B_ECI_s': The s-coordinate of the quaternion. Optional.
|
67
|
+
- 'w_B_ECI_in_B_x': The x-coordinate of the angular velocity. Optional.
|
68
|
+
- 'w_B_ECI_in_B_y': The y-coordinate of the angular velocity. Optional.
|
69
|
+
- 'w_B_ECI_in_B_z': The z-coordinate of the angular velocity. Optional.
|
70
|
+
- 'drag_coefficient'/'cd': The drag coefficient. Optional.
|
71
|
+
- 'cross_sectional_area'/'surface_area': The cross-sectional area. Optional.
|
72
|
+
- 'mass': The mass. Optional.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
data (dict): The dictionary.
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
State: The State.
|
79
|
+
"""
|
80
|
+
|
81
|
+
instant: Instant = coerce_to_instant(data["timestamp"])
|
82
|
+
|
83
|
+
eci_columns: list[str] = [
|
84
|
+
"rx_eci",
|
85
|
+
"ry_eci",
|
86
|
+
"rz_eci",
|
87
|
+
"vx_eci",
|
88
|
+
"vy_eci",
|
89
|
+
"vz_eci",
|
90
|
+
]
|
91
|
+
ecef_columns: list[str] = [
|
92
|
+
"rx_ecef",
|
93
|
+
"ry_ecef",
|
94
|
+
"rz_ecef",
|
95
|
+
"vx_ecef",
|
96
|
+
"vy_ecef",
|
97
|
+
"vz_ecef",
|
98
|
+
]
|
99
|
+
generic_columns: list[str] = [
|
100
|
+
"rx",
|
101
|
+
"ry",
|
102
|
+
"rz",
|
103
|
+
"vx",
|
104
|
+
"vy",
|
105
|
+
"vz",
|
106
|
+
]
|
107
|
+
|
108
|
+
# Replace non-standard position keys with canonical representation
|
109
|
+
if all(key in data.keys() for key in ("x_eci", "y_eci", "z_eci")):
|
110
|
+
data["rx_eci"] = data["x_eci"]
|
111
|
+
data["ry_eci"] = data["y_eci"]
|
112
|
+
data["rz_eci"] = data["z_eci"]
|
113
|
+
|
114
|
+
if all(key in data.keys() for key in ("x_ecef", "y_ecef", "z_ecef")):
|
115
|
+
data["rx_ecef"] = data["x_ecef"]
|
116
|
+
data["ry_ecef"] = data["y_ecef"]
|
117
|
+
data["rz_ecef"] = data["z_ecef"]
|
118
|
+
|
119
|
+
frame: Frame
|
120
|
+
coordinates: np.ndarray
|
121
|
+
|
122
|
+
coordinate_subsets: list[CoordinateSubset] = [
|
123
|
+
CartesianPosition.default(),
|
124
|
+
CartesianVelocity.default(),
|
125
|
+
]
|
126
|
+
|
127
|
+
match_groups: list[re.Match] = [
|
128
|
+
re.match(CANONICAL_FORMAT, column) for column in data.keys()
|
129
|
+
]
|
130
|
+
|
131
|
+
if len(matches := [match for match in match_groups if match is not None]) == 6:
|
132
|
+
frame_name: str = matches[0].group(2)
|
133
|
+
try:
|
134
|
+
frame: Frame = Frame.with_name(frame_name) or getattr(Frame, frame_name)()
|
135
|
+
except Exception:
|
136
|
+
raise ValueError(f"No frame exists with name [{frame_name}].")
|
137
|
+
|
138
|
+
coordinates = np.array([data[match.group(0)] for match in matches])
|
139
|
+
|
140
|
+
elif all(column in data for column in eci_columns):
|
141
|
+
frame: Frame = Frame.GCRF()
|
142
|
+
coordinates = np.array(
|
143
|
+
[
|
144
|
+
data["rx_eci"],
|
145
|
+
data["ry_eci"],
|
146
|
+
data["rz_eci"],
|
147
|
+
data["vx_eci"],
|
148
|
+
data["vy_eci"],
|
149
|
+
data["vz_eci"],
|
150
|
+
]
|
151
|
+
)
|
152
|
+
|
153
|
+
elif all(column in data for column in ecef_columns):
|
154
|
+
frame = Frame.ITRF()
|
155
|
+
coordinates = np.array(
|
156
|
+
[
|
157
|
+
data["rx_ecef"],
|
158
|
+
data["ry_ecef"],
|
159
|
+
data["rz_ecef"],
|
160
|
+
data["vx_ecef"],
|
161
|
+
data["vy_ecef"],
|
162
|
+
data["vz_ecef"],
|
163
|
+
]
|
164
|
+
)
|
165
|
+
|
166
|
+
elif all(column in data for column in generic_columns):
|
167
|
+
if "frame" not in data:
|
168
|
+
raise ValueError("Frame must be provided for generic columns.")
|
169
|
+
|
170
|
+
if isinstance(data["frame"], str):
|
171
|
+
if Frame.exists(data["frame"]):
|
172
|
+
frame = Frame.with_name(data["frame"])
|
173
|
+
else:
|
174
|
+
raise ValueError(f"No frame exists with name [{data['frame']}].")
|
175
|
+
elif isinstance(data["frame"], Frame):
|
176
|
+
frame = data["frame"]
|
177
|
+
else:
|
178
|
+
raise ValueError(f"Invalid frame data [{data['frame']}].")
|
179
|
+
|
180
|
+
coordinates = np.array(
|
181
|
+
[
|
182
|
+
data["rx"],
|
183
|
+
data["ry"],
|
184
|
+
data["rz"],
|
185
|
+
data["vx"],
|
186
|
+
data["vy"],
|
187
|
+
data["vz"],
|
188
|
+
]
|
189
|
+
)
|
190
|
+
else:
|
191
|
+
raise ValueError("Invalid state data.")
|
192
|
+
|
193
|
+
if all(
|
194
|
+
column in data for column in ["q_B_ECI_x", "q_B_ECI_y", "q_B_ECI_z", "q_B_ECI_s"]
|
195
|
+
):
|
196
|
+
coordinate_subsets.append(AttitudeQuaternion.default())
|
197
|
+
coordinates = np.append(
|
198
|
+
coordinates,
|
199
|
+
[
|
200
|
+
data["q_B_ECI_x"],
|
201
|
+
data["q_B_ECI_y"],
|
202
|
+
data["q_B_ECI_z"],
|
203
|
+
data["q_B_ECI_s"],
|
204
|
+
],
|
205
|
+
)
|
206
|
+
|
207
|
+
if all(
|
208
|
+
column in data
|
209
|
+
for column in ["w_B_ECI_in_B_x", "w_B_ECI_in_B_y", "w_B_ECI_in_B_z"]
|
210
|
+
):
|
211
|
+
coordinate_subsets.append(AngularVelocity.default())
|
212
|
+
coordinates = np.append(
|
213
|
+
coordinates,
|
214
|
+
[
|
215
|
+
data["w_B_ECI_in_B_x"],
|
216
|
+
data["w_B_ECI_in_B_y"],
|
217
|
+
data["w_B_ECI_in_B_z"],
|
218
|
+
],
|
219
|
+
)
|
220
|
+
|
221
|
+
if "drag_coefficient" in data or "cd" in data:
|
222
|
+
coordinate_subsets.append(CoordinateSubset.drag_coefficient())
|
223
|
+
coordinates = np.append(
|
224
|
+
coordinates,
|
225
|
+
data.get("drag_coefficient", data.get("cd")),
|
226
|
+
)
|
227
|
+
|
228
|
+
if "cross_sectional_area" in data or "surface_area" in data:
|
229
|
+
coordinate_subsets.append(CoordinateSubset.surface_area())
|
230
|
+
coordinates = np.append(
|
231
|
+
coordinates,
|
232
|
+
data.get("cross_sectional_area", data.get("surface_area")),
|
233
|
+
)
|
234
|
+
|
235
|
+
if "mass" in data:
|
236
|
+
coordinate_subsets.append(CoordinateSubset.mass())
|
237
|
+
coordinates = np.append(
|
238
|
+
coordinates,
|
239
|
+
data["mass"],
|
240
|
+
)
|
241
|
+
|
242
|
+
return State(
|
243
|
+
instant=instant,
|
244
|
+
coordinates=coordinates,
|
245
|
+
frame=frame,
|
246
|
+
coordinate_subsets=coordinate_subsets,
|
247
|
+
)
|
248
|
+
|
249
|
+
|
250
|
+
State.from_dict = from_dict
|
36
251
|
State.template = custom_class_generator
|
@@ -115,5 +115,5 @@ def aer(azimuth: Angle, elevation: Angle, range: Length) -> LLA:
|
|
115
115
|
|
116
116
|
|
117
117
|
@pytest.fixture
|
118
|
-
def trajectory(position: Position) -> Trajectory:
|
119
|
-
return Trajectory.position(position)
|
118
|
+
def trajectory(position: Position, instant_1: Instant) -> Trajectory:
|
119
|
+
return Trajectory.position(position.in_frame(Frame.ITRF(), instant_1))
|
@@ -8,6 +8,7 @@ from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
|
|
8
8
|
|
9
9
|
from ostk.physics import Environment
|
10
10
|
from ostk.physics.time import DateTime
|
11
|
+
from ostk.physics.time import Duration
|
11
12
|
from ostk.physics.time import Time
|
12
13
|
from ostk.physics.time import Scale
|
13
14
|
from ostk.physics.time import Instant
|
@@ -29,27 +30,121 @@ from ostk.astrodynamics.flight.profile.model import Tabulated as TabulatedModel
|
|
29
30
|
|
30
31
|
@pytest.fixture
|
31
32
|
def instant() -> Instant:
|
32
|
-
return Instant.date_time(DateTime(2020, 1,
|
33
|
+
return Instant.date_time(DateTime(2020, 1, 1, 0, 0, 30), Scale.UTC)
|
33
34
|
|
34
35
|
|
35
36
|
@pytest.fixture
|
36
|
-
def
|
37
|
+
def environment() -> Environment:
|
38
|
+
return Environment.default()
|
39
|
+
|
40
|
+
|
41
|
+
@pytest.fixture
|
42
|
+
def orbit(instant: Instant, environment: Environment) -> Orbit:
|
43
|
+
return Orbit.sun_synchronous(
|
44
|
+
epoch=instant,
|
45
|
+
altitude=Length.kilometers(500.0),
|
46
|
+
local_time_at_descending_node=Time(14, 0, 0),
|
47
|
+
celestial_object=environment.access_celestial_object_with_name("Earth"),
|
48
|
+
)
|
49
|
+
|
50
|
+
|
51
|
+
@pytest.fixture
|
52
|
+
def transform_model() -> TransformModel:
|
37
53
|
def dynamic_provider_generator(instant: Instant):
|
38
54
|
return Transform.identity(instant)
|
39
55
|
|
40
|
-
return
|
41
|
-
|
42
|
-
|
43
|
-
frame=Frame.GCRF(),
|
44
|
-
),
|
56
|
+
return TransformModel(
|
57
|
+
dynamic_provider=DynamicProvider(dynamic_provider_generator),
|
58
|
+
frame=Frame.GCRF(),
|
45
59
|
)
|
46
60
|
|
47
61
|
|
62
|
+
@pytest.fixture
|
63
|
+
def tabulated_model() -> TabulatedModel:
|
64
|
+
return TabulatedModel(
|
65
|
+
states=[
|
66
|
+
State(
|
67
|
+
instant=Instant.date_time(datetime(2020, 1, 1, 0, 0, 0), Scale.UTC),
|
68
|
+
position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
|
69
|
+
velocity=Velocity.meters_per_second((0.0, 0.0, 0.0), Frame.GCRF()),
|
70
|
+
attitude=Quaternion.unit(),
|
71
|
+
angular_velocity=(0.0, 0.0, 0.0),
|
72
|
+
attitude_frame=Frame.GCRF(),
|
73
|
+
),
|
74
|
+
State(
|
75
|
+
instant=Instant.date_time(datetime(2020, 1, 1, 0, 1, 0), Scale.UTC),
|
76
|
+
position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
|
77
|
+
velocity=Velocity.meters_per_second((0.0, 0.0, 0.0), Frame.GCRF()),
|
78
|
+
attitude=Quaternion.unit(),
|
79
|
+
angular_velocity=(0.0, 0.0, 0.0),
|
80
|
+
attitude_frame=Frame.GCRF(),
|
81
|
+
),
|
82
|
+
],
|
83
|
+
)
|
84
|
+
|
85
|
+
|
86
|
+
@pytest.fixture(
|
87
|
+
params=[
|
88
|
+
"transform_model",
|
89
|
+
"tabulated_model",
|
90
|
+
]
|
91
|
+
)
|
92
|
+
def profile(request) -> Profile:
|
93
|
+
model: TransformModel | TabulatedModel = request.getfixturevalue(request.param)
|
94
|
+
return Profile(model=model)
|
95
|
+
|
96
|
+
|
97
|
+
@pytest.fixture(
|
98
|
+
params=[
|
99
|
+
Profile.Target(Profile.TargetType.GeocentricNadir, Profile.Axis.X),
|
100
|
+
Profile.TrajectoryTarget(
|
101
|
+
Trajectory.position(Position.meters((0.0, 0.0, 0.0), Frame.ITRF())),
|
102
|
+
Profile.Axis.X,
|
103
|
+
),
|
104
|
+
Profile.OrientationProfileTarget(
|
105
|
+
[
|
106
|
+
(Instant.J2000(), [1.0, 0.0, 0.0]),
|
107
|
+
(Instant.J2000() + Duration.minutes(1.0), [1.0, 0.0, 0.0]),
|
108
|
+
(Instant.J2000() + Duration.minutes(2.0), [1.0, 0.0, 0.0]),
|
109
|
+
(Instant.J2000() + Duration.minutes(3.0), [1.0, 0.0, 0.0]),
|
110
|
+
],
|
111
|
+
Profile.Axis.X,
|
112
|
+
),
|
113
|
+
Profile.CustomTarget(
|
114
|
+
lambda state: [1.0, 0.0, 0.0],
|
115
|
+
Profile.Axis.X,
|
116
|
+
),
|
117
|
+
]
|
118
|
+
)
|
119
|
+
def alignment_target() -> Profile.Target:
|
120
|
+
return Profile.Target(Profile.TargetType.GeocentricNadir, Profile.Axis.X)
|
121
|
+
|
122
|
+
|
123
|
+
@pytest.fixture
|
124
|
+
def clocking_target() -> Profile.Target:
|
125
|
+
return Profile.Target(Profile.TargetType.VelocityECI, Profile.Axis.Y)
|
126
|
+
|
127
|
+
|
48
128
|
class TestProfile:
|
49
129
|
def test_constructors(self, profile: Profile):
|
50
130
|
assert profile is not None
|
51
131
|
assert isinstance(profile, Profile)
|
52
132
|
|
133
|
+
def test_profile_target(self, alignment_target: Profile.Target):
|
134
|
+
assert alignment_target is not None
|
135
|
+
assert isinstance(alignment_target, Profile.Target)
|
136
|
+
|
137
|
+
def test_access_model(self, profile: Profile):
|
138
|
+
model = profile.access_model()
|
139
|
+
|
140
|
+
assert model is not None
|
141
|
+
|
142
|
+
if model.is_transform():
|
143
|
+
assert model.as_transform() is not None
|
144
|
+
|
145
|
+
if model.is_tabulated():
|
146
|
+
assert model.as_tabulated() is not None
|
147
|
+
|
53
148
|
def test_get_state_at(self, profile: Profile, instant: Instant):
|
54
149
|
state: State = profile.get_state_at(instant)
|
55
150
|
|
@@ -68,7 +163,10 @@ class TestProfile:
|
|
68
163
|
assert axes is not None
|
69
164
|
assert isinstance(axes, Axes)
|
70
165
|
|
71
|
-
def test_get_body_frame(self, profile: Profile
|
166
|
+
def test_get_body_frame(self, profile: Profile):
|
167
|
+
if Frame.exists("Name"):
|
168
|
+
Frame.destruct("Name")
|
169
|
+
|
72
170
|
frame = profile.get_body_frame("Name")
|
73
171
|
|
74
172
|
assert frame is not None
|
@@ -85,7 +183,7 @@ class TestProfile:
|
|
85
183
|
quaternion: Quaternion = Quaternion([0.0, 0.0, 0.0, 1.0], Quaternion.Format.XYZS)
|
86
184
|
|
87
185
|
trajectory: Trajectory = Trajectory.position(
|
88
|
-
Position.meters((0.0, 0.0, 0.0), Frame.
|
186
|
+
Position.meters((0.0, 0.0, 0.0), Frame.ITRF())
|
89
187
|
)
|
90
188
|
|
91
189
|
profile: Profile = Profile.inertial_pointing(trajectory, quaternion)
|
@@ -94,60 +192,62 @@ class TestProfile:
|
|
94
192
|
assert isinstance(profile, Profile)
|
95
193
|
assert profile.is_defined()
|
96
194
|
|
97
|
-
def test_nadir_pointing(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
epoch=Instant.date_time(datetime(2020, 1, 1, 0, 0, 0), Scale.UTC),
|
102
|
-
altitude=Length.kilometers(500.0),
|
103
|
-
local_time_at_descending_node=Time(14, 0, 0),
|
104
|
-
celestial_object=environment.access_celestial_object_with_name("Earth"),
|
105
|
-
)
|
106
|
-
|
195
|
+
def test_nadir_pointing(
|
196
|
+
self,
|
197
|
+
orbit: Orbit,
|
198
|
+
):
|
107
199
|
profile: Profile = Profile.nadir_pointing(orbit, Orbit.FrameType.VVLH)
|
108
200
|
|
109
201
|
assert profile is not None
|
110
202
|
assert isinstance(profile, Profile)
|
111
203
|
assert profile.is_defined()
|
112
204
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
|
122
|
-
velocity=Velocity.meters_per_second(
|
123
|
-
(0.0, 0.0, 0.0), Frame.GCRF()
|
124
|
-
),
|
125
|
-
attitude=Quaternion.unit(),
|
126
|
-
angular_velocity=(0.0, 0.0, 0.0),
|
127
|
-
attitude_frame=Frame.GCRF(),
|
128
|
-
),
|
129
|
-
State(
|
130
|
-
instant=Instant.date_time(
|
131
|
-
datetime(2020, 1, 1, 0, 1, 0), Scale.UTC
|
132
|
-
),
|
133
|
-
position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
|
134
|
-
velocity=Velocity.meters_per_second(
|
135
|
-
(0.0, 0.0, 0.0), Frame.GCRF()
|
136
|
-
),
|
137
|
-
attitude=Quaternion.unit(),
|
138
|
-
angular_velocity=(0.0, 0.0, 0.0),
|
139
|
-
attitude_frame=Frame.GCRF(),
|
140
|
-
),
|
141
|
-
],
|
142
|
-
),
|
205
|
+
def test_custom_pointing(
|
206
|
+
self,
|
207
|
+
orbit: Orbit,
|
208
|
+
alignment_target: Profile.Target,
|
209
|
+
clocking_target: Profile.Target,
|
210
|
+
):
|
211
|
+
profile = Profile.custom_pointing(
|
212
|
+
orbit, Profile.align_and_constrain(alignment_target, clocking_target)
|
143
213
|
)
|
144
214
|
|
145
|
-
assert
|
215
|
+
assert profile is not None
|
146
216
|
assert profile.is_defined()
|
147
217
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
218
|
+
def test_align_and_constrain(
|
219
|
+
self,
|
220
|
+
orbit: Orbit,
|
221
|
+
instant: Instant,
|
222
|
+
alignment_target: Profile.Target,
|
223
|
+
clocking_target: Profile.Target,
|
224
|
+
):
|
225
|
+
orientation = Profile.align_and_constrain(
|
226
|
+
alignment_target=alignment_target,
|
227
|
+
clocking_target=clocking_target,
|
228
|
+
)
|
229
|
+
|
230
|
+
assert orientation is not None
|
231
|
+
assert orientation(orbit.get_state_at(instant)) is not None
|
232
|
+
|
233
|
+
def test_custom_pointing(
|
234
|
+
self,
|
235
|
+
orbit: Orbit,
|
236
|
+
alignment_target: Profile.Target,
|
237
|
+
clocking_target: Profile.Target,
|
238
|
+
):
|
239
|
+
profile = Profile.custom_pointing(
|
240
|
+
orbit, Profile.align_and_constrain(alignment_target, clocking_target)
|
153
241
|
)
|
242
|
+
|
243
|
+
assert profile is not None
|
244
|
+
assert profile.is_defined()
|
245
|
+
|
246
|
+
profile = Profile.custom_pointing(
|
247
|
+
orbit,
|
248
|
+
alignment_target,
|
249
|
+
clocking_target,
|
250
|
+
)
|
251
|
+
|
252
|
+
assert profile is not None
|
253
|
+
assert profile.is_defined()
|