Geodetic Transformations¶
Geodetic longitude, latitude, altitude coordinates represent positions relative to the WGS84 ellipsoidal Earth model. These coordinates can be converted to and from Earth-Centered Earth-Fixed (ECEF) Cartesian coordinates. This coordinate system is more accurate than the geocentric system for near-surface applications because it accounts for Earth's equatorial bulge.
For complete API details, see the Geodetic Coordinates API Reference.
Geodetic Coordinate System¶
Geodetic coordinates represent a position using:
- Longitude (\(\lambda\)): East-west angle from the prime meridian, in degrees [-180°, +180°] or radians \([-\pi, +\pi]\)
- Latitude (\(\varphi\)): North-south angle from the equatorial plane, measured perpendicular to the ellipsoid surface, in degrees [-90°, +90°] or radians [\(-\frac{\pi}{2}\), \(+\frac{\pi}{2}\)]
- Altitude (\(h\)): Height above the WGS84 ellipsoid surface, in meters
Combined as: [longitude, latitude, altitude], often abbreviated as [lon, lat, alt].
Info
Geodetic latitude is measured perpendicular to the ellipsoid surface, not from Earth's center. This differs from geocentric latitude, which is measured from the center. For a point on the surface, these can differ by up to 11 arcminutes (about 0.2°).
WGS84 Ellipsoid Model¶
The key difference between geodetic and geocentric coordinates is the Earth model:
- Geodetic: Earth is an ellipsoid (oblate spheroid) with parameters:
- Semi-major axis:
WGS84_A = 6378137.0meters (equatorial radius) - Flattening:
WGS84_F = 1/298.257223563
- Semi-major axis:
- Geocentric: Earth is a perfect sphere of radius
WGS84_A
The difference between equatorial and polar radii is approximately 21 km, which significantly affects position calculations near Earth's surface.
Converting Geodetic to ECEF¶
Earth-Centered Earth-Fixed (ECEF) is a Cartesian coordinate system with:
- Origin at Earth's center of mass
- X-axis through the intersection of the prime meridian and equator
- Z-axis through the North Pole
- Y-axis completing a right-handed system
You can convert geodetic coordinates to ECEF Cartesian coordinates using the following:
import brahe as bh
import numpy as np
bh.initialize_eop()
# Define a location in geodetic coordinates (WGS84 ellipsoid model)
# Boulder, Colorado (approximately)
lon = -122.4194 # Longitude (deg)
lat = 37.7749 # Latitude (deg)
alt = 16.0 # Altitude above WGS84 ellipsoid (m)
print("Geodetic coordinates (WGS84 ellipsoid model):")
print(f"Longitude: {lon:.4f}° = {np.radians(lon):.6f} rad")
print(f"Latitude: {lat:.4f}° = {np.radians(lat):.6f} rad")
print(f"Altitude: {alt:.1f} m\n")
# Longitude: -122.4194° = -2.136622 rad
# Latitude: 37.7749° = 0.659296 rad
# Altitude: 16.0 m
# Convert geodetic to ECEF Cartesian
geodetic = np.array([lon, lat, alt])
ecef = bh.position_geodetic_to_ecef(geodetic, bh.AngleFormat.DEGREES)
print("ECEF Cartesian coordinates:")
print(f"x = {ecef[0]:.3f} m")
print(f"y = {ecef[1]:.3f} m")
print(f"z = {ecef[2]:.3f} m")
print(f"Distance from Earth center: {np.linalg.norm(ecef):.3f} m\n")
# x = -2706181.627 m
# y = -4261070.165 m
# z = 3885735.291 m
# Distance from Earth center: 6370170.853 m
use brahe as bh;
use nalgebra as na;
fn main() {
bh::initialize_eop().unwrap();
// Define a location in geodetic coordinates (WGS84 ellipsoid model)
// Boulder, Colorado (approximately)
let lon = -122.4194_f64; // Longitude (deg)
let lat = 37.7749_f64; // Latitude (deg)
let alt = 16.0; // Altitude above WGS84 ellipsoid (m)
println!("Geodetic coordinates (WGS84 ellipsoid model):");
println!("Longitude: {:.4}° = {:.6} rad", lon, lon.to_radians());
println!("Latitude: {:.4}° = {:.6} rad", lat, lat.to_radians());
println!("Altitude: {:.1} m\n", alt);
// Expected output:
// Longitude: -122.4194° = -2.136622 rad
// Latitude: 37.7749° = 0.659296 rad
// Altitude: 16.0 m
// Convert geodetic to ECEF Cartesian
let geodetic = na::Vector3::new(lon, lat, alt);
let ecef = bh::position_geodetic_to_ecef(geodetic, bh::AngleFormat::Degrees).unwrap();
println!("ECEF Cartesian coordinates:");
println!("x = {:.3} m", ecef[0]);
println!("y = {:.3} m", ecef[1]);
println!("z = {:.3} m", ecef[2]);
let distance = (ecef[0].powi(2) + ecef[1].powi(2) + ecef[2].powi(2)).sqrt();
println!("Distance from Earth center: {:.3} m", distance);
// Expected output:
// x = -2706181.627 m
// y = -4261070.165 m
// z = 3885735.291 m
// Distance from Earth center: 6370170.853 m
}
Info
The conversion from geodetic to ECEF accounts for the ellipsoidal shape using the radius of curvature in the prime vertical and the first eccentricity of the ellipsoid.
Converting ECEF to Geodetic¶
The reverse transformation converts Cartesian ECEF coordinates back to geodetic coordinates. This requires an iterative algorithm due to the ellipsoidal geometry:
import brahe as bh
import numpy as np
bh.initialize_eop()
# Define a satellite state (convert orbital elements to ECEF state)
epc = bh.Epoch(2024, 1, 1, 0, 0, 0.0, time_system=bh.UTC)
state_oe = np.array(
[
bh.R_EARTH + 500e3, # Semi-major axis (m)
0.0, # Eccentricity
97.8, # Inclination (deg)
15.0, # Right ascension of ascending node (deg)
30.0, # Argument of periapsis (deg)
45.0, # Mean anomaly (deg)
]
)
state_ecef = bh.state_eci_to_ecef(
epc, bh.state_osculating_to_cartesian(state_oe, bh.AngleFormat.DEGREES)
)
print("ECEF Cartesian state [x, y, z, vx, vy, vz] (m, m/s):")
print(f"Position: [{state_ecef[0]:.3f}, {state_ecef[1]:.3f}, {state_ecef[2]:.3f}]")
print(f"Velocity: [{state_ecef[3]:.6f}, {state_ecef[4]:.6f}, {state_ecef[5]:.6f}]\n")
# Position: [-735665.465, -1838913.314, 6586801.432]
# Velocity: [-1060.370171, 7357.551468, 1935.662061]
# Convert ECEF Cartesian to geodetic position
ecef_pos = state_ecef[0:3]
geodetic = bh.position_ecef_to_geodetic(ecef_pos, bh.AngleFormat.DEGREES)
print("Geodetic coordinates (WGS84 ellipsoid model):")
print(f"Longitude: {geodetic[0]:.4f}° = {np.radians(geodetic[0]):.6f} rad")
print(f"Latitude: {geodetic[1]:.4f}° = {np.radians(geodetic[1]):.6f} rad")
print(f"Altitude: {geodetic[2]:.1f} m")
# Longitude: -111.8041° = -1.951350 rad
# Latitude: 73.3622° = 1.280412 rad
# Altitude: 519618.1 m
use brahe as bh;
use nalgebra as na;
fn main() {
bh::initialize_eop().unwrap();
// Define a satellite state (convert orbital elements to ECEF state)
let epc = bh::Epoch::from_datetime(2024, 1, 1, 0, 0, 0.0, 0.0, bh::TimeSystem::UTC);
let state_oe = na::SVector::<f64, 6>::new(
bh::R_EARTH + 500e3, // Semi-major axis (m)
0.0, // Eccentricity
97.8_f64, // Inclination (deg)
15.0_f64, // Right ascension of ascending node (deg)
30.0_f64, // Argument of periapsis (deg)
45.0_f64 // Mean anomaly (deg)
);
let state_eci = bh::state_osculating_to_cartesian(state_oe, bh::AngleFormat::Degrees);
let state_ecef = bh::state_eci_to_ecef(epc, state_eci);
println!("ECEF Cartesian state [x, y, z, vx, vy, vz] (m, m/s):");
println!("Position: [{:.3}, {:.3}, {:.3}]", state_ecef[0], state_ecef[1], state_ecef[2]);
println!("Velocity: [{:.6}, {:.6}, {:.6}]\n", state_ecef[3], state_ecef[4], state_ecef[5]);
// Expected output:
// Position: [-735665.465, -1838913.314, 6586801.432]
// Velocity: [-1060.370171, 7357.551468, 1935.662061]
// Convert ECEF Cartesian to geodetic position
let ecef_pos = na::Vector3::new(state_ecef[0], state_ecef[1], state_ecef[2]);
let geodetic = bh::position_ecef_to_geodetic(ecef_pos, bh::AngleFormat::Degrees);
println!("Geodetic coordinates (WGS84 ellipsoid model):");
println!("Longitude: {:.4}° = {:.6} rad", geodetic[0], geodetic[0].to_radians());
println!("Latitude: {:.4}° = {:.6} rad", geodetic[1], geodetic[1].to_radians());
println!("Altitude: {:.1} m", geodetic[2]);
// Expected output:
// Longitude: -111.8041° = -1.951350 rad
// Latitude: 73.3622° = 1.280412 rad
// Altitude: 519618.1 m
}
Info
The ECEF to geodetic conversion uses an iterative algorithm that typically converges in 3-5 iterations to sub-millimeter precision.
Geodetic vs Geocentric Accuracy¶
For the same longitude, latitude, and altitude values, geodetic and geocentric coordinates produce different ECEF positions. The difference is smallest near the equator and largest near the poles.
For most applications, it's best to use geodetic coordinates since any computational overhead is negligible compared to the improved accuracy near Earth's surface.
See Also¶
- Geodetic Coordinates API Reference - Complete function documentation
- Geocentric Transformations - Simpler spherical Earth model
- Topocentric Transformations - Local horizon coordinate systems