elements_to_state_vector
Convert orbital elements (semi_major_axis, eccentricity, etc.) into a position and velocity state vector in the J2000 inertial frame for spacecraft trajectory calculations.
Instructions
Convert orbital elements to state vector in J2000 frame.
Args: orbital_elements: Dict with orbital elements (semi_major_axis_m, eccentricity, etc.)
Returns: JSON string with position [x,y,z] in meters and velocity [vx,vy,vz] in m/s in the J2000 inertial frame.
Raises: No exceptions are raised directly; errors are returned as formatted strings.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| orbital_elements | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- Core implementation of elements_to_state_vector conversion. Takes OrbitElements (Keplerian orbital elements), converts to Cartesian state vector in the J2000 inertial frame using the perifocal (PQW) frame approach with the 3-1-3 Euler angle rotation sequence (RAAN, inclination, argument of periapsis). Algorithm from Vallado (4th ed., Algorithm 10). Returns a StateVector dataclass with position_m, velocity_ms, epoch_utc, and frame='J2000'.
def elements_to_state_vector(elements: OrbitElements) -> StateVector: """Convert classical orbital elements to a Cartesian state vector. Algorithm (Vallado, 4th ed., Algorithm 10): 1. Compute the orbital radius from the conic equation. 2. Express position and velocity in the perifocal (PQW) frame. 3. Rotate from PQW to the J2000 inertial frame using the 3-1-3 Euler angle rotation sequence (RAAN, inclination, argument of periapsis). Args: elements: Classical (Keplerian) orbital elements. Returns: State vector in the J2000 Earth-centered inertial frame. """ # Convert angles to radians i = deg_to_rad(elements.inclination_deg) raan = deg_to_rad(elements.raan_deg) arg_pe = deg_to_rad(elements.arg_periapsis_deg) nu = deg_to_rad(elements.true_anomaly_deg) # Semi-major axis and eccentricity a = elements.semi_major_axis_m e = elements.eccentricity # Conic equation: r = p / (1 + e*cos(nu)), where p = a*(1 - e^2) # is the semi-latus rectum. r = a * (1 - e**2) / (1 + e * math.cos(nu)) # Position in perifocal (PQW) coordinates: x along periapsis, y # perpendicular in the orbital plane, z = 0 (by definition). r_peri = [r * math.cos(nu), r * math.sin(nu), 0.0] # Semi-latus rectum p = a*(1 - e^2) p = a * (1 - e**2) # Velocity in perifocal coordinates derived from the vis-viva # relations in the PQW frame: # v_P = -sqrt(mu/p) * sin(nu) # v_Q = sqrt(mu/p) * (e + cos(nu)) v_peri = [ -math.sqrt(MU_EARTH / p) * math.sin(nu), math.sqrt(MU_EARTH / p) * (e + math.cos(nu)), 0.0, ] # Pre-compute trigonometric values for the rotation matrix cos_raan, sin_raan = math.cos(raan), math.sin(raan) cos_i, sin_i = math.cos(i), math.sin(i) cos_arg, sin_arg = math.cos(arg_pe), math.sin(arg_pe) # Rotation matrix [R] = R3(-RAAN) * R1(-i) * R3(-omega) # Transforms perifocal (PQW) -> J2000 inertial frame. # See Vallado (2013), Eq. 4-44. R11 = cos_raan * cos_arg - sin_raan * sin_arg * cos_i R12 = -cos_raan * sin_arg - sin_raan * cos_arg * cos_i R13 = sin_raan * sin_i R21 = sin_raan * cos_arg + cos_raan * sin_arg * cos_i R22 = -sin_raan * sin_arg + cos_raan * cos_arg * cos_i R23 = -cos_raan * sin_i R31 = sin_arg * sin_i R32 = cos_arg * sin_i R33 = cos_i # Apply rotation: r_J2000 = [R] * r_PQW r_j2000 = [ R11 * r_peri[0] + R12 * r_peri[1] + R13 * r_peri[2], R21 * r_peri[0] + R22 * r_peri[1] + R23 * r_peri[2], R31 * r_peri[0] + R32 * r_peri[1] + R33 * r_peri[2], ] # Apply same rotation to velocity: v_J2000 = [R] * v_PQW v_j2000 = [ R11 * v_peri[0] + R12 * v_peri[1] + R13 * v_peri[2], R21 * v_peri[0] + R22 * v_peri[1] + R23 * v_peri[2], R31 * v_peri[0] + R32 * v_peri[1] + R33 * v_peri[2], ] return StateVector( position_m=r_j2000, velocity_ms=v_j2000, epoch_utc=elements.epoch_utc, frame="J2000", ) - aerospace_mcp/tools/orbits.py:278-324 (handler)Tool-level wrapper that accepts a dict (not OrbitElements), constructs OrbitElements from it, calls the integration-level _elements_to_state, and returns a JSON-formatted string with position and velocity. Handles ImportError (if orbital packages not installed) and general exceptions gracefully.
def elements_to_state_vector(orbital_elements: dict) -> str: """Convert orbital elements to state vector in J2000 frame. Args: orbital_elements: Dict with orbital elements (semi_major_axis_m, eccentricity, etc.) Returns: JSON string with position [x,y,z] in meters and velocity [vx,vy,vz] in m/s in the J2000 inertial frame. Raises: No exceptions are raised directly; errors are returned as formatted strings. """ try: from ..integrations.orbits import ( OrbitElements, ) from ..integrations.orbits import ( elements_to_state_vector as _elements_to_state, ) elements = OrbitElements(**orbital_elements) result = _elements_to_state(elements) return json.dumps( { "position_m": { "x": result.position_m[0], "y": result.position_m[1], "z": result.position_m[2], }, "velocity_ms": { "x": result.velocity_ms[0], "y": result.velocity_ms[1], "z": result.velocity_ms[2], }, "reference_frame": "J2000", "units": {"position": "meters", "velocity": "m/s"}, }, indent=2, ) except ImportError: return "Orbital mechanics not available - install orbital packages" except Exception as e: logger.error(f"Elements to state vector error: {str(e)}", exc_info=True) return f"Elements to state vector error: {str(e)}" - OrbitElements dataclass defining the input schema for elements_to_state_vector. Fields: semi_major_axis_m, eccentricity, inclination_deg, raan_deg, arg_periapsis_deg, true_anomaly_deg, epoch_utc.
@dataclass class OrbitElements: """Classical (Keplerian) orbital elements. The six classical orbital elements uniquely define a two-body conic orbit and the position of a body along that orbit at a given epoch. Attributes: semi_major_axis_m: Semi-major axis *a* (m). Defines orbit size. eccentricity: Eccentricity *e* (dimensionless, 0 = circle, <1 = ellipse). inclination_deg: Inclination *i* (degrees). Angle between the orbital plane and the equatorial plane. raan_deg: Right ascension of ascending node *Omega* (degrees). Angle in the equatorial plane from the vernal equinox to the ascending node. arg_periapsis_deg: Argument of periapsis *omega* (degrees). Angle in the orbital plane from the ascending node to periapsis. true_anomaly_deg: True anomaly *nu* (degrees). Angle in the orbital plane from periapsis to the current position. epoch_utc: Reference epoch in ISO-8601 UTC format. """ semi_major_axis_m: float # Semi-major axis (m) eccentricity: float # Eccentricity (dimensionless) inclination_deg: float # Inclination (degrees) raan_deg: float # Right ascension of ascending node (degrees) arg_periapsis_deg: float # Argument of periapsis (degrees) true_anomaly_deg: float # True anomaly (degrees) epoch_utc: str # Epoch in UTC ISO format - StateVector dataclass defining the output schema for elements_to_state_vector. Fields: position_m, velocity_ms, epoch_utc, frame (default 'J2000').
@dataclass class StateVector: """Cartesian position and velocity state vector in an inertial frame. Attributes: position_m: Position vector [x, y, z] in meters. velocity_ms: Velocity vector [vx, vy, vz] in m/s. epoch_utc: Reference epoch in ISO-8601 UTC format. frame: Reference frame identifier (default ``"J2000"``). """ position_m: list[float] # Position vector [x, y, z] in meters velocity_ms: list[float] # Velocity vector [vx, vy, vz] in m/s epoch_utc: str # Epoch in UTC ISO format frame: str = "J2000" # Reference frame - aerospace_mcp/fastmcp_server.py:217-217 (registration)Registration of elements_to_state_vector as an MCP tool via mcp.tool() in the FastMCP server.
mcp.tool(elements_to_state_vector)