docs: bilingual comments for the dump examples

This commit is contained in:
ApsisRS contributors 2026-10-02 01:52:26 +08:00
parent 1eb7564bde
commit 172ef61c06
15 changed files with 244 additions and 0 deletions

View File

@ -9,6 +9,15 @@
//! higher orbit, where it is large; the equatorial and polar cases; and a //! higher orbit, where it is large; the equatorial and polar cases; and a
//! zero mask, where the footprint reaches the horizon. //! zero mask, where the footprint reaches the horizon.
//! //!
//! 写出本工作区为一组用例计算的覆盖几何。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/constellation/check_coverage.py` 消费,后者从球面三角形
//! 关系重算相同的量并比较。
//!
//! 各用例的选取跨越了有意思的几何:低仰角遮蔽的低轨,其覆盖区相对地球很小;
//! 更高的轨道,其覆盖区很大;赤道与极地情形;以及零遮蔽,其覆盖区直到地平。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -27,15 +36,28 @@ use core::f64::consts::PI;
/// The coverage geometry is spherical, so a single radius is used. The /// The coverage geometry is spherical, so a single radius is used. The
/// value comes from the shared constants rather than being repeated, so a /// value comes from the shared constants rather than being repeated, so a
/// change to the ellipsoid reaches here. /// change to the ellipsoid reaches here.
///
/// WGS 84 赤道半径,单位为千米。
///
/// 覆盖几何是球面的,故只用一个半径。该值来自共享常量而非重复书写,故椭球的
/// 改动会传到这里。
const BODY_RADIUS_KM: f64 = apsis_core::constant::EARTH_EQUATORIAL_RADIUS; const BODY_RADIUS_KM: f64 = apsis_core::constant::EARTH_EQUATORIAL_RADIUS;
/// One coverage case: an orbital radius and an elevation mask. /// One coverage case: an orbital radius and an elevation mask.
///
/// 一个覆盖用例:一个轨道半径与一个仰角遮蔽。
struct Case { struct Case {
/// A name for the case, so a failure in the report is readable. /// A name for the case, so a failure in the report is readable.
///
/// 用例的名称,使报告中的失败可读。
name: &'static str, name: &'static str,
/// The geocentric radius of the satellite, in kilometers. /// The geocentric radius of the satellite, in kilometers.
///
/// 卫星的地心半径,单位为千米。
satellite_radius_km: f64, satellite_radius_km: f64,
/// The elevation mask at the ground point, in degrees. /// The elevation mask at the ground point, in degrees.
///
/// 地面点处的仰角遮蔽,单位为度。
elevation_mask_degrees: f64, elevation_mask_degrees: f64,
} }
@ -44,6 +66,11 @@ struct Case {
/// The satellite radii span a low Earth orbit, two higher altitudes, and a /// The satellite radii span a low Earth orbit, two higher altitudes, and a
/// geostationary one. The masks span the horizon, a typical station mask, and /// geostationary one. The masks span the horizon, a typical station mask, and
/// a strict one. /// a strict one.
///
/// 被检查的各用例。
///
/// 卫星半径跨越低轨、两个更高高度以及一个地球静止轨道。遮蔽跨越地平、典型
/// 地面站遮蔽,以及一个严格遮蔽。
const CASES: &[Case] = &[ const CASES: &[Case] = &[
Case { Case {
name: "leo_low_mask", name: "leo_low_mask",
@ -83,11 +110,19 @@ const CASES: &[Case] = &[
/// is fed back through `earth_central_angle`, so the pair must compose to the /// is fed back through `earth_central_angle`, so the pair must compose to the
/// identity. The angles span zero to a little past the largest footprint the /// identity. The angles span zero to a little past the largest footprint the
/// cases produce. /// cases produce.
///
/// 一组用于反解关系检查的中心角,单位为度。
///
/// 每个都被送入 `elevation_from_central_angle`,其返回的仰角经
/// `earth_central_angle` 送回,故这一对必须合成为恒等。各角从零到略超过各用例
/// 所产生的最大覆盖区。
const CENTRAL_ANGLES_DEGREES: &[f64] = &[0.0, 1.0, 5.0, 15.0, 30.0, 45.0, 60.0, 75.0]; const CENTRAL_ANGLES_DEGREES: &[f64] = &[0.0, 1.0, 5.0, 15.0, 30.0, 45.0, 60.0, 75.0];
fn main() { fn main() {
// The header names every column so that the Python side can read by name // The header names every column so that the Python side can read by name
// rather than by position. // rather than by position.
//
// 表头为每一列命名,使 Python 侧可以按名而非按位置读取。
println!( println!(
"case,satellite_radius_km,body_radius_km,elevation_mask_rad,\ "case,satellite_radius_km,body_radius_km,elevation_mask_rad,\
nadir_rad,central_rad,slant_range_km,footprint_central_rad,\ nadir_rad,central_rad,slant_range_km,footprint_central_rad,\
@ -127,6 +162,8 @@ fn main() {
// The inverse relation, written with its own header so the Python side // The inverse relation, written with its own header so the Python side
// can tell the two blocks apart by the first column. // can tell the two blocks apart by the first column.
//
// 反解关系,带上它自己的表头,使 Python 侧可以按第一列区分两个块。
println!(); println!();
println!("inverse_central_degrees,elevation_rad,round_trip_central_degrees"); println!("inverse_central_degrees,elevation_rad,round_trip_central_degrees");
for degrees in CENTRAL_ANGLES_DEGREES { for degrees in CENTRAL_ANGLES_DEGREES {
@ -134,6 +171,9 @@ fn main() {
// Use the equatorial radius as the satellite radius for the inverse // Use the equatorial radius as the satellite radius for the inverse
// check, so the geometry is the degenerate one where the elevation is // check, so the geometry is the degenerate one where the elevation is
// always zero. A more useful check uses a satellite altitude. // always zero. A more useful check uses a satellite altitude.
//
// 反解检查把赤道半径用作卫星半径,故几何是退化的那种,其中仰角恒为零。更
// 有用的检查要用卫星高度。
let satellite_radius = BODY_RADIUS_KM + 550.0; let satellite_radius = BODY_RADIUS_KM + 550.0;
let Ok(elevation) = let Ok(elevation) =
elevation_from_central_angle(satellite_radius, BODY_RADIUS_KM, central).ok_or(()) elevation_from_central_angle(satellite_radius, BODY_RADIUS_KM, central).ok_or(())
@ -141,6 +181,8 @@ fn main() {
// Beyond the horizon the inverse has no solution, which is // Beyond the horizon the inverse has no solution, which is
// reported as an empty row rather than skipped, so the count of // reported as an empty row rather than skipped, so the count of
// rows stays fixed. // rows stays fixed.
//
// 在地平之外反解无解,故报告为一个空行而非跳过,使行数保持固定。
println!("{degrees},,"); println!("{degrees},,");
continue; continue;
}; };

View File

@ -1,6 +1,8 @@
//! Writes the specific and zenith gaseous attenuation computed by this //! Writes the specific and zenith gaseous attenuation computed by this
//! workspace, for cross-checking against ITU-R P.676-12. //! workspace, for cross-checking against ITU-R P.676-12.
//! //!
//! 写出本工作区计算的比与天顶气体衰减,用于对照 ITU-R P.676-12 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -15,6 +17,9 @@ use apsis_atmosphere::{
/// The frequencies sampled, in gigahertz. They span the oxygen complex near /// The frequencies sampled, in gigahertz. They span the oxygen complex near
/// 60 GHz, the water vapour lines at 22.235 and 183.31 GHz, and the windows /// 60 GHz, the water vapour lines at 22.235 and 183.31 GHz, and the windows
/// between them. /// between them.
///
/// 所采样的频率,单位为吉赫兹。它们跨越 60 GHz 附近的氧复合体、22.235 与
/// 183.31 GHz 的水汽线,以及其间的窗口。
const FREQUENCIES_GHZ: &[f64] = &[ const FREQUENCIES_GHZ: &[f64] = &[
1.0, 2.0, 4.0, 6.0, 10.0, 12.0, 15.0, 20.0, 22.235, 30.0, 40.0, 50.0, 60.0, 70.0, 100.0, 118.0, 1.0, 2.0, 4.0, 6.0, 10.0, 12.0, 15.0, 20.0, 22.235, 30.0, 40.0, 50.0, 60.0, 70.0, 100.0, 118.0,
183.0, 300.0, 183.0, 300.0,

View File

@ -1,6 +1,8 @@
//! Writes the exact slant path gaseous attenuation computed by this //! Writes the exact slant path gaseous attenuation computed by this
//! workspace, for cross-checking against ITU-R P.676-12. //! workspace, for cross-checking against ITU-R P.676-12.
//! //!
//! 写出本工作区计算的精确斜路径气体衰减,用于对照 ITU-R P.676-12 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -12,6 +14,8 @@ use apsis_atmosphere::{Atmosphere, slant_path_attenuation_exact};
/// The scenarios sampled, as frequency in gigahertz and elevation in /// The scenarios sampled, as frequency in gigahertz and elevation in
/// degrees. /// degrees.
///
/// 所采样的场景,以吉赫兹计的频率与以度计的仰角。
const SCENARIOS: &[(f64, f64)] = &[ const SCENARIOS: &[(f64, f64)] = &[
(12.0, 90.0), (12.0, 90.0),
(12.0, 30.0), (12.0, 30.0),

View File

@ -5,6 +5,12 @@
//! by `validation/python/coord/check_geodetic.py`, which recomputes the same //! by `validation/python/coord/check_geodetic.py`, which recomputes the same
//! positions with a reference implementation and compares the two. //! positions with a reference implementation and compares the two.
//! //!
//! 写出一个大地位置网格,以及本工作区为它们计算的地固直角坐标。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/coord/check_geodetic.py` 消费,后者用参考实现重算相同的
//! 位置并比较二者。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text

View File

@ -1,6 +1,8 @@
//! Writes the IAU 2000/2006 Earth orientation quantities computed by this //! Writes the IAU 2000/2006 Earth orientation quantities computed by this
//! workspace, for cross-checking against ERFA. //! workspace, for cross-checking against ERFA.
//! //!
//! 写出本工作区计算的 IAU 2000/2006 地球定向量,用于对照 ERFA 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -17,20 +19,31 @@ use apsis_math::Mat3;
/// The Modified Julian Dates sampled. They span from 1970 to 2050 so that /// The Modified Julian Dates sampled. They span from 1970 to 2050 so that
/// the precession is exercised over a range of a century. /// the precession is exercised over a range of a century.
///
/// 所采样的约化儒略日。它们从 1970 到 2050,使岁差在一个世纪的跨度上被
/// 检验。
const MJD: &[f64] = &[ const MJD: &[f64] = &[
40_587.0, 51_544.5, 53_000.0, 55_000.0, 57_000.0, 58_000.0, 60_000.0, 62_000.0, 40_587.0, 51_544.5, 53_000.0, 55_000.0, 57_000.0, 58_000.0, 60_000.0, 62_000.0,
]; ];
/// The Terrestrial Time offset from TAI, in seconds. /// The Terrestrial Time offset from TAI, in seconds.
///
/// 地球时相对 TAI 的偏移,单位为秒。
const TT_MINUS_TAI: f64 = 32.184; const TT_MINUS_TAI: f64 = 32.184;
/// The TAI minus UTC offset used for this check, in seconds. It is the value /// The TAI minus UTC offset used for this check, in seconds. It is the value
/// in force from 2017 onward. /// in force from 2017 onward.
///
/// 本检查所用的 TAI 减 UTC 偏移,单位为秒。它是自 2017 年起生效的值。
const TAI_MINUS_UTC: f64 = 37.0; const TAI_MINUS_UTC: f64 = 37.0;
/// Returns the TT Julian date for a Modified Julian Date on the UTC scale. /// Returns the TT Julian date for a Modified Julian Date on the UTC scale.
///
/// 返回 UTC 时标上某约化儒略日对应的 TT 儒略日。
fn tt_julian_date(utc_mjd: f64) -> f64 { fn tt_julian_date(utc_mjd: f64) -> f64 {
// TAI = UTC + 37, TT = TAI + 32.184, so TT = UTC + 69.184 seconds. // TAI = UTC + 37, TT = TAI + 32.184, so TT = UTC + 69.184 seconds.
//
// TAI = UTC + 37,TT = TAI + 32.184,故 TT = UTC + 69.184 秒。
utc_mjd + 2_400_000.5 + (TT_MINUS_TAI + TAI_MINUS_UTC) / 86_400.0 utc_mjd + 2_400_000.5 + (TT_MINUS_TAI + TAI_MINUS_UTC) / 86_400.0
} }
@ -41,19 +54,27 @@ fn main() {
let t = (tt - 2_451_545.0) / 36_525.0; let t = (tt - 2_451_545.0) / 36_525.0;
// The obliquity, in radians. // The obliquity, in radians.
//
// 黄赤交角,单位为弧度。
println!("{mjd},obliquity,0,{:.17e}", mean_obliquity(t)); println!("{mjd},obliquity,0,{:.17e}", mean_obliquity(t));
// The nutation, from the IAU 2000A model. // The nutation, from the IAU 2000A model.
//
// 章动,取自 IAU 2000A 模型。
let nutation = nutation_2000a(t); let nutation = nutation_2000a(t);
println!("{mjd},nutation_longitude_a,0,{:.17e}", nutation.longitude); println!("{mjd},nutation_longitude_a,0,{:.17e}", nutation.longitude);
println!("{mjd},nutation_obliquity_a,0,{:.17e}", nutation.obliquity); println!("{mjd},nutation_obliquity_a,0,{:.17e}", nutation.obliquity);
// The nutation with the IAU 2006 adjustment. // The nutation with the IAU 2006 adjustment.
//
// 施加 IAU 2006 调整后的章动。
let adjusted = nutation_2000a_with_2006_adjustment(t); let adjusted = nutation_2000a_with_2006_adjustment(t);
println!("{mjd},nutation_longitude_06a,0,{:.17e}", adjusted.longitude); println!("{mjd},nutation_longitude_06a,0,{:.17e}", adjusted.longitude);
println!("{mjd},nutation_obliquity_06a,0,{:.17e}", adjusted.obliquity); println!("{mjd},nutation_obliquity_06a,0,{:.17e}", adjusted.obliquity);
// The four precession angles. // The four precession angles.
//
// 四个岁差角。
let angles = precession_angles(t); let angles = precession_angles(t);
println!("{mjd},precession_gamma_bar,0,{:.17e}", angles.gamma_bar); println!("{mjd},precession_gamma_bar,0,{:.17e}", angles.gamma_bar);
println!("{mjd},precession_phi_bar,0,{:.17e}", angles.phi_bar); println!("{mjd},precession_phi_bar,0,{:.17e}", angles.phi_bar);
@ -62,6 +83,8 @@ fn main() {
// The bias-precession-nutation matrix, which carries the celestial // The bias-precession-nutation matrix, which carries the celestial
// reference frame to the true equator and equinox of date. // reference frame to the true equator and equinox of date.
//
// 偏差-岁差-章动矩阵,它把天球参考系带到该日的真赤道与真春分点。
let bpn = bias_precession_nutation_matrix(t); let bpn = bias_precession_nutation_matrix(t);
for row in 0..3 { for row in 0..3 {
for column in 0..3 { for column in 0..3 {
@ -71,12 +94,16 @@ fn main() {
} }
// Greenwich apparent sidereal time, in radians. // Greenwich apparent sidereal time, in radians.
//
// 格林尼治视恒星时,单位为弧度。
println!( println!(
"{mjd},gast,0,{:.17e}", "{mjd},gast,0,{:.17e}",
greenwich_apparent_sidereal_time(tt, tt) greenwich_apparent_sidereal_time(tt, tt)
); );
// The celestial-to-terrestrial matrix, with zero polar motion. // The celestial-to-terrestrial matrix, with zero polar motion.
//
// 天球到地球坐标系矩阵,极移为零。
let matrix = celestial_to_terrestrial_matrix(tt, tt, PolarMotion::NONE); let matrix = celestial_to_terrestrial_matrix(tt, tt, PolarMotion::NONE);
for row in 0..3 { for row in 0..3 {
for column in 0..3 { for column in 0..3 {
@ -88,5 +115,7 @@ fn main() {
} }
/// Keeps the matrix type in scope for the documentation build. /// Keeps the matrix type in scope for the documentation build.
///
/// 为使文档构建保持在作用域内而保留矩阵类型。
#[allow(dead_code)] #[allow(dead_code)]
fn _uses_matrix(_matrix: Mat3) {} fn _uses_matrix(_matrix: Mat3) {}

View File

@ -12,6 +12,16 @@
//! elements, which exercises the vector algebra and the conic section //! elements, which exercises the vector algebra and the conic section
//! relations rather than a single formula. //! relations rather than a single formula.
//! //!
//! 写出本工作区计算的二体换算。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/orbit/check_kepler.py` 消费,后者从闭式表达式重算相同的量
//! 并比较。Python 侧是依据几何而非依据本代码写成的,故转录错误会表现为不一致。
//!
//! 写出两张表。第一张在一系列轨道上把开普勒根数转成直角坐标状态,这是规划调用方
//! 所用的路径。第二张往另一方向转并记录所恢复的根数,它检验的是矢量代数与圆锥
//! 曲线关系,而非单一公式。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -22,28 +32,48 @@
use apsis_kepler::{GravityParameter, KeplerianElements}; use apsis_kepler::{GravityParameter, KeplerianElements};
/// The gravitational parameter used throughout, WGS 84. /// The gravitational parameter used throughout, WGS 84.
///
/// 全程所用的引力参数,WGS 84。
const MU: GravityParameter = GravityParameter::WGS84; const MU: GravityParameter = GravityParameter::WGS84;
/// One orbit to convert, chosen to span the shapes the model must handle. /// One orbit to convert, chosen to span the shapes the model must handle.
///
/// 一个要转换的轨道,其选取跨越该模型必须处理的各形状。
struct Case { struct Case {
/// A name for the case, so a failure in the report is readable. /// A name for the case, so a failure in the report is readable.
///
/// 用例的名称,使报告中的失败可读。
name: &'static str, name: &'static str,
/// Semi-major axis, in kilometers. /// Semi-major axis, in kilometers.
///
/// 半长轴,单位为千米。
semi_major_axis: f64, semi_major_axis: f64,
/// Eccentricity, dimensionless. /// Eccentricity, dimensionless.
///
/// 偏心率,无量纲。
eccentricity: f64, eccentricity: f64,
/// Inclination, in degrees. /// Inclination, in degrees.
///
/// 倾角,单位为度。
inclination_deg: f64, inclination_deg: f64,
/// Right ascension of the ascending node, in degrees. /// Right ascension of the ascending node, in degrees.
///
/// 升交点赤经,单位为度。
right_ascension_deg: f64, right_ascension_deg: f64,
/// Argument of perigee, in degrees. /// Argument of perigee, in degrees.
///
/// 近地点幅角,单位为度。
argument_of_perigee_deg: f64, argument_of_perigee_deg: f64,
/// True anomaly, in degrees. /// True anomaly, in degrees.
///
/// 真近点角,单位为度。
true_anomaly_deg: f64, true_anomaly_deg: f64,
} }
impl Case { impl Case {
/// Returns the case as elements in the units the crate uses. /// Returns the case as elements in the units the crate uses.
///
/// 以本 crate 所用的单位把该用例返回为根数。
fn elements(&self) -> KeplerianElements { fn elements(&self) -> KeplerianElements {
KeplerianElements { KeplerianElements {
semi_major_axis: self.semi_major_axis, semi_major_axis: self.semi_major_axis,
@ -61,6 +91,11 @@ impl Case {
/// The set spans a circular orbit, two mildly eccentric ones, a highly /// The set spans a circular orbit, two mildly eccentric ones, a highly
/// eccentric one that exercises the near-parabolic branch of the anomaly /// eccentric one that exercises the near-parabolic branch of the anomaly
/// iteration, a retrograde one, and one inclined close to the polar limit. /// iteration, a retrograde one, and one inclined close to the polar limit.
///
/// 被转换的各轨道。
///
/// 该集合跨越一个圆轨道、两个轻度偏心者、一个检验近点角迭代近抛物线分支的
/// 高度偏心者、一个逆行轨道,以及一个倾角接近极地极限的轨道。
const CASES: &[Case] = &[ const CASES: &[Case] = &[
Case { Case {
name: "circular_equatorial", name: "circular_equatorial",
@ -119,10 +154,14 @@ const CASES: &[Case] = &[
]; ];
/// The geostationary radius, used for a circular orbit at that altitude. /// The geostationary radius, used for a circular orbit at that altitude.
///
/// 地球静止轨道半径,用于该高度处的圆轨道。
const GEO_RADIUS: f64 = 42_164.0; const GEO_RADIUS: f64 = 42_164.0;
fn main() { fn main() {
// The first table: elements to a Cartesian state. // The first table: elements to a Cartesian state.
//
// 第一张表:根数到直角坐标状态。
println!( println!(
"case,semi_major_axis_km,eccentricity,inclination_rad,right_ascension_rad,\ "case,semi_major_axis_km,eccentricity,inclination_rad,right_ascension_rad,\
argument_of_perigee_rad,true_anomaly_rad,x_km,y_km,z_km,vx_kms,vy_kms,vz_kms,\ argument_of_perigee_rad,true_anomaly_rad,x_km,y_km,z_km,vx_kms,vy_kms,vz_kms,\
@ -136,6 +175,8 @@ fn main() {
// The specific energy is reported as well, because it is the // The specific energy is reported as well, because it is the
// quantity the Python side uses to check the speed independently of // quantity the Python side uses to check the speed independently of
// the direction. // the direction.
//
// 比能量也被报告,因为它是 Python 侧用来独立于方向核对速率的量。
let radius = state.position.norm(); let radius = state.position.norm();
let energy = state.velocity.norm_squared() / 2.0 - MU.value() / radius; let energy = state.velocity.norm_squared() / 2.0 - MU.value() / radius;
println!( println!(
@ -160,6 +201,8 @@ fn main() {
// A circular orbit at the geostationary radius, whose speed has a closed // A circular orbit at the geostationary radius, whose speed has a closed
// form, is included in the same table under its own name. // form, is included in the same table under its own name.
//
// 地球静止半径处的圆轨道,其速率有闭式,故以它自己的名称纳入同一张表。
let geo = KeplerianElements { let geo = KeplerianElements {
semi_major_axis: GEO_RADIUS, semi_major_axis: GEO_RADIUS,
eccentricity: 0.0, eccentricity: 0.0,
@ -192,6 +235,9 @@ fn main() {
// The second table: a state back to elements, over a grid of true // The second table: a state back to elements, over a grid of true
// anomalies on one orbit. This exercises the vector algebra rather than // anomalies on one orbit. This exercises the vector algebra rather than
// the perifocal formulae the first table uses. // the perifocal formulae the first table uses.
//
// 第二张表:在一个轨道的真近点角网格上从状态转回根数。它检验矢量代数,而非
// 第一张表所用的近焦点公式。
println!(); println!();
println!( println!(
"true_anomaly_deg,recovered_semi_major_axis_km,recovered_eccentricity,\ "true_anomaly_deg,recovered_semi_major_axis_km,recovered_eccentricity,\

View File

@ -5,6 +5,12 @@
//! by `validation/python/link/check_link.py`, which recomputes the same //! by `validation/python/link/check_link.py`, which recomputes the same
//! quantities from the link equation and compares. //! quantities from the link equation and compares.
//! //!
//! 写出链路预算输入以及本工作区为它们计算的各数字。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/link/check_link.py` 消费,后者从链路方程重算相同的量并
//! 比较。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -19,6 +25,11 @@ use apsis_rf::{Decibel, Gain, Power};
/// ///
/// The unit of each field is in its name: powers and gains in decibels, /// The unit of each field is in its name: powers and gains in decibels,
/// temperature in kelvin, and everything else in SI base units. /// temperature in kelvin, and everything else in SI base units.
///
/// 一个链路场景,命名使各字段在每次使用时保持可读。
///
/// 每个字段的单位在其名称中:功率与增益以分贝计,温度以开尔文计,其余以 SI
/// 基本单位计。
struct Scenario { struct Scenario {
transmit_dbw: f64, transmit_dbw: f64,
transmit_dbi: f64, transmit_dbi: f64,
@ -33,6 +44,9 @@ struct Scenario {
/// The scenarios checked. They cover a Ku band downlink, an S band link, a /// The scenarios checked. They cover a Ku band downlink, an S band link, a
/// wideband Ka link, and an L band link with a warmer receiver. /// wideband Ka link, and an L band link with a warmer receiver.
///
/// 被检查的各场景。它们覆盖 Ku 频段下行、S 频段链路、宽带 Ka 链路,以及一个
/// 接收机更热的 L 频段链路。
const SCENARIOS: &[Scenario] = &[ const SCENARIOS: &[Scenario] = &[
Scenario { Scenario {
transmit_dbw: 10.0, transmit_dbw: 10.0,
@ -130,6 +144,8 @@ fn main() {
let cn = budget.carrier_to_noise().map(|value| value.db()); let cn = budget.carrier_to_noise().map(|value| value.db());
// The energy per bit ratio is reported at a fixed data rate equal to // The energy per bit ratio is reported at a fixed data rate equal to
// the bandwidth, which makes it the carrier to noise ratio. // the bandwidth, which makes it the carrier to noise ratio.
//
// 每比特能量比在等于带宽的固定数据速率下报告,这使它即为载噪比。
let ebn0 = budget let ebn0 = budget
.energy_per_bit_over_noise(bandwidth) .energy_per_bit_over_noise(bandwidth)
.map(|value| value.db()); .map(|value| value.db());

View File

@ -6,6 +6,12 @@
//! which propagates the same element sets with the reference implementation //! which propagates the same element sets with the reference implementation
//! and compares. //! and compares.
//! //!
//! 为一组根数集与时刻写出传播后的状态。
//!
//! 输出是标准输出上的 CSV,表头命名根数集下标、距历元的分钟数,以及位置与速度
//! 分量。它由 `validation/python/orbit/check_sgp4.py` 消费,后者用参考实现传播
//! 相同的根数集并比较。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -19,24 +25,35 @@ use apsis_tle::TwoLineElement;
/// The element sets used by the cross-check. They are the historical test /// The element sets used by the cross-check. They are the historical test
/// cases distributed with the SGP4 reference implementation, which cover /// cases distributed with the SGP4 reference implementation, which cover
/// low, medium, and high eccentricity and the deep space branch. /// low, medium, and high eccentricity and the deep space branch.
///
/// 交叉核对所用的各根数集。它们是随 SGP4 参考实现分发的历史测试用例,覆盖低、
/// 中、高偏心率以及深空分支。
const ELEMENT_SETS: &[&str] = &[ const ELEMENT_SETS: &[&str] = &[
// International Space Station, near circular low Earth orbit. // International Space Station, near circular low Earth orbit.
//
// 国际空间站,近圆形低轨。
concat!( concat!(
"1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927\r\n", "1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927\r\n",
"2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537\r\n", "2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537\r\n",
), ),
// A highly eccentric orbit, which exercises the eccentric anomaly // A highly eccentric orbit, which exercises the eccentric anomaly
// iteration and the drag terms away from circular motion. // iteration and the drag terms away from circular motion.
//
// 一个高度偏心的轨道,它检验偏近点角迭代以及远离圆运动时的阻力项。
concat!( concat!(
"1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753\r\n", "1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753\r\n",
"2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667\r\n", "2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667\r\n",
), ),
// A geostationary transfer orbit with a low perigee. // A geostationary transfer orbit with a low perigee.
//
// 一个近地点很低的地球静止转移轨道。
concat!( concat!(
"1 27651U 03004A 06185.99374200 .00000109 00000-0 19909-4 0 445\r\n", "1 27651U 03004A 06185.99374200 .00000109 00000-0 19909-4 0 445\r\n",
"2 27651 7.1743 182.9443 7867251 269.0386 18.6601 1.03461646 9884\r\n", "2 27651 7.1743 182.9443 7867251 269.0386 18.6601 1.03461646 9884\r\n",
), ),
// A deep space orbit, whose period exceeds 225 minutes. // A deep space orbit, whose period exceeds 225 minutes.
//
// 一个深空轨道,其周期超过 225 分钟。
concat!( concat!(
"1 09880U 77021A 06174.85710247 .00000090 00000-0 10000-3 0 7322\r\n", "1 09880U 77021A 06174.85710247 .00000090 00000-0 10000-3 0 7322\r\n",
"2 09880 64.1526 313.1296 6546925 103.4683 305.3980 2.00754276 13047\r\n", "2 09880 64.1526 313.1296 6546925 103.4683 305.3980 2.00754276 13047\r\n",
@ -44,6 +61,8 @@ const ELEMENT_SETS: &[&str] = &[
]; ];
/// The times to sample, in minutes from the element epoch. /// The times to sample, in minutes from the element epoch.
///
/// 要采样的时刻,以距根数历元的分钟数计。
const TIMES_MINUTES: &[f64] = &[ const TIMES_MINUTES: &[f64] = &[
0.0, 1.0, 60.0, 360.0, 720.0, 1_440.0, 2_880.0, 10_080.0, -1_440.0, 0.0, 1.0, 60.0, 360.0, 720.0, 1_440.0, 2_880.0, 10_080.0, -1_440.0,
]; ];

View File

@ -1,6 +1,8 @@
//! Writes the rain height computed by this workspace, for cross-checking //! Writes the rain height computed by this workspace, for cross-checking
//! against ITU-R P.839-4. //! against ITU-R P.839-4.
//! //!
//! 写出本工作区计算的雨顶高度,用于对照 ITU-R P.839-4 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -11,6 +13,8 @@
use apsis_atmosphere::{rain_height, zero_isotherm_height}; use apsis_atmosphere::{rain_height, zero_isotherm_height};
/// The locations sampled, as latitude and longitude in degrees. /// The locations sampled, as latitude and longitude in degrees.
///
/// 所采样的位置,以度计的纬度与经度。
const POINTS: &[(f64, f64)] = &[ const POINTS: &[(f64, f64)] = &[
(0.0, 0.0), (0.0, 0.0),
(45.0, 0.0), (45.0, 0.0),

View File

@ -1,6 +1,8 @@
//! Writes the P.838-3 rain coefficients computed by this workspace, for //! Writes the P.838-3 rain coefficients computed by this workspace, for
//! cross-checking against ITU-R P.838-3. //! cross-checking against ITU-R P.838-3.
//! //!
//! 写出本工作区计算的 P.838-3 降雨系数,用于对照 ITU-R P.838-3 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -11,6 +13,8 @@
use apsis_atmosphere::rain_coefficients; use apsis_atmosphere::rain_coefficients;
/// The frequencies sampled, in gigahertz. /// The frequencies sampled, in gigahertz.
///
/// 所采样的频率,单位为吉赫兹。
const FREQUENCIES_GHZ: &[f64] = &[ const FREQUENCIES_GHZ: &[f64] = &[
1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 15.0, 20.0, 22.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 15.0, 20.0, 22.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0,
100.0, 100.0,
@ -21,6 +25,8 @@ fn main() {
for &frequency in FREQUENCIES_GHZ { for &frequency in FREQUENCIES_GHZ {
// A horizontal path, which removes the elevation dependence and // A horizontal path, which removes the elevation dependence and
// isolates the coefficient curves. // isolates the coefficient curves.
//
// 水平路径,它去除仰角依赖并分离出各系数曲线。
for &(elevation_degrees, polarisation_degrees) in for &(elevation_degrees, polarisation_degrees) in
&[(90.0_f64, 0.0_f64), (90.0, 90.0), (30.0, 0.0), (30.0, 45.0)] &[(90.0_f64, 0.0_f64), (90.0, 90.0), (30.0, 0.0), (30.0, 45.0)]
{ {

View File

@ -1,6 +1,8 @@
//! Writes rain path attenuation computed by this workspace, for //! Writes rain path attenuation computed by this workspace, for
//! cross-checking the ITU-R P.618-13 slant path method. //! cross-checking the ITU-R P.618-13 slant path method.
//! //!
//! 写出本工作区计算的降雨路径衰减,用于交叉核对 ITU-R P.618-13 斜路径方法。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -13,6 +15,9 @@ use apsis_atmosphere::{DEFAULT_RAIN_HEIGHT_KM, rain_attenuation};
/// The scenarios sampled. Each is a rain rate in millimeters per hour, a /// The scenarios sampled. Each is a rain rate in millimeters per hour, a
/// frequency in gigahertz, an elevation in degrees, and a latitude in /// frequency in gigahertz, an elevation in degrees, and a latitude in
/// degrees. The station height is zero and the rain height is the default. /// degrees. The station height is zero and the rain height is the default.
///
/// 所采样的场景。每个都是以毫米每小时计的降雨率、以吉赫兹计的频率、以度计的
/// 仰角,以及以度计的纬度。站高为零,雨顶高度为缺省值。
const SCENARIOS: &[(f64, f64, f64, f64)] = &[ const SCENARIOS: &[(f64, f64, f64, f64)] = &[
(20.0, 12.0, 30.0, 45.0), (20.0, 12.0, 30.0, 45.0),
(20.0, 12.0, 10.0, 45.0), (20.0, 12.0, 10.0, 45.0),

View File

@ -1,6 +1,8 @@
//! Writes the ITU-R S.465 reference pattern computed by this workspace, for //! Writes the ITU-R S.465 reference pattern computed by this workspace, for
//! cross-checking against the recommendation. //! cross-checking against the recommendation.
//! //!
//! 写出本工作区计算的 ITU-R S.465 参考方向图,用于对照该建议书交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -11,9 +13,13 @@
use apsis_antenna::{main_lobe_break_angle, reference_pattern_gain, reference_peak_gain}; use apsis_antenna::{main_lobe_break_angle, reference_pattern_gain, reference_peak_gain};
/// The antenna sizes sampled, as diameter to wavelength ratios. /// The antenna sizes sampled, as diameter to wavelength ratios.
///
/// 所采样的天线尺寸,以口径与波长之比表示。
const RATIOS: &[f64] = &[50.0, 100.0, 200.0]; const RATIOS: &[f64] = &[50.0, 100.0, 200.0];
/// The off-axis angles sampled, in degrees. /// The off-axis angles sampled, in degrees.
///
/// 所采样的偏轴角,单位为度。
const ANGLES_DEGREES: &[f64] = &[0.1, 0.5, 1.0, 5.0, 20.0, 36.0, 48.0, 90.0]; const ANGLES_DEGREES: &[f64] = &[0.1, 0.5, 1.0, 5.0, 20.0, 36.0, 48.0, 90.0];
fn main() { fn main() {

View File

@ -1,6 +1,8 @@
//! Writes the TEME to Earth-fixed transformation computed by this workspace, //! Writes the TEME to Earth-fixed transformation computed by this workspace,
//! for cross-checking against astropy. //! for cross-checking against astropy.
//! //!
//! 写出本工作区计算的 TEME 到地固坐标变换,用于对照 astropy 交叉核对。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -12,6 +14,8 @@ use apsis_frames::iau2000::{PolarMotion, teme_to_terrestrial_matrix};
/// The samples, as a UTC Modified Julian Date and a TEME position in /// The samples, as a UTC Modified Julian Date and a TEME position in
/// kilometers. /// kilometers.
///
/// 各样本,为一个 UTC 约化儒略日与一个以千米计的 TEME 位置。
const SAMPLES: &[(f64, [f64; 3])] = &[ const SAMPLES: &[(f64, [f64; 3])] = &[
(60_481.5, [7_000.0, 1_000.0, 2_000.0]), (60_481.5, [7_000.0, 1_000.0, 2_000.0]),
(51_544.5, [7_000.0, -3_000.0, 1_000.0]), (51_544.5, [7_000.0, -3_000.0, 1_000.0]),
@ -28,6 +32,10 @@ fn main() {
// is used directly here and the check tolerates that difference. // is used directly here and the check tolerates that difference.
// The Julian date is split into a whole number of days and a // The Julian date is split into a whole number of days and a
// fraction, which preserves more of the day than a single value. // fraction, which preserves more of the day than a single value.
//
// 该变换需要 UT1 时间,因为是地球自转在带动坐标系。UT1 与 UTC 相差不到
// 0.9 秒,即 0.0037 度的转动,故此处直接使用 UTC 值,而检查容忍该差异。儒略日
// 被拆成整数天数与零头,这比单个值保留更多当日信息。
let matrix = teme_to_terrestrial_matrix(2_400_000.5, utc_mjd, PolarMotion::NONE); let matrix = teme_to_terrestrial_matrix(2_400_000.5, utc_mjd, PolarMotion::NONE);
let vector = apsis_math::Vec3::new(position[0], position[1], position[2]); let vector = apsis_math::Vec3::new(position[0], position[1], position[2]);
let result = matrix * vector; let result = matrix * vector;

View File

@ -10,6 +10,15 @@
//! Julian Date near 60 000 to better than about 40 microseconds. The two //! Julian Date near 60 000 to better than about 40 microseconds. The two
//! parts let the checker compare instants to well below a microsecond. //! parts let the checker compare instants to well below a microsecond.
//! //!
//! 写出闰秒偏移以及本工作区在一系列瞬时上计算的时标换算。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/time/check_time.py` 消费,后者用参考实现重算每个瞬时。
//!
//! TAI 瞬时按两部分写出,一个整数约化儒略日与一天的零头,因为单个 `f64` 无法
//! 把接近 60 000 的约化儒略日保持到优于约 40 微秒。两部分使检查器能把瞬时比较
//! 到远低于一微秒。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -21,6 +30,8 @@ use apsis_leap::{LEAP_SECONDS, tai_minus_utc_at_mjd};
use apsis_time::{Calendar, Epoch, TT_MINUS_TAI, TimeScale}; use apsis_time::{Calendar, Epoch, TT_MINUS_TAI, TimeScale};
/// Splits a Modified Julian Date into its integer day and its fraction. /// Splits a Modified Julian Date into its integer day and its fraction.
///
/// 把约化儒略日拆为其整数日与零头。
fn split(mjd: f64) -> (i64, f64) { fn split(mjd: f64) -> (i64, f64) {
let day = mjd.floor(); let day = mjd.floor();
(day as i64, mjd - day) (day as i64, mjd - day)
@ -51,6 +62,8 @@ fn main() {
// Sample every leap second boundary at several times of day, so that // Sample every leap second boundary at several times of day, so that
// the step behaviour and the interior of each interval are covered. // the step behaviour and the interior of each interval are covered.
//
// 在一天中的若干时刻对每个闰秒边界采样,使阶跃行为与每个区间的内部都被覆盖。
for entry in LEAP_SECONDS { for entry in LEAP_SECONDS {
for (hour, minute, second) in [(0, 0, 0.0), (6, 0, 0.0), (12, 0, 0.0), (18, 0, 0.0)] { for (hour, minute, second) in [(0, 0, 0.0), (6, 0, 0.0), (12, 0, 0.0), (18, 0, 0.0)] {
let calendar = Calendar::new(entry.year, entry.month, entry.day, hour, minute, second); let calendar = Calendar::new(entry.year, entry.month, entry.day, hour, minute, second);
@ -61,6 +74,8 @@ fn main() {
} }
// The last second before a leap second and the first second after it. // The last second before a leap second and the first second after it.
//
// 闰秒前的最后一秒与其后的第一秒。
for (year, month, day, hour, minute, second) in [ for (year, month, day, hour, minute, second) in [
(2016, 12, 31, 23, 59, 59.0), (2016, 12, 31, 23, 59, 59.0),
(2017, 1, 1, 0, 0, 0.0), (2017, 1, 1, 0, 0, 0.0),
@ -76,5 +91,7 @@ fn main() {
// The Terrestrial Time offset is a defining constant, written here so // The Terrestrial Time offset is a defining constant, written here so
// that the checker can verify it without recomputing the calendar. // that the checker can verify it without recomputing the calendar.
//
// 地球时偏移是一个定义常量,写在这里使检查器无需重算日历即可核验它。
println!("# tt_minus_tai_seconds={TT_MINUS_TAI:.3}"); println!("# tt_minus_tai_seconds={TT_MINUS_TAI:.3}");
} }

View File

@ -11,6 +11,15 @@
//! eccentricity, a retrograde inclination, a negative drag term, and a century //! eccentricity, a retrograde inclination, a negative drag term, and a century
//! rollover in the two digit epoch year. //! rollover in the two digit epoch year.
//! //!
//! 写出本工作区从两行集解析出的根数字段。
//!
//! 输出是标准输出上的 CSV,带一行表头。它由
//! `validation/python/orbit/check_tle.py` 消费,后者用一个独立的、按列索引的
//! 读取器重新解析相同的集合、比较每个字段,并重算每行对十取模的校验和。
//!
//! 各集合包括随 SGP4 参考实现分发的历史测试用例,以及检验格式各角落的合成用例:
//! 偏心率带隐含前导零的圆轨道、逆行倾角、负阻力项,以及两位历元年份的世纪翻转。
//!
//! Usage: //! Usage:
//! //!
//! ```text //! ```text
@ -22,10 +31,16 @@ use apsis_time::TimeScale;
use apsis_tle::{Classification, TwoLineElement, line_checksum}; use apsis_tle::{Classification, TwoLineElement, line_checksum};
/// One element set to parse, with a name for the report. /// One element set to parse, with a name for the report.
///
/// 一个要解析的根数集,带一个用于报告的名称。
struct Sample { struct Sample {
/// A name for the sample, so a failure in the report is readable. /// A name for the sample, so a failure in the report is readable.
///
/// 样本的名称,使报告中的失败可读。
name: &'static str, name: &'static str,
/// The two lines of the set, without a trailing carriage return. /// The two lines of the set, without a trailing carriage return.
///
/// 该集合的两行,不带尾随回车。
lines: [&'static str; 2], lines: [&'static str; 2],
} }
@ -43,6 +58,12 @@ const fn sample(name: &'static str, first: &'static str, second: &'static str) -
/// the format: an implied leading zero in the eccentricity, a retrograde /// the format: an implied leading zero in the eccentricity, a retrograde
/// inclination, a negative first derivative of the mean motion, a century /// inclination, a negative first derivative of the mean motion, a century
/// rollover in the two digit epoch year, and a name line. /// rollover in the two digit epoch year, and a name line.
///
/// 被解析的各根数集。
///
/// 前四个是随 SGP4 参考实现分发的历史测试用例。其余是合成的,覆盖格式的边缘:
/// 偏心率带隐含前导零、逆行倾角、平运动一阶导数为负、两位历元年份的世纪翻转,
/// 以及一个名称行。
const SAMPLES: &[Sample] = &[ const SAMPLES: &[Sample] = &[
sample( sample(
"vanguard_1", "vanguard_1",
@ -77,6 +98,8 @@ const SAMPLES: &[Sample] = &[
sample( sample(
// A two digit year of 99 must expand to 1999, the last year of the // A two digit year of 99 must expand to 1999, the last year of the
// twentieth century branch of the convention. // twentieth century branch of the convention.
//
// 两位年份 99 必须展开为 1999,即该约定二十世纪分支的最后一年。
"two_digit_year_1999", "two_digit_year_1999",
"1 10000U 99001A 99365.00000000 .00000000 00000-0 00000-0 0 05", "1 10000U 99001A 99365.00000000 .00000000 00000-0 00000-0 0 05",
"2 10000 45.0000 10.0000 0001000 0.0000 0.0000 14.00000000 09", "2 10000 45.0000 10.0000 0001000 0.0000 0.0000 14.00000000 09",
@ -93,6 +116,11 @@ const SAMPLES: &[Sample] = &[
/// The epoch field of an element set stores the day of the year and its /// The epoch field of an element set stores the day of the year and its
/// fraction, so the year and month are combined back into a day of year /// fraction, so the year and month are combined back into a day of year
/// before the fraction of the day is added. /// before the fraction of the day is added.
///
/// 返回某日历日期在该年中的第几天,以小数表示。
///
/// 根数集的历元字段保存一年中的第几天及其零头,故年与月先合回一年中的第几天,
/// 再加上当日的零头。
fn day_of_year_fraction(year: i32, month: u32, day: u32) -> f64 { fn day_of_year_fraction(year: i32, month: u32, day: u32) -> f64 {
use apsis_time::days_in_month; use apsis_time::days_in_month;
let mut total = 0_u32; let mut total = 0_u32;
@ -123,6 +151,9 @@ fn main() {
// The epoch is stored as a Modified Julian Date; the calendar form // The epoch is stored as a Modified Julian Date; the calendar form
// is written so the reader can compare the year and the day of year // is written so the reader can compare the year and the day of year
// against the two digit year and fraction the line encodes. // against the two digit year and fraction the line encodes.
//
// 历元存为约化儒略日;写出日历形式,使读者可以把年与一年中的第几天对照该行
// 所编码的两位年份与零头。
let calendar = element let calendar = element
.epoch .epoch
.calendar(TimeScale::Utc) .calendar(TimeScale::Utc)