1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/// Computes the rotation matrix transforming a vector in the radial, along-track, cross-track (RTN)
/// frame to the Earth-Centered Inertial (ECI) frame.
///
/// The ECI frame can be any inertial frame centered at the Earth's center, such as GCRF or EME2000.
///
/// The RTN frame is defined as follows:
/// - R (Radial): Points from the Earth's center to the satellite's position.
/// - N (Cross-Track): Perpendicular to the orbital plane, defined by the angular momentum vector (cross product of position and velocity).
/// - T (Along-Track): Completes the right-handed coordinate system, lying in the orbital plane and perpendicular to R and N.
///
/// Args:
/// x_eci (numpy.ndarray or list): 6D state vector in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
///
/// Returns:
/// numpy.ndarray: 3x3 rotation matrix transforming from RTN to ECI frame, shape (3, 3)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// # Define satellite state
/// sma = bh.R_EARTH + 700e3 # Semi-major axis in meters
/// state = np.array([sma, 0.0, 0.0, 0.0, bh.perigee_velocity(sma, 0.0), 0.0])
///
/// # Get rotation matrix
/// R = bh.rotation_rtn_to_eci(state)
/// print(f"RTN to ECI rotation matrix:\n{R}")
/// ```
unsafe
/// Computes the rotation matrix transforming a vector in the Earth-Centered Inertial (ECI)
/// frame to the radial, along-track, cross-track (RTN) frame.
///
/// This is the transpose (inverse) of the RTN-to-ECI rotation matrix.
///
/// Args:
/// x_eci (numpy.ndarray or list): 6D state vector in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
///
/// Returns:
/// numpy.ndarray: 3x3 rotation matrix transforming from ECI to RTN frame, shape (3, 3)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// # Define satellite state
/// sma = bh.R_EARTH + 700e3 # Semi-major axis in meters
/// state = np.array([sma, 0.0, 0.0, 0.0, bh.perigee_velocity(sma, 0.0), 0.0])
///
/// # Get rotation matrix
/// R = bh.rotation_eci_to_rtn(state)
/// print(f"ECI to RTN rotation matrix:\n{R}")
/// ```
unsafe
/// Transforms the absolute states of a chief and deputy satellite from the Earth-Centered Inertial (ECI)
/// frame to the relative state of the deputy with respect to the chief in the rotating
/// Radial, Along-Track, Cross-Track (RTN) frame.
///
/// Args:
/// x_chief (numpy.ndarray or list): 6D state vector of the chief satellite in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
/// x_deputy (numpy.ndarray or list): 6D state vector of the deputy satellite in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
///
/// Returns:
/// numpy.ndarray: 6D relative state vector of the deputy with respect to the chief in the RTN frame [ρ_R, ρ_T, ρ_N, ρ̇_R, ρ̇_T, ρ̇_N] (m, m/s), shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// bh.initialize_eop()
///
/// # Define chief and deputy orbital elements
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// oe_deputy = np.array([bh.R_EARTH + 701e3, 0.0015, 97.85, 15.05, 30.05, 45.05])
///
/// # Convert to Cartesian states
/// x_chief = bh.state_koe_to_eci(oe_chief, bh.AngleFormat.DEGREES)
/// x_deputy = bh.state_koe_to_eci(oe_deputy, bh.AngleFormat.DEGREES)
///
/// # Transform to relative RTN state
/// x_rel_rtn = bh.state_eci_to_rtn(x_chief, x_deputy)
/// print(f"Relative state in RTN: {x_rel_rtn}")
/// ```
unsafe
/// Transforms the relative state of a deputy satellite with respect to a chief satellite
/// from the rotating Radial, Along-Track, Cross-Track (RTN) frame to the absolute state
/// of the deputy in the Earth-Centered Inertial (ECI) frame.
///
/// Args:
/// x_chief (numpy.ndarray or list): 6D state vector of the chief satellite in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
/// x_rel_rtn (numpy.ndarray or list): 6D relative state vector of the deputy with respect to the chief in the RTN frame [ρ_R, ρ_T, ρ_N, ρ̇_R, ρ̇_T, ρ̇_N] (m, m/s), shape (6,)
///
/// Returns:
/// numpy.ndarray: 6D state vector of the deputy satellite in the ECI frame [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// bh.initialize_eop()
///
/// # Define chief state and relative RTN state
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// x_chief = bh.state_koe_to_eci(oe_chief, bh.AngleFormat.DEGREES)
///
/// # Relative state: 1km radial, 0.5km along-track, -0.3km cross-track
/// x_rel_rtn = np.array([1000.0, 500.0, -300.0, 0.0, 0.0, 0.0])
///
/// # Transform to absolute deputy ECI state
/// x_deputy = bh.state_rtn_to_eci(x_chief, x_rel_rtn)
/// print(f"Deputy state in ECI: {x_deputy}")
/// ```
unsafe
/// Converts chief and deputy satellite orbital elements (OE) to quasi-nonsingular relative orbital elements (ROE).
///
/// The ROE formulation provides a mean description of relative motion that is nonsingular for
/// circular and near-circular orbits. The ROE vector contains:
/// - da: Relative semi-major axis (dimensionless)
/// - dλ: Relative mean longitude (degrees or radians)
/// - dex: x-component of relative eccentricity vector (dimensionless)
/// - dey: y-component of relative eccentricity vector (dimensionless)
/// - dix: x-component of relative inclination vector (degrees or radians)
/// - diy: y-component of relative inclination vector (degrees or radians)
///
/// Args:
/// oe_chief (numpy.ndarray or list): Chief satellite orbital elements [a, e, i, Ω, ω, M] shape (6,)
/// oe_deputy (numpy.ndarray or list): Deputy satellite orbital elements [a, e, i, Ω, ω, M] shape (6,)
/// angle_format (AngleFormat): Format of angular elements (DEGREES or RADIANS)
///
/// Returns:
/// numpy.ndarray: Relative orbital elements [da, dλ, dex, dey, dix, diy] shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// # Define chief and deputy orbital elements (degrees)
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// oe_deputy = np.array([bh.R_EARTH + 701e3, 0.0015, 97.85, 15.05, 30.05, 45.05])
///
/// # Convert to ROE
/// roe = bh.state_oe_to_roe(oe_chief, oe_deputy, bh.AngleFormat.DEGREES)
/// print(f"Relative orbital elements: {roe}")
/// # Relative orbital elements: [1.413e-4, 9.321e-2, 4.324e-4, 2.511e-4, 5.0e-2, 4.954e-2]
/// ```
unsafe
/// Converts chief satellite orbital elements (OE) and quasi-nonsingular relative orbital elements (ROE)
/// to deputy satellite orbital elements.
///
/// This is the inverse transformation of `state_oe_to_roe`, converting from ROE representation
/// back to classical orbital elements for the deputy satellite.
///
/// Args:
/// oe_chief (numpy.ndarray or list): Chief satellite orbital elements [a, e, i, Ω, ω, M] shape (6,)
/// roe (numpy.ndarray or list): Relative orbital elements [da, dλ, dex, dey, dix, diy] shape (6,)
/// angle_format (AngleFormat): Format of angular elements (DEGREES or RADIANS)
///
/// Returns:
/// numpy.ndarray: Deputy satellite orbital elements [a, e, i, Ω, ω, M] shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// # Define chief orbital elements and ROE (degrees)
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// roe = np.array([1.413e-4, 9.321e-2, 4.324e-4, 2.511e-4, 5.0e-2, 4.954e-2])
///
/// # Convert to deputy OE
/// oe_deputy = bh.state_roe_to_oe(oe_chief, roe, bh.AngleFormat.DEGREES)
/// print(f"Deputy orbital elements: {oe_deputy}")
/// # Deputy orbital elements: [7.079e6, 1.5e-3, 97.85, 15.05, 30.05, 45.05]
/// ```
unsafe
/// Converts chief and deputy satellite ECI state vectors to quasi-nonsingular Relative Orbital Elements (ROE).
///
/// This function converts both ECI states to Keplerian orbital elements, then computes
/// the quasi-nonsingular Relative Orbital Elements between them.
///
/// The ROE formulation provides a mean description of relative motion that is nonsingular for
/// circular and near-circular orbits. The ROE vector contains:
/// - da: Relative semi-major axis (dimensionless)
/// - dλ: Relative mean longitude (degrees or radians)
/// - dex: x-component of relative eccentricity vector (dimensionless)
/// - dey: y-component of relative eccentricity vector (dimensionless)
/// - dix: x-component of relative inclination vector (degrees or radians)
/// - diy: y-component of relative inclination vector (degrees or radians)
///
/// Args:
/// x_chief (numpy.ndarray or list): 6D ECI state vector of the chief satellite [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
/// x_deputy (numpy.ndarray or list): 6D ECI state vector of the deputy satellite [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
/// angle_format (AngleFormat): Format of angular elements in output (DEGREES or RADIANS)
///
/// Returns:
/// numpy.ndarray: Relative orbital elements [da, dλ, dex, dey, dix, diy] shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// bh.initialize_eop()
///
/// # Define chief and deputy orbital elements (degrees)
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// oe_deputy = np.array([bh.R_EARTH + 701e3, 0.0015, 97.85, 15.05, 30.05, 45.05])
///
/// # Convert to ECI states
/// x_chief = bh.state_koe_to_eci(oe_chief, bh.AngleFormat.DEGREES)
/// x_deputy = bh.state_koe_to_eci(oe_deputy, bh.AngleFormat.DEGREES)
///
/// # Compute ROE directly from ECI states
/// roe = bh.state_eci_to_roe(x_chief, x_deputy, bh.AngleFormat.DEGREES)
/// print(f"Relative orbital elements: {roe}")
/// # Relative orbital elements: [1.413e-4, 9.321e-2, 4.324e-4, 2.511e-4, 5.0e-2, 4.954e-2]
/// ```
unsafe
/// Converts chief satellite ECI state and quasi-nonsingular Relative Orbital Elements (ROE)
/// to deputy satellite ECI state.
///
/// This function converts the chief ECI state to Keplerian orbital elements, applies
/// the ROE to obtain deputy orbital elements, then converts back to ECI state.
///
/// Args:
/// x_chief (numpy.ndarray or list): 6D ECI state vector of the chief satellite [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
/// roe (numpy.ndarray or list): Relative orbital elements [da, dλ, dex, dey, dix, diy] shape (6,)
/// angle_format (AngleFormat): Format of angular elements in input ROE (DEGREES or RADIANS)
///
/// Returns:
/// numpy.ndarray: 6D ECI state vector of the deputy satellite [x, y, z, vx, vy, vz] (m, m/s), shape (6,)
///
/// Example:
/// ```python
/// import brahe as bh
/// import numpy as np
///
/// bh.initialize_eop()
///
/// # Define chief orbital elements and convert to ECI
/// oe_chief = np.array([bh.R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0])
/// x_chief = bh.state_koe_to_eci(oe_chief, bh.AngleFormat.DEGREES)
///
/// # Define ROE (small relative orbit)
/// roe = np.array([1.413e-4, 9.321e-2, 4.324e-4, 2.511e-4, 5.0e-2, 4.954e-2])
///
/// # Compute deputy ECI state from chief and ROE
/// x_deputy = bh.state_roe_to_eci(x_chief, roe, bh.AngleFormat.DEGREES)
/// print(f"Deputy ECI state: {x_deputy}")
/// ```
unsafe