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.
Files changed (151) hide show
  1. open_space_toolkit_astrodynamics-17.2.0.dist-info/METADATA +30 -0
  2. open_space_toolkit_astrodynamics-17.2.0.dist-info/RECORD +151 -0
  3. open_space_toolkit_astrodynamics-17.2.0.dist-info/WHEEL +5 -0
  4. open_space_toolkit_astrodynamics-17.2.0.dist-info/top_level.txt +1 -0
  5. open_space_toolkit_astrodynamics-17.2.0.dist-info/zip-safe +1 -0
  6. ostk/__init__.py +1 -0
  7. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so +0 -0
  8. ostk/astrodynamics/__init__.py +11 -0
  9. ostk/astrodynamics/__init__.pyi +720 -0
  10. ostk/astrodynamics/access.pyi +577 -0
  11. ostk/astrodynamics/conjunction/__init__.pyi +121 -0
  12. ostk/astrodynamics/conjunction/close_approach.pyi +89 -0
  13. ostk/astrodynamics/conjunction/message/__init__.pyi +3 -0
  14. ostk/astrodynamics/conjunction/message/ccsds.pyi +705 -0
  15. ostk/astrodynamics/converters.py +130 -0
  16. ostk/astrodynamics/converters.pyi +58 -0
  17. ostk/astrodynamics/data/__init__.pyi +3 -0
  18. ostk/astrodynamics/data/provider.pyi +22 -0
  19. ostk/astrodynamics/dataframe.py +597 -0
  20. ostk/astrodynamics/display.py +281 -0
  21. ostk/astrodynamics/dynamics.pyi +311 -0
  22. ostk/astrodynamics/eclipse.pyi +70 -0
  23. ostk/astrodynamics/estimator.pyi +268 -0
  24. ostk/astrodynamics/event_condition.pyi +910 -0
  25. ostk/astrodynamics/flight/__init__.pyi +626 -0
  26. ostk/astrodynamics/flight/profile/__init__.pyi +99 -0
  27. ostk/astrodynamics/flight/profile/model.pyi +179 -0
  28. ostk/astrodynamics/flight/system.pyi +268 -0
  29. ostk/astrodynamics/guidance_law.pyi +416 -0
  30. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.17 +0 -0
  31. ostk/astrodynamics/pytrajectory/__init__.py +1 -0
  32. ostk/astrodynamics/pytrajectory/__init__.pyi +3 -0
  33. ostk/astrodynamics/pytrajectory/pystate.py +263 -0
  34. ostk/astrodynamics/pytrajectory/pystate.pyi +66 -0
  35. ostk/astrodynamics/solver.pyi +432 -0
  36. ostk/astrodynamics/test/__init__.py +1 -0
  37. ostk/astrodynamics/test/access/__init__.py +1 -0
  38. ostk/astrodynamics/test/access/test_generator.py +319 -0
  39. ostk/astrodynamics/test/access/test_visibility_criterion.py +201 -0
  40. ostk/astrodynamics/test/conftest.py +119 -0
  41. ostk/astrodynamics/test/conjunction/close_approach/__init__.py +0 -0
  42. ostk/astrodynamics/test/conjunction/close_approach/test_generator.py +228 -0
  43. ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
  44. ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
  45. ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
  46. ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
  47. ostk/astrodynamics/test/conjunction/test_close_approach.py +244 -0
  48. ostk/astrodynamics/test/data/provider/test_off_nadir.py +58 -0
  49. ostk/astrodynamics/test/dynamics/__init__.py +1 -0
  50. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
  51. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
  52. ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
  53. ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
  54. ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
  55. ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
  56. ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
  57. ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
  58. ostk/astrodynamics/test/dynamics/test_thruster.py +157 -0
  59. ostk/astrodynamics/test/eclipse/__init__.py +1 -0
  60. ostk/astrodynamics/test/eclipse/test_generator.py +138 -0
  61. ostk/astrodynamics/test/estimator/test_orbit_determination_solver.py +261 -0
  62. ostk/astrodynamics/test/estimator/test_tle_solver.py +216 -0
  63. ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
  64. ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
  65. ostk/astrodynamics/test/event_condition/test_brouwer_lyddane_mean_long_condition.py +135 -0
  66. ostk/astrodynamics/test/event_condition/test_coe_condition.py +135 -0
  67. ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
  68. ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
  69. ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
  70. ostk/astrodynamics/test/flight/__init__.py +1 -0
  71. ostk/astrodynamics/test/flight/profile/model/test_tabulated_profile.py +115 -0
  72. ostk/astrodynamics/test/flight/system/__init__.py +1 -0
  73. ostk/astrodynamics/test/flight/system/test_propulsion_system.py +64 -0
  74. ostk/astrodynamics/test/flight/system/test_satellite_system.py +83 -0
  75. ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
  76. ostk/astrodynamics/test/flight/test_maneuver.py +231 -0
  77. ostk/astrodynamics/test/flight/test_profile.py +293 -0
  78. ostk/astrodynamics/test/flight/test_system.py +45 -0
  79. ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +177 -0
  80. ostk/astrodynamics/test/guidance_law/test_guidance_law.py +60 -0
  81. ostk/astrodynamics/test/guidance_law/test_heterogeneous_guidance_law.py +164 -0
  82. ostk/astrodynamics/test/guidance_law/test_qlaw.py +209 -0
  83. ostk/astrodynamics/test/solvers/__init__.py +1 -0
  84. ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +196 -0
  85. ostk/astrodynamics/test/solvers/test_least_squares_solver.py +334 -0
  86. ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +161 -0
  87. ostk/astrodynamics/test/test_access.py +128 -0
  88. ostk/astrodynamics/test/test_converters.py +290 -0
  89. ostk/astrodynamics/test/test_dataframe.py +1355 -0
  90. ostk/astrodynamics/test/test_display.py +184 -0
  91. ostk/astrodynamics/test/test_event_condition.py +80 -0
  92. ostk/astrodynamics/test/test_import.py +26 -0
  93. ostk/astrodynamics/test/test_root_solver.py +70 -0
  94. ostk/astrodynamics/test/test_trajectory.py +126 -0
  95. ostk/astrodynamics/test/test_utilities.py +338 -0
  96. ostk/astrodynamics/test/test_viewer.py +318 -0
  97. ostk/astrodynamics/test/trajectory/__init__.py +1 -0
  98. ostk/astrodynamics/test/trajectory/model/test_nadir_trajectory.py +87 -0
  99. ostk/astrodynamics/test/trajectory/model/test_tabulated_trajectory.py +303 -0
  100. ostk/astrodynamics/test/trajectory/model/test_target_scan_trajectory.py +126 -0
  101. ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
  102. ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
  103. ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
  104. ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
  105. ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
  106. ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
  107. ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
  108. ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
  109. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
  110. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
  111. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
  112. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +305 -0
  113. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
  114. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +337 -0
  115. ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
  116. ostk/astrodynamics/test/trajectory/orbit/models/test_modified_equinoctial.py +142 -0
  117. ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
  118. ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
  119. ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
  120. ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
  121. ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
  122. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
  123. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
  124. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_acceleration.py +136 -0
  125. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
  126. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
  127. ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
  128. ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +58 -0
  129. ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +316 -0
  130. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
  131. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +119 -0
  132. ostk/astrodynamics/test/trajectory/test_model.py +1 -0
  133. ostk/astrodynamics/test/trajectory/test_orbit.py +212 -0
  134. ostk/astrodynamics/test/trajectory/test_propagator.py +452 -0
  135. ostk/astrodynamics/test/trajectory/test_segment.py +694 -0
  136. ostk/astrodynamics/test/trajectory/test_sequence.py +550 -0
  137. ostk/astrodynamics/test/trajectory/test_state.py +629 -0
  138. ostk/astrodynamics/test/trajectory/test_state_builder.py +172 -0
  139. ostk/astrodynamics/trajectory/__init__.pyi +1982 -0
  140. ostk/astrodynamics/trajectory/model.pyi +259 -0
  141. ostk/astrodynamics/trajectory/orbit/__init__.pyi +349 -0
  142. ostk/astrodynamics/trajectory/orbit/message/__init__.pyi +3 -0
  143. ostk/astrodynamics/trajectory/orbit/message/spacex.pyi +264 -0
  144. ostk/astrodynamics/trajectory/orbit/model/__init__.pyi +648 -0
  145. ostk/astrodynamics/trajectory/orbit/model/brouwerLyddaneMean.pyi +121 -0
  146. ostk/astrodynamics/trajectory/orbit/model/kepler.pyi +709 -0
  147. ostk/astrodynamics/trajectory/orbit/model/sgp4.pyi +330 -0
  148. ostk/astrodynamics/trajectory/state/__init__.pyi +402 -0
  149. ostk/astrodynamics/trajectory/state/coordinate_subset.pyi +208 -0
  150. ostk/astrodynamics/utilities.py +396 -0
  151. 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)