docs: repair partial translations, sentence splits and duplicated blocks
The bilingual sweep had left some blocks with only their last paragraph translated, a few with the Chinese inserted inside an English sentence, and some with a repeated paragraph from a re-applied table. A rewrite of the coverage checks found them; this fixes every block and restores the comment separators that a cleanup pass had emptied.
This commit is contained in:
parent
4203bf2789
commit
05b5199a69
|
|
@ -51,6 +51,10 @@
|
|||
//! ```text
|
||||
//! cargo run --release -p apsis-rs --features full --example bench_parallel
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_access::{AccessFinder, OrbitSample};
|
||||
use apsis_coord::Eci;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@
|
|||
//! ```text
|
||||
//! cargo run --release -p apsis-rs --features full --example bench_scale
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_access::{AccessFinder, OrbitSample};
|
||||
use apsis_constellation::{Constellation, WalkerPattern};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
//! cargo run -p apsis-rs --features network --example dump_coverage \
|
||||
//! > validation/data/expected/rust_coverage.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_coverage::{
|
||||
earth_central_angle, elevation_from_central_angle, footprint_area, footprint_central_angle,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//! cargo run -p apsis-rs --features rf --example dump_gas \
|
||||
//! > validation/data/expected/rust_gas.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_atmosphere::{
|
||||
Atmosphere, equivalent_heights, specific_attenuation_dry_air, specific_attenuation_water_vapour,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//! cargo run -p apsis-rs --features rf --example dump_gas_exact \
|
||||
//! > validation/data/expected/rust_gas_exact.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_atmosphere::{Atmosphere, slant_path_attenuation_exact};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
//! cargo run -p apsis-rs --features physics --example dump_geodesy \
|
||||
//! > validation/data/expected/rust_geodetic.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_coord::{Geodetic, WGS84};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//! cargo run -p apsis-rs --features physics --example dump_iau2000 \
|
||||
//! > validation/data/expected/rust_iau2000.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_frames::iau2000::{
|
||||
PolarMotion, bias_precession_nutation_matrix, celestial_to_terrestrial_matrix,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
//! cargo run -p apsis-rs --features rf --example dump_link \
|
||||
//! > validation/data/expected/rust_link.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_link::{LinkBudget, LinkGeometry};
|
||||
use apsis_rf::{Decibel, Gain, Power};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
//! cargo run -p apsis-rs --features orbit --example dump_orbit \
|
||||
//! > validation/data/expected/rust_sgp4.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_sgp4::{GravityModel, Satellite};
|
||||
use apsis_tle::TwoLineElement;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//! cargo run -p apsis-rs --features rf --example dump_rain_path \
|
||||
//! > validation/data/expected/rust_rain_path.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_atmosphere::{DEFAULT_RAIN_HEIGHT_KM, rain_attenuation};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//! cargo run -p apsis-rs --features physics --example dump_teme \
|
||||
//! > validation/data/expected/rust_teme.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_frames::iau2000::{PolarMotion, teme_to_terrestrial_matrix};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
//! cargo run -p apsis-rs --features physics --example dump_time \
|
||||
//! > validation/data/expected/rust_time.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_leap::{LEAP_SECONDS, tai_minus_utc_at_mjd};
|
||||
use apsis_time::{Calendar, Epoch, TT_MINUS_TAI, TimeScale};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
//! cargo run -p apsis-rs --features orbit --example dump_tle \
|
||||
//! > validation/data/expected/rust_tle.csv
|
||||
//! ```
|
||||
//!
|
||||
//! 用法:
|
||||
//!
|
||||
//! 运行上方的命令即可得到该示例的输出。
|
||||
|
||||
use apsis_time::TimeScale;
|
||||
use apsis_tle::{Classification, TwoLineElement, line_checksum};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,20 @@
|
|||
//! because several derived quantities depend on the exact value rather than
|
||||
//! the rounded printed one.
|
||||
//!
|
||||
//! 工作区各处在用的物理与天文常量。
|
||||
//!
|
||||
//! 除非名称或文档注释另有说明,所有值以 SI 单位表达。由定义固定的值精确给出;
|
||||
//! 实测值携带公共来源所证明的有效数字位数。
|
||||
//!
|
||||
//! 出处:
|
||||
//!
|
||||
//! - SI 定义常量:BIPM,*The International System of Units (SI)*,第 9 版,
|
||||
//! 2019。
|
||||
//! - CODATA 2018 推荐值:E. Tiesinga 等,*CODATA recommended values of the
|
||||
//! fundamental physical constants: 2018*,Rev. Mod. Phys. 93,025010,2021。
|
||||
//! - 地球引力参数与赤道半径:WGS 84,NIMA TR8350.2,2000。
|
||||
//! - 天文单位:IAU 2012 Resolution B2。
|
||||
//!
|
||||
//! 当某个数值由标准精确定义时,文档注释会指出这一点,因为若干导出量依赖精确值
|
||||
//! 而非取整后的打印值。
|
||||
|
||||
|
|
|
|||
|
|
@ -117,10 +117,12 @@ impl Error {
|
|||
|
||||
/// Creates an error with the given kind and message.
|
||||
///
|
||||
/// 用给定类别与消息创建一个错误。
|
||||
///
|
||||
/// The message should describe the concrete cause of this specific
|
||||
/// failure. It is meant for humans reading logs, not for matching.
|
||||
///
|
||||
/// 用给定类别与消息创建一个错误。
|
||||
///
|
||||
/// 该消息应描述这一具体失败的具体原因。它意在供人阅读日志,而非供匹配。
|
||||
pub fn with_message(kind: ErrorKind, message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
|
|
|
|||
|
|
@ -26,11 +26,14 @@ use core::fmt;
|
|||
|
||||
/// A unit of a single physical dimension.
|
||||
///
|
||||
/// 单一物理量纲的单位。
|
||||
///
|
||||
/// Implementors are zero sized marker types. Two units that implement
|
||||
/// `Unit` for the same dimension convert through
|
||||
/// [`Quantity::to_unit`](crate::Quantity::to_unit).
|
||||
///
|
||||
/// 单一物理量纲的单位。
|
||||
///
|
||||
/// 实现者是零尺寸标记类型。对同一量纲实现 `Unit` 的两个单位经
|
||||
/// [`Quantity::to_unit`](crate::Quantity::to_unit) 换算。
|
||||
pub trait Unit: Copy + fmt::Debug + fmt::Display + 'static {
|
||||
/// The physical dimension this unit measures, such as length or time.
|
||||
///
|
||||
|
|
@ -39,10 +42,12 @@ pub trait Unit: Copy + fmt::Debug + fmt::Display + 'static {
|
|||
|
||||
/// The number of base units in one of this unit.
|
||||
///
|
||||
/// 一个该单位相当于多少个基本单位。
|
||||
///
|
||||
/// For example a kilometer has a factor of 1000 when the base unit is
|
||||
/// the meter. The base unit of a dimension has a factor of exactly one.
|
||||
///
|
||||
/// 一个该单位相当于多少个基本单位。
|
||||
///
|
||||
/// 例如当基本单位是米时,一千米的因子为 1000。某量纲的基本单位其因子恰为一。
|
||||
fn factor_to_base() -> f64;
|
||||
|
||||
/// The symbol used to print the unit, such as `m` or `s`.
|
||||
|
|
@ -53,11 +58,14 @@ pub trait Unit: Copy + fmt::Debug + fmt::Display + 'static {
|
|||
|
||||
/// A value paired with a unit.
|
||||
///
|
||||
/// 与单位配对的一个数值。
|
||||
///
|
||||
/// Implementors are newtypes over `f64` and a [`Unit`]. The trait gives
|
||||
/// generic code access to the stored value and its unit without assuming
|
||||
/// which newtype it was handed.
|
||||
///
|
||||
/// 与单位配对的一个数值。
|
||||
///
|
||||
/// 实现者是包装 `f64` 与 [`Unit`] 的 newtype。该 trait 使泛型代码能访问所存的
|
||||
/// 值与其单位,而不假定所接到的是哪个 newtype。
|
||||
pub trait Quantity: Copy {
|
||||
/// The unit this quantity is expressed in.
|
||||
///
|
||||
|
|
@ -76,12 +84,15 @@ pub trait Quantity: Copy {
|
|||
|
||||
/// Converts this quantity to another unit of the same dimension.
|
||||
///
|
||||
/// 把该量换算为同一量纲的另一个单位。
|
||||
///
|
||||
/// The value is scaled by the ratio of the two unit factors. The
|
||||
/// conversion is exact only when the factors are exact powers of ten,
|
||||
/// so callers that need a specific unit for output should convert once
|
||||
/// at the boundary rather than repeatedly.
|
||||
///
|
||||
/// 把该量换算为同一量纲的另一个单位。
|
||||
///
|
||||
/// 该值按两个单位因子之比缩放。仅当因子是十的精确幂时换算才精确,故需要特定
|
||||
/// 单位作输出的调用方宜在边界处换算一次,而非反复换算。
|
||||
fn to_unit<U>(self) -> U
|
||||
where
|
||||
U: Quantity,
|
||||
|
|
|
|||
|
|
@ -15,30 +15,19 @@ use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAss
|
|||
///
|
||||
/// 分量名为 `x`、`y`、`z`。此处不赋予它们任何含义;参考系由使用该向量的
|
||||
/// crate 定义。
|
||||
///
|
||||
/// 三分量列向量。
|
||||
///
|
||||
/// 分量名为 `x`、`y`、`z`。此处不赋予它们任何含义;参考系由使用该向量的
|
||||
/// crate 定义。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct Vec3 {
|
||||
/// First component.
|
||||
///
|
||||
/// 第一分量。
|
||||
///
|
||||
/// 第一分量。
|
||||
pub x: f64,
|
||||
/// Second component.
|
||||
///
|
||||
/// 第二分量。
|
||||
///
|
||||
/// 第二分量。
|
||||
pub y: f64,
|
||||
/// Third component.
|
||||
///
|
||||
/// 第三分量。
|
||||
///
|
||||
/// 第三分量。
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
|
|
@ -46,36 +35,26 @@ impl Vec3 {
|
|||
/// The zero vector.
|
||||
///
|
||||
/// 零向量。
|
||||
///
|
||||
/// 零向量。
|
||||
pub const ZERO: Self = Self::new(0.0, 0.0, 0.0);
|
||||
|
||||
/// The unit vector along the first axis.
|
||||
///
|
||||
/// 沿第一轴的单位向量。
|
||||
///
|
||||
/// 沿第一轴的单位向量。
|
||||
pub const X: Self = Self::new(1.0, 0.0, 0.0);
|
||||
|
||||
/// The unit vector along the second axis.
|
||||
///
|
||||
/// 沿第二轴的单位向量。
|
||||
///
|
||||
/// 沿第二轴的单位向量。
|
||||
pub const Y: Self = Self::new(0.0, 1.0, 0.0);
|
||||
|
||||
/// The unit vector along the third axis.
|
||||
///
|
||||
/// 沿第三轴的单位向量。
|
||||
///
|
||||
/// 沿第三轴的单位向量。
|
||||
pub const Z: Self = Self::new(0.0, 0.0, 1.0);
|
||||
|
||||
/// Creates a vector from its three components.
|
||||
///
|
||||
/// 由三个分量创建向量。
|
||||
///
|
||||
/// 由三个分量创建向量。
|
||||
pub const fn new(x: f64, y: f64, z: f64) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
|
@ -83,8 +62,6 @@ impl Vec3 {
|
|||
/// Creates a vector whose three components all equal `value`.
|
||||
///
|
||||
/// 创建三个分量都等于 `value` 的向量。
|
||||
///
|
||||
/// 创建三个分量都等于 `value` 的向量。
|
||||
pub const fn splat(value: f64) -> Self {
|
||||
Self::new(value, value, value)
|
||||
}
|
||||
|
|
@ -92,8 +69,6 @@ impl Vec3 {
|
|||
/// Returns the first component.
|
||||
///
|
||||
/// 返回第一分量。
|
||||
///
|
||||
/// 返回第一分量。
|
||||
pub const fn x(self) -> f64 {
|
||||
self.x
|
||||
}
|
||||
|
|
@ -101,8 +76,6 @@ impl Vec3 {
|
|||
/// Returns the second component.
|
||||
///
|
||||
/// 返回第二分量。
|
||||
///
|
||||
/// 返回第二分量。
|
||||
pub const fn y(self) -> f64 {
|
||||
self.y
|
||||
}
|
||||
|
|
@ -110,8 +83,6 @@ impl Vec3 {
|
|||
/// Returns the third component.
|
||||
///
|
||||
/// 返回第三分量。
|
||||
///
|
||||
/// 返回第三分量。
|
||||
pub const fn z(self) -> f64 {
|
||||
self.z
|
||||
}
|
||||
|
|
@ -124,10 +95,6 @@ impl Vec3 {
|
|||
/// 返回由 `index` 选定的分量,其中 `0`、`1`、`2` 分别对应 `x`、`y`、`z`。
|
||||
///
|
||||
/// `index` 超出 `0..=2` 时返回 `None`。
|
||||
///
|
||||
/// 返回由 `index` 选定的分量,其中 `0`、`1`、`2` 分别对应 `x`、`y`、`z`。
|
||||
///
|
||||
/// `index` 超出 `0..=2` 时返回 `None`。
|
||||
pub const fn get(self, index: usize) -> Option<f64> {
|
||||
match index {
|
||||
0 => Some(self.x),
|
||||
|
|
@ -140,8 +107,6 @@ impl Vec3 {
|
|||
/// Returns the dot product of `self` and `rhs`.
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 的点积。
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 的点积。
|
||||
pub fn dot(self, rhs: Self) -> f64 {
|
||||
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
|
||||
}
|
||||
|
|
@ -155,11 +120,6 @@ impl Vec3 {
|
|||
///
|
||||
/// 结果同时垂直于两个输入并遵循右手定则,因此 `Vec3::X.cross(Vec3::Y)`
|
||||
/// 等于 `Vec3::Z`。
|
||||
///
|
||||
/// 返回叉积 `self x rhs`。
|
||||
///
|
||||
/// 结果同时垂直于两个输入并遵循右手定则,因此 `Vec3::X.cross(Vec3::Y)`
|
||||
/// 等于 `Vec3::Z`。
|
||||
pub fn cross(self, rhs: Self) -> Self {
|
||||
Self::new(
|
||||
self.y * rhs.z - self.z * rhs.y,
|
||||
|
|
@ -176,10 +136,6 @@ impl Vec3 {
|
|||
/// 返回该向量的欧几里得长度平方。
|
||||
///
|
||||
/// 比较长度时优先用它而非 [`Vec3::norm`],因为它省去一次开方。
|
||||
///
|
||||
/// 返回该向量的欧几里得长度平方。
|
||||
///
|
||||
/// 比较长度时优先用它而非 [`Vec3::norm`],因为它省去一次开方。
|
||||
pub fn norm_squared(self) -> f64 {
|
||||
self.dot(self)
|
||||
}
|
||||
|
|
@ -187,8 +143,6 @@ impl Vec3 {
|
|||
/// Returns the Euclidean length of this vector.
|
||||
///
|
||||
/// 返回该向量的欧几里得长度。
|
||||
///
|
||||
/// 返回该向量的欧几里得长度。
|
||||
pub fn norm(self) -> f64 {
|
||||
self.norm_squared().sqrt()
|
||||
}
|
||||
|
|
@ -201,10 +155,6 @@ impl Vec3 {
|
|||
/// 返回该向量缩放到单位长度后的结果。
|
||||
///
|
||||
/// 长度为零或非有限时返回 `None`,此时方向未定义。
|
||||
///
|
||||
/// 返回该向量缩放到单位长度后的结果。
|
||||
///
|
||||
/// 长度为零或非有限时返回 `None`,此时方向未定义。
|
||||
pub fn normalize(self) -> Option<Self> {
|
||||
let norm = self.norm();
|
||||
if norm > 0.0 && norm.is_finite() {
|
||||
|
|
@ -217,8 +167,6 @@ impl Vec3 {
|
|||
/// Returns the Euclidean distance between `self` and `rhs`.
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之间的欧几里得距离。
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之间的欧几里得距离。
|
||||
pub fn distance(self, rhs: Self) -> f64 {
|
||||
(self - rhs).norm()
|
||||
}
|
||||
|
|
@ -226,8 +174,6 @@ impl Vec3 {
|
|||
/// Returns the squared Euclidean distance between `self` and `rhs`.
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之间的欧几里得距离平方。
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之间的欧几里得距离平方。
|
||||
pub fn distance_squared(self, rhs: Self) -> f64 {
|
||||
(self - rhs).norm_squared()
|
||||
}
|
||||
|
|
@ -238,8 +184,6 @@ impl Vec3 {
|
|||
/// zero or non-finite length, or when either vector has a non-finite
|
||||
/// component.
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之间的夹角,单位为弧度。
|
||||
///
|
||||
/// 结果位于 `[0, pi]`。当任一向量长度为零或非有限,或任一向量含非有限
|
||||
/// 分量时返回 `None`。
|
||||
///
|
||||
|
|
@ -268,10 +212,6 @@ impl Vec3 {
|
|||
/// 返回线性插值 `self + t * (rhs - self)`。
|
||||
///
|
||||
/// `t = 0` 返回 `self`,`t = 1` 返回 `rhs`。`[0, 1]` 之外的值为外推。
|
||||
///
|
||||
/// 返回线性插值 `self + t * (rhs - self)`。
|
||||
///
|
||||
/// `t = 0` 返回 `self`,`t = 1` 返回 `rhs`。`[0, 1]` 之外的值为外推。
|
||||
pub fn lerp(self, rhs: Self, t: f64) -> Self {
|
||||
self + (rhs - self) * t
|
||||
}
|
||||
|
|
@ -279,8 +219,6 @@ impl Vec3 {
|
|||
/// Returns a vector with each component replaced by its absolute value.
|
||||
///
|
||||
/// 返回各分量取绝对值后的向量。
|
||||
///
|
||||
/// 返回各分量取绝对值后的向量。
|
||||
pub fn abs(self) -> Self {
|
||||
Self::new(self.x.abs(), self.y.abs(), self.z.abs())
|
||||
}
|
||||
|
|
@ -288,8 +226,6 @@ impl Vec3 {
|
|||
/// Returns the largest component.
|
||||
///
|
||||
/// 返回最大分量。
|
||||
///
|
||||
/// 返回最大分量。
|
||||
pub fn max_component(self) -> f64 {
|
||||
self.x.max(self.y).max(self.z)
|
||||
}
|
||||
|
|
@ -297,8 +233,6 @@ impl Vec3 {
|
|||
/// Returns the smallest component.
|
||||
///
|
||||
/// 返回最小分量。
|
||||
///
|
||||
/// 返回最小分量。
|
||||
pub fn min_component(self) -> f64 {
|
||||
self.x.min(self.y).min(self.z)
|
||||
}
|
||||
|
|
@ -306,8 +240,6 @@ impl Vec3 {
|
|||
/// Returns `true` when all three components are finite.
|
||||
///
|
||||
/// 当三个分量都有限时返回 `true`。
|
||||
///
|
||||
/// 当三个分量都有限时返回 `true`。
|
||||
pub fn is_finite(self) -> bool {
|
||||
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
//! Searching access windows for many tracks, optionally across several
|
||||
//! threads.
|
||||
//!
|
||||
//! 为许多轨迹搜索可见性窗口,可选跨多个线程。
|
||||
//!
|
||||
//! A ground station sees a whole constellation, so the access schedule is
|
||||
//! the search of one track per satellite. Each track is independent of the
|
||||
//! others, which makes the search the natural place to use several cores: the
|
||||
|
|
@ -12,6 +10,15 @@
|
|||
//! The parallel entry point returns exactly what the sequential one does, in
|
||||
//! the same order, so a caller can switch between them without changing what
|
||||
//! it computes.
|
||||
//!
|
||||
//! 为许多轨迹搜索可见性窗口,可选跨多个线程。
|
||||
//!
|
||||
//! 一座地面站看到整个星座,故可见性调度即是每颗卫星一条轨迹的搜索。每条轨迹与
|
||||
//! 其余独立,这使该搜索成为使用多核的自然之处:工作量与卫星数成正比,而几百颗的
|
||||
//! 壳层已足以值得动用线程。
|
||||
//!
|
||||
//! 并行入口所返回的与顺序入口完全相同,次序也相同,故调用方可在二者之间切换而
|
||||
//! 不改变它所计算的东西。
|
||||
|
||||
use crate::{AccessError, AccessFinder, OrbitSample, PassSummary};
|
||||
use apsis_math::parallel::map_index;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Ground station access windows.
|
||||
//!
|
||||
//! 地面站可见性窗口。
|
||||
//!
|
||||
//! A satellite is accessible from a ground station during the intervals when
|
||||
//! it rises above the station's elevation mask. Each such interval is a
|
||||
//! pass, or access window, and the sequence of windows over a period is the
|
||||
|
|
@ -32,6 +30,18 @@
|
|||
//! };
|
||||
//! assert!(finder.is_valid());
|
||||
//! ```
|
||||
//!
|
||||
//! 地面站可见性窗口。
|
||||
//!
|
||||
//! 当卫星升到地面站仰角遮蔽之上时,它在那段时间内可从该站访问。每个这样的区间
|
||||
//! 是一次过境,或称可见性窗口,而一段时间上的窗口序列即可见性调度。本 crate 从
|
||||
//! 传播后的轨道找出这些窗口,并报告其开始、结束、时长以及峰值处的几何。
|
||||
//!
|
||||
//! 窗口通过对仰角以固定步长采样、并对仰角穿过遮蔽的每个穿越加以细化来找到。采样
|
||||
//! 步长设定所能找到的最短过境,而细化给出独立于步长的穿越时刻精度。
|
||||
//!
|
||||
//! 仰角由地固系中的卫星位置求值,故调用方提供从轨道坐标系来的变换。在本工作区中
|
||||
//! 那是 `apsis-coord` 中的换算,配以来自 `apsis-frames` 的地球自转角。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ impl ConstellationError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: ConstellationErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -68,8 +66,6 @@ impl ConstellationError {
|
|||
/// Attaches a description of the values that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -78,8 +74,6 @@ impl ConstellationError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> ConstellationErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ impl Footprint {
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回覆盖区的中心半角,单位为弧度。
|
||||
///
|
||||
/// 这是卫星仍高于仰角遮蔽时的最大中心角。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn footprint_central_angle(
|
||||
satellite_radius: f64,
|
||||
|
|
@ -128,6 +132,8 @@ pub fn footprint_central_angle(
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回卫星与仰角遮蔽所对应的覆盖区。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn footprint(
|
||||
satellite_radius: f64,
|
||||
|
|
@ -146,6 +152,10 @@ pub fn footprint(
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回覆盖区的面积,单位为平方千米。
|
||||
///
|
||||
/// 这是 [`Footprint::area`] 的自由函数形式。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn footprint_area(satellite_radius: f64, body_radius: f64, elevation_mask: f64) -> Option<f64> {
|
||||
Some(footprint(satellite_radius, body_radius, elevation_mask)?.area())
|
||||
|
|
@ -155,6 +165,8 @@ pub fn footprint_area(satellite_radius: f64, body_radius: f64, elevation_mask: f
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回覆盖区所占地球表面的比例。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn footprint_fraction(
|
||||
satellite_radius: f64,
|
||||
|
|
@ -226,6 +238,11 @@ pub fn point_in_footprint(
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回自地面看覆盖区边缘的仰角,单位为弧度。
|
||||
///
|
||||
/// 它是 [`footprint_central_angle`] 的逆,当已知覆盖区而想求它对应的遮蔽时
|
||||
/// 有用。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn footprint_edge_elevation(satellite_radius: f64, footprint: &Footprint) -> Option<f64> {
|
||||
elevation_from_central_angle(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
//! The spherical geometry of a satellite, a ground point, and the Earth's
|
||||
//! centre.
|
||||
//!
|
||||
//! 卫星、地面点与地心的球面几何。
|
||||
//!
|
||||
//! The three points form a triangle. The angles of that triangle are the
|
||||
//! elevation at the ground point, the nadir angle at the satellite, and the
|
||||
//! central angle at the centre of the Earth. Because the ground point is
|
||||
|
|
@ -27,6 +25,27 @@
|
|||
//! is the distance from the centre of the Earth to the ground point, so a
|
||||
//! station above sea level should pass its own radius rather than the
|
||||
//! equatorial radius.
|
||||
//!
|
||||
//! 卫星、地面点与地心的球面几何。
|
||||
//!
|
||||
//! 三个点构成一个三角形。该三角形的角是地面点处的仰角、卫星处的天底角,以及
|
||||
//! 地心处的中心角。因为地面点正位于当地地平之下,仰角与地面点处的邻角互补,故
|
||||
//! 三个角满足
|
||||
//!
|
||||
//! ```text
|
||||
//! elevation + nadir + central = 90 degrees
|
||||
//! ```
|
||||
//!
|
||||
//! 所关注的各量由正弦定理施加于该三角形得出:
|
||||
//!
|
||||
//! ```text
|
||||
//! sin(nadir) / body_radius = cos(elevation) / satellite_radius
|
||||
//! ```
|
||||
//!
|
||||
//! 其中出现余弦,是因为三角形内地面点处的角是仰角的余角。
|
||||
//!
|
||||
//! 所有角以弧度计,所有长度以千米计。天体半径是自地心到地面点的距离,故海拔高于
|
||||
//! 海平面的站应传其自身的半径,而非赤道半径。
|
||||
|
||||
use core::f64::consts::FRAC_PI_2;
|
||||
|
||||
|
|
@ -68,6 +87,10 @@ pub fn nadir_angle(satellite_radius: f64, body_radius: f64, elevation: f64) -> O
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回星下点与地面点之间的地心中心角,单位为弧度。
|
||||
///
|
||||
/// 中心角是地心处两个径向方向之间的角。它是沿地表的距离除以天体半径。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn earth_central_angle(satellite_radius: f64, body_radius: f64, elevation: f64) -> Option<f64> {
|
||||
let nadir = nadir_angle(satellite_radius, body_radius, elevation)?;
|
||||
|
|
@ -101,6 +124,21 @@ pub fn earth_central_angle(satellite_radius: f64, body_radius: f64, elevation: f
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回卫星与地面点之间的斜距,单位为千米。
|
||||
///
|
||||
/// 该距离是直线距离,而非沿地表的距离。它是链路预算所需的量,因为它决定自由
|
||||
/// 空间路径损耗。
|
||||
///
|
||||
/// 该关系是余弦定理施加于卫星、地面点与地心构成的三角形:
|
||||
///
|
||||
/// ```text
|
||||
/// range^2 = satellite_radius^2 + body_radius^2
|
||||
/// - 2 satellite_radius body_radius cos(central)
|
||||
/// ```
|
||||
///
|
||||
/// 此处用余弦定理而非等价形式 `Rs sin(central) / cos(elevation)`,因为后者在
|
||||
/// 天顶处奇异,那里仰角是直角、其余弦为零,尽管那里的距离恰是高度。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn slant_range(satellite_radius: f64, body_radius: f64, elevation: f64) -> Option<f64> {
|
||||
let central = earth_central_angle(satellite_radius, body_radius, elevation)?;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Ground coverage analysis.
|
||||
//!
|
||||
//! 地面覆盖分析。
|
||||
//!
|
||||
//! A satellite covers the part of the Earth's surface from which it can be
|
||||
//! seen above a minimum elevation angle. That part is a circle, called the
|
||||
//! footprint, whose size depends on the satellite altitude and on the
|
||||
|
|
@ -43,6 +41,26 @@
|
|||
//! .expect("valid geometry");
|
||||
//! assert!((range - 1_815.65).abs() < 0.01);
|
||||
//! ```
|
||||
//!
|
||||
//! 地面覆盖分析。
|
||||
//!
|
||||
//! 卫星覆盖地表上能在最小仰角以上看到它的那部分。那部分是一个圆,称为覆盖区,
|
||||
//! 其大小取决于卫星高度与仰角遮蔽。本 crate 计算覆盖区几何、判定某地面点是否落在
|
||||
//! 覆盖区内,并度量某区域被覆盖的比例。
|
||||
//!
|
||||
//! [`geometry`](self) 中的球面模型把地球当作一个球。对星座设计已足够准确,那里
|
||||
//! 所要的量是覆盖区半径到万分之几以及可见卫星数。[`line_of_sight`] 中的精确视线
|
||||
//! 判定使用实际位置,故它计入了扁率以及高于椭球的地面点。
|
||||
//!
|
||||
//! 卫星、地面点与地心构成的几何是一个三角形。其三个角是地面点处的仰角、卫星处的
|
||||
//! 天底角,以及地心处的中心角,它们相加为直角:
|
||||
//!
|
||||
//! ```text
|
||||
//! elevation + nadir + central = 90 degrees
|
||||
//! ```
|
||||
//!
|
||||
//! 出处:此处所用的关系是标准的卫星几何,例如见 Vallado, D. A.,*Fundamentals of
|
||||
//! Astrodynamics and Applications*,第 4 版,microcosm Press,2013,第 5.3 节。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -19,10 +19,6 @@ pub struct GroundPoint {
|
|||
/// The ellipsoid the position is referred to.
|
||||
///
|
||||
/// 该位置所参照的椭球。
|
||||
///
|
||||
/// 该位置所参照的椭球。
|
||||
///
|
||||
/// 该位置所参照的椭球。
|
||||
pub ellipsoid: Ellipsoid,
|
||||
/// The sensor elevation mask, in radians.
|
||||
///
|
||||
|
|
@ -332,6 +328,11 @@ pub fn visible_from_geodetic(
|
|||
///
|
||||
/// Returns `None` when the geometry is not usable.
|
||||
///
|
||||
/// 返回卫星与地面站之间的中心角,单位为弧度。
|
||||
///
|
||||
/// 它使用两个半径与仰角之间的球面关系,故与覆盖区几何一致。卫星位置只用于其
|
||||
/// 半径。
|
||||
///
|
||||
/// 几何不可用时返回 `None`。
|
||||
pub fn central_angle_to_station(
|
||||
satellite_ecef_km: Vec3,
|
||||
|
|
|
|||
|
|
@ -201,6 +201,20 @@ fn validate(policy: &HandoverPolicy, candidates: &[Candidate]) -> Result<(), Han
|
|||
///
|
||||
/// Returns an error when the candidates or the policy are not usable.
|
||||
///
|
||||
/// 返回策略在不设驻留时间时所蕴含的决策。
|
||||
///
|
||||
/// 这是终端在每一瞬时独立决策、而调用方自行跟踪历史时所用的形式。当必须强制
|
||||
/// 驻留时间时,用 [`decide_with_history`]。
|
||||
///
|
||||
/// 各条规则,按其施加次序:
|
||||
///
|
||||
/// 1. 没有当前服务星时,获取最优候选;若没有一个满足最低质量,则放弃。
|
||||
/// 2. 当前服务星不在候选中时,它已不可用,故切换到最优候选;若没有一个满足
|
||||
/// 最低质量,则放弃。
|
||||
/// 3. 当前服务星低于最低质量时,放弃它而取最优候选;若没有一个满足最低质量,
|
||||
/// 则放弃。
|
||||
/// 4. 否则保持,除非某候选超出当前服务星的质量多于余量。
|
||||
///
|
||||
/// 候选或策略不可用时返回错误。
|
||||
pub fn decide(
|
||||
policy: &HandoverPolicy,
|
||||
|
|
@ -222,6 +236,13 @@ pub fn decide(
|
|||
///
|
||||
/// Returns an error when the candidates or the policy are not usable.
|
||||
///
|
||||
/// 返回策略在强制驻留时间时所蕴含的决策。
|
||||
///
|
||||
/// 它在 [`decide`] 的各条规则之上再加一条。当距上次切换的时间少于驻留时间时,
|
||||
/// 本会因质量增益而发生的切换被拒绝,终端保持。被强制的切换——因为当前服务星
|
||||
/// 已不可用或已跌至最低质量以下——无论如何都允许:拒绝它会掉链,这比驻留时间
|
||||
/// 所要防止的频繁切换更糟。
|
||||
///
|
||||
/// 候选或策略不可用时返回错误。
|
||||
pub fn decide_with_history(
|
||||
policy: &HandoverPolicy,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Handover decision logic for mobile terminals.
|
||||
//!
|
||||
//! 移动终端的切换决策逻辑。
|
||||
//!
|
||||
//! A terminal that can be served by more than one satellite must choose one,
|
||||
//! and it must change its choice when the current server becomes unsuitable.
|
||||
//! This crate makes that decision. It does not compute access windows, which
|
||||
|
|
@ -47,6 +45,27 @@
|
|||
//! let decision = decide(&policy, Some(1), &candidates).expect("valid input");
|
||||
//! assert_eq!(decision, HandoverDecision::Stay);
|
||||
//! ```
|
||||
//!
|
||||
//! 移动终端的切换决策逻辑。
|
||||
//!
|
||||
//! 能被不止一颗卫星服务的终端必须选择其一,并在当前服务星变得不合适时改变其
|
||||
//! 选择。本 crate 作出该决策。它不计算可见性窗口,那属于可见性层;它接收一份带有
|
||||
//! 各自质量的候选卫星列表,并决定是否切换。
|
||||
//!
|
||||
//! 有两种效果相互对抗,二者都必须纳入策略:
|
||||
//!
|
||||
//! - **切换太迟**会掉链。若当前服务星跌到终端的最低值以下,链路在切换发生之前即
|
||||
//! 失效。
|
||||
//! - **切换太频繁**浪费容量与时间。每次切换都要付出信令代价并中断数据流,故在每个
|
||||
//! 小起伏上都切换的终端表现很差,即便每个单独的选择看起来更好。
|
||||
//!
|
||||
//! 故该策略有三部分:当前服务星被视为不可用的阈值、候选在值得切换之前必须超出
|
||||
//! 当前服务星的余量,以及两次切换之间的最短时间。该余量正是抑制振荡者,也是该
|
||||
//! 决策的滞回。
|
||||
//!
|
||||
//! 出处:阈值、余量与驻留时间的结构即蜂窝网与卫星网中切换所用者,例如见 ITU-R
|
||||
//! 建议书 M.1184 关于移动卫星系统技术特性的内容,以及移动无线电中切换滞回的一般
|
||||
//! 论述。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -284,6 +284,11 @@ impl HandoverTracker {
|
|||
///
|
||||
/// Returns an error when the candidates or the policy are not usable.
|
||||
///
|
||||
/// 在某一时刻把策略施加于一组候选。
|
||||
///
|
||||
/// 跟踪器按该决策更新其状态并返回该决策,使调用方既能对它作出反应,也能
|
||||
/// 依赖跟踪器已记录它。
|
||||
///
|
||||
/// 候选或策略不可用时返回错误。
|
||||
pub fn step(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Deciding many links at once, optionally across several threads.
|
||||
//!
|
||||
//! 一次判定许多链路,可选跨多个线程。
|
||||
//!
|
||||
//! Building a constellation's topology asks the same question for every pair
|
||||
//! of satellites, which is a quadratic number of independent geometry tests.
|
||||
//! Each one is small, but there are so many that the loop is the dominant
|
||||
|
|
@ -11,6 +9,15 @@
|
|||
//! The parallel entry point returns exactly what the sequential one does, in
|
||||
//! the same order, so a caller can switch between them without changing the
|
||||
//! graph it builds.
|
||||
//!
|
||||
//! 一次判定许多链路,可选跨多个线程。
|
||||
//!
|
||||
//! 构建星座的拓扑会对每对卫星问同一个问题,即二次数量的独立几何判定。每个都很
|
||||
//! 小,但数量如此之多,使该循环成为构建图的主要代价,且各判定彼此独立,故它们是
|
||||
//! 使用多核的自然之处。
|
||||
//!
|
||||
//! 并行入口所返回的与顺序入口完全相同,次序也相同,故调用方可在二者之间切换而
|
||||
//! 不改变它所构建的图。
|
||||
|
||||
use crate::geometry::mutual_visibility;
|
||||
use apsis_math::{Vec3, parallel::map_index};
|
||||
|
|
@ -44,7 +51,6 @@ pub fn visibility_matrix(positions: &[Vec3], body_radius: f64) -> Vec<bool> {
|
|||
}
|
||||
|
||||
/// Returns the visibility of every ordered pair of positions, across several
|
||||
/// 跨多个线程返回各位置有序对的可见性。
|
||||
/// threads.
|
||||
///
|
||||
/// The result matches [`visibility_matrix`] element for element and in the
|
||||
|
|
@ -58,6 +64,15 @@ pub fn visibility_matrix(positions: &[Vec3], body_radius: f64) -> Vec<bool> {
|
|||
/// hundred satellites already gain, while a few dozen lose. The sequential
|
||||
/// form is the better choice for a small shell, and this one exists for the
|
||||
/// large ones where the quadratic sweep dominates.
|
||||
///
|
||||
/// 跨多个线程返回各位置有序对的可见性。
|
||||
///
|
||||
/// 结果与 [`visibility_matrix`] 逐元素、逐次序相同。各对相互独立,故把扁平的
|
||||
/// 下标空间跨线程划分无需协调,且无论工作如何划分都产生相同的矩阵。
|
||||
///
|
||||
/// 此处的线程收益不大,并随矩阵变小而缩小。单次可见性判定只有几纳秒,故启动
|
||||
/// 线程的代价只有大矩阵才回收:在十六核机器上,几百颗卫星已有收益,而几十颗则
|
||||
/// 亏损。顺序形式是小壳层的更好选择,而这个存在是为了二次扫描占主导的大壳层。
|
||||
pub fn visibility_matrix_parallel(positions: &[Vec3], body_radius: f64) -> Vec<bool> {
|
||||
let len = positions.len();
|
||||
// The pairs are independent, so splitting the flat index space across
|
||||
|
|
|
|||
|
|
@ -106,8 +106,6 @@ pub fn link_geometry(first: Vec3, second: Vec3, body_radius: f64) -> Option<Link
|
|||
/// Returns `true` when the Sun is within the field of view of an optical
|
||||
/// link.
|
||||
///
|
||||
/// 当太阳位于某光链路的视场内时返回 `true`。
|
||||
///
|
||||
/// The test is the angle between the link direction and the direction to the
|
||||
/// Sun. If that angle is within the field of view at either terminal, the
|
||||
/// Sun is in the beam and the link cannot be used.
|
||||
|
|
@ -122,6 +120,18 @@ pub fn link_geometry(first: Vec3, second: Vec3, body_radius: f64) -> Option<Link
|
|||
/// caller with such an ephemeris supplies the direction.
|
||||
///
|
||||
/// Returns `None` when the directions or the field of view are not usable.
|
||||
///
|
||||
/// 当太阳位于某光链路的视场内时返回 `true`。
|
||||
///
|
||||
/// 判据是链路方向与太阳方向之间的夹角。若该夹角落在任一终端的视场内,则太阳进入
|
||||
/// 波束,该链路不可用。
|
||||
///
|
||||
/// 视场以半角(弧度)给出,即望远镜的接受锥角。典型光终端的半角为若干微弧度。
|
||||
///
|
||||
/// 太阳方向是与位置同系的单位矢量。本 crate 不计算它,因为这需要太阳星历,而
|
||||
/// orbit 层当前不提供;拥有该星历的调用方自行提供该方向。
|
||||
///
|
||||
/// 方向或视场不可用时返回 `None`。
|
||||
pub fn sun_blocks_link(
|
||||
link: &LinkGeometry,
|
||||
sun_direction: Vec3,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Inter-satellite link geometry and visibility.
|
||||
//!
|
||||
//! 星间链路几何与可见性。
|
||||
//!
|
||||
//! Two satellites can form a link when the straight line between them does
|
||||
//! not pass through the Earth. This crate decides that condition, gives the
|
||||
//! geometry a link budget needs, and reports the range and the angles at
|
||||
|
|
@ -34,6 +32,20 @@
|
|||
//! let opposite = Vec3::new(-6_928.137, 0.0, 0.0);
|
||||
//! assert_eq!(mutual_visibility(first, opposite, 6_378.137), Some(false));
|
||||
//! ```
|
||||
//!
|
||||
//! 星间链路几何与可见性。
|
||||
//!
|
||||
//! 当两颗卫星之间的直线不穿过地球时,它们可以形成一条链路。本 crate 判定该条件、
|
||||
//! 给出链路预算所需的几何,并报告距离以及每颗卫星必须指向的角度。
|
||||
//!
|
||||
//! 遮挡判据是两点之间的线段是否有点位于天体内部。对球形天体而言这是一个垂距判定,
|
||||
//! 它精确且廉价,故此处采用它。
|
||||
//!
|
||||
//! 光链路还加一个条件:太阳不得位于任一终端的视场内,因为背景会淹没信号。那是一个
|
||||
//! 单独的判定,作为 [`sun_blocks_link`] 提供,它接收太阳方向。
|
||||
//!
|
||||
//! 长度以千米计,角度以弧度计。各位置所在的坐标系中地球是给定半径的球,对链路
|
||||
//! 几何而言它与 orbit 层所产生的是同一坐标系。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Mesh connectivity abstractions.
|
||||
//!
|
||||
//! 网格连通性抽象。
|
||||
//!
|
||||
//! A satellite mesh is a set of terminals that reach each other through
|
||||
//! links, some of which are satellite links and some of which are ground
|
||||
//! links. This crate provides the abstractions that a mesh application needs
|
||||
|
|
@ -40,6 +38,25 @@
|
|||
//! assert!(mesh.is_connected());
|
||||
//! assert_eq!(mesh.edge_connectivity(0, 1), Some(2));
|
||||
//! ```
|
||||
//!
|
||||
//! 网格连通性抽象。
|
||||
//!
|
||||
//! 卫星网格是一组经链路互相到达的终端,其中一些是卫星链路、一些是地面链路。本
|
||||
//! crate 提供网格应用在拓扑之上所需的抽象:哪些终端能到达哪些其他终端、有多少条
|
||||
//! 独立路径可以做到,以及哪些链路是关键。
|
||||
//!
|
||||
//! 本 crate 回答的三个问题:
|
||||
//!
|
||||
//! - **可达性**:自某给定终端可达的终端集合。
|
||||
//! - **冗余度**:连接两个终端的独立路径条数,即可独立失效的链路数。依 Menger 定理,
|
||||
//! 它是该图的边连通度。
|
||||
//! - **关键性**:移除后会切开网格的那些链路,即网络运营者必须保护的链路。
|
||||
//!
|
||||
//! 冗余度计算对卫星网格所呈现的小图是精确的。它使用 Menger 定理的边版本,从一
|
||||
//! 系列单位容量的最大流问题计算连通度。
|
||||
//!
|
||||
//! 出处:Menger 定理,以及把边连通度归约为最大流,见 Cormen 等,
|
||||
//! *Introduction to Algorithms*,第 3 版,MIT Press,2009,第 26 章。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Shortest path computation over a topology.
|
||||
//!
|
||||
//! 某拓扑上的最短路径计算。
|
||||
//!
|
||||
//! The algorithm is Dijkstra's, using a binary heap keyed by the tentative
|
||||
//! distance. Costs are positive, so a node's distance is final when it is
|
||||
//! first removed from the heap, which makes the algorithm exact.
|
||||
|
|
@ -10,6 +8,22 @@
|
|||
//! standard library's [`BinaryHeap`](std::collections::BinaryHeap) is a
|
||||
//! maximum heap. The key is the tentative distance, and ties are broken by
|
||||
//! the node index so that the result is deterministic for a given topology.
|
||||
//!
|
||||
//! 该算法是 Dijkstra 的,使用以暂定距离为键的二叉堆。代价为正,故某节点首次从
|
||||
//! 堆中取出时其距离即为最终,这使该算法精确。
|
||||
//!
|
||||
//! 该堆是反转排序键上的最小堆,因为标准库的
|
||||
//! [`BinaryHeap`](std::collections::BinaryHeap) 是最大堆。键是暂定距离,并列时按
|
||||
//! 节点下标打破,使结果对给定拓扑是确定的。
|
||||
//!
|
||||
//! 某拓扑上的最短路径计算。
|
||||
//!
|
||||
//! 该算法是 Dijkstra 的,使用以暂定距离为键的二叉堆。代价为正,故某节点首次从
|
||||
//! 堆中取出时其距离即为最终,这使该算法精确。
|
||||
//!
|
||||
//! 该堆是反转排序键上的最小堆,因为标准库的
|
||||
//! [`BinaryHeap`](std::collections::BinaryHeap) 是最大堆。键是暂定距离,并列时按
|
||||
//! 节点下标打破,使结果对给定拓扑是确定的。
|
||||
|
||||
use crate::error::{RoutingError, RoutingErrorKind};
|
||||
use crate::route::{Route, RouteLeg, RouteStep};
|
||||
|
|
@ -58,12 +72,15 @@ impl PartialOrd for Candidate {
|
|||
|
||||
/// The result of a single source shortest path computation.
|
||||
///
|
||||
/// 单源最短路计算的结果。
|
||||
///
|
||||
/// The distances are to every node reachable from the source, and the
|
||||
/// predecessor map records the edge by which each node was reached. Both are
|
||||
/// what a routing table needs, and a single computation fills a whole row of
|
||||
/// it.
|
||||
///
|
||||
/// 单源最短路计算的结果。
|
||||
///
|
||||
/// 各距离是自源到每个可达节点的距离,而前驱图记录每个节点是经哪条边到达的。二者
|
||||
/// 都是路由表所需的,且一次计算即填满它的一整行。
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct PathTree {
|
||||
/// The source node.
|
||||
|
|
@ -83,10 +100,12 @@ pub struct PathTree {
|
|||
impl PathTree {
|
||||
/// Returns the distance to a node.
|
||||
///
|
||||
/// 返回到某节点的距离。
|
||||
///
|
||||
/// Returns `None` when the node index is out of range or the node is
|
||||
/// unreachable.
|
||||
///
|
||||
/// 返回到某节点的距离。
|
||||
///
|
||||
/// 当节点下标越界或节点不可达时返回 `None`。
|
||||
pub fn distance(&self, node: usize) -> Option<f64> {
|
||||
let distance = *self.distances.get(node)?;
|
||||
distance.is_finite().then_some(distance)
|
||||
|
|
@ -102,8 +121,6 @@ impl PathTree {
|
|||
/// Returns the number of reachable nodes, including the source itself.
|
||||
///
|
||||
/// 返回可达节点的数量,含源点自身。
|
||||
///
|
||||
/// 返回可达节点的数量,含源点自身。
|
||||
pub fn reachable_count(&self) -> usize {
|
||||
self.distances
|
||||
.iter()
|
||||
|
|
@ -209,10 +226,14 @@ pub fn shortest_paths_from(topology: &Topology, source: usize) -> Result<PathTre
|
|||
})
|
||||
}
|
||||
|
||||
/// 返回两节点之间的最短路由。
|
||||
/// Returns the shortest route between two nodes.
|
||||
///
|
||||
/// Returns an error when either node is out of range, when they are the
|
||||
/// same node, or when no route exists.
|
||||
///
|
||||
/// 返回两节点之间的最短路由。
|
||||
///
|
||||
/// 任一节点越界、两者相同,或不存在路由时返回错误。
|
||||
pub fn shortest_path(
|
||||
topology: &Topology,
|
||||
source: usize,
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ impl RoutingError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: RoutingErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -67,8 +65,6 @@ impl RoutingError {
|
|||
/// Attaches a description of the values that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -77,8 +73,6 @@ impl RoutingError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> RoutingErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -86,8 +80,6 @@ impl RoutingError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Routing over time-varying satellite topologies.
|
||||
//!
|
||||
//! 时变卫星拓扑上的路由。
|
||||
//!
|
||||
//! The topology of a satellite network changes as the satellites move, so a
|
||||
//! route is only valid over an interval. This crate computes least cost
|
||||
//! routes through a [`Topology`] and reports the
|
||||
|
|
@ -41,6 +39,27 @@
|
|||
//! assert_eq!(route.nodes, vec![0, 1, 2]);
|
||||
//! assert!((route.cost - 2.0).abs() < 1e-12);
|
||||
//! ```
|
||||
//!
|
||||
//! 时变卫星拓扑上的路由。
|
||||
//!
|
||||
//! 卫星网络的拓扑随卫星移动而改变,故一条路由只在一个区间上有效。本 crate 计算
|
||||
//! 穿过 [`Topology`] 的最小代价路由,并把该路由连同其保持有效的时间一起报告。
|
||||
//!
|
||||
//! 提供两种路由形式:
|
||||
//!
|
||||
//! - [`shortest_path`] 找出在某一瞬时生效的拓扑中的最小代价路由。
|
||||
//! - [`route_over_series`] 找出对整个区间都有效的路由,方法是取该区间内各拓扑的
|
||||
//! 交集。
|
||||
//!
|
||||
//! 第二种形式是存储转发网络所需者。穿过一条中途改变的拓扑的路由,在新拓扑中可能
|
||||
//! 不存在,故一条路由只有在其每条链路都存活于它所规划的那个区间时才有用。
|
||||
//!
|
||||
//! 该算法是 Dijkstra 的,配以二叉堆。代价必须为正,这由拓扑层强制,故该算法精确:
|
||||
//! 某节点首次从堆中取出时其距离即为最终。
|
||||
//!
|
||||
//! 出处:Dijkstra, E. W.,*A note on two problems in connexion with graphs*,
|
||||
//! Numerische Mathematik 1,1959,以及二叉堆的表述,见 Cormen 等,
|
||||
//! *Introduction to Algorithms*,第 3 版,MIT Press,2009,第 24 章。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Time-varying network topology.
|
||||
//!
|
||||
//! 时变网络拓扑。
|
||||
//!
|
||||
//! A satellite network is not a single graph. The set of usable links
|
||||
//! changes as the satellites move, so the network is a sequence of graphs
|
||||
//! indexed by time, and this crate provides the data structures for that
|
||||
|
|
@ -35,6 +33,21 @@
|
|||
//! assert_eq!(series.len(), 1);
|
||||
//! assert!(series.topology_at(0.0).expect("a topology exists").has_edge(0, 1));
|
||||
//! ```
|
||||
//!
|
||||
//! 时变网络拓扑。
|
||||
//!
|
||||
//! 卫星网络不是单一的图。可用链路的集合随卫星移动而改变,故该网络是按时间索引的
|
||||
//! 一个图序列,而本 crate 提供该序列的数据结构。
|
||||
//!
|
||||
//! 模型有意简单。一个 [`Topology`] 是节点集合固定、边集合可有可无的图,节点是卫星
|
||||
//! 或地面站。一个 [`TopologySeries`] 是递增时刻上一串拓扑,连同各自适用的区间。
|
||||
//!
|
||||
//! 该序列是阶跃函数:一个拓扑从其自身时间起保持到下一项的时间。这是时变图的标准
|
||||
//! 离散时间模型,也是对该序列路由所期望的。
|
||||
//!
|
||||
//! 边除存在与否外还携带代价,使路由算法有可最小化之物。该代价是一个普通数,故
|
||||
//! 调用方可以放一个时延、一个跳数,或任何别的东西,只要路由算法与代价在含义上
|
||||
//! 一致。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Resource and time conflict detection.
|
||||
//!
|
||||
//! 资源与时间冲突检测。
|
||||
//!
|
||||
//! A schedule can be wrong in several ways, and this crate finds them. It
|
||||
//! reports conflicts rather than refusing them, so that a plan loaded from a
|
||||
//! file can be checked in full and every problem listed at once instead of
|
||||
|
|
@ -45,6 +43,22 @@
|
|||
//! assert_eq!(report.conflicts().len(), 0);
|
||||
//! let _ = ConflictKind::Capacity;
|
||||
//! ```
|
||||
//!
|
||||
//! 资源与时间冲突检测。
|
||||
//!
|
||||
//! 一份调度可能以若干方式出错,本 crate 找出它们。它报告冲突而非拒绝它们,使从
|
||||
//! 文件加载的计划能被完整检查,并一次列出每个问题,而不是每次尝试报一个。
|
||||
//!
|
||||
//! 检测五类冲突:
|
||||
//!
|
||||
//! - **容量**:两处放置在同一瞬时需要的某资源超过该资源所有。
|
||||
//! - **窗口**:一处放置在任务可开始之前开始,或在它必须结束之后结束。
|
||||
//! - **需求**:一处放置的任务未知,或其时长与调度不符。
|
||||
//! - **可用性**:一处放置落在它所需某资源的可用性窗口之外,故该资源实际上不在场。
|
||||
//! - **先后**:一个必须跟随另一任务的任务在其结束之前开始。
|
||||
//!
|
||||
//! 容量冲突与可用性冲突之别在实践中要紧:前者说明计划超额承诺,后者说明计划在资源
|
||||
//! 被关闭或不可见之时索求它,二者是不同的修复。
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ impl ResourceError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: ResourceErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -72,8 +70,6 @@ impl ResourceError {
|
|||
/// Attaches a description of the values that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -82,8 +78,6 @@ impl ResourceError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> ResourceErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -91,8 +85,6 @@ impl ResourceError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@ impl ScheduleError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: ScheduleErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -77,8 +75,6 @@ impl ScheduleError {
|
|||
/// Attaches a description of the values that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -87,8 +83,6 @@ impl ScheduleError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> ScheduleErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -96,8 +90,6 @@ impl ScheduleError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,8 +186,6 @@ impl Evaluation {
|
|||
/// Returns `true` when every offered task was placed.
|
||||
///
|
||||
/// 当所有提交任务均被放置时返回 `true`。
|
||||
///
|
||||
/// 当所有提交任务均被放置时返回 `true`。
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.placed_count == self.offered_count
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! A second pass that tries to place what the greedy first pass left out.
|
||||
//!
|
||||
//! 第二遍,尝试放置贪心第一遍所遗漏的。
|
||||
//!
|
||||
//! The greedy pass places each task at the earliest time it fits and never
|
||||
//! moves a placement once it is made, so a task that does not fit is lost
|
||||
//! even when moving a placement would make room. This pass addresses the
|
||||
|
|
@ -27,6 +25,26 @@
|
|||
//! with resource constraints is intractable, so the pass reduces the loss
|
||||
//! rather than removing it, and the caller continues to see what was left
|
||||
//! out.
|
||||
//!
|
||||
//! 第二遍,尝试放置贪心第一遍所遗漏的。
|
||||
//!
|
||||
//! 贪心遍把每个任务放到它放得下的最早时间,且一处放置作出后绝不移动,故放不下的
|
||||
//! 任务会丢失,即便移动一处放置能腾出空间。本遍处理该问题中最便宜的情形。
|
||||
//!
|
||||
//! 对一个被遗漏的任务,本遍查看阻挡它的各放置,即与它共享某个它所需资源的放置。
|
||||
//! 对每个阻挡者,它尝试对这一对做重定位:
|
||||
//!
|
||||
//! 1. 记下阻挡者所在,然后移除它。
|
||||
//! 2. 找出等待任务在无它时放得下的最早时间。
|
||||
//! 3. 把等待任务放到那里,然后问阻挡者在有了新邻居后能否放到别处。
|
||||
//! 4. 当二者都放得下时保留新安排,否则撤销它。
|
||||
//!
|
||||
//! 第 4 步的检查就是整个安全性论证:仅当两处放置都通过贪心遍所用的同一可行性判定时
|
||||
//! 才保留这一对,故每次被接受的重定位都使调度保持可行。
|
||||
//!
|
||||
//! 本遍是有界的。每对重定位花费两次可行性搜索,而每对只尝试有界次数,故本遍在任务
|
||||
//! 数上保持线性。它仍是启发式:带资源约束的调度是难解的,故本遍减少损失而非消除它,
|
||||
//! 而调用方继续看到被遗漏的内容。
|
||||
|
||||
use crate::sweep::earliest_feasible_start;
|
||||
use apsis_resource::ResourceSet;
|
||||
|
|
|
|||
|
|
@ -126,8 +126,6 @@ impl SchedulingResult {
|
|||
/// Returns `true` when every offered task was placed.
|
||||
///
|
||||
/// 当所有提交任务均被放置时返回 `true`。
|
||||
///
|
||||
/// 当所有提交任务均被放置时返回 `true`。
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.outcomes.iter().all(PlanOutcome::is_scheduled)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! The earliest start search, done in one pass over the schedule.
|
||||
//!
|
||||
//! 最早开始搜索,对调度做一遍完成。
|
||||
//!
|
||||
//! The sequential form asks the same question in a loop: it lists every time
|
||||
//! at which feasibility could change, sorts them, and tests each in turn until
|
||||
//! one passes. That is correct but it recomputes the busy profile of every
|
||||
|
|
@ -21,6 +19,21 @@
|
|||
//! sweep and the direct test disagree because of floating point rounding at a
|
||||
//! capacity boundary. The fast path is therefore an accelerator, never a
|
||||
//! second definition of what is feasible.
|
||||
//!
|
||||
//! 最早开始搜索,对调度做一遍完成。
|
||||
//!
|
||||
//! 顺序形式在循环中问同一个问题:它列出可行性可能改变的每个时刻,排序,并逐个
|
||||
//! 检验直到有一个通过。这正确,但它对每个候选都重算每个资源的繁忙廓线,故在一
|
||||
//! 资源上有很多放置的计划,判定每个任务花费二次工作,整个计划花费三次工作。
|
||||
//!
|
||||
//! 廓线并不依赖于候选。一处放置在它的开始与结束之间繁忙,无论新任务被提议在什么
|
||||
//! 时间,故该资源没有空档的各区间对每个候选都相同。本模块把它们计算一次,从可用性
|
||||
//! 窗口中减去,并从最前读出所存活的最早开始。这是每个资源一次扫描加一次线性合并,
|
||||
//! 而不是每个候选一次扫描。
|
||||
//!
|
||||
//! 结果在返回前用 [`feasible_at`] 确认,而候选枚举被保留为回退,用于扫描与直接判定
|
||||
//! 因容量边界处的浮点舍入而不一致的罕见情形。故该快路径是加速器,绝不是可行性的
|
||||
//! 第二种定义。
|
||||
|
||||
use crate::greedy::{feasible_at_indexed, resources_have_capacity};
|
||||
use apsis_resource::ResourceId;
|
||||
|
|
|
|||
|
|
@ -78,8 +78,6 @@ impl TaskError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: TaskErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -87,8 +85,6 @@ impl TaskError {
|
|||
/// Attaches a description of the values that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -97,8 +93,6 @@ impl TaskError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> TaskErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -106,8 +100,6 @@ impl TaskError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Precedence constraints between tasks.
|
||||
//!
|
||||
//! 任务之间的先后约束。
|
||||
//!
|
||||
//! A precedence constraint says that one task must finish before another
|
||||
//! starts. A set of such constraints forms a directed acyclic graph, and a
|
||||
//! scheduler must respect it: a task cannot be placed until every task that
|
||||
|
|
@ -16,6 +14,18 @@
|
|||
//! because the constraints are a property of the set of tasks rather than of
|
||||
//! any one task, and because a caller may want to plan the same tasks under
|
||||
//! different constraint graphs.
|
||||
//!
|
||||
//! 任务之间的先后约束。
|
||||
//!
|
||||
//! 一条先后约束说一个任务必须在另一个开始之前完成。一组这样的约束构成有向无环图,
|
||||
//! 而调度器必须遵守它:一个任务在其必须先行的每个任务都被放置并完成之前无法被
|
||||
//! 放置。
|
||||
//!
|
||||
//! 该图以邻接表存储。它在添加边时拒绝环,因为环不是一组可满足的约束,且否则会产生
|
||||
//! 一个空的拓扑序,调用方可能把它误认为调度失败而非建模错误。
|
||||
//!
|
||||
//! 先后关系图是与 [`Task`](crate::Task) 不同的类型,因为约束是任务集合的性质而非
|
||||
//! 任一单个任务的性质,也因为调用方可能想在不同约束图下规划同一批任务。
|
||||
|
||||
use crate::error::{TaskError, TaskErrorKind};
|
||||
use crate::task::TaskId;
|
||||
|
|
|
|||
|
|
@ -20,20 +20,14 @@ pub struct Sample {
|
|||
/// The time of the sample, in seconds from the caller's origin.
|
||||
///
|
||||
/// 样本时刻,单位为自调用方原点起的秒数。
|
||||
///
|
||||
/// 样本时刻,单位为自调用方原点起的秒数。
|
||||
pub seconds: f64,
|
||||
/// Position, in kilometers.
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
pub position: Vec3,
|
||||
/// Velocity, in kilometers per second.
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
pub velocity: Vec3,
|
||||
}
|
||||
|
||||
|
|
@ -41,8 +35,6 @@ impl Sample {
|
|||
/// Creates a sample.
|
||||
///
|
||||
/// 创建一个样本。
|
||||
///
|
||||
/// 创建一个样本。
|
||||
pub const fn new(seconds: f64, position: Vec3, velocity: Vec3) -> Self {
|
||||
Self {
|
||||
seconds,
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ impl EphemerisError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: EphemerisErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -72,8 +70,6 @@ impl EphemerisError {
|
|||
/// Attaches a description of the value that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -82,8 +78,6 @@ impl EphemerisError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub const fn kind(&self) -> EphemerisErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -91,8 +85,6 @@ impl EphemerisError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,20 +39,14 @@ pub struct KeplerianElements {
|
|||
/// Right ascension of the ascending node, in radians.
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
pub right_ascension: f64,
|
||||
/// Argument of perigee, in radians.
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
pub argument_of_perigee: f64,
|
||||
/// True anomaly, in radians.
|
||||
///
|
||||
/// 真近点角,单位为弧度。
|
||||
///
|
||||
/// 真近点角,单位为弧度。
|
||||
pub true_anomaly: f64,
|
||||
}
|
||||
|
||||
|
|
@ -72,14 +66,10 @@ pub struct State {
|
|||
/// Position, in kilometers.
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
pub position: Vec3,
|
||||
/// Velocity, in kilometers per second.
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
pub velocity: Vec3,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ impl ManeuverError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: ManeuverErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -72,8 +70,6 @@ impl ManeuverError {
|
|||
/// Attaches a description of the value that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -82,8 +78,6 @@ impl ManeuverError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub const fn kind(&self) -> ManeuverErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -91,8 +85,6 @@ impl ManeuverError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ const ZNL: f64 = 1.583_521_8e-4;
|
|||
/// The rate of rotation of the Earth used by the resonance integral, in
|
||||
/// radians per minute.
|
||||
///
|
||||
/// 共振积分所用的地球自转速率,单位为每分钟弧度。
|
||||
///
|
||||
/// 该值为 `7.292 115 146 688 55e-5` 弧度每秒。
|
||||
const RPTIM: f64 = 4.375_269_088_011_3e-3;
|
||||
|
||||
|
|
@ -819,7 +821,8 @@ fn initialise_resonance(satellite: &Satellite, ls: &Lunisolar, deep: &mut DeepSp
|
|||
// Half-day resonance. The eccentricity series is evaluated at the
|
||||
// eccentricity from the element set, not the value carried through
|
||||
// the secular rates.
|
||||
// 半日共振。偏心率级数取
|
||||
// 半日共振。偏心率级数按根数集给出的偏心率求值,而非按经长期速率
|
||||
// 传递后的值。
|
||||
let cosisq = cosim * cosim;
|
||||
let emo = em;
|
||||
let em = satellite.ecco;
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ impl PropagationError {
|
|||
/// Creates an error with the given category.
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
///
|
||||
/// 用给定类别创建一个错误。
|
||||
pub fn new(kind: PropagationErrorKind) -> Self {
|
||||
Self { kind, detail: None }
|
||||
}
|
||||
|
|
@ -61,8 +59,6 @@ impl PropagationError {
|
|||
/// Attaches a description of the value that caused the failure.
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
///
|
||||
/// 附加对该失败所涉数值的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -71,8 +67,6 @@ impl PropagationError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> PropagationErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -80,8 +74,6 @@ impl PropagationError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,32 +78,22 @@ pub struct Elements {
|
|||
/// Eccentricity, dimensionless.
|
||||
///
|
||||
/// 偏心率,无量纲。
|
||||
///
|
||||
/// 偏心率,无量纲。
|
||||
pub eccentricity: f64,
|
||||
/// Inclination, in radians.
|
||||
///
|
||||
/// 倾角,单位为弧度。
|
||||
///
|
||||
/// 倾角,单位为弧度。
|
||||
pub inclination: f64,
|
||||
/// Right ascension of the ascending node, in radians.
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
pub right_ascension: f64,
|
||||
/// Argument of perigee, in radians.
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
pub argument_of_perigee: f64,
|
||||
/// Mean anomaly, in radians.
|
||||
///
|
||||
/// 平近点角,单位为弧度。
|
||||
///
|
||||
/// 平近点角,单位为弧度。
|
||||
pub mean_anomaly: f64,
|
||||
}
|
||||
|
||||
|
|
@ -139,19 +129,6 @@ impl Elements {
|
|||
}
|
||||
}
|
||||
|
||||
/// Applies the Kozai to Brouwer mean motion correction.
|
||||
///
|
||||
/// The mean motion in an element set is a Kozai mean motion, which the
|
||||
/// theory must convert to a Brouwer mean motion before use. The relation is
|
||||
///
|
||||
/// ```text
|
||||
/// n0 = n / (1 + 1.5 k2 (3 cos^2 i - 1) / (a^2 sqrt(1 - e^2)) / a^2)
|
||||
/// ```
|
||||
///
|
||||
/// written in the form used here as a fixed point iteration, because `a`
|
||||
/// depends on `n0` through Kepler's third law. The iteration converges from
|
||||
/// the unmodified mean motion in a few steps for every orbit that appears in
|
||||
/// an element set.
|
||||
/// Applies the Kozai to Brouwer mean motion correction.
|
||||
///
|
||||
/// The mean motion in an element set is a Kozai mean motion, which the
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ pub(crate) fn propagate(satellite: &Satellite, minutes: f64) -> Result<State, Pr
|
|||
// The `aycof` and `xlcof` used below come from the perturbed
|
||||
// inclination in the deep space branch and from the epoch inclination
|
||||
// otherwise.
|
||||
// 下文所用的 `aycof` 与 `xlcof` 来自受扰动的
|
||||
// 下文所用的 `aycof` 与 `xlcof`,在深空分支中来自受扰动的倾角,其余
|
||||
// 情形下来自历元倾角。
|
||||
let (aycof, xlcof) = if satellite.method == Method::DeepSpace {
|
||||
let aycof = -0.5 * satellite.model.j3_over_j2() * sin_perturbed;
|
||||
let xlcof = if (cos_perturbed + 1.0).abs() > INCLINATION_GUARD {
|
||||
|
|
|
|||
|
|
@ -64,26 +64,18 @@ pub struct Satellite {
|
|||
/// Inclination, in radians.
|
||||
///
|
||||
/// 倾角,单位为弧度。
|
||||
///
|
||||
/// 倾角,单位为弧度。
|
||||
pub(crate) inclo: f64,
|
||||
/// Right ascension of the ascending node, in radians.
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
///
|
||||
/// 升交点赤经,单位为弧度。
|
||||
pub(crate) nodeo: f64,
|
||||
/// Argument of perigee, in radians.
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
///
|
||||
/// 近地点幅角,单位为弧度。
|
||||
pub(crate) argpo: f64,
|
||||
/// Mean anomaly, in radians.
|
||||
///
|
||||
/// 平近点角,单位为弧度。
|
||||
///
|
||||
/// 平近点角,单位为弧度。
|
||||
pub(crate) mo: f64,
|
||||
/// `BSTAR` drag term, in inverse Earth radii.
|
||||
///
|
||||
|
|
@ -234,6 +226,8 @@ impl Satellite {
|
|||
/// the elements are rejected.
|
||||
///
|
||||
/// 由已解析的根数集初始化卫星。
|
||||
///
|
||||
/// 当根数被拒绝时,返回一个说明哪个根数不可传播的错误。
|
||||
pub fn try_from_element(
|
||||
element: &TwoLineElement,
|
||||
model: GravityModel,
|
||||
|
|
@ -290,6 +284,8 @@ impl Satellite {
|
|||
/// The instant is a Modified Julian Date on the TAI scale.
|
||||
///
|
||||
/// 返回卫星在某瞬时的状态。
|
||||
///
|
||||
/// 该瞬时是 TAI 时标上的约化儒略日。
|
||||
pub fn propagate_at(&self, tai_mjd: f64) -> Result<State, PropagationError> {
|
||||
self.propagate_minutes(self.minutes_since_epoch(tai_mjd))
|
||||
}
|
||||
|
|
@ -307,6 +303,9 @@ impl Satellite {
|
|||
///
|
||||
/// 返回卫星距根数集历元若干分钟处的状态。
|
||||
///
|
||||
/// 负值向后传播。结果在真赤道平春分点坐标系中,位置以千米计、速度以千米
|
||||
/// 每秒计。
|
||||
///
|
||||
/// 当传播所得半径低于一个地球半径时返回
|
||||
/// [`PropagationErrorKind::Decayed`](crate::PropagationErrorKind::Decayed),
|
||||
/// 模型将其视为卫星已经再入。
|
||||
|
|
|
|||
|
|
@ -21,14 +21,10 @@ pub struct State {
|
|||
/// Position, in kilometers.
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
///
|
||||
/// 位置,单位为千米。
|
||||
pub position: Vec3,
|
||||
/// Velocity, in kilometers per second.
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
///
|
||||
/// 速度,单位为千米每秒。
|
||||
pub velocity: Vec3,
|
||||
/// The propagated semi-major axis, in kilometers.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -87,8 +87,6 @@ impl ElementError {
|
|||
/// Attaches a description of the offending text.
|
||||
///
|
||||
/// 附加对有问题的文本的说明。
|
||||
///
|
||||
/// 附加对有问题的文本的说明。
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
|
|
@ -97,8 +95,6 @@ impl ElementError {
|
|||
/// Returns the category of this failure.
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
///
|
||||
/// 返回该失败的类别。
|
||||
pub fn kind(&self) -> ElementErrorKind {
|
||||
self.kind
|
||||
}
|
||||
|
|
@ -120,8 +116,6 @@ impl ElementError {
|
|||
/// Returns the detail text attached to this error, if any.
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
///
|
||||
/// 返回附加在该错误上的说明文本,若有。
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_deref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,8 +257,6 @@ pub struct DelaunayArguments {
|
|||
/// The mean anomaly of the Moon.
|
||||
///
|
||||
/// 月球的平近点角。
|
||||
///
|
||||
/// 月球的平近点角。
|
||||
pub l: f64,
|
||||
/// The mean anomaly of the Sun.
|
||||
///
|
||||
|
|
@ -267,20 +265,14 @@ pub struct DelaunayArguments {
|
|||
/// The mean argument of latitude of the Moon.
|
||||
///
|
||||
/// 月球的平纬度参数。
|
||||
///
|
||||
/// 月球的平纬度参数。
|
||||
pub f: f64,
|
||||
/// The mean elongation of the Moon from the Sun.
|
||||
///
|
||||
/// 月球相对太阳的平距角。
|
||||
///
|
||||
/// 月球相对太阳的平距角。
|
||||
pub d: f64,
|
||||
/// The mean longitude of the Moon's ascending node.
|
||||
///
|
||||
/// 月球升交点的平黄经。
|
||||
///
|
||||
/// 月球升交点的平黄经。
|
||||
pub omega: f64,
|
||||
}
|
||||
|
||||
|
|
@ -301,8 +293,6 @@ impl DelaunayArguments {
|
|||
/// Returns the arguments as an array in series order.
|
||||
///
|
||||
/// 按级数次序把各参数作为数组返回。
|
||||
///
|
||||
/// 按级数次序把各参数作为数组返回。
|
||||
pub const fn as_array(self) -> [f64; 5] {
|
||||
[self.l, self.l_prime, self.f, self.d, self.omega]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,11 +158,16 @@ fn planetary_term(term: &PlanetaryTerm, arguments: &PlanetaryArguments) -> Nutat
|
|||
/// Returns the nutation in longitude and obliquity for a time.
|
||||
///
|
||||
/// The time is in Julian centuries from J2000.0 on the Terrestrial Time
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度
|
||||
/// scale. This is the IAU 2000A model, which includes the planetary terms.
|
||||
///
|
||||
/// Source: IAU 2000A, as implemented by `eraNut00a`.
|
||||
///
|
||||
/// 返回某时刻的黄经与黄赤交角方向的章动。
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度。这是 IAU 2000A
|
||||
/// 模型,含行星项。
|
||||
///
|
||||
/// 出处:IAU 2000A,按 `eraNut00a` 所实现。
|
||||
pub fn nutation_2000a(t: f64) -> Nutation {
|
||||
let delaunay = DelaunayArguments::at(t);
|
||||
let planetary = PlanetaryArguments::at(t);
|
||||
|
|
|
|||
|
|
@ -130,11 +130,15 @@ pub fn mean_obliquity(t: f64) -> f64 {
|
|||
/// Returns the four precession angles for a time.
|
||||
///
|
||||
/// The time is in Julian centuries from J2000.0 on the Terrestrial Time
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度
|
||||
/// scale.
|
||||
///
|
||||
/// Source: the P03 precession, as implemented by `eraPfw06`.
|
||||
///
|
||||
/// 返回某时刻的四个岁差角。
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度。
|
||||
///
|
||||
/// 出处:P03 岁差,按 `eraPfw06` 所实现。
|
||||
pub fn precession_angles(t: f64) -> PrecessionAngles {
|
||||
let gamma_bar = -0.052_928
|
||||
+ t * (10.556_378
|
||||
|
|
@ -191,11 +195,17 @@ pub fn frame_bias_matrix() -> Mat3 {
|
|||
/// reach the true equator and equinox of date.
|
||||
///
|
||||
/// The time is in Julian centuries from J2000.0 on the Terrestrial Time
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度
|
||||
/// scale.
|
||||
///
|
||||
/// Source: as implemented by `eraPmat06`.
|
||||
///
|
||||
/// 返回从天球参考系到该日平赤道与平春分点的转动。
|
||||
///
|
||||
/// 这是偏差-岁差矩阵。章动施加于其上,以到达该日的真赤道与真春分点。
|
||||
///
|
||||
/// 时间以 J2000.0 起的儒略世纪计,位于地球时(TT)标度。
|
||||
///
|
||||
/// 出处:按 `eraPmat06` 所实现。
|
||||
pub fn bias_precession_matrix(t: f64) -> Mat3 {
|
||||
let angles = precession_angles(t);
|
||||
frame_to_mean_of_date(&angles)
|
||||
|
|
|
|||
|
|
@ -195,14 +195,10 @@ pub enum Pattern {
|
|||
/// The peak gain on boresight.
|
||||
///
|
||||
/// 视轴上的峰值增益。
|
||||
///
|
||||
/// 视轴上的峰值增益。
|
||||
peak: Gain,
|
||||
/// The half power beam width, in radians.
|
||||
///
|
||||
/// 半功率波束宽度,单位为弧度。
|
||||
///
|
||||
/// 半功率波束宽度,单位为弧度。
|
||||
beam_width: f64,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ fn sidelobe_branch(diameter_over_wavelength: f64) -> (f64, f64) {
|
|||
///
|
||||
/// Returns `None` when the ratio is not positive and finite.
|
||||
///
|
||||
/// 返回参考方向图的峰值增益,相对各向同性辐射体以分贝计。
|
||||
///
|
||||
/// 表达式为 `20 log10(D / lambda) + 7.7`。
|
||||
///
|
||||
/// 比值非正或非有限时返回 `None`。
|
||||
pub fn reference_peak_gain(diameter_over_wavelength: f64) -> Option<f64> {
|
||||
if !diameter_over_wavelength.is_finite() || diameter_over_wavelength <= 0.0 {
|
||||
|
|
@ -248,6 +252,11 @@ pub fn diameter_over_wavelength_from_peak_gain(peak_gain_dbi: f64) -> Option<f64
|
|||
///
|
||||
/// Returns `None` when the ratio is not positive and finite.
|
||||
///
|
||||
/// 返回参考方向图主瓣的半功率波束宽度,单位为弧度。
|
||||
///
|
||||
/// 主瓣在距视轴 `phi = sqrt(3 / 2.5e-3) / (D / lambda)` 度处降到三分贝,故
|
||||
/// 两个三分贝点之间的全宽是该值的两倍。
|
||||
///
|
||||
/// 比值非正或非有限时返回 `None`。
|
||||
pub fn reference_beam_width(diameter_over_wavelength: f64) -> Option<f64> {
|
||||
if !diameter_over_wavelength.is_finite() || diameter_over_wavelength <= 0.0 {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Specific attenuation of atmospheric gases.
|
||||
//!
|
||||
//! 大气气体的比衰减。
|
||||
//!
|
||||
//! The attenuation caused by oxygen and water vapour is computed by the
|
||||
//! line-by-line summation of ITU-R Recommendation P.676. Each absorption
|
||||
//! line contributes a resonance whose strength depends on the temperature
|
||||
|
|
@ -22,6 +20,23 @@
|
|||
//! gases*, sections 1 and 2. The line tables are the ones tabulated in
|
||||
//! tables 1 and 2 of that recommendation, and the expressions for the line
|
||||
//! widths and the strengths are equations 1 through 8.
|
||||
//!
|
||||
//! 大气气体的比衰减。
|
||||
//!
|
||||
//! 氧与水汽造成的衰减由 ITU-R 建议书 P.676 的逐线求和计算。每条吸收线贡献一个
|
||||
//! 共振,其强度经线宽与气压频移取决于温度与气压。
|
||||
//!
|
||||
//! 该模型由四个大气量参数化:
|
||||
//!
|
||||
//! - 干空气气压,以百帕计。
|
||||
//! - 水汽密度,以克每立方米计。
|
||||
//! - 温度,以开尔文计。
|
||||
//! - 频率,以吉赫兹计。
|
||||
//!
|
||||
//! 气压是干空气气压,而非总气压。水汽分压由密度与温度得出,二者在线宽中分开使用。
|
||||
//!
|
||||
//! 出处:ITU-R 建议书 P.676-12,*Attenuation by atmospheric gases*,第 1 与第 2
|
||||
//! 节。各线表即该建议书表 1 与表 2 所列,而线宽与线强的表达式是式 1 至式 8。
|
||||
|
||||
use core::f64::consts::E;
|
||||
|
||||
|
|
@ -40,32 +55,22 @@ struct OxygenLine {
|
|||
/// The line frequency, in gigahertz.
|
||||
///
|
||||
/// 线频率,以吉赫兹计。
|
||||
///
|
||||
/// 线频率,以吉赫兹计。
|
||||
f0: f64,
|
||||
/// Line strength coefficient.
|
||||
///
|
||||
/// 谱线强度系数。
|
||||
///
|
||||
/// 谱线强度系数。
|
||||
a1: f64,
|
||||
/// Temperature dependence of the line strength.
|
||||
///
|
||||
/// 谱线强度的温度依赖。
|
||||
///
|
||||
/// 谱线强度的温度依赖。
|
||||
a2: f64,
|
||||
/// Line width coefficient.
|
||||
///
|
||||
/// 谱线宽度系数。
|
||||
///
|
||||
/// 谱线宽度系数。
|
||||
a3: f64,
|
||||
/// Pressure dependence of the line width.
|
||||
///
|
||||
/// 谱线宽度的气压依赖。
|
||||
///
|
||||
/// 谱线宽度的气压依赖。
|
||||
a4: f64,
|
||||
/// Pressure shift coefficient.
|
||||
///
|
||||
|
|
@ -934,10 +939,15 @@ impl Atmosphere {
|
|||
///
|
||||
/// The frequency is in gigahertz.
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// Returns `None` when the frequency or atmosphere is not usable.
|
||||
///
|
||||
/// 返回干空气的比衰减,单位为分贝每千米。
|
||||
///
|
||||
/// 这是氧的贡献,由 ITU-R P.676-12 式 1 的逐线求和计算,加上计入所有谱线远翼
|
||||
/// 合在一起的非共振 Debye 项。
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// 频率或大气不可用时返回 `None`。
|
||||
pub fn specific_attenuation_dry_air(frequency_ghz: f64, atmosphere: Atmosphere) -> Option<f64> {
|
||||
if !frequency_ghz.is_finite() || frequency_ghz <= 0.0 || !atmosphere.is_valid() {
|
||||
|
|
@ -989,10 +999,14 @@ pub fn specific_attenuation_dry_air(frequency_ghz: f64, atmosphere: Atmosphere)
|
|||
///
|
||||
/// The frequency is in gigahertz.
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// Returns `None` when the frequency or atmosphere is not usable.
|
||||
///
|
||||
/// 返回水汽的比衰减,单位为分贝每千米。
|
||||
///
|
||||
/// 这是水汽的贡献,由 ITU-R P.676-12 式 1 的逐线求和计算。
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// 频率或大气不可用时返回 `None`。
|
||||
pub fn specific_attenuation_water_vapour(
|
||||
frequency_ghz: f64,
|
||||
|
|
@ -1035,6 +1049,10 @@ pub fn specific_attenuation_water_vapour(
|
|||
///
|
||||
/// Returns `None` when the frequency or atmosphere is not usable.
|
||||
///
|
||||
/// 返回大气的总比衰减,单位为分贝每千米。
|
||||
///
|
||||
/// 这是干空气与水汽贡献之和。
|
||||
///
|
||||
/// 频率或大气不可用时返回 `None`。
|
||||
pub fn specific_attenuation(frequency_ghz: f64, atmosphere: Atmosphere) -> Option<f64> {
|
||||
Some(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Slant path attenuation through the atmosphere.
|
||||
//!
|
||||
//! 穿过大气的斜路径衰减。
|
||||
//!
|
||||
//! The attenuation along a slant path is not simply the specific attenuation
|
||||
//! divided by the sine of the elevation, because the atmosphere thins with
|
||||
//! height and the path is curved. ITU-R Recommendation P.676 reduces the
|
||||
|
|
@ -15,6 +13,17 @@
|
|||
//! pressure and temperature.
|
||||
//!
|
||||
//! Source: ITU-R Recommendation P.676-12, equations 30 through 38.
|
||||
//!
|
||||
//! 穿过大气的斜路径衰减。
|
||||
//!
|
||||
//! 斜路径上的衰减并非简单地是比衰减除以仰角的正弦,因为大气随高度变稀薄且路径
|
||||
//! 是弯曲的。ITU-R 建议书 P.676 把问题归约为两个等效高度,一为干空气、一为水汽,
|
||||
//! 使天顶衰减是地表处的比衰减乘以该高度。
|
||||
//!
|
||||
//! 干空气的等效高度经氧复合体的形状取决于频率,水汽的等效高度取决于频率与水汽
|
||||
//! 密度。二者都依赖于地表气压与温度。
|
||||
//!
|
||||
//! 出处:ITU-R 建议书 P.676-12,式 30 至式 38。
|
||||
|
||||
use crate::gaseous::{Atmosphere, specific_attenuation_dry_air, specific_attenuation_water_vapour};
|
||||
|
||||
|
|
@ -89,9 +98,16 @@ pub struct EquivalentHeights {
|
|||
///
|
||||
/// Returns `None` when the frequency or atmosphere is not usable.
|
||||
///
|
||||
/// 返回干空气与水汽的等效高度。
|
||||
///
|
||||
/// 各高度是这样的长度:乘以地表比衰减即给出天顶衰减。干空气高度在 70 GHz
|
||||
/// 以下被限制到一个依赖气压的界,那里氧复合体足够窄,否则该高度会被高估。
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// 频率或大气不可用时返回 `None`。
|
||||
///
|
||||
/// Source: ITU-R Recommendation P.676-12, equations 30 through 38.
|
||||
/// 出处:ITU-R 建议书 P.676-12,式 30 至式 38。
|
||||
pub fn equivalent_heights(frequency_ghz: f64, atmosphere: Atmosphere) -> Option<EquivalentHeights> {
|
||||
if !frequency_ghz.is_finite() || frequency_ghz <= 0.0 || !atmosphere.is_valid() {
|
||||
return None;
|
||||
|
|
@ -167,6 +183,12 @@ pub fn equivalent_heights(frequency_ghz: f64, atmosphere: Atmosphere) -> Option<
|
|||
///
|
||||
/// Returns `None` when the frequency or atmosphere is not usable.
|
||||
///
|
||||
/// 返回大气的天顶衰减,单位为分贝。
|
||||
///
|
||||
/// 这是地表比衰减乘以等效高度,并对两个成分求和。
|
||||
///
|
||||
/// 频率单位为吉赫。
|
||||
///
|
||||
/// 频率或大气不可用时返回 `None`。
|
||||
pub fn zenith_attenuation(frequency_ghz: f64, atmosphere: Atmosphere) -> Option<f64> {
|
||||
let heights = equivalent_heights(frequency_ghz, atmosphere)?;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! The reference standard atmosphere of ITU-R Recommendation P.835.
|
||||
//!
|
||||
//! ITU-R 建议书 P.835 的参考标准大气。
|
||||
//!
|
||||
//! The exact slant path method of Recommendation P.676 integrates the
|
||||
//! specific attenuation through a stack of layers, so it needs the
|
||||
//! temperature, pressure, and water vapour density at each layer height.
|
||||
|
|
@ -15,6 +13,17 @@
|
|||
//!
|
||||
//! Source: ITU-R Recommendation P.835-6, *Reference Standard Atmospheres*,
|
||||
//! section 1, the mean annual global reference atmosphere.
|
||||
//!
|
||||
//! ITU-R 建议书 P.835 的参考标准大气。
|
||||
//!
|
||||
//! 建议书 P.676 的精确斜路径方法在一叠层上积分比衰减,故它需要每一层高度处的
|
||||
//! 温度、气压与水汽密度。本模块由建议书 P.835 的年平均全球参考大气提供这些。
|
||||
//!
|
||||
//! 高度在热层底部以下以势高度度量。势高度是为引力随高度变化而调整过的几何高度,
|
||||
//! 它是温度与气压廓线所表达的自变量。
|
||||
//!
|
||||
//! 出处:ITU-R 建议书 P.835-6,*Reference Standard Atmospheres*,第 1 节,年
|
||||
//! 平均全球参考大气。
|
||||
|
||||
/// The radius of the Earth used in the geopotential conversion, in
|
||||
/// kilometers.
|
||||
|
|
@ -66,6 +75,11 @@ pub fn geopotential_height(geometric_height_km: f64) -> f64 {
|
|||
///
|
||||
/// The geometric height is in kilometers.
|
||||
///
|
||||
/// 返回参考大气的温度,单位为开尔文。
|
||||
///
|
||||
/// 该廓线在势高度 84.852 km 以下分段线性,其后由延伸至 100 km 的两段定义。
|
||||
/// 100 km 以上该建议书不定义全球廓线,本函数返回 100 km 处的值。
|
||||
///
|
||||
/// 几何高度单位为千米。
|
||||
pub fn standard_temperature(geometric_height_km: f64) -> f64 {
|
||||
let height = geopotential_height(geometric_height_km);
|
||||
|
|
@ -101,6 +115,10 @@ pub fn standard_temperature(geometric_height_km: f64) -> f64 {
|
|||
///
|
||||
/// The geometric height is in kilometers.
|
||||
///
|
||||
/// 返回参考大气的气压,单位为百帕。
|
||||
///
|
||||
/// 该廓线是分段的,在各分段边界处连续,由静力关系施加于每个温度分段得出。
|
||||
///
|
||||
/// 几何高度单位为千米。
|
||||
pub fn standard_pressure(geometric_height_km: f64) -> f64 {
|
||||
let height = geopotential_height(geometric_height_km);
|
||||
|
|
@ -136,6 +154,10 @@ pub fn standard_pressure(geometric_height_km: f64) -> f64 {
|
|||
///
|
||||
/// The geometric height is in kilometers.
|
||||
///
|
||||
/// 返回参考大气的水汽密度,单位为克每立方米。
|
||||
///
|
||||
/// 该廓线是指数式的,标高两千米,并缩放使地表的密度为所给值。
|
||||
///
|
||||
/// 几何高度单位为千米。
|
||||
pub fn standard_water_vapour_density(geometric_height_km: f64, surface_density: f64) -> f64 {
|
||||
surface_density * (-geometric_height_km / 2.0).exp()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! The rain height model of ITU-R Recommendation P.839.
|
||||
//!
|
||||
//! ITU-R 建议书 P.839 的雨顶高度模型。
|
||||
//!
|
||||
//! The height of the rain layer is taken as the height of the zero degree
|
||||
//! isotherm above sea level. The recommendation tabulates that height on a
|
||||
//! global grid, and the value at a given location is found by bilinear
|
||||
|
|
@ -14,6 +12,16 @@
|
|||
//!
|
||||
//! Source: ITU-R Recommendation P.839-4, *Rain height model for prediction
|
||||
//! methods*.
|
||||
//!
|
||||
//! ITU-R 建议书 P.839 的雨顶高度模型。
|
||||
//!
|
||||
//! 雨层的高度取为零度等温线在海平面以上的高度。该建议书把该高度列在一个全球网格
|
||||
//! 上,而给定位置处的值由周围四个网格点之间的双线性插值求得。
|
||||
//!
|
||||
//! 雨顶高度是下落雪花融化的高度,其下降水为液态。其上的衰减小得多,故它是衰减层的
|
||||
//! 有效厚度,也是建议书 P.618 路径计算的输入。
|
||||
//!
|
||||
//! 出处:ITU-R 建议书 P.839-4,*Rain height model for prediction methods*。
|
||||
|
||||
use crate::p839_table::ZERO_ISOTHERM_HEIGHT_METRES;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//! Rain attenuation.
|
||||
//!
|
||||
//! 降雨衰减。
|
||||
//!
|
||||
//! The specific attenuation of rain is modelled as a power law in the rain
|
||||
//! rate, `gamma = k R^alpha`, where `k` and `alpha` depend on the frequency,
|
||||
//! on the polarisation, and on the elevation. The coefficients are given by
|
||||
|
|
@ -23,6 +21,24 @@
|
|||
//! - Slant path method: ITU-R Recommendation P.618-13, *Propagation data and
|
||||
//! prediction methods required for the design of Earth-space
|
||||
//! telecommunication systems*, equations 1 through 10.
|
||||
//!
|
||||
//! 降雨衰减。
|
||||
//!
|
||||
//! 降雨的比衰减建模为降雨率中的幂律 `gamma = k R^alpha`,其中 `k` 与 `alpha`
|
||||
//! 取决于频率、极化与仰角。各系数由 ITU-R 建议书 P.838 以闭式曲线拟合而非表格给出,
|
||||
//! 这是该建议书当前修订版所采用的。
|
||||
//!
|
||||
//! 斜路径上的衰减遵循 ITU-R 建议书 P.618。穿过降雨的路径长度受站上方雨层高度限制,
|
||||
//! 而两个缩减因子计入降雨率沿路径并不均匀这一事实:一个水平缩减与一个垂直调整。
|
||||
//! 二者都依赖于比衰减,故该计算不是速率与长度的简单乘积。
|
||||
//!
|
||||
//! 出处:
|
||||
//!
|
||||
//! - 比衰减系数:ITU-R 建议书 P.838-3,*Specific attenuation model for rain for
|
||||
//! use in prediction methods*,式 2 与式 3 以及表 1 与表 2。
|
||||
//! - 斜路径方法:ITU-R 建议书 P.618-13,*Propagation data and prediction methods
|
||||
//! required for the design of Earth-space telecommunication systems*,式 1 至
|
||||
//! 式 10。
|
||||
|
||||
use apsis_rf::Decibel;
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ pub fn carrier_to_interference(carrier: Power, interferers: &[Interferer]) -> Op
|
|||
///
|
||||
/// Returns `None` when either power is not positive.
|
||||
///
|
||||
/// 返回单个干扰源下的载干比。
|
||||
///
|
||||
/// 这是为一个占主导的干扰源这一常见情形提供的便利。
|
||||
///
|
||||
/// 两个功率之一非正时返回 `None`。
|
||||
pub fn carrier_to_interference_single(carrier: Power, interferer: Interferer) -> Option<Decibel> {
|
||||
carrier_to_interference(carrier, &[interferer])
|
||||
|
|
@ -211,6 +215,11 @@ pub fn carrier_to_noise_plus_interference(
|
|||
///
|
||||
/// Returns `None` when either power is not positive.
|
||||
///
|
||||
/// 返回干扰与噪声之比。
|
||||
///
|
||||
/// 它把干扰功率与接收机中的热噪声功率相比较。远低于零分贝的值意味着干扰相对
|
||||
/// 噪声可忽略、可以不计;接近或高于零的值意味着必须计入它。
|
||||
///
|
||||
/// 两个功率之一非正时返回 `None`。
|
||||
pub fn interference_to_noise_ratio(interference: Power, noise: Power) -> Option<Decibel> {
|
||||
if !interference.is_valid() || !noise.is_valid() {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,11 @@ impl LinkBudget {
|
|||
///
|
||||
/// Returns `None` when any input is not usable.
|
||||
///
|
||||
/// 返回等效全向辐射功率,单位为瓦特。
|
||||
///
|
||||
/// 这是发射功率减去发射损耗、加上发射天线增益。它是一个各向同性辐射体为
|
||||
/// 在接收机方向上产生相同通量密度所必须辐射的功率。
|
||||
///
|
||||
/// 任一输入不可用时返回 `None`。
|
||||
pub fn eirp(&self) -> Option<Power> {
|
||||
if !self.transmit_loss.is_finite() || !self.geometry.is_valid() {
|
||||
|
|
@ -117,6 +122,8 @@ impl LinkBudget {
|
|||
///
|
||||
/// Returns `None` when any input is not usable.
|
||||
///
|
||||
/// 返回接收机输入端的载波功率,单位为瓦特。
|
||||
///
|
||||
/// 任一输入不可用时返回 `None`。
|
||||
pub fn received_power(&self) -> Option<Power> {
|
||||
if !self.receive_loss.is_finite() {
|
||||
|
|
@ -160,6 +167,11 @@ impl LinkBudget {
|
|||
///
|
||||
/// Returns `None` when any input is not usable.
|
||||
///
|
||||
/// 返回载噪密度比。
|
||||
///
|
||||
/// 这是载波功率除以一赫兹内的噪声功率。它是把链路与某调制的每比特能量要求
|
||||
/// 相比较所用的形式,因为数据速率被分开计入。
|
||||
///
|
||||
/// 任一输入不可用时返回 `None`。
|
||||
pub fn carrier_to_noise_density(&self) -> Option<Decibel> {
|
||||
let carrier = self.received_power()?;
|
||||
|
|
@ -183,6 +195,11 @@ impl LinkBudget {
|
|||
///
|
||||
/// Returns `None` when any input is not usable.
|
||||
///
|
||||
/// 返回接收机带宽内的载噪比。
|
||||
///
|
||||
/// 这是载噪密度比减去带宽的贡献。与密度比不同,它依赖于接收机,这正是同一
|
||||
/// 链路在不同带宽的接收机中可显示不同载噪比的原因。
|
||||
///
|
||||
/// 任一输入不可用时返回 `None`。
|
||||
pub fn carrier_to_noise(&self) -> Option<Decibel> {
|
||||
if !self.bandwidth.is_finite() || self.bandwidth <= 0.0 {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ use core::fmt;
|
|||
|
||||
/// A ratio expressed in decibels.
|
||||
///
|
||||
/// 以分贝表示的比值。
|
||||
///
|
||||
/// A decibel is ten times the base ten logarithm of a power ratio, so a
|
||||
/// value of zero is unity gain or loss, a value of three is very close to a
|
||||
/// doubling, and a value of minus three is very close to a halving.
|
||||
|
|
@ -15,6 +13,14 @@ use core::fmt;
|
|||
/// The type stores the decibel value rather than the ratio, because a chain
|
||||
/// of gains and losses is then a sum, which is both faster and less prone to
|
||||
/// overflow than a product of ratios.
|
||||
///
|
||||
/// 以分贝表示的比值。
|
||||
///
|
||||
/// 分贝是功率比的十进对数的十倍,故值为零是单位增益或损耗,值为三非常接近加倍,
|
||||
/// 值为负三非常接近减半。
|
||||
///
|
||||
/// 该类型存储分贝值而非比值,因为一串增益与损耗于是成为求和,这比比值之积既更快
|
||||
/// 也更不易溢出。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
|
||||
pub struct Decibel(f64);
|
||||
|
||||
|
|
@ -38,10 +44,12 @@ impl Decibel {
|
|||
|
||||
/// Creates a value from a power ratio.
|
||||
///
|
||||
/// 由功率比创建一个取值。
|
||||
///
|
||||
/// Returns `None` when the ratio is not positive and finite, because the
|
||||
/// logarithm is not defined there.
|
||||
///
|
||||
/// 由功率比创建一个取值。
|
||||
///
|
||||
/// 比值非正且非有限时返回 `None`,因为那里没有定义对数。
|
||||
pub fn from_ratio(ratio: f64) -> Option<Self> {
|
||||
if ratio > 0.0 && ratio.is_finite() {
|
||||
Some(Self(10.0 * ratio.log10()))
|
||||
|
|
|
|||
|
|
@ -82,8 +82,6 @@ impl Gain {
|
|||
/// Creates a gain from a linear ratio.
|
||||
///
|
||||
/// 由线性比值创建增益。
|
||||
///
|
||||
/// 由线性比值创建增益。
|
||||
pub const fn from_ratio(ratio: f64) -> Self {
|
||||
Self(ratio)
|
||||
}
|
||||
|
|
@ -129,6 +127,8 @@ impl Gain {
|
|||
///
|
||||
/// Returns `None` when the ratio is not positive.
|
||||
///
|
||||
/// 返回该增益,相对各向同性辐射体以分贝计。
|
||||
///
|
||||
/// 比值非正时返回 `None`。
|
||||
pub fn dbi(self) -> Option<f64> {
|
||||
if self.0 > 0.0 && self.0.is_finite() {
|
||||
|
|
@ -142,6 +142,8 @@ impl Gain {
|
|||
///
|
||||
/// Returns `None` when the ratio is not positive.
|
||||
///
|
||||
/// 返回该增益,相对半波振子以分贝计。
|
||||
///
|
||||
/// 比值非正时返回 `None`。
|
||||
pub fn dbd(self) -> Option<f64> {
|
||||
self.dbi().map(|dbi| dbi - DIPOLE_OVER_ISOTROPIC_DB)
|
||||
|
|
@ -151,6 +153,8 @@ impl Gain {
|
|||
///
|
||||
/// Returns `None` when the ratio is not positive.
|
||||
///
|
||||
/// 返回该增益,以分贝比表示。
|
||||
///
|
||||
/// 比值非正时返回 `None`。
|
||||
pub fn as_decibel(self) -> Option<Decibel> {
|
||||
Decibel::from_ratio(self.0)
|
||||
|
|
|
|||
|
|
@ -148,6 +148,10 @@ impl Power {
|
|||
///
|
||||
/// Returns `None` when either power is not positive.
|
||||
///
|
||||
/// 返回 `self` 与 `rhs` 之比,以分贝计。
|
||||
///
|
||||
/// 这是链路预算中用来表达两个功率电平之间损耗或增益的形式。
|
||||
///
|
||||
/// 两个功率之一非正时返回 `None`。
|
||||
pub fn ratio_in_decibels(self, rhs: Self) -> Option<Decibel> {
|
||||
if self.0 > 0.0 && rhs.0 > 0.0 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue