Skip to content

Commit 40c3021

Browse files
authored
feat: add state from dict ballistic coefficient (#546)
1 parent 4dc1ab5 commit 40c3021

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

bindings/python/test/trajectory/test_state.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,41 @@ def test_from_dict_with_mass(self):
458458
assert isinstance(state, State)
459459
assert state.get_size() == 6
460460

461+
def test_from_dict_with_ballistic_coefficient(self):
462+
data: dict = {
463+
"timestamp": datetime.now(timezone.utc).isoformat(),
464+
"rx_eci": 7000.0,
465+
"ry_eci": 0.0,
466+
"rz_eci": 0.0,
467+
"vx_eci": 0.0,
468+
"vy_eci": 7.5,
469+
"vz_eci": 0.0,
470+
"ballistic_coefficient": 2.2,
471+
}
472+
473+
state: State = State.from_dict(data)
474+
475+
assert state is not None
476+
assert isinstance(state, State)
477+
assert state.get_size() == 7
478+
479+
data: dict = {
480+
"timestamp": datetime.now(timezone.utc).isoformat(),
481+
"rx_eci": 7000.0,
482+
"ry_eci": 0.0,
483+
"rz_eci": 0.0,
484+
"vx_eci": 0.0,
485+
"vy_eci": 7.5,
486+
"vz_eci": 0.0,
487+
"ballistic_coefficient": None,
488+
}
489+
490+
state: State = State.from_dict(data)
491+
492+
assert state is not None
493+
assert isinstance(state, State)
494+
assert state.get_size() == 6
495+
461496
@pytest.mark.parametrize(
462497
("data", "expected_length", "expected_frame"),
463498
[

bindings/python/tools/python/ostk/astrodynamics/pytrajectory/pystate.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
AngularVelocity,
1919
)
2020

21-
CANONICAL_FORMAT: str = r"(r|v)_(.*?)_(x|y|z)"
21+
POS_VEL_CANONICAL_FORMAT: str = r"(r|v)_(.*?)_(x|y|z)"
2222

2323

2424
def custom_class_generator(frame: Frame, coordinate_subsets: list) -> type:
@@ -68,6 +68,7 @@ def from_dict(data: dict) -> State:
6868
- 'drag_coefficient'/'cd': The drag coefficient. Optional.
6969
- 'cross_sectional_area'/'surface_area': The cross-sectional area. Optional.
7070
- 'mass': The mass. Optional.
71+
- 'ballistic_coefficient'/'bc': The ballistic coefficient. Optional.
7172
7273
Args:
7374
data (dict): The dictionary.
@@ -76,7 +77,7 @@ def from_dict(data: dict) -> State:
7677
State: The State.
7778
"""
7879

79-
instant: Instant = coerce_to_instant(data["timestamp"])
80+
# Position and velocity subsets
8081

8182
eci_columns: list[str] = [
8283
"rx_eci",
@@ -123,7 +124,7 @@ def from_dict(data: dict) -> State:
123124
]
124125

125126
match_groups: list[re.Match] = [
126-
re.match(CANONICAL_FORMAT, column) for column in data.keys()
127+
re.match(POS_VEL_CANONICAL_FORMAT, column) for column in data.keys()
127128
]
128129

129130
if len(matches := [match for match in match_groups if match is not None]) == 6:
@@ -188,6 +189,8 @@ def from_dict(data: dict) -> State:
188189
else:
189190
raise ValueError("Invalid state data.")
190191

192+
# Attitude and angular velocity subsets
193+
191194
if all(
192195
column in data for column in ["q_B_ECI_x", "q_B_ECI_y", "q_B_ECI_z", "q_B_ECI_s"]
193196
):
@@ -216,6 +219,8 @@ def from_dict(data: dict) -> State:
216219
],
217220
)
218221

222+
# Extra subsets
223+
219224
if (data.get("drag_coefficient") is not None) or (data.get("cd") is not None):
220225
coordinate_subsets.append(CoordinateSubset.drag_coefficient())
221226
coordinates = np.append(
@@ -239,8 +244,15 @@ def from_dict(data: dict) -> State:
239244
data["mass"],
240245
)
241246

247+
if (data.get("ballistic_coefficient") is not None) or (data.get("bc") is not None):
248+
coordinate_subsets.append(CoordinateSubset.ballistic_coefficient())
249+
coordinates = np.append(
250+
coordinates,
251+
data.get("ballistic_coefficient", data.get("bc")),
252+
)
253+
242254
return State(
243-
instant=instant,
255+
instant=coerce_to_instant(data["timestamp"]),
244256
coordinates=coordinates,
245257
frame=frame,
246258
coordinate_subsets=coordinate_subsets,

0 commit comments

Comments
 (0)