{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial 03: State Vectors & Orbital Elements\n", "\n", "This tutorial covers conversions between Cartesian State Vectors (Position, Velocity) and various orbital element representations.\n", "\n", "--- \n", "## Theory Prerequisites\n", "\n", "### 1. Classical Orbital Elements (COE)\n", "A set of 6 parameters uniquely describing an orbit:\n", "- **$a$**: Semi-major axis (Size)\n", "- **$e$**: Eccentricity (Shape)\n", "- **$i$**: Inclination (Tilt)\n", "- **$\\Omega$ (RAAN)**: Right Ascension of Ascending Node (Orientation)\n", "- **$\\omega$**: Argument of Perigee (Location of perigee)\n", "- **$\\nu$**: True Anomaly (Current position along orbit)\n", "\n", "### 2. Equinoctial elements\n", "Non-singular for circular ($e=0$) and equatorial ($i=0$) orbits.\n", "- $a$: Semi-major axis\n", "- $h = e \\sin(\\Omega + \\omega)$\n", "- $k = e \\cos(\\Omega + \\omega)$\n", "- $p = \\tan(i/2) \\sin(\\Omega)$\n", "- $q = \\tan(i/2) \\cos(\\Omega)$\n", "- $\\lambda_M = \\Omega + \\omega + M$ (Mean longitude)\n", "\n", "---" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Imports successful.\n" ] } ], "source": [ "import numpy as np\n", "from opengnc.utils.state_to_elements import eci2kepler, kepler2eci, anomalies\n", "from opengnc.utils.equinoctial_utils import kepler2equinoctial, equinoctial2kepler, equinoctial2eci\n", "from opengnc.ssa.tle_interface import TLECatalog, TLEEntity\n", "\n", "print(\"Imports successful.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. State Vector to Keplerian (COE)\n", "\n", "Let's define a position and velocity vector in ECI for a spacecraft in a standard orbit." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Semi-major axis (a): 6766.42 km\n", "Eccentricity (e): 0.000677\n", "Inclination (i): 0.00 deg\n", "RAAN (\\Omega): 0.00 deg\n", "Arg. of Perigee (\\omega): 180.00 deg\n", "True Anomaly (\n", "u): 180.00 deg\n", "\n", "Round-trip Position Error: 4.629332e-26 m\n" ] } ], "source": [ "# Define State Vector (ECI)\n", "r_eci = np.array([6771000.0, 0.0, 0.0]) # [m]\n", "v_eci = np.array([0.0, 7670.0, 0.0]) # [m/s]\n", "\n", "# Convert to Keplerian Elements\n", "a, ecc, incl, raan, argp, nu, M, E, p, arglat, truelon, lonper = eci2kepler(r_eci, v_eci)\n", "\n", "print(f\"Semi-major axis (a): {a/1000.0:.2f} km\")\n", "print(f\"Eccentricity (e): {ecc:.6f}\")\n", "print(f\"Inclination (i): {np.degrees(incl):.2f} deg\")\n", "print(f\"RAAN (\\Omega): {np.degrees(raan):.2f} deg\")\n", "print(f\"Arg. of Perigee (\\omega): {np.degrees(argp):.2f} deg\")\n", "print(f\"True Anomaly (\\nu): {np.degrees(nu):.2f} deg\")\n", "\n", "# Verify round-trip\n", "r_eci_rt, v_eci_rt = kepler2eci(a, ecc, incl, raan, argp, nu)\n", "print(f\"\\nRound-trip Position Error: {np.linalg.norm(r_eci - r_eci_rt):.6e} m\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Equinoctial elements Conversion\n", "\n", "Equinoctial elements avoid singularities. Let's convert our Keplerian elements to Equinoctial." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Equinoctial Elements:\n", " a: 6766.42 km\n", " h: 8.294149e-20\n", " k: -6.772687e-04\n", " p: 0.000000e+00\n", " q: 0.000000e+00\n", " lambda_mean: 0.00 deg\n", "\n", "Recovered Eccentricity: 0.000677 (Original: 0.000677)\n", "Recovered Inclination: 0.00 deg (Original: 0.00 deg)\n" ] } ], "source": [ "# Convert Keplerian to Equinoctial\n", "a_eq, h, k, p_eq, q, l_mean = kepler2equinoctial(a, ecc, incl, raan, argp, M)\n", "\n", "print(f\"Equinoctial Elements:\")\n", "print(f\" a: {a_eq/1000.0:.2f} km\")\n", "print(f\" h: {h:.6e}\")\n", "print(f\" k: {k:.6e}\")\n", "print(f\" p: {p_eq:.6e}\")\n", "print(f\" q: {q:.6e}\")\n", "print(f\" lambda_mean: {np.degrees(l_mean):.2f} deg\")\n", "\n", "# Convert back to Keplerian\n", "a_r, ecc_r, incl_r, raan_r, argp_r, nu_r, M_r = equinoctial2kepler(a_eq, h, k, p_eq, q, l_mean)\n", "print(f\"\\nRecovered Eccentricity: {ecc_r:.6f} (Original: {ecc:.6f})\")\n", "print(f\"Recovered Inclination: {np.degrees(incl_r):.2f} deg (Original: {np.degrees(incl):.2f} deg)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. TLE Interface & SGP4 Propagator\n", "\n", "Load a TLE and initialize a propagator to propagate the orbit." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Listing satellites in catalog: ['ISS (ZARYA)']\n", "\n", "Time: +0 minutes\n", "Position [TEME]: [-4674.10165916 1268.98804622 4754.93741611] km\n", "Velocity [TEME]: [-4.30887388 -5.74033591 -2.69314811] km/s\n", "\n", "Time: +10 minutes\n", "Position [TEME]: [-6036.28965614 -2197.92391076 2209.02466488] km\n", "Velocity [TEME]: [-0.05695672 -5.37151248 -5.465966 ] km/s\n", "\n", "Time: +20 minutes\n", "Position [TEME]: [-4738.02654378 -4696.3084195 -1313.38204718] km\n", "Velocity [TEME]: [ 4.21667521 -2.63738784 -5.82276693] km/s\n" ] } ], "source": [ "# Example TLE for ISS\n", "tle_name = \"ISS (ZARYA)\"\n", "line1 = \"1 25544U 98067A 24083.42875141 .00015504 00000-0 27807-3 0 9993\"\n", "line2 = \"2 25544 51.6416 35.8453 0004455 67.2341 49.3490 15.49842535445218\"\n", "\n", "# Create TLE Catalog\n", "catalog = TLECatalog()\n", "catalog.add_tle(tle_name, line1, line2)\n", "\n", "print(f\"Listing satellites in catalog: {catalog.list_satellites()}\")\n", "\n", "# Get propagator for the satellite\n", "sat = catalog.get_by_name(tle_name)\n", "propagator = sat.get_propagator()\n", "\n", "# Propagate orbit forward in seconds\n", "for t_min in [0, 10, 20]:\n", " dt_sec = t_min * 60.0\n", " pos, vel = propagator.propagate(None, None, dt_sec)\n", " print(f\"\\nTime: +{t_min} minutes\")\n", " print(f\"Position [TEME]: {pos/1000.0} km\")\n", " print(f\"Velocity [TEME]: {vel/1000.0} km/s\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.11" } }, "nbformat": 4, "nbformat_minor": 4 }