Kepler and Lambert¶
Two-body tools that need no data files. The Keplerian Elements and Lambert's Problem guides cover the conventions and algorithms; this page shows the Rust API.
Keplerian elements: kepler::Kepler¶
Kepler holds the semi-major axis a (m), eccentricity eccen, inclination incl, RAAN raan, argument of periapsis argp and true anomaly nu (radians), and the gravitational parameter mu (Earth by default; with_mu / from_pv_with_mu for another body). Construct it with:
Kepler::try_new(a, e, i, raan, argp, anomaly), which validates the elements and returnskepler::Error::InvalidElementfor one out of its domain, orKepler::new, which does not;anomalyisAnomaly::True,Anomaly::MeanorAnomaly::Eccentric;Kepler::from_pv(r, v)from an inertial position and velocity (elliptical orbits only).
to_pv() returns the Cartesian state, propagate(&dt) moves the anomaly along a two-body orbit, and the derived quantities are methods: period(), mean_motion(), mean_anomaly(), eccentric_anomaly(), periapsis(), apoapsis(), semiparameter(), specific_energy(), angular_momentum(), flight_path_angle(), argument_of_latitude(), true_longitude(). SatState::from_kepler starts a numerical propagation from elements.
Lambert's problem: lambert::lambert¶
lambert(&r1, &r2, tof, mu, prograde) returns the departure and arrival velocities of every transfer from r1 to r2 in tof seconds, using Izzo's algorithm: the zero-revolution solution first, then a short- and long-period pair per revolution count that fits in the time of flight. prograde picks the transfer direction (angular momentum along +z or −z). Out-of-domain input returns a lambert::Error.
Example¶
//! Keplerian elements, two-body propagation, and Lambert targeting.
//!
//! Runs offline with no data files.
//!
//! ```text
//! cargo run --example kepler_lambert
//! ```
use satkit::consts::{EARTH_RADIUS, MU_EARTH};
use satkit::kepler::{Anomaly, Kepler};
use satkit::lambert::lambert;
use satkit::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Elements: a (m), e, i, RAAN, argument of perigee (radians), anomaly
let k = Kepler::try_new(
7000.0e3,
0.001,
98.0_f64.to_radians(),
45.0_f64.to_radians(),
0.0,
Anomaly::Mean(30.0_f64.to_radians()),
)?;
println!(
"a = {:.1} km, period = {:.2} min, perigee alt = {:.1} km",
k.a / 1e3,
k.period() / 60.0,
(k.periapsis() - EARTH_RADIUS) / 1e3
);
// Elements -> Cartesian state (inertial, m and m/s) -> elements
let (r, v) = k.to_pv();
let k2 = Kepler::from_pv(r, v)?;
println!(
"|r| = {:.3} km, |v| = {:.4} km/s, round trip da = {:.1e} m",
r.norm() / 1e3,
v.norm() / 1e3,
(k2.a - k.a).abs()
);
// Two-body propagation by a quarter period
let k3 = k.propagate(&Duration::from_seconds(k.period() / 4.0));
println!(
"mean anomaly after T/4: {:.3} deg (true anomaly {:.3} deg)",
k3.mean_anomaly().to_degrees(),
k3.nu.to_degrees()
);
// Lambert: the transfer from r1 to r2 in a given time of flight, here
// from 7000 km to 12000 km radius, 150 deg further along
let r1 = satkit::Vector3::from_array([7000.0e3, 0.0, 0.0]);
let theta = 150.0_f64.to_radians();
let r2 = satkit::Vector3::from_array([12000.0e3 * theta.cos(), 12000.0e3 * theta.sin(), 0.0]);
let tof = 3900.0;
let solutions = lambert(&r1, &r2, tof, MU_EARTH, true)?;
let (v1, v2) = solutions[0]; // the zero-revolution solution comes first
println!(
"Lambert ({} solution(s)): v1 = {:.1} m/s, v2 = {:.1} m/s",
solutions.len(),
v1,
v2
);
// Check: propagate the departure state and compare with r2
let transfer = Kepler::from_pv(r1, v1)?;
let (r_arrive, _) = transfer.propagate(&Duration::from_seconds(tof)).to_pv();
println!(
"transfer: a = {:.1} km, e = {:.4}, perigee alt = {:.1} km, arrival miss = {:.2e} m",
transfer.a / 1e3,
transfer.eccen,
(transfer.periapsis() - EARTH_RADIUS) / 1e3,
(r_arrive - r2).norm()
);
Ok(())
}
$ cargo run --example kepler_lambert
a = 7000.0 km, period = 97.14 min, perigee alt = 614.9 km
|r| = 6993.940 km, |v| = 7.5526 km/s, round trip da = 3.7e-9 m
mean anomaly after T/4: 120.000 deg (true anomaly 120.099 deg)
Lambert (1 solution(s)): v1 = [644.1, 8451.9, 0.0] m/s, v2 = [-2724.5, -4120.0, 0.0] m/s
transfer: a = 9482.4 km, e = 0.2719, perigee alt = 526.3 km, arrival miss = 1.86e-8 m
See also¶
- Keplerian Elements and Lambert's Problem, with the Keplerian Elements and Lambert Targeting tutorials.
keplerandlamberton docs.rs.