def from_sbdb(cls, name, **kargs): """Return osculating `Orbit` by using `SBDB` from Astroquery. Parameters ---------- body_name: string Name of the body to make the request. Returns ------- ss: poliastro.twobody.orbit.Orbit Orbit corresponding to body_name Examples -------- >>> from poliastro.twobody.orbit import Orbit >>> apophis_orbit = Orbit.from_sbdb('apophis') """ obj = SBDB.query(name, full_precision=True, **kargs) if "count" in obj: # no error till now ---> more than one object has been found # contains all the name of the objects objects_name = obj["list"]["name"] objects_name_in_str = ( "" ) # used to store them in string form each in new line for i in objects_name: objects_name_in_str += i + "\n" raise ValueError( str(obj["count"]) + " different objects found: \n" + objects_name_in_str ) a = obj["orbit"]["elements"]["a"].to(u.AU) * u.AU ecc = float(obj["orbit"]["elements"]["e"]) * u.one inc = obj["orbit"]["elements"]["i"].to(u.deg) * u.deg raan = obj["orbit"]["elements"]["om"].to(u.deg) * u.deg argp = obj["orbit"]["elements"]["w"].to(u.deg) * u.deg # Since JPL provides Mean Anomaly (M) we need to make # the conversion to the true anomaly (\nu) nu = M_to_nu(obj["orbit"]["elements"]["ma"].to(u.deg) * u.deg, ecc) epoch = time.Time(obj["orbit"]["epoch"].to(u.d), format="jd") ss = cls.from_classical( Sun, a, ecc, inc, raan, argp, nu, epoch=epoch.tdb, plane=Planes.EARTH_ECLIPTIC, ) return ss
def orbit_from_record(record): """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record. Retrieve info from JPL DASTCOM5 database. Parameters ---------- record : int Object record. Returns ------- orbit : ~poliastro.twobody.orbit.Orbit NEO orbit. """ body_data = read_record(record) a = body_data['A'].item() * u.au ecc = body_data['EC'].item() * u.one inc = body_data['IN'].item() * u.deg raan = body_data['OM'].item() * u.deg argp = body_data['W'].item() * u.deg m = body_data['MA'].item() * u.deg nu = M_to_nu(m, ecc) epoch = Time(body_data['EPOCH'].item(), format='jd') orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch) return orbit
def orbit_from_record(record): """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record. Retrieve info from JPL DASTCOM5 database. Parameters ---------- record : int Object record. Returns ------- orbit : ~poliastro.twobody.orbit.Orbit NEO orbit. """ body_data = read_record(record) a = body_data["A"].item() * u.au ecc = body_data["EC"].item() * u.one inc = body_data["IN"].item() * u.deg raan = body_data["OM"].item() * u.deg argp = body_data["W"].item() * u.deg m = body_data["MA"].item() * u.deg nu = M_to_nu(m, ecc) epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb") orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch) orbit._frame = HeliocentricEclipticJ2000(obstime=epoch) return orbit
def mean_motion(orbit, tof, **kwargs): r"""Propagates orbit using mean motion .. versionadded:: 0.9.0 Parameters ---------- orbit : ~poliastro.twobody.orbit.Orbit the Orbit object to propagate. tof : float Time of flight (s). Notes ----- This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters, increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}` The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9 """ k = orbit.attractor.k.to(u.km**3 / u.s**2).value r0 = orbit.r.to(u.km).value v0 = orbit.v.to(u.km / u.s).value # get the initial true anomaly and orbit parameters that are constant over time p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0) # get the initial mean anomaly M0 = nu_to_M(nu0, ecc) # strong elliptic or strong hyperbolic orbits if np.abs(ecc - 1.0) > 1e-2: a = p / (1.0 - ecc**2) # given the initial mean anomaly, calculate mean anomaly # at the end, mean motion (n) equals sqrt(mu / |a^3|) with u.set_enabled_equivalencies(u.dimensionless_angles()): M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad nu = M_to_nu(M, ecc) # near-parabolic orbit else: q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc**2) # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit with u.set_enabled_equivalencies(u.dimensionless_angles()): M = M0 + tof * np.sqrt(k / 2.0 / (q**3)) nu = M_to_nu(M, ecc) with u.set_enabled_equivalencies(u.dimensionless_angles()): return coe2rv(k, p, ecc, inc, raan, argp, nu)
def mean_motion(k, r0, v0, tof, **kwargs): r"""Propagates orbit using mean motion Parameters ---------- k : float Gravitational constant of main attractor (km^3 / s^2). r0 : array Initial position (km). v0 : array Initial velocity (km). ad : function(t0, u, k), optional Non Keplerian acceleration (km/s2), default to None. tof : float Time of flight (s). Notes ----- This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters, increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}` The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9 """ # get the initial true anomaly and orbit parameters that are constant over time p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0) # get the initial mean anomaly M0 = nu_to_M(nu0, ecc) # elliptic or hyperbolic orbits if not np.isclose(ecc, 1.0, rtol=1e-06): a = p / (1.0 - ecc**2) # given the initial mean anomaly, calculate mean anomaly # at the end, mean motion (n) equals sqrt(mu / |a^3|) with u.set_enabled_equivalencies(u.dimensionless_angles()): M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad nu = M_to_nu(M, ecc) # parabolic orbit else: q = p / 2.0 # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit with u.set_enabled_equivalencies(u.dimensionless_angles()): M = M0 + tof * np.sqrt(k / (2.0 * q**3)) # using Barker's equation, which is solved analytically # for parabolic orbit, get true anomaly B = 3.0 * M / 2.0 A = (B + np.sqrt(1.0 + B**2))**(2.0 / 3.0) D = 2.0 * A * B / (1.0 + A + A**2) nu = 2.0 * np.arctan(D) with u.set_enabled_equivalencies(u.dimensionless_angles()): return coe2rv(k, p, ecc, inc, raan, argp, nu)
def orbit_from_spk_id(spk_id, api_key=None): """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a SPK-ID. Retrieve info from NASA NeoWS API, and therefore it only works with NEAs (Near Earth Asteroids). Parameters ---------- spk_id : str SPK-ID number, which is given to each body by JPL. api_key : str NASA OPEN APIs key (default: `DEMO_KEY`) Returns ------- orbit : ~poliastro.twobody.orbit.Orbit NEA orbit. """ payload = {"api_key": api_key or DEFAULT_API_KEY} response = requests.get(NEOWS_URL + spk_id, params=payload) response.raise_for_status() orbital_data = response.json()["orbital_data"] attractor = Sun a = float(orbital_data["semi_major_axis"]) * u.AU ecc = float(orbital_data["eccentricity"]) * u.one inc = float(orbital_data["inclination"]) * u.deg raan = float(orbital_data["ascending_node_longitude"]) * u.deg argp = float(orbital_data["perihelion_argument"]) * u.deg m = float(orbital_data["mean_anomaly"]) * u.deg nu = M_to_nu(m.to(u.rad), ecc) epoch = Time(float(orbital_data["epoch_osculation"]), format="jd", scale="tdb") ss = Orbit.from_classical(attractor, a, ecc, inc, raan, argp, nu, epoch, plane=Planes.EARTH_ECLIPTIC) return ss
def from_sbdb(cls, name, **kargs): """Return osculating `Orbit` by using `SBDB` from Astroquery. Parameters ---------- body_name: string Name of the body to make the request. Returns ------- ss: poliastro.twobody.orbit.Orbit Orbit corresponding to body_name Examples -------- >>> from poliastro.twobody.orbit import Orbit >>> apophis_orbit = Orbit.from_sbdb('apophis') """ obj = SBDB.query(name, full_precision=True, **kargs) a = obj["orbit"]["elements"]["a"].to(u.AU) * u.AU ecc = float(obj["orbit"]["elements"]["e"]) * u.one inc = obj["orbit"]["elements"]["i"].to(u.deg) * u.deg raan = obj["orbit"]["elements"]["om"].to(u.deg) * u.deg argp = obj["orbit"]["elements"]["w"].to(u.deg) * u.deg # Since JPL provides Mean Anomaly (M) we need to make # the conversion to the true anomaly (\nu) nu = M_to_nu(obj["orbit"]["elements"]["ma"].to(u.deg) * u.deg, ecc) epoch = time.Time(obj["orbit"]["epoch"].to(u.d), format="jd") ss = cls.from_classical( Sun, a, ecc, inc, raan, argp, nu, epoch=epoch.tdb, plane=Planes.EARTH_ECLIPTIC, ) return ss
def test_from_sbdb(): # Dictionary with structure: 'Object': [a, e, i, raan, argp, nu, epoch] # Notice JPL provides Mean anomaly, a conversion is needed to obtain nu SBDB_DATA = { "Ceres": ( 2.769165146349478 * u.AU, 0.07600902762923671 * u.one, 10.59406732590292 * u.deg, 80.30553084093981 * u.deg, 73.59769486239257 * u.deg, M_to_nu(77.37209773768207 * u.deg, 0.07600902762923671 * u.one), ) } for target_name in SBDB_DATA.keys(): ss_target = Orbit.from_sbdb(target_name) ss_classical = ss_target.classical() assert ss_classical == SBDB_DATA[target_name]
def orbit_from_spk_id(spk_id, api_key='DEMO_KEY'): """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a SPK-ID. Retrieve info from NASA NeoWS API, and therefore it only works with NEAs (Near Earth Asteroids). Parameters ---------- spk_id : str SPK-ID number, which is given to each body by JPL. api_key : str NASA OPEN APIs key (default: `DEMO_KEY`) Returns ------- orbit : ~poliastro.twobody.orbit.Orbit NEA orbit. """ payload = {'api_key': api_key} response = requests.get(NEOWS_URL + spk_id, params=payload) response.raise_for_status() orbital_data = response.json()['orbital_data'] attractor = Sun a = float(orbital_data['semi_major_axis']) * u.AU ecc = float(orbital_data['eccentricity']) * u.one inc = float(orbital_data['inclination']) * u.deg raan = float(orbital_data['ascending_node_longitude']) * u.deg argp = float(orbital_data['perihelion_argument']) * u.deg m = float(orbital_data['mean_anomaly']) * u.deg nu = M_to_nu(m.to(u.rad), ecc) epoch = Time(float(orbital_data['epoch_osculation']), format='jd', scale='tdb') return Orbit.from_classical(attractor, a, ecc, inc, raan, argp, nu, epoch)
def test_from_sbdb(): # Dictionary with structure: 'Object': [a, e, i, raan, argp, nu, epoch] # Notice JPL provides Mean anomaly, a conversion is needed to obtain nu SBDB_DATA = { "Ceres": ( 2.76916515450648 * u.AU, 0.07600902910070946 * u.one, 10.59406704424526 * u.deg, 80.30553156826473 * u.deg, 73.597694115971 * u.deg, M_to_nu(77.37209588584763 * u.deg, 0.07600902910070946 * u.one), ) } for target_name in SBDB_DATA.keys(): ss_target = Orbit.from_sbdb(target_name) ss_classical = ss_target.classical() assert ss_classical == SBDB_DATA[target_name]
import numpy as np from astropy import units as u from poliastro.twobody import Orbit from poliastro.twobody.angles import M_to_nu from poliastro.bodies import Sun MU69_ecc = 0.05046617 * u.one # Eccentricity MU69_i = 2.44996247 * u.deg # Inclination MU69_a = 6676495970 * u.km # Semimajor axisº MU69_raan = 159.04395317345 * u.deg # Right ascension of the ascending node MU69_argp = 181.14813924539 * u.deg # Argument of perihelion MU69_M = 310.91947579009 * u.deg # Mean anomaly MU69_nu = M_to_nu(MU69_M, MU69_ecc) # True anomaly orbit = Orbit.from_classical(Sun, MU69_a, MU69_ecc, MU69_i, MU69_raan, MU69_argp, MU69_nu)