Frames and sign conventions
In short
- What it models: the directions and signs the whole simulator shares: a frame fixed to the Earth at its center, the launch-site frame (east, north, up), the rocket’s body frame and its angle to the airflow, and its attitude (which way it points) and launch angles.
- Sources: the WGS 84 standard, NGA.STND.0036 (2014), as in Geodesy; J. Solà, Quaternion kinematics for the error-state Kalman filter (2017); RocketPy 1.13.0, for its launch-angle convention.
- How well it is validated: unit tests, and one check against another simulator: for 8 rail setups, launch angles give RocketPy’s starting attitude to 1e-12 rad. Over 1e6 integration steps, attitude stays within 1e-9 rad of the exact answer. No real-flight check.
- What it leaves out: heights are above the WGS 84 ellipsoid, not sea level; the two are up to about 100 m apart. The attitude equations leave out the Earth’s rotation rate, 7.3e-5 rad/s, which is tiny next to a rocket’s pitch rates (ADR-011, the rigid-body flight decision).
Code and sources
This is the single definition of the frames, and every crate follows it. Code:
hpr_core::{geodesy, frames, attitude}. ADR-003, the frames and gravity decision,
records why these choices were made.
Units and angles
- SI throughout: meters, seconds, kilograms, radians. Degrees exist only at I/O boundaries
(
Geodetic::from_degrees). - Every rotation is right-handed.
R_x(θ),R_y(θ)andR_z(θ)turn vectors by+θabout the named axis (active rotations).
Earth-centered Earth-fixed (ECEF)
The WGS 84 conventional terrestrial frame:
- origin at the Earth’s center of mass;
+Zalong the rotation axis toward the north pole;+Xthrough the prime meridian at the equator;+Ycompletes the right-handed set (90° E).
A geodetic position (φ, λ, h) gives the latitude φ (positive north, in [−π/2, π/2]),
the longitude λ (positive east), and the height h above the ellipsoid along its normal.
h is ellipsoidal height, not height above mean sea level. The two differ by the geoid
undulation N (h = H + N, with |N| up to about 100 m). Inputs quoted above sea level must be
converted before use. hpr has no geoid model, so a flight takes N at the launch site as an input;
Atmosphere shows where it is used.
Launch frame L (East-North-Up)
-
Origin: the launch site’s geodetic position
(φ₀, λ₀, h₀), at the pad on the ground. -
Axes:
x_Least,y_Lnorth,z_Lup along the ellipsoid normal at the origin. -
To ECEF:
r_ECEF = r₀ + R r_L. The columns ofRare, in ECEF components:ê = (−sin λ₀, cos λ₀, 0) n̂ = (−sin φ₀ cos λ₀, −sin φ₀ sin λ₀, cos φ₀) û = (cos φ₀ cos λ₀, cos φ₀ sin λ₀, sin φ₀) -
Earth-fixed, so non-inertial. It turns with the Earth at
Ω = ω (0, cos φ₀, sin φ₀)inLcomponents, withω = 7.292115e-5 rad/s. The translational equations inLadd the Coriolis term−2Ω × v. The centrifugal term is already inside normal gravity and must not be added again (Gravity). -
z_Lis not altitude.Lis a tangent plane, so a point atz_L = 0at horizontal distancedfrom the pad is aboutd²/(2R)above the ellipsoid: 7.8 m at 10 km. Height above the ellipsoid comes fromLaunchFrame::geodetic_from_enu. The flight engine detects apogee and ground contact with that height, not withz_L(Rigid-body flight, Loft lesson L35).
Body frame B
- Origin: the nose tip, on the axis (ADR-007, the design-tree decision). Positions in mass properties are measured from it.
- Axes:
z_Blies along the axis of symmetry, positive toward the nose.x_Bis the design’s zero radial direction, the angle from which fins, rail buttons and lugs are placed.y_B = z_B × x_B. - Thrust of a motor aligned with the axis acts along
+z_B. - Design stations measured aft from the nose tip, as design files state them, map to
z_B = z_ref − swithz_ref = 0, soz_B = −sand the whole rocket lies atz_B ≤ 0(Design tree).
Aerodynamic angles
- Angle of attack
α: the total angle between+z_Band the rocket’s velocity relative to the air, in[0, π]. - Flow roll
φ: the direction in which the air crosses the body, measured in thex_B–y_Bplane fromx_Btowardy_B. Finkof a set sits atΛ_k = θ₀ + 2πk/N − φfrom the lateral airflow, withθ₀the set’s base angle. - Force directions. With
ŵ = (cos φ, sin φ, 0)the lateral air direction inB, the normal and side forces areq A_ref (C_N ŵ + C_Y (z_B × ŵ)):C_Nis positive alongŵ, the way the crossing air pushes the body, andC_Yis across the flow’s plane (Aerodynamics). The axial force is−q A_ref C_A z_B:C_Ais positive when the flow meets the nose and drag pushes toward the tail, and negative pastα = 90°, when the rocket moves tail first. - Rolling moment.
q A_ref d C_labout+z_B, right-handed, withdthe reference diameter: positive turnsx_Btowardy_B. A fin set’s positive cant turns fin 0’s (the fin along+x_B) leading edge toward−y_B, so it turns the rocket about−z_B, clockwise seen from ahead of the nose, and the roll ratep = ω_zsettles negative (Roll: forcing and damping).
Attitude
The attitude is a unit Hamilton quaternion q (glam DQuat, stored x, y, z, w) that maps
body components to launch-frame components:
v_L = q ⊗ v_B ⊗ q* (glam: q.mul_vec3(v_B))
qand−qare the same attitude.- The body angular velocity
ω_Bis the rate ofBrelative toL, inBcomponents. - The kinematics are
q̇ = ½ q ⊗ (0, ω_B)(Solà 2017, eq. 200). The integrator renormalizesqafter every step (attitude::renormalize). Litself turns atΩ(above), soω_Bdiffers from the inertial rate byR(q)ᵀ Ω, at most 7.3e-5 rad/s. The flight engine’s rotational equations leave that term out (ADR-011, the rigid-body flight decision).
Launch angles
Launch-rail-style angles describe the attitude for input and output (frames::LaunchAngles):
- azimuth
A: the heading of the body axis, clockwise from true north (π/2is east), in[0, 2π); - elevation
E: the angle of the body axis above the horizon (π/2is vertical), in[−π/2, π/2]; - roll
φ: the turn aboutz_B, in(−π, π].
q = R_z(−A) ⊗ R_x(E − π/2) ⊗ R_z(φ)
z_B in L = (sin A cos E, cos A cos E, sin E)
- Zero roll.
x_Bis horizontal, to the right of the heading:(cos A, −sin A, 0)inL.y_Bis(sin E sin A, sin E cos A, −cos E). - Vertical singularity. At
E = ±π/2,Aandφturn about the same axis.LaunchAngles::from_quaternionthen reportsA = 0and puts the whole turn intoφ. This is for reporting only: the state is always the quaternion. - RocketPy correspondence. This is RocketPy’s 3-1-3 convention:
Ais the heading andEthe inclination.φis the rail-button angular position for atail_to_noserocket, and 2π minus it for anose_to_tailrocket.- RocketPy 1.13.0 sets precession
ψ = −heading, nutationθ = inclination − 90°and spinφ, then buildsq = q_z(ψ) q_x(θ) q_z(φ)(rocketpy/simulation/flight.py:1557-1579,rocketpy/tools.pyeuler313_to_quaternions). validation/oracles/rocketpy/attitude.pybuilds real RocketPy flights for 8 rail setups, with both orientations, and records the initiale0…e3.frames::tests::launch_angles_match_the_rocketpy_oraclechecks thatq(w, x, y, z) is the same attitude to 1e-12 rad.- RocketPy’s body
+zalso points toward the nose.
Tests that pin this
hpr_core::geodesy::tests:- geodetic → ECEF → geodetic, from −10 km to 1000 km;
- ECEF → geodetic → ECEF, from 6250 km to 46,000 km from the center;
- axis points, the sphere limit, and the ENU rotation being proper with
ûnormal to the ellipsoid.
hpr_core::frames::tests:- angles → quaternion → angles (off vertical), and quaternion → angles → quaternion (everywhere, exactly vertical included);
- ENU ↔ ECEF ↔ geodetic round trips for sites anywhere, within 2000 km and up to 1000 km high;
- named attitudes, and the tangent-plane rise
d²/(2N).
hpr_core::attitude::tests: the kinematic equation checked against a closed-form coning motion, and norm drift ≤ 1e-12 over 1e6 RK4 steps with attitude error < 1e-9 rad.