186 lines
7.2 KiB
Rust
186 lines
7.2 KiB
Rust
//! 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,
|
||
)
|
||
}
|