Writeup Hack-A-Sat: Fiddlin' John Carson

Writeup Hack-A-Sat: Fiddlin' John Carson

2024-08-20

Challenge description: Your spacecraft has provided its Cartesian ICRF position (km) and velocity (km/s). What is its orbit (expressed as Keplerian elements)?
The challenge is available at this address.
Let's connect to the challenge instance:
> docker run --rm -i -e FLAG=pouet kepler:challenge KEPLER CHALLANGE a e i Ω ω υ . . ,' ,=, . , / \ . . | | . . \ / . + '=' . . .' . . ' ' Your spacecraft reports that its Cartesian ICRF position (km) and velocity (km/s) are: Pos (km): [8449.401305, 9125.794363, -17.461357] Vel (km/s): [-1.419072, 6.780149, 0.002865] Time: 2021-06-26-19:20:00.000-UTC What is its orbit (expressed as Keplerian elements a, e, i, Ω, ω, and υ)? Semimajor axis, a (km):
We need to determine the orbital parameters from the given Cartesian position and velocity.
It's important to understand what these orbital elements represent. If you need a refresher, check out this lesson on TLE basics (just here) :)
Below is a diagram illustrating the various parameters (note: the spacecraft’s placement is arbitrary for illustration):
Kepler Diagram
The calculations to extract the orbital elements can be pretty involved. So instead, we’ll use the Python library poliastro to do the heavy lifting.
First, let's convert our lists for position and velocity into objects with proper physical units so we can perform calculations:
from poliastro.twobody.orbit import u pos = [8449.401305, 9125.794363, -17.461357] vel = [-1.419072, 6.780149, 0.002865] pos_km = [*pos] * u.km vel_kms = [*vel] * u.km / u.s
Here, u.km and u.km / u.s are units from the astropy library.
By multiplying our lists by these units, each coordinate is converted into a Quantity object, so x, y, and z are now properly treated as being in kilometers and km/s. This allows us to perform physical calculations directly.
Similarly, u.s stands for seconds, so u.km / u.s "transforms" our velocity list into the correct unit (km/s).
Next, and this is where the magic happens, we just call the method Orbit.from_vectors which will do all the calculations for us so we can retrieve everything we need:
from poliastro.bodies import Earth from poliastro.twobody import Orbit time = "2021-06-26 19:20:00.000" orb = Orbit.from_vectors(Earth, pos_km, vel_kms, time)
Here, Earth is just an object containing the gravitational and geometric parameters of Earth, which are necessary for the calculation (no need to go into detail).
Don't forget to specify the exact time (time) at which the position and velocity were measured. Orbital parameters can change over time due to various gravitational perturbations, so specifying the time is important.
Once we've called Orbit.from_vectors, we just need to extract our six Keplerian elements:
a = orb.a # Semimajor axis in km e = orb.ecc # Eccentricity i = orb.inc.to_value(u.deg) # Inclination (converted to degrees) Omega = orb.raan.to_value(u.deg) # Right ascension of the ascending node (deg) omega = orb.argp.to_value(u.deg) # Argument of perigee (deg) nu = orb.nu.to_value(u.deg) # True anomaly (deg)
With the to_value(u.deg) method from astropy, we can directly convert a value to the unit of our choice. Since the angles are returned in radians, we use this to convert them to degrees.
Now, just print all the orbital parameters and fill in the challenge:
> docker run --rm -i -e FLAG=pouet kepler:challenge KEPLER CHALLANGE a e i Ω ω υ . . ,' ,=, . , / \ . . | | . . \ / . + '=' . . .' . . ' ' Your spacecraft reports that its Cartesian ICRF position (km) and velocity (km/s) are: Pos (km): [8449.401305, 9125.794363, -17.461357] Vel (km/s): [-1.419072, 6.780149, 0.002865] Time: 2021-06-26-19:20:00.000-UTC What is its orbit (expressed as Keplerian elements a, e, i, Ω, ω, and υ)? Semimajor axis, a (km): 24732.885760723184 Eccentricity, e: 0.7068070220620631 Inclination, i (deg): 0.11790360842507447 Right ascension of the ascending node, Ω (deg): 90.22650379956278 Argument of perigee, ω (deg): 226.58745900876278 True anomaly, υ (deg): 90.389955034578 You got it! Here's your flag: pouet