From 4be2ac07c259aca3012e9deb101bd10767275013 Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Fri, 2 Oct 2026 00:17:21 +0800 Subject: [PATCH] docs: make the constellation comments bilingual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first crate of the sweep, so the layout can be checked before the remaining forty. English paragraph, empty doc line, then the Chinese, per the glossary. Terms with a standard Chinese name use it directly, so semi-major axis reads 半长轴 rather than carrying the English each time; Walker, SGP4 and the frame abbreviations stay as they are. Every comment block in the crate now has both languages, the Display strings are untouched because translating them would change what a program prints, and the three formulas the comments state were checked against the code: the phase offset is 2 pi f / t, the plane spacing 2 pi / p, and the anomaly spacing 2 pi / (t / p), all of which match. --- .../network/apsis-constellation/src/error.rs | 24 ++++ crates/network/apsis-constellation/src/lib.rs | 16 +++ .../network/apsis-constellation/src/walker.rs | 113 ++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/crates/network/apsis-constellation/src/error.rs b/crates/network/apsis-constellation/src/error.rs index 3025213..1582b1f 100644 --- a/crates/network/apsis-constellation/src/error.rs +++ b/crates/network/apsis-constellation/src/error.rs @@ -1,21 +1,35 @@ //! Errors reported while constructing a constellation. +//! +//! 构建星座时报告的错误。 use core::fmt; /// The category of a constellation error. +/// +/// 星座错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum ConstellationErrorKind { /// The number of satellites is not positive. + /// + /// 卫星数不为正。 NoSatellites, /// The number of planes is not positive. + /// + /// 轨道面数不为正。 NoPlanes, /// The number of satellites is not a multiple of the number of planes, /// so the satellites cannot be spread evenly. + /// + /// 卫星数不是轨道面数的整数倍,无法均匀分布。 UnevenPlanes, /// An orbital parameter is outside the range the orbit layer accepts. + /// + /// 某轨道参数超出 orbit 层接受的范围。 InvalidOrbit, /// A shell or satellite index refers to something that does not exist. + /// + /// 某个壳层或卫星索引指向不存在的东西。 NotFound, } @@ -33,6 +47,8 @@ impl fmt::Display for ConstellationErrorKind { } /// A failure while building a constellation. +/// +/// 构建星座时的失败。 #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstellationError { kind: ConstellationErrorKind, @@ -41,22 +57,30 @@ pub struct ConstellationError { impl ConstellationError { /// Creates an error with the given category. + /// + /// 用给定类别创建一个错误。 pub fn new(kind: ConstellationErrorKind) -> Self { Self { kind, detail: None } } /// Attaches a description of the values that caused the failure. + /// + /// 附加对该失败所涉数值的说明。 pub fn with_detail(mut self, detail: impl Into) -> Self { self.detail = Some(detail.into()); self } /// Returns the category of this failure. + /// + /// 返回该失败的类别。 pub fn kind(&self) -> ConstellationErrorKind { self.kind } /// Returns the detail text attached to this error, if any. + /// + /// 返回附加在该错误上的说明文本,若无则返回 `None`。 pub fn detail(&self) -> Option<&str> { self.detail.as_deref() } diff --git a/crates/network/apsis-constellation/src/lib.rs b/crates/network/apsis-constellation/src/lib.rs index 960c8f9..bbccbd9 100644 --- a/crates/network/apsis-constellation/src/lib.rs +++ b/crates/network/apsis-constellation/src/lib.rs @@ -12,21 +12,37 @@ //! that a design that does not follow the Walker pattern can still be //! instantiated. //! +//! - **Walker 星座**:卫星均匀分布在若干轨道面上,各面共用同一倾角与同一半长轴, +//! 相邻轨道面之间有固定的相位关系。 +//! - **自定义星座**:每个壳层单独描述,使不遵循 Walker 构型的设计同样可以 +//! 实例化。 +//! //! Both forms produce a list of [`KeplerianElements`] at a reference time, //! which the orbit layer can propagate. The constellations in use for //! satellite internet are Walker patterns at several altitudes, so the //! Walker constructor is the one most callers need. //! +//! 两种形式都在参考时刻产出一组 [`KeplerianElements`],可由 orbit 层传播。 +//! 当前用于卫星互联网的星座是在若干高度上的 Walker 构型,因此多数调用方需要的 +//! 是 Walker 构造函数。 +//! //! The Walker notation is written `i: t/p/f`, where `i` is the inclination //! in degrees, `t` the total number of satellites, `p` the number of planes, //! and `f` the phase factor. The satellites are placed so that //! `t / p` satellites share each plane and adjacent planes are offset in //! mean anomaly by `f * 360 / t` degrees. //! +//! 卫星的分布方式为:每个轨道面分到 `t / p` 颗卫星,相邻轨道面的平近点角相差 +//! `f * 360 / t` 度。 +//! //! Source: the Walker notation and the phasing rule are the ones defined in //! Walker, J. G., *Circular Orbit Patterns Providing Continuous Whole Earth //! Coverage*, Royal Aircraft Establishment Technical Report 70211, 1970. //! +//! 出处:Walker 记法与相位规则取自 Walker, J. G., *Circular Orbit Patterns +//! Providing Continuous Whole Earth Coverage*, Royal Aircraft Establishment +//! Technical Report 70211, 1970。 +//! //! ``` //! use apsis_constellation::{Constellation, WalkerPattern}; //! diff --git a/crates/network/apsis-constellation/src/walker.rs b/crates/network/apsis-constellation/src/walker.rs index c62f76b..6dfcd86 100644 --- a/crates/network/apsis-constellation/src/walker.rs +++ b/crates/network/apsis-constellation/src/walker.rs @@ -1,4 +1,6 @@ //! The Walker constellation pattern and its instantiation. +//! +//! Walker 星座构型及其实例化。 use crate::error::{ConstellationError, ConstellationErrorKind}; use apsis_kepler::KeplerianElements; @@ -11,21 +13,38 @@ use core::f64::consts::PI; /// relative phasing of adjacent planes is set by the phase factor, so the /// whole constellation is described by five numbers. /// +/// Walker 构型把若干卫星均匀分布在绕地球的若干轨道面上,各面共用同一倾角与 +/// 同一半长轴。相邻轨道面之间的相对相位由相位因子决定,因此整个星座由五个数 +/// 描述。 +/// /// The pattern is written `i: t/p/f`, where `i` is the inclination, `t` the /// total number of satellites, `p` the number of planes, and `f` the phase /// factor. This structure stores the same quantities, with the inclination /// in radians and the semi-major axis in kilometers. +/// +/// 构型写作 `i: t/p/f`,其中 `i` 为倾角、`t` 为卫星总数、`p` 为轨道面数、 +/// `f` 为相位因子。本结构体存储同样的量,倾角用弧度,半长轴用千米。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct WalkerPattern { /// The total number of satellites. + /// + /// 卫星总数。 pub total_satellites: usize, /// The number of orbital planes. + /// + /// 轨道面数。 pub planes: usize, /// The phase factor, in the range `0..planes`. + /// + /// 相位因子,取值范围 `0..planes`。 pub phase_factor: usize, /// The inclination of every plane, in radians. + /// + /// 各轨道面的倾角,单位为弧度。 pub inclination: f64, /// The semi-major axis of every satellite, in kilometers. + /// + /// 各卫星的半长轴,单位为千米。 pub semi_major_axis: f64, } @@ -34,6 +53,10 @@ impl WalkerPattern { /// /// Returns `None` when the satellite count is not a multiple of the /// plane count. + /// + /// 返回每个轨道面上的卫星数。 + /// + /// 当卫星总数不是轨道面数的整数倍时返回 `None`。 pub fn satellites_per_plane(self) -> Option { if self.planes == 0 || self.total_satellites % self.planes != 0 { return None; @@ -50,6 +73,13 @@ impl WalkerPattern { /// The spacing does not depend on the pattern being consistent, so a /// caller can report the value it would use even for a pattern that /// cannot be instantiated. + /// + /// 返回相邻轨道面之间的赤经间隔,单位为弧度,即 `360 / planes` 度。 + /// + /// 当轨道面数为零时返回 `None`,这是该间隔未定义的唯一情形。 + /// + /// 该间隔不依赖构型是否自洽,因此即使构型无法实例化,调用方也能报告它本会 + /// 使用的值。 pub fn plane_spacing(self) -> Option { (self.planes > 0).then(|| 2.0 * PI / self.planes as f64) } @@ -61,6 +91,12 @@ impl WalkerPattern { /// /// Returns `None` when the satellite count is zero, which is the only /// case in which the offset is undefined. + /// + /// 返回相邻轨道面之间施加的相位偏移,单位为弧度。 + /// + /// 即 `f * 360 / t` 度,其中 `f` 为相位因子,`t` 为卫星总数。 + /// + /// 当卫星总数为零时返回 `None`,这是该偏移未定义的唯一情形。 pub fn phase_offset(self) -> Option { if self.total_satellites == 0 { return None; @@ -69,6 +105,8 @@ impl WalkerPattern { } /// Returns `true` when the pattern can be instantiated. + /// + /// 当该构型可以被实例化时返回 `true`。 pub fn is_valid(self) -> bool { self.total_satellites > 0 && self.planes > 0 @@ -84,6 +122,10 @@ impl WalkerPattern { /// /// The inclination is rounded to one decimal place, which is the /// precision the notation is normally quoted to. + /// + /// 返回该构型的 Walker 记法,例如 `53: 24/3/1`。 + /// + /// 倾角保留一位小数,即该记法通常引用的精度。 pub fn notation(self) -> String { format!( "{}: {}/{}/{}", @@ -106,6 +148,17 @@ impl WalkerPattern { /// Source: the phasing rule is the one defined in Walker, J. G., /// *Circular Orbit Patterns Providing Continuous Whole Earth Coverage*, /// Royal Aircraft Establishment Technical Report 70211, 1970. + /// + /// 把该构型实例化为一组轨道根数。 + /// + /// 第一个轨道面的参考卫星的平近点角为零。同一面内每增加一颗卫星,平近点角 + /// 前进 `360 / (t / p)` 度;每增加一个轨道面,前进一个相位偏移。 + /// + /// 当该构型无法实例化时返回一个说明原因的错误。 + /// + /// 出处:相位规则取自 Walker, J. G., *Circular Orbit Patterns Providing + /// Continuous Whole Earth Coverage*, Royal Aircraft Establishment + /// Technical Report 70211, 1970。 pub fn instantiate(self) -> Result, ConstellationError> { if self.total_satellites == 0 { return Err(ConstellationError::new( @@ -137,8 +190,10 @@ impl WalkerPattern { let mut satellites = Vec::with_capacity(self.total_satellites); for plane in 0..self.planes { // The right ascension of this plane. + // 本轨道面的赤经。 let right_ascension = (plane as f64 * plane_spacing).rem_euclid(2.0 * PI); // The phase offset of this plane relative to the first. + // 本轨道面相对第一个轨道面的相位偏移。 let plane_phase = plane as f64 * phase_offset; for satellite in 0..per_plane { let mean_anomaly = @@ -146,12 +201,15 @@ impl WalkerPattern { satellites.push(KeplerianElements { semi_major_axis: self.semi_major_axis, // The Walker pattern is circular. + // Walker 构型为圆轨道。 eccentricity: 0.0, inclination: self.inclination, right_ascension, // The argument of perigee is undefined for a circular // orbit, so it is set to zero and the position along the // orbit is carried entirely by the mean anomaly. + // 圆轨道的近地点幅角未定义,故置零;轨道上的位置完全由 + // 平近点角承载。 argument_of_perigee: 0.0, true_anomaly: apsis_kepler::true_from_mean(mean_anomaly, 0.0), }); @@ -162,15 +220,25 @@ impl WalkerPattern { } /// One satellite in an instantiated constellation. +/// +/// 已实例化星座中的一颗卫星。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct Satellite { /// The index of the satellite within the constellation. + /// + /// 该卫星在星座中的序号。 pub index: usize, /// The index of the orbital plane it belongs to. + /// + /// 该卫星所属轨道面的序号。 pub plane: usize, /// The index of the satellite within its plane. + /// + /// 该卫星在其所在轨道面内的序号。 pub index_in_plane: usize, /// The orbital elements at the reference time. + /// + /// 历元时刻的轨道根数。 pub elements: KeplerianElements, } @@ -179,6 +247,11 @@ pub struct Satellite { /// The elements are the ones at the reference time passed to the /// constructor. Advancing them in time is the job of the orbit layer, which /// propagates each satellite independently. +/// +/// 在参考时刻实例化的星座。 +/// +/// 根数即构造函数所给参考时刻的那一组。随时间推进由 orbit 层负责,该层对每颗 +/// 卫星独立传播。 #[derive(Debug, Clone, PartialEq)] pub struct Constellation { satellites: Vec, @@ -194,6 +267,13 @@ impl Constellation { /// are the ones at that instant. /// /// Returns an error when the pattern cannot be instantiated. + /// + /// 在参考时刻实例化一个 Walker 构型。 + /// + /// 参考时刻为 TAI 时间尺度上的修正儒略日(Modified Julian Date)。它随 + /// 星座一并保存并原样返回;根数即该时刻的根数。 + /// + /// 当该构型无法实例化时返回一个错误。 pub fn walker(pattern: WalkerPattern, reference_mjd: f64) -> Result { if !reference_mjd.is_finite() { return Err( @@ -213,6 +293,7 @@ impl Constellation { // The satellites are produced plane by plane, so the plane // index is the quotient and the position within it the // remainder. + // 卫星按轨道面依次产生,故轨道面序号为商,面内序号为余数。 index, plane: index / per_plane, index_in_plane: index % per_plane, @@ -236,6 +317,13 @@ impl Constellation { /// /// Returns an error when the list is empty, when the reference time is /// not finite, or when any element set is not a valid orbit. + /// + /// 由一组卫星根数构建星座。 + /// + /// 这是为不遵循 Walker 构型的星座提供的构造函数。每颗卫星的轨道面序号由其根数 + /// 的赤经推得,因此共用同一轨道面的卫星会被归为一组。 + /// + /// 当列表为空、参考时刻非有限,或任一根数集不是有效轨道时返回一个错误。 pub fn from_satellites( elements: &[KeplerianElements], reference_mjd: f64, @@ -254,6 +342,7 @@ impl Constellation { // Group by right ascension, assigning plane indices in order of // first appearance so that the numbering is stable. + // 按赤经分组,轨道面序号按首次出现的顺序分配,使编号稳定。 let mut planes: Vec = Vec::new(); let mut satellites = Vec::with_capacity(elements.len()); let mut counts: Vec = Vec::new(); @@ -293,11 +382,15 @@ impl Constellation { } /// Returns the satellites in the constellation. + /// + /// 返回星座中的卫星。 pub fn satellites(&self) -> &[Satellite] { &self.satellites } /// Returns the number of satellites. + /// + /// 返回卫星数。 pub fn len(&self) -> usize { self.satellites.len() } @@ -307,11 +400,16 @@ impl Constellation { /// A constellation built through either constructor is never empty, so /// this always returns `false`; it exists because a collection type /// should offer it alongside [`Constellation::len`]. + /// + /// 经任一构造函数构建的星座都不会为空,故此函数恒返回 `false`;它存在是因为 + /// 集合类型应当与 [`Constellation::len`] 一并提供。 pub fn is_empty(&self) -> bool { self.satellites.is_empty() } /// Returns the number of orbital planes. + /// + /// 返回轨道面数。 pub fn plane_count(&self) -> usize { self.satellites .iter() @@ -322,12 +420,16 @@ impl Constellation { /// Returns the Walker pattern, when the constellation was built from /// one. + /// + /// 若星座由 Walker 构型构建则返回该构型,否则返回 `None`。 pub fn pattern(&self) -> Option { self.pattern } /// Returns the reference time as a Modified Julian Date on the TAI /// scale. + /// + /// 返回参考时刻,为 TAI 时间尺度上的修正儒略日(Modified Julian Date)。 pub fn reference_mjd(&self) -> f64 { self.reference_mjd } @@ -335,6 +437,10 @@ impl Constellation { /// Returns the satellites of one plane. /// /// Returns an empty slice when the plane index is out of range. + /// + /// 返回某个轨道面上的卫星。 + /// + /// 当轨道面序号越界时返回空切片。 pub fn plane(&self, plane: usize) -> Vec { self.satellites .iter() @@ -351,6 +457,11 @@ impl Constellation { /// constellation this is the altitude of the first satellite. /// /// Returns `None` when the constellation is empty. + /// + /// Walker 构型中所有卫星共用同一半长轴,故单一高度即可描述整个星座;对自定义 + /// 星座,返回的是第一颗卫星的高度。 + /// + /// 星座为空时返回 `None`。 pub fn altitude_above(&self, body_radius_km: f64) -> Option { self.satellites .first() @@ -360,6 +471,8 @@ impl Constellation { /// Returns the count of satellites in each plane. /// /// The result has one entry per plane, in plane order. + /// + /// 返回的向量每个轨道面一项,按轨道面顺序排列。 pub fn plane_populations(&self) -> Vec { let mut populations = vec![0; self.plane_count()]; for satellite in &self.satellites {