def hohmann(k, rv, r_f): r"""Calculate the Hohmann maneuver velocities and the duration of the maneuver. By defining the relationship between orbit radius: .. math:: a_{trans} = \frac{r_{i} + r_{f}}{2} The Hohmann maneuver velocities can be expressed as: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans}}} \end{align} The time that takes to complete the maneuver can be computed as: .. math:: \tau_{trans} = \pi \sqrt{\frac{(a_{trans})^{3}}{\mu}} Parameters ---------- k : float Standard Gravitational parameter rv : numpy.ndarray, numpy.ndarray Position and velocity vectors r_f : float Final orbital radius """ _, ecc, inc, raan, argp, nu = rv2coe(k, *rv) h_i = norm(cross(*rv)) p_i = h_i**2 / k r_i, v_i = rv_pqw(k, p_i, ecc, nu) r_i = norm(r_i) v_i = norm(v_i) a_trans = (r_i + r_f) / 2 dv_a = np.sqrt(2 * k / r_i - k / a_trans) - v_i dv_b = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans) dv_a = np.array([0, dv_a, 0]) dv_b = np.array([0, -dv_b, 0]) rot_matrix = coe_rotation_matrix(inc, raan, argp) dv_a = rot_matrix @ dv_a dv_b = rot_matrix @ dv_b t_trans = np.pi * np.sqrt(a_trans**3 / k) return dv_a, dv_b, t_trans
def eclipse_function(k, u_, r_sec, R_sec, R_primary, umbra=True): """Calculates a continuous shadow function. Parameters ---------- k: float Standard gravitational parameter (km^3 / s^2). u_: ~np.array Satellite position and velocity vector with respect to the primary body. r_sec: ~np.array Position vector of the secondary body with respect to the primary body. R_sec: float Equatorial radius of the secondary body. R_primary: float Equatorial radius of the primary body. umbra: bool Whether to calculate the shadow function for umbra or penumbra, defaults to True i.e. calculates for umbra. Note ---- The shadow function is taken from Escobal, P. (1985). Methods of orbit determination. The current implementation assumes circular bodies and doesn't account for flattening. """ # Plus or minus condition pm = 1 if umbra else -1 p, ecc, inc, raan, argp, nu = rv2coe(k, u_[:3], u_[3:]) PQW = coe_rotation_matrix(inc, raan, argp) # Make arrays contiguous for faster dot product with numba. P_, Q_ = np.ascontiguousarray(PQW[:, 0]), np.ascontiguousarray(PQW[:, 1]) r_sec_norm = norm(r_sec) beta = np.dot(P_, r_sec) / r_sec_norm zeta = np.dot(Q_, r_sec) / r_sec_norm sin_delta_shadow = np.sin((R_sec - pm * R_primary) / r_sec_norm) cos_psi = beta * np.cos(nu) + zeta * np.sin(nu) shadow_function = (((R_primary**2) * (1 + ecc * np.cos(nu))**2) + (p**2) * (cos_psi**2) - p**2 + pm * (2 * p * R_primary * cos_psi) * (1 + ecc * np.cos(nu)) * sin_delta_shadow) return shadow_function
def hohmann(cls, orbit_i, r_f): r"""Compute a Hohmann transfer between two circular orbits. By defining the relationship between orbit radius: .. math:: a_{trans} = \frac{r_{i} + r_{f}}{2} The Hohmann maneuver velocities can be expressed as: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans}}} \end{align} The time that takes to complete the maneuver can be computed as: .. math:: \tau_{trans} = \pi \sqrt{\frac{(a_{trans})^{3}}{\mu}} Parameters ---------- orbit_i: poliastro.twobody.orbit.Orbit Initial orbit r_f: astropy.unit.Quantity Final altitude of the orbit """ if orbit_i.nu is not 0 * u.deg: orbit_i = orbit_i.propagate_to_anomaly(0 * u.deg) # Initial orbit data k = orbit_i.attractor.k r_i = orbit_i.r v_i = orbit_i.v h_i = norm(cross(r_i.to(u.m).value, v_i.to(u.m / u.s).value) * u.m ** 2 / u.s) p_i = h_i ** 2 / k.to(u.m ** 3 / u.s ** 2) # Hohmann is defined always from the PQW frame, since it is the # natural plane of the orbit r_i, v_i = rv_pqw( k.to(u.m ** 3 / u.s ** 2).value, p_i.to(u.m).value, orbit_i.ecc.value, orbit_i.nu.to(u.rad).value, ) # Now, we apply Hohmman maneuver r_i = norm(r_i * u.m) v_i = norm(v_i * u.m / u.s) a_trans = (r_i + r_f) / 2 # This is the modulus of the velocities dv_a = np.sqrt(2 * k / r_i - k / a_trans) - v_i dv_b = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans) # Write them in PQW frame dv_a = np.array([0, dv_a.to(u.m / u.s).value, 0]) dv_b = np.array([0, -dv_b.to(u.m / u.s).value, 0]) # Transform to IJK frame rot_matrix = coe_rotation_matrix( orbit_i.inc.to(u.rad).value, orbit_i.raan.to(u.rad).value, orbit_i.argp.to(u.rad).value, ) dv_a = (rot_matrix @ dv_a) * u.m / u.s dv_b = (rot_matrix @ dv_b) * u.m / u.s t_trans = np.pi * np.sqrt(a_trans ** 3 / k) return cls((0 * u.s, dv_a), (t_trans, dv_b))
def bielliptic(cls, orbit_i, r_b, r_f): r"""Compute a bielliptic transfer between two circular orbits. The bielliptic maneuver employs two Hohmann transfers, therefore two intermediate orbits are established. We define the different radius relationships as follows: .. math:: \begin{align} a_{trans1} &= \frac{r_{i} + r_{b}}{2}\\ a_{trans2} &= \frac{r_{b} + r_{f}}{2}\\ \end{align} The increments in the velocity are: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans1}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_{trans2}}} - \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_trans{1}}}\\ \Delta v_{c} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans2}}}\\ \end{align} The time of flight for this maneuver is the addition of the time needed for both transition orbits, following the same formula as Hohmann: .. math:: \begin{align} \tau_{trans1} &= \pi \sqrt{\frac{a_{trans1}^{3}}{\mu}}\\ \tau_{trans2} &= \pi \sqrt{\frac{a_{trans2}^{3}}{\mu}}\\ \end{align} Parameters ---------- orbit_i: poliastro.twobody.orbit.Orbit Initial orbit r_b: astropy.unit.Quantity Altitude of the intermediate orbit r_f: astropy.unit.Quantity Final altitude of the orbit """ if orbit_i.nu is not 0 * u.deg: orbit_i = orbit_i.propagate_to_anomaly(0 * u.deg) # Initial orbit data k = orbit_i.attractor.k r_i = orbit_i.r v_i = orbit_i.v h_i = norm(cross(r_i.to(u.m).value, v_i.to(u.m / u.s).value) * u.m ** 2 / u.s) p_i = h_i ** 2 / k.to(u.m ** 3 / u.s ** 2) # Bielliptic is defined always from the PQW frame, since it is the # natural plane of the orbit r_i, v_i = rv_pqw( k.to(u.m ** 3 / u.s ** 2).value, p_i.to(u.m).value, orbit_i.ecc.value, orbit_i.nu.to(u.rad).value, ) # Define the transfer radius r_i = norm(r_i * u.m) v_i = norm(v_i * u.m / u.s) a_trans1 = (r_i + r_b) / 2 a_trans2 = (r_b + r_f) / 2 # Compute impulses dv_a = np.sqrt(2 * k / r_i - k / a_trans1) - v_i dv_b = np.sqrt(2 * k / r_b - k / a_trans2) - np.sqrt(2 * k / r_b - k / a_trans1) dv_c = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans2) # Write impulses in PQW frame dv_a = np.array([0, dv_a.to(u.m / u.s).value, 0]) dv_b = np.array([0, -dv_b.to(u.m / u.s).value, 0]) dv_c = np.array([0, dv_c.to(u.m / u.s).value, 0]) rot_matrix = coe_rotation_matrix( orbit_i.inc.to(u.rad).value, orbit_i.raan.to(u.rad).value, orbit_i.argp.to(u.rad).value, ) # Transform to IJK frame dv_a = (rot_matrix @ dv_a) * u.m / u.s dv_b = (rot_matrix @ dv_b) * u.m / u.s dv_c = (rot_matrix @ dv_c) * u.m / u.s # Compute time for maneuver t_trans1 = np.pi * np.sqrt(a_trans1 ** 3 / k) t_trans2 = np.pi * np.sqrt(a_trans2 ** 3 / k) return cls((0 * u.s, dv_a), (t_trans1, dv_b), (t_trans2, dv_c))
def hohmann(cls, orbit_i, r_f): r"""Compute a Hohmann transfer between two circular orbits. By defining the relationship between orbit radius: .. math:: a_{trans} = \frac{r_{i} + r_{f}}{2} The Hohmann maneuver velocities can be expressed as: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans}}} \end{align} The time that takes to complete the maneuver can be computed as: .. math:: \tau_{trans} = \pi \sqrt{\frac{(a_{trans})^{3}}{\mu}} Parameters ---------- orbit_i: poliastro.twobody.orbit.Orbit Initial orbit r_f: astropy.unit.Quantity Final altitude of the orbit """ if orbit_i.nu is not 0 * u.deg: orbit_i = orbit_i.propagate_to_anomaly(0 * u.deg) # Initial orbit data k = orbit_i.attractor.k r_i = orbit_i.r v_i = orbit_i.v h_i = norm( cross(r_i.to(u.m).value, v_i.to(u.m / u.s).value) * u.m**2 / u.s) p_i = h_i**2 / k.to(u.m**3 / u.s**2) # Hohmann is defined always from the PQW frame, since it is the # natural plane of the orbit r_i, v_i = rv_pqw( k.to(u.m**3 / u.s**2).value, p_i.to(u.m).value, orbit_i.ecc.value, orbit_i.nu.to(u.rad).value, ) # Now, we apply Hohmman maneuver r_i = norm(r_i * u.m) v_i = norm(v_i * u.m / u.s) a_trans = (r_i + r_f) / 2 # This is the modulus of the velocities dv_a = np.sqrt(2 * k / r_i - k / a_trans) - v_i dv_b = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans) # Write them in PQW frame dv_a = np.array([0, dv_a.to(u.m / u.s).value, 0]) dv_b = np.array([0, -dv_b.to(u.m / u.s).value, 0]) # Transform to IJK frame rot_matrix = coe_rotation_matrix( orbit_i.inc.to(u.rad).value, orbit_i.raan.to(u.rad).value, orbit_i.argp.to(u.rad).value, ) dv_a = (rot_matrix @ dv_a) * u.m / u.s dv_b = (rot_matrix @ dv_b) * u.m / u.s t_trans = np.pi * np.sqrt(a_trans**3 / k) return cls((0 * u.s, dv_a), (t_trans, dv_b))
def bielliptic(cls, orbit_i, r_b, r_f): r"""Compute a bielliptic transfer between two circular orbits. The bielliptic maneuver employs two Hohmann transfers, therefore two intermediate orbits are established. We define the different radius relationships as follows: .. math:: \begin{align} a_{trans1} &= \frac{r_{i} + r_{b}}{2}\\ a_{trans2} &= \frac{r_{b} + r_{f}}{2}\\ \end{align} The increments in the velocity are: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans1}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_{trans2}}} - \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_trans{1}}}\\ \Delta v_{c} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans2}}}\\ \end{align} The time of flight for this maneuver is the addition of the time needed for both transition orbits, following the same formula as Hohmann: .. math:: \begin{align} \tau_{trans1} &= \pi \sqrt{\frac{a_{trans1}^{3}}{\mu}}\\ \tau_{trans2} &= \pi \sqrt{\frac{a_{trans2}^{3}}{\mu}}\\ \end{align} Parameters ---------- orbit_i: poliastro.twobody.orbit.Orbit Initial orbit r_b: astropy.unit.Quantity Altitude of the intermediate orbit r_f: astropy.unit.Quantity Final altitude of the orbit """ if orbit_i.nu is not 0 * u.deg: orbit_i = orbit_i.propagate_to_anomaly(0 * u.deg) # Initial orbit data k = orbit_i.attractor.k r_i = orbit_i.r v_i = orbit_i.v h_i = norm( cross(r_i.to(u.m).value, v_i.to(u.m / u.s).value) * u.m**2 / u.s) p_i = h_i**2 / k.to(u.m**3 / u.s**2) # Bielliptic is defined always from the PQW frame, since it is the # natural plane of the orbit r_i, v_i = rv_pqw( k.to(u.m**3 / u.s**2).value, p_i.to(u.m).value, orbit_i.ecc.value, orbit_i.nu.to(u.rad).value, ) # Define the transfer radius r_i = norm(r_i * u.m) v_i = norm(v_i * u.m / u.s) a_trans1 = (r_i + r_b) / 2 a_trans2 = (r_b + r_f) / 2 # Compute impulses dv_a = np.sqrt(2 * k / r_i - k / a_trans1) - v_i dv_b = np.sqrt(2 * k / r_b - k / a_trans2) - np.sqrt(2 * k / r_b - k / a_trans1) dv_c = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans2) # Write impulses in PQW frame dv_a = np.array([0, dv_a.to(u.m / u.s).value, 0]) dv_b = np.array([0, -dv_b.to(u.m / u.s).value, 0]) dv_c = np.array([0, dv_c.to(u.m / u.s).value, 0]) rot_matrix = coe_rotation_matrix( orbit_i.inc.to(u.rad).value, orbit_i.raan.to(u.rad).value, orbit_i.argp.to(u.rad).value, ) # Transform to IJK frame dv_a = (rot_matrix @ dv_a) * u.m / u.s dv_b = (rot_matrix @ dv_b) * u.m / u.s dv_c = (rot_matrix @ dv_c) * u.m / u.s # Compute time for maneuver t_trans1 = np.pi * np.sqrt(a_trans1**3 / k) t_trans2 = np.pi * np.sqrt(a_trans2**3 / k) return cls((0 * u.s, dv_a), (t_trans1, dv_b), (t_trans2, dv_c))
def bielliptic(k, r_b, r_f, rv): r"""Calculate the increments in the velocities and the time of flight of the maneuver The bielliptic maneuver employs two Hohmann transfers, therefore two intermediate orbits are established. We define the different radius relationships as follows: .. math:: \begin{align} a_{trans1} &= \frac{r_{i} + r_{b}}{2}\\ a_{trans2} &= \frac{r_{b} + r_{f}}{2}\\ \end{align} The increments in the velocity are: .. math:: \begin{align} \Delta v_{a} &= \sqrt{\frac{2\mu}{r_{i}} - \frac{\mu}{a_{trans1}}} - v_{i}\\ \Delta v_{b} &= \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_{trans2}}} - \sqrt{\frac{2\mu}{r_{b}} - \frac{\mu}{a_trans{1}}}\\ \Delta v_{c} &= \sqrt{\frac{\mu}{r_{f}}} - \sqrt{\frac{2\mu}{r_{f}} - \frac{\mu}{a_{trans2}}}\\ \end{align} The time of flight for this maneuver is the addition of the time needed for both transition orbits, following the same formula as Hohmann: .. math:: \begin{align} \tau_{trans1} &= \pi \sqrt{\frac{a_{trans1}^{3}}{\mu}}\\ \tau_{trans2} &= \pi \sqrt{\frac{a_{trans2}^{3}}{\mu}}\\ \end{align} Parameters ---------- k : float Standard Gravitational parameter r_b : float Altitude of the intermediate orbit r_f : float Final orbital radius rv : numpy.ndarray, numpy.ndarray Position and velocity vectors """ _, ecc, inc, raan, argp, nu = rv2coe(k, *rv) h_i = norm(cross(*rv)) p_i = h_i**2 / k r_i, v_i = rv_pqw(k, p_i, ecc, nu) r_i = norm(r_i) v_i = norm(v_i) a_trans1 = (r_i + r_b) / 2 a_trans2 = (r_b + r_f) / 2 dv_a = np.sqrt(2 * k / r_i - k / a_trans1) - v_i dv_b = np.sqrt(2 * k / r_b - k / a_trans2) - np.sqrt(2 * k / r_b - k / a_trans1) dv_c = np.sqrt(k / r_f) - np.sqrt(2 * k / r_f - k / a_trans2) dv_a = np.array([0, dv_a, 0]) dv_b = np.array([0, -dv_b, 0]) dv_c = np.array([0, dv_c, 0]) rot_matrix = coe_rotation_matrix(inc, raan, argp) dv_a = rot_matrix @ dv_a dv_b = rot_matrix @ dv_b dv_c = rot_matrix @ dv_c t_trans1 = np.pi * np.sqrt(a_trans1**3 / k) t_trans2 = np.pi * np.sqrt(a_trans2**3 / k) return dv_a, dv_b, dv_c, t_trans1, t_trans2