[OLD] Ramblings about Earth orbit - poliastro/poliastro GitHub Wiki

This was implemented in the poliastro.earth module

New ideas for the object hierarchy

Current ideas

Remember Orbit = BaseState + epoch

Many Orbit properties like this:

@property
def raan(self):
    return self.state.raan
  1. EarthOrbit(Orbit) is a bad idea, for example:
  • synchronous stop receiving an attractor
  • if .propagate() hardcodes method "SGP4"
  • (there are other examples)
  1. _BaseOrbit with some shared functionality, and then Orbit(_BaseOrbit) and EartOrbit(_BaseOrbit) ...
  2. Try to minimize inheritance and leverage composition, for example adding more functionality a BaseState

Current API is like this:

orb = Orbit.from_vectors(Mars, r, v, Time.now())

print(orb.a)
print(orb.ecc)
new_orb = orb.propagate(10 * u.min, method=farnocchia)

new_orb = orb.propagate(
    10 * u.min,
    method=lambda ...: cowell(..., a_d=...)
)
orb.plot()

# Before: BaseCoordinateFrame = data (BaseRepresentation) + transformations
# Now: BaseRepresentation
# orb.sample()

User story: Load an orbit from a TLE/OMM.

from poliastro.earth.atmosphere import JR77
# from poliastro.earth.gravity import EGM96

# EarthSatellite contains an Orbit + ... (can grow)
# orb = EarthSatellite.from_tle(tle)
orb = EarthSatellite.from_vectors(r, v)
orb = EarthSatellite.from_classical(a, ecc, inc, raan, argp, nu)
orb.propagate(10 * u.min, atmosphere=JR77)

class EarthSatellite:
    def propagate(self, tof, *, atmosphere=None, gravity=None):
        if atmosphere is None and gravity is None:
            return self.orbit.propagate()

        # a_d = _a_d_from_perturbations(atmosphere=atmosphere)  # Magic
        a_d = functools.partial(atmospheric_drag_model, model=atmosphere)
        return self.orbit.propagate(tof, method=cowell, a_d=a_d)

Propagators:

  • Two body propagators: farnocchia, vallado, mikkola, ...
    • func(k, r, v, tofs, **kwargs)
  • Semianalytic(??) propagators: J2, ...
    • func(k, r, v, tofs, J2)
  • Generic(??) propagators: cowell, "Encke"?
    • func(k, r, v, tofs, rtol=1e-11, *, events=None, ad=None, **ad_kwargs)

Class-based propagators:

class Vallado(Propagator):
    def __init__(self, numiter):
        super()
        self.numiter = numiter

    # def propagate
    def __call__(self, r, v, tofs):
        # internally uses self.numiter


class Cowell(Propagator):
    def __init__(self, rtol, events, ad, **ad_kwargs):
        super()
        self.rtol = rtol
        ...

    def __call__(self, r, v, tofs):
        # internally use self.events, self.ad, ...
        ...


# NO!
class SGP4(Propagator):
    def __init__(self, ndot, nddot, bc, bstar, ...):
        ...

    # def __call__(self, r, v, tofs):  # NOPE!
    def __call__(self, n_brouwer, e_brouwer, i_brouwer, raan_brouwer, ...):

orb.propagate(10 * u.min, method=Vallado(numiter=35))

Upper layer:

ClassicalState = attractor + ClassicalElementSet + plane

TLE =
    attractor = Earth
    (hardcoded SGP4 propagator) +
    frame=TEME +
    ClassicalElementSet(n, e, i, raan, argp, M) +
    epoch +
    extra_parameters +
    metadata

tle = TLE.from_string(...)
tle.propagate(10 * u.min)  # TEME(x, y, z, d_x, d_y, d_z)
tle.plot()
tle.sample()

plotter = OrbitPlotter()
plotter.plot(tle)  # NotImplementedError: Cannot plot BaseCoordinateFrame
tle = """
...
...
"""
orb = TLE.from_string(tle)
print(orb.attractor)  # Earth
print(orb.ballistic_coefficient)  # 0.01 [...]
print(orb.a)  # Mean or osculating?
new_orb = orb.propagate(10 * u.min)  # SGP4 is mandatory

Problems with frames:

orb = Orbit.from_coords(
    Mars,
    HCRS(..., obstime=Time.now()),
    plane=Planes.EARTH_EQUATOR
)  # Why do you need planes?
orb = Orbit.from_coords(
    Earth,
    ITRS(..., obstime=Time.now()),
)  # How do you guarantee this is inertial?