apsis-rs/crates/orbit/apsis-kepler/src/anomaly.rs

186 lines
7.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Conversions between the three anomalies.
//!
//! An anomaly is an angle that measures how far a satellite has travelled
//! around its orbit. The three forms used here are:
//!
//! - The true anomaly, the angle from perigee to the satellite as seen from
//! the focus where the central body sits. It is the only one with a direct
//! geometric meaning.
//! - The eccentric anomaly, the angle from perigee to the projection of the
//! satellite onto the auxiliary circle of the ellipse, as seen from the
//! center of the ellipse.
//! - The mean anomaly, a linear function of time that is proportional to the
//! area swept since perigee. It has no direct geometric meaning, but it is
//! the form in which an orbit propagates in time.
//!
//! Kepler's equation relates the mean and eccentric anomalies and has no
//! closed form solution. It is solved here by Newton's method from a
//! starting guess that is accurate enough to converge in a few iterations
//! for every eccentricity below one.
//!
//! All angles are in radians. The functions reduce their results into
//! `[-pi, pi)` so that a value is comparable without further wrapping.
//!
//! 三种近点角之间的换算。
//!
//! 近点角是度量卫星绕其轨道走了多远的角。此处所用的三种形式是:
//!
//! - 真近点角,自近地点到卫星的角,从中心天体所在的焦点看。它是唯一具有
//! 直接几何意义者。
//! - 偏近点角,自近地点到卫星在椭圆辅助圆上的投影的角,从椭圆中心看。
//! - 平近点角,时间的线性函数,与自近地点起扫过的面积成正比。它没有直接的
//! 几何意义,但它是轨道随时间传播所采用的形式。
//!
//! 开普勒方程联系平近点角与偏近点角,且没有闭式解。此处用牛顿法求解,其
//! 初值足够准确,对小于一的每个偏心率都能在几次迭代内收敛。
//!
//! 所有角度都以弧度计。各函数把结果归约到 `[-pi, pi)`,使值无需再作环绕即可
//! 比较。
use core::f64::consts::PI;
/// The maximum number of Newton iterations used to solve Kepler's equation.
///
/// 求解开普勒方程所用的 Newton 迭代最大步数。
const MAX_ITERATIONS: usize = 30;
/// The convergence tolerance of the Newton iteration, in radians.
///
/// Newton 迭代的收敛容差,单位为弧度。
const TOLERANCE: f64 = 1e-14;
/// Reduces an angle into `[-pi, pi)`.
///
/// 把角度归约到 `[-pi, pi)`。
pub fn wrap_to_pi(angle: f64) -> f64 {
let wrapped = (angle + PI).rem_euclid(2.0 * PI) - PI;
// `rem_euclid` can return exactly pi for an input just below pi, which
// the half-open interval excludes.
// 对略小于 pi 的输入,`rem_euclid` 可能恰好返回 pi,而半开区间不含该端点。
if wrapped >= PI {
wrapped - 2.0 * PI
} else {
wrapped
}
}
/// Returns the true anomaly for an eccentric anomaly and eccentricity.
///
/// The relation follows from the geometry of the auxiliary circle:
///
/// ```text
/// tan(nu / 2) = sqrt((1 + e) / (1 - e)) tan(E / 2)
/// ```
///
/// The half angle form is used rather than the direct cosine relation so
/// that the result is correct in all four quadrants without a quadrant
/// check.
///
/// 由偏近点角与偏心率返回真近点角。
///
/// 该关系来自辅助圆的几何性质:
///
/// ```text
/// tan(nu / 2) = sqrt((1 + e) / (1 - e)) tan(E / 2)
/// ```
///
/// 采用半角形式而非直接的余弦关系,使结果在四个象限中都正确,无需判别象限。
pub fn true_from_eccentric(eccentric_anomaly: f64, eccentricity: f64) -> f64 {
let half = eccentric_anomaly / 2.0;
let factor = ((1.0 + eccentricity) / (1.0 - eccentricity)).sqrt();
wrap_to_pi(2.0 * (factor * half.tan()).atan())
}
/// Returns the eccentric anomaly for a true anomaly and eccentricity.
///
/// This is the inverse of [`true_from_eccentric`].
///
/// 由真近点角与偏心率返回偏近点角。
///
/// 这是 [`true_from_eccentric`] 的逆运算。
pub fn eccentric_from_true(true_anomaly: f64, eccentricity: f64) -> f64 {
let half = true_anomaly / 2.0;
let factor = ((1.0 - eccentricity) / (1.0 + eccentricity)).sqrt();
wrap_to_pi(2.0 * (factor * half.tan()).atan())
}
/// Returns the eccentric anomaly for a mean anomaly and eccentricity.
///
/// This solves Kepler's equation
///
/// ```text
/// M = E - e sin E
/// ```
///
/// by Newton's method. The starting guess is the mean anomaly plus a term
/// proportional to the eccentricity, which keeps the iteration stable for
/// eccentricities approaching one. The iteration always terminates, and the
/// result is the value reached after at most a fixed number of steps.
///
/// 由平近点角与偏心率返回偏近点角。
///
/// 用 Newton 法求解开普勒方程
///
/// ```text
/// M = E - e sin E
/// ```
///
/// 初值取平近点角加上一个正比于偏心率的项,使迭代在偏心率趋近一时保持稳定。
/// 迭代总会终止,结果是至多固定步数后达到的值。
pub fn eccentric_from_mean(mean_anomaly: f64, eccentricity: f64) -> f64 {
let mean = wrap_to_pi(mean_anomaly);
// A first order correction to the circular guess.
// 对圆轨道猜测的一阶修正。
let mut eccentric = mean + eccentricity * mean.sin() * (1.0 + eccentricity * mean.cos());
for _ in 0..MAX_ITERATIONS {
let residual = eccentric - eccentricity * eccentric.sin() - mean;
let derivative = 1.0 - eccentricity * eccentric.cos();
if derivative.abs() < f64::MIN_POSITIVE {
break;
}
let step = residual / derivative;
eccentric -= step;
if step.abs() < TOLERANCE {
break;
}
}
wrap_to_pi(eccentric)
}
/// Returns the mean anomaly for an eccentric anomaly and eccentricity.
///
/// This is Kepler's equation evaluated directly, `M = E - e sin E`.
///
/// 由偏近点角与偏心率返回平近点角。
///
/// 这是直接求值的开普勒方程,`M = E - e sin E`。
pub fn mean_from_eccentric(eccentric_anomaly: f64, eccentricity: f64) -> f64 {
wrap_to_pi(eccentric_anomaly - eccentricity * eccentric_anomaly.sin())
}
/// Returns the mean anomaly for a true anomaly and eccentricity.
///
/// The true anomaly is first converted to the eccentric anomaly, and the
/// mean anomaly then follows from Kepler's equation. Going through the
/// eccentric anomaly avoids the separate closed form for the swept area and
/// keeps a single expression responsible for the relation.
///
/// 由真近点角与偏心率返回平近点角。
///
/// 先把真近点角转为偏近点角,再由开普勒方程得平近点角。绕经偏近点角避免了
/// 另立扫过面积的闭式解,使该关系只由一个表达式负责。
pub fn mean_from_true(true_anomaly: f64, eccentricity: f64) -> f64 {
let eccentric_anomaly = eccentric_from_true(true_anomaly, eccentricity);
mean_from_eccentric(eccentric_anomaly, eccentricity)
}
/// Returns the true anomaly for a mean anomaly and eccentricity.
///
/// 由平近点角与偏心率返回真近点角。
pub fn true_from_mean(mean_anomaly: f64, eccentricity: f64) -> f64 {
true_from_eccentric(
eccentric_from_mean(mean_anomaly, eccentricity),
eccentricity,
)
}