From 39c0ebce03e29497d4148b974e83c409a0d4a65e Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Fri, 2 Oct 2026 01:31:41 +0800 Subject: [PATCH] docs: bilingual comments for the antenna, doppler, interference and noise crates --- crates/rf/apsis-antenna/src/parabolic.rs | 66 +++++++++++++ crates/rf/apsis-antenna/src/pattern.rs | 4 + crates/rf/apsis-antenna/src/reference.rs | 54 +++++++++++ crates/rf/apsis-doppler/src/shift.rs | 111 ++++++++++++++++++++++ crates/rf/apsis-interference/src/ratio.rs | 80 ++++++++++++++++ crates/rf/apsis-noise/src/cascade.rs | 52 ++++++++++ crates/rf/apsis-noise/src/temperature.rs | 54 +++++++++++ crates/rf/apsis-rf/src/free_space.rs | 38 ++++++++ crates/rf/apsis-rf/src/gain.rs | 13 +++ 9 files changed, 472 insertions(+) diff --git a/crates/rf/apsis-antenna/src/parabolic.rs b/crates/rf/apsis-antenna/src/parabolic.rs index e720ee1..768e6a6 100644 --- a/crates/rf/apsis-antenna/src/parabolic.rs +++ b/crates/rf/apsis-antenna/src/parabolic.rs @@ -10,16 +10,28 @@ use core::f64::consts::PI; /// wave: illumination taper, spillover, blockage by the feed and its /// supports, and surface error. A well adjusted dish reaches 0.65 to 0.70, /// and a small or simply built one is nearer 0.55. +/// +/// 由其直径与孔径效率描述的抛物面反射体。 +/// +/// 孔径效率汇集了从送到馈源的功率到以均匀平面波离开孔径的功率之间的 +/// 每一项损耗:照射锥削、溢出、馈源及其支撑的遮挡,以及表面误差。调准 +/// 良好的天线达到 0.65 至 0.70,小而简易的接近 0.55。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct ParabolicAperture { /// The reflector diameter, in meters. + /// + /// 反射面直径,单位为米。 pub diameter: f64, /// The aperture efficiency, dimensionless, in `(0, 1]`. + /// + /// 孔径效率,无量纲,落在 `(0, 1]` 内。 pub efficiency: f64, } impl ParabolicAperture { /// Returns the physical area of the aperture, in square meters. + /// + /// 返回孔径的物理面积,单位为平方米。 pub fn area(self) -> f64 { PI * (self.diameter / 2.0).powi(2) } @@ -29,11 +41,18 @@ impl ParabolicAperture { /// This is the physical area scaled by the aperture efficiency. It is /// the area that, if it collected uniformly, would deliver the observed /// power. + /// + /// 返回有效面积,单位为平方米。 + /// + /// 这是物理面积按孔径效率缩放后的值。它是这样一块面积:若均匀收集, + /// 将给出所观测到的功率。 pub fn effective_area(self) -> f64 { self.area() * self.efficiency } /// Returns `true` when the aperture describes a usable dish. + /// + /// 当该孔径描述一个可用天线时返回 `true`。 pub fn is_valid(self) -> bool { self.diameter.is_finite() && self.diameter > 0.0 @@ -53,6 +72,17 @@ impl ParabolicAperture { /// which follows from the effective area through /// [`Gain::from_effective_aperture`]. Returns `None` for an invalid /// aperture or wavelength. + /// + /// 返回给定波长处视轴上的峰值增益。 + /// + /// 关系为 + /// + /// ```text + /// G = eta (pi D / lambda)^2 + /// ``` + /// + /// 它由有效面积经 [`Gain::from_effective_aperture`] 得出。孔径或波长 + /// 无效时返回 `None`。 pub fn peak_gain(self, wavelength: f64) -> Option { if !self.is_valid() { return None; @@ -69,6 +99,14 @@ impl ParabolicAperture { /// include the taper. /// /// Returns `None` for an invalid aperture or wavelength. + /// + /// 返回给定波长处的半功率波束宽度,单位为弧度。 + /// + /// 这里用的是均匀照射关系,即该直径天线所能达到的最窄。带照射锥削 + /// 的实际天线更宽;要计入锥削请用 + /// [`ParabolicAperture::half_power_beam_width`]。 + /// + /// 孔径或波长无效时返回 `None`。 pub fn uniform_beam_width(self, wavelength: f64) -> Option { if !self.is_valid() { return None; @@ -86,6 +124,14 @@ impl ParabolicAperture { /// well designed dish. /// /// Returns `None` for an invalid aperture or wavelength. + /// + /// 返回给定波长处的半功率波束宽度(弧度),并计入照射锥削。 + /// + /// 锥削照射以加宽主瓣为代价降低旁瓣。`theta = k lambda / D` 中的因子 + /// `k` 从均匀照射的约 1.02 升到最小化旁瓣的锥削的约 1.2。1.15 是 + /// 设计良好的天线的代表值。 + /// + /// 孔径或波长无效时返回 `None`。 pub fn half_power_beam_width(self, wavelength: f64) -> Option { if !self.is_valid() { return None; @@ -107,6 +153,17 @@ impl ParabolicAperture { /// /// Returns `None` when the diameter or wavelength is not positive, or when /// `k` is not positive. +/// +/// 返回圆孔径的半功率波束宽度,单位为弧度。 +/// +/// 关系为 `theta = k lambda / D`,其中 `k` 取决于孔径如何被照射。均匀 +/// 照射给出最窄波束,`k` 约为 1.02;抑制旁瓣的锥削给出最宽的,`k` 约为 +/// 1.2。 +/// +/// 结果是两个三分贝点之间的全宽,而非半宽。它是小角近似,故调用方应 +/// 确认所得宽度相对一弧度很小。 +/// +/// 直径或波长非正,或 `k` 非正时返回 `None`。 pub fn beam_width(diameter: f64, wavelength: f64, k: f64) -> Option { if !diameter.is_finite() || diameter <= 0.0 @@ -130,6 +187,15 @@ pub fn beam_width(diameter: f64, wavelength: f64, k: f64) -> Option { /// `theta = theta_0 sqrt(floor / 12)`. /// /// Returns `None` when the beam width or floor is not positive and finite. +/// +/// 返回 [`off_axis_attenuation`](crate::off_axis_attenuation) 的角平方律 +/// 到达旁瓣底限的角度。 +/// +/// 超过该角度后,模型把增益保持在底限,而非任其无界下降。该角度由令 +/// 衰减 `12 (theta / theta_0)^2` 等于底限得出,即 +/// `theta = theta_0 sqrt(floor / 12)`。 +/// +/// 波束宽度或底限非正且非有限时返回 `None`。 pub fn floor_angle(beam_width: f64, floor_db: f64) -> Option { if !beam_width.is_finite() || beam_width <= 0.0 { return None; diff --git a/crates/rf/apsis-antenna/src/pattern.rs b/crates/rf/apsis-antenna/src/pattern.rs index bc8ecdd..a332aa0 100644 --- a/crates/rf/apsis-antenna/src/pattern.rs +++ b/crates/rf/apsis-antenna/src/pattern.rs @@ -261,8 +261,12 @@ impl Pattern { #[derive(Debug, Clone, Copy, PartialEq)] pub struct ElementPattern { /// The peak gain on boresight. + /// + /// 视轴上的峰值增益。 pub peak: Gain, /// The half power beam width, in radians. + /// + /// 半功率波束宽度,单位为弧度。 pub beam_width: f64, /// The sidelobe floor, in decibels below the peak. /// diff --git a/crates/rf/apsis-antenna/src/reference.rs b/crates/rf/apsis-antenna/src/reference.rs index 5682aeb..dd6aea8 100644 --- a/crates/rf/apsis-antenna/src/reference.rs +++ b/crates/rf/apsis-antenna/src/reference.rs @@ -29,12 +29,22 @@ use core::f64::consts::PI; /// which corresponds to an aperture efficiency near 0.6. It is slightly /// below what a well adjusted dish reaches, because the reference pattern /// represents a typical rather than an optimal antenna. +/// +/// 参考方向图的峰值增益偏移,单位为分贝。 +/// +/// 建议书把峰值增益给出为 `20 log10(D / lambda) + 7.7`,对应约 0.6 的 +/// 孔径效率。它略低于调准良好的天线所达到者,因为参考方向图代表的是 +/// 典型天线而非最优天线。 pub const PEAK_GAIN_OFFSET_DB: f64 = 7.7; /// The diameter to wavelength ratio at which the pattern changes form. /// /// A larger antenna has a narrower main lobe, so its sidelobe region begins /// earlier and reaches the floor earlier. +/// +/// 方向图改变形式处的口径与波长之比。 +/// +/// 更大的天线主瓣更窄,故其旁瓣区开始得更早、到达底限也更早。 const LARGE_APERTURE_RATIO: f64 = 100.0; /// The constant and floor angle of the sidelobe region. @@ -42,6 +52,11 @@ const LARGE_APERTURE_RATIO: f64 = 100.0; /// The constant is the value of `G + 25 log10(phi_deg)` in the sidelobe /// region, and the floor angle is the angle at which the region reaches its /// floor. +/// +/// 旁瓣区的常数与底限角。 +/// +/// 该常数是旁瓣区内 `G + 25 log10(phi_deg)` 的值,底限角是该区到达其 +/// 底限的角度。 fn sidelobe_branch(diameter_over_wavelength: f64) -> (f64, f64) { if diameter_over_wavelength >= LARGE_APERTURE_RATIO { (29.0, 36.0) @@ -75,6 +90,14 @@ pub fn reference_peak_gain(diameter_over_wavelength: f64) -> Option { /// bisection reliable. /// /// The result lies between zero and the floor angle of the sidelobe region. +/// +/// 返回主瓣与旁瓣区相接的角度,单位为度。 +/// +/// 两个表达式在该角度处相交,且没有闭式解,故该值以二分法求得。主瓣按 +/// 角度的平方下降,而旁瓣区按其对数下降,故二者之差在所搜索区间内只有 +/// 一个零点,这使二分法可靠。 +/// +/// 结果落在零与旁瓣区底限角之间。 pub fn main_lobe_break_angle(diameter_over_wavelength: f64) -> Option { let peak = reference_peak_gain(diameter_over_wavelength)?; let (head, floor_angle) = sidelobe_branch(diameter_over_wavelength); @@ -87,6 +110,8 @@ pub fn main_lobe_break_angle(diameter_over_wavelength: f64) -> Option { // The main lobe dominates at very small angles and the sidelobe // expression dominates at the floor angle, so the zero lies between. + // 在很小的角度处主瓣占主导,在底限角处旁瓣表达式占主导,故零点位于 + // 二者之间。 let mut low = 1.0e-9; let mut high = floor_angle; if difference(high) > 0.0 { @@ -124,6 +149,25 @@ pub fn main_lobe_break_angle(diameter_over_wavelength: f64) -> Option { /// over. /// /// Returns `None` when the ratio or the angle is not usable. +/// +/// 返回 S.465 参考方向图在偏轴某角度处的增益。 +/// +/// 角度以弧度计。三个区是 +/// +/// ```text +/// G = G_max - 2.5e-3 (D/lambda phi_deg)^2 for 0 <= phi < phi_break +/// G = head - 25 log10(phi_deg) for phi_break <= phi < phi_floor +/// G = -10 for phi_floor <= phi <= 180 +/// ``` +/// +/// 其中 `phi_break` 是 [`main_lobe_break_angle`] 返回的角度,head 对大 +/// 孔径为 29、对小孔径为 32,底限角相应地是 36 或 48 度。 +/// +/// 下降的旁瓣表达式在底限角处并不精确达到负十分贝,故方向图在那里有 +/// 几百分之一分贝的台阶。这是建议书的性质,它把各区分开定义;此处照实 +/// 再现而非加以平滑。 +/// +/// 比值或角度不可用时返回 `None`。 pub fn reference_pattern_gain(diameter_over_wavelength: f64, off_axis_angle: f64) -> Option { if !off_axis_angle.is_finite() || off_axis_angle < 0.0 { return None; @@ -144,6 +188,10 @@ pub fn reference_pattern_gain(diameter_over_wavelength: f64, off_axis_angle: f64 /// Returns the gain of the S.465 reference pattern as a decibel value. /// /// Returns `None` when the ratio or the angle is not usable. +/// +/// 返回 S.465 参考方向图的增益,以分贝值表示。 +/// +/// 比值或角度不可用时返回 `None`。 pub fn reference_pattern_decibel( diameter_over_wavelength: f64, off_axis_angle: f64, @@ -161,6 +209,12 @@ pub fn reference_pattern_decibel( /// specified by its gain rather than its size. /// /// Returns `None` when the gain is not finite. +/// +/// 返回某峰值增益天线的口径与波长之比。 +/// +/// 它反解峰值增益表达式,当某站以其增益而非尺寸规定时有用。 +/// +/// 增益非有限时返回 `None`。 pub fn diameter_over_wavelength_from_peak_gain(peak_gain_dbi: f64) -> Option { if !peak_gain_dbi.is_finite() { return None; diff --git a/crates/rf/apsis-doppler/src/shift.rs b/crates/rf/apsis-doppler/src/shift.rs index 0511635..a670e8a 100644 --- a/crates/rf/apsis-doppler/src/shift.rs +++ b/crates/rf/apsis-doppler/src/shift.rs @@ -17,6 +17,16 @@ use core::fmt; /// /// Returns `None` when the separation is zero, because no line of sight is /// defined there, or when either argument is not finite. +/// +/// 返回两终端之间的距离变化率,单位为米每秒。 +/// +/// 距离变化率是相对速度沿两终端连线的分量。正值表示间距在增大。 +/// +/// 第一个参数是远端终端相对本地终端的位置,故其模即间距。第二个是远端 +/// 终端相对本地终端的速度。两者均为 SI 单位。 +/// +/// 间距为零时返回 `None`,因为那里没有定义视线;或任一参数非有限时 +/// 返回 `None`。 pub fn range_rate_from_velocity(relative_position: Vec3, relative_velocity: Vec3) -> Option { if !relative_position.is_finite() || !relative_velocity.is_finite() { return None; @@ -49,6 +59,23 @@ pub fn range_rate_from_velocity(relative_position: Vec3, relative_velocity: Vec3 /// /// Returns `None` when the frequency is not positive and finite, or when the /// range rate is not finite. +/// +/// 返回某频率对应某距离变化率的经典多普勒频移,单位为赫兹。 +/// +/// 关系为 +/// +/// ```text +/// delta f = -f_0 (v_r / c) +/// ``` +/// +/// 其中 `v_r` 是距离变化率,远离时为正。远离的终端其频移为负,故接收 +/// 频率低于发射频率。 +/// +/// 该频移的幅度相对载波很小:12 GHz 下 7 km/s 的距离变化率约给出 +/// 280 kHz,即十万分之二。故调用方必须把频率当作双精度处理,且移位后的 +/// 频率是单独返回,而非把一个小频移加到一个大数上。 +/// +/// 频率非正且非有限,或距离变化率非有限时返回 `None`。 pub fn classical_shift(carrier_frequency: f64, range_rate: f64) -> Option { if !carrier_frequency.is_finite() || carrier_frequency <= 0.0 { return None; @@ -75,6 +102,19 @@ pub fn classical_shift(carrier_frequency: f64, range_rate: f64) -> Option { /// /// Returns `None` when the range rate is not finite, or when its magnitude /// reaches the speed of light, where the expression has no real value. +/// +/// 返回某距离变化率的相对论多普勒因子。 +/// +/// 该因子为 `sqrt((1 - beta) / (1 + beta))`,其中 `beta = v_r / c`。把 +/// 发射频率乘以它便给出对 `beta` 各阶都正确的接收频率,故它不是对经典 +/// 频移的小修正,而是经典频移所近似的量。 +/// +/// 其展开为 `1 - beta + beta^2 / 2 - ...`。前两项是经典结果,它在本身为 +/// 二阶的因子之内即 `1 - beta`;其余项是两种处理之差。对轨道速度的 +/// 卫星,`beta` 约为 `2.3e-5`,二阶项约为载波的 `2.7e-10`,故两者相符 +/// 到十的十次方分之几。 +/// +/// 距离变化率非有限,或其幅度达到光速(此时该式无实值)时返回 `None`。 pub fn relativistic_doppler_factor(range_rate: f64) -> Option { if !range_rate.is_finite() { return None; @@ -91,11 +131,20 @@ pub fn relativistic_doppler_factor(range_rate: f64) -> Option { /// The type carries the carrier frequency and the range rate, so the /// transmitted and received frequencies and the shift itself are all /// available without ambiguity about which sign convention was used. +/// +/// 施加于载波的多普勒频移。 +/// +/// 该类型带有载波频率与距离变化率,故发射频率、接收频率以及频移本身都 +/// 可得,而不必对所用符号约定存疑。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct DopplerShift { /// The transmitted frequency, in hertz. + /// + /// 发射频率,单位为赫兹。 carrier: f64, /// The range rate, in meters per second, positive when receding. + /// + /// 距离变化率,单位为米每秒,远离时为正。 range_rate: f64, } @@ -104,6 +153,10 @@ impl DopplerShift { /// /// Returns `None` when the frequency is not positive and finite, or when /// the range rate is not finite. + /// + /// 由载波频率与距离变化率创建频移。 + /// + /// 频率非正且非有限,或距离变化率非有限时返回 `None`。 pub fn from_range_rate(carrier_frequency: f64, range_rate: f64) -> Option { classical_shift(carrier_frequency, range_rate)?; Some(Self { @@ -113,11 +166,15 @@ impl DopplerShift { } /// Returns the transmitted frequency, in hertz. + /// + /// 返回发射频率,单位为赫兹。 pub const fn carrier_frequency(self) -> f64 { self.carrier } /// Returns the range rate, in meters per second, positive when receding. + /// + /// 返回距离变化率,单位为米每秒,远离时为正。 pub const fn range_rate(self) -> f64 { self.range_rate } @@ -125,11 +182,17 @@ impl DopplerShift { /// Returns the shift, in hertz. /// /// The value is negative when the terminals are receding. + /// + /// 返回频移,单位为赫兹。 + /// + /// 两终端远离时该值为负。 pub fn shift(self) -> f64 { classical_shift(self.carrier, self.range_rate).unwrap_or(0.0) } /// Returns the received frequency, in hertz. + /// + /// 返回接收频率,单位为赫兹。 pub fn shifted_frequency(self) -> f64 { self.carrier + self.shift() } @@ -153,6 +216,20 @@ impl DopplerShift { /// the shift were added to the carrier before the correction. /// /// Returns `None` when the range rate reaches the speed of light. + /// + /// 返回含相对论钟改正的频移,单位为赫兹。 + /// + /// 接收频率是载波乘以相对论因子,故频移为 `f_0 (factor - 1)`。 + /// + /// 这不是经典频移加一个小修正:该因子已含一阶项,其展开为 + /// `1 - beta + beta^2 / 2 - ...`,其首项恰是经典频移。经典值是对它的 + /// 一阶近似,两者只差二阶及更高阶项,量级为 `beta^2`,对卫星而言是 + /// 载波的十的十次方分之几。 + /// + /// 先求因子、后乘载波,因为它与一之差极小,若在改正之前把频移加到 + /// 载波上会损失精度。 + /// + /// 距离变化率达到光速时返回 `None`。 pub fn shift_including_relativity(self) -> Option { let factor = relativistic_doppler_factor(self.range_rate)?; Some(self.carrier * (factor - 1.0)) @@ -162,6 +239,10 @@ impl DopplerShift { /// /// This is a convenient way to compare the shift of links on different /// carriers. + /// + /// 返回频移,以载波的百万分率计。 + /// + /// 这是比较位于不同载波上的链路频移的便利方式。 pub fn shift_in_ppm(self) -> f64 { self.shift() / self.carrier * 1.0e6 } @@ -172,6 +253,12 @@ impl DopplerShift { /// range acceleration. /// /// Returns `None` when the acceleration is not finite. + /// + /// 返回频移的变化率,单位为赫兹每秒。 + /// + /// 这是多普勒跟踪器必须跟随的量,它由距离加速度得出。 + /// + /// 加速度非有限时返回 `None`。 pub fn shift_rate(self, range_acceleration: f64) -> Option { if !range_acceleration.is_finite() { return None; @@ -181,6 +268,8 @@ impl DopplerShift { /// Returns `true` when the shift is a redshift, meaning the terminals /// are receding and the received frequency is lower. + /// + /// 当该频移是红移(即两终端远离、接收频率更低)时返回 `true`。 pub fn is_receding(self) -> bool { self.range_rate > 0.0 } @@ -209,6 +298,15 @@ impl fmt::Display for DopplerShift { /// /// Returns `None` when the velocity has zero length or either argument is /// not finite. +/// +/// 返回视线与速度之间的夹角,单位为弧度。 +/// +/// 它是二者所在平面内通常仰角的余角,当已知距离变化率且已知来自轨道的 +/// 速度时有用:该角由二者之比得出。 +/// +/// 结果落在 `[0, pi]` 内。 +/// +/// 速度为零长或任一参数非有限时返回 `None`。 pub fn angle_from_range_rate(velocity: Vec3, range_rate: f64) -> Option { if !velocity.is_finite() || !range_rate.is_finite() { return None; @@ -229,6 +327,13 @@ pub fn angle_from_range_rate(velocity: Vec3, range_rate: f64) -> Option { /// /// The result is returned as a positive magnitude. Returns `None` when the /// carrier or speed is not positive and finite. +/// +/// 返回某载波与某速度下可能的最大频移幅度,单位为赫兹。 +/// +/// 这是运动完全沿视线时的频移,即接收机必须覆盖的捕获范围宽度。它是在 +/// 接近与远离两个极端之间的总跨度的一半。 +/// +/// 结果以正幅度返回。载波或速度非正且非有限时返回 `None`。 pub fn maximum_shift(carrier_frequency: f64, speed: f64) -> Option { if !carrier_frequency.is_finite() || carrier_frequency <= 0.0 { return None; @@ -246,6 +351,12 @@ pub fn maximum_shift(carrier_frequency: f64, speed: f64) -> Option { /// the maximum shift. /// /// Returns `None` when the carrier or speed is not usable. +/// +/// 返回接收机为覆盖直到给定速度的每个距离变化率所必须接受的总频率跨度。 +/// +/// 接近与远离给出符号相反的频移,故该跨度是最大频移的两倍。 +/// +/// 载波或速度不可用时返回 `None`。 pub fn acquisition_span(carrier_frequency: f64, speed: f64) -> Option { maximum_shift(carrier_frequency, speed).map(|shift| 2.0 * shift) } diff --git a/crates/rf/apsis-interference/src/ratio.rs b/crates/rf/apsis-interference/src/ratio.rs index 802ba6c..a951daa 100644 --- a/crates/rf/apsis-interference/src/ratio.rs +++ b/crates/rf/apsis-interference/src/ratio.rs @@ -10,30 +10,50 @@ use apsis_rf::{Decibel, Power}; /// receive antenna gain in the direction of the interferer, and any /// propagation loss. This crate combines the powers; it does not compute the /// geometry. +/// +/// 在接收机输入端看到的一个干扰载波。 +/// +/// 功率是到达接收机的干扰功率,其中已含发射功率、发射增益、路径损耗、 +/// 干扰源方向上的接收天线增益,以及任何传播损耗。本 crate 只合并功率; +/// 它不计算几何。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct Interferer { /// The interfering power at the receiver input, in watts. + /// + /// 接收机输入端的干扰功率,单位为瓦特。 pub power: Power, } impl Interferer { /// Creates an interferer from a power at the receiver input. + /// + /// 由接收机输入端的功率创建干扰源。 pub const fn new(power: Power) -> Self { Self { power } } } /// The combined result of a wanted carrier and its interference. +/// +/// 有用载波与其干扰合并所得的结果。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct InterferenceSummary { /// The wanted carrier power, in watts. + /// + /// 有用载波功率,单位为瓦特。 pub carrier: Power, /// The total interfering power, in watts. + /// + /// 总干扰功率,单位为瓦特。 pub interference: Power, /// The carrier to interference ratio. + /// + /// 载干比。 pub carrier_to_interference: Decibel, /// The carrier to noise plus interference ratio, when a noise power was /// given. + /// + /// 载波与噪声加干扰之比,当给出了噪声功率时。 pub carrier_to_noise_plus_interference: Option, } @@ -42,6 +62,10 @@ impl InterferenceSummary { /// /// This is the reciprocal of the carrier to interference ratio and is /// the form some specifications use. + /// + /// 返回干扰与载波之比。 + /// + /// 它是载干比的倒数,是某些规范所用的形式。 pub fn interference_to_carrier(self) -> Decibel { self.carrier_to_interference.negated() } @@ -55,6 +79,13 @@ impl InterferenceSummary { /// six. /// /// Returns `None` when any interferer has an invalid power. +/// +/// 返回一组干扰源的总干扰功率。 +/// +/// 各干扰功率相加,因为它们是独立信号,要紧的是其功率而非幅度。故两个 +/// 相等的干扰源给出单个的两倍功率,即三分贝而非六分贝。 +/// +/// 任一干扰源的功率无效时返回 `None`。 pub fn total_interference(interferers: &[Interferer]) -> Option { let mut total = 0.0; for interferer in interferers { @@ -75,6 +106,13 @@ pub fn total_interference(interferers: &[Interferer]) -> Option { /// Returns `None` when the carrier is not positive, when any interferer is /// invalid, or when the total interference is zero, which would give an /// infinite ratio. +/// +/// 返回某载波与一组干扰源的载干比。 +/// +/// 该比是有用载波功率除以各干扰功率之和。比大意味着干扰源弱。 +/// +/// 载波非正、任一干扰源无效,或总干扰为零(会给出无穷的比)时返回 +/// `None`。 pub fn carrier_to_interference(carrier: Power, interferers: &[Interferer]) -> Option { if !carrier.is_valid() || carrier.watts() <= 0.0 { return None; @@ -112,12 +150,26 @@ pub fn carrier_to_interference_single(carrier: Power, interferer: Interferer) -> /// carrier to noise plus interference ratio. /// /// Returns `None` when either value is not finite. +/// +/// 把一个比与另一个同类之比合并。 +/// +/// 当两种独立损伤共同作用时,它们的效果按倒数之比相加,以分贝表示即 +/// +/// ```text +/// 1 / R = 1 / R_1 + 1 / R_2 +/// ``` +/// +/// 结果总低于两者中较小者,故加入第二种损伤只会降低合并之比。载噪比与 +/// 载干比正是这样合并为载波与噪声加干扰之比的。 +/// +/// 任一值非有限时返回 `None`。 pub fn combine(first: Decibel, second: Decibel) -> Option { if !first.is_finite() || !second.is_finite() { return None; } // A ratio of zero in decibels means an infinite impairment, so the // combination is also infinite. + // 分贝表示的比为零意味着无穷的损伤,故合并也是无穷的。 let first_ratio = first.ratio(); let second_ratio = second.ratio(); if !first_ratio.is_finite() || !second_ratio.is_finite() { @@ -134,6 +186,13 @@ pub fn combine(first: Decibel, second: Decibel) -> Option { /// carrier. /// /// Returns `None` when either ratio is not finite. +/// +/// 返回载波与噪声加干扰之比。 +/// +/// 它通过 [`combine`] 把载噪比与载干比合并。这是接收机实际经历的比,因为 +/// 它无法把热噪声与竞争载波分开。 +/// +/// 任一比非有限时返回 `None`。 pub fn carrier_to_noise_plus_interference( carrier_to_noise: Decibel, carrier_to_interference: Decibel, @@ -178,6 +237,20 @@ pub fn interference_to_noise_ratio(interference: Power, noise: Power) -> Option< /// /// Returns `None` when the power is not positive or the bandwidth is not /// positive and finite. +/// +/// 返回与某干扰功率等效的噪声温度。 +/// +/// 接收机当作噪声处理的干扰源可以折算为系统噪声温度的增量计入链路 +/// 预算。在温度上关系为 +/// +/// ```text +/// T = P / (k B) +/// ``` +/// +/// 其中 `P` 是干扰功率,`k` 是玻尔兹曼常量,`B` 是接收机噪声带宽。该 +/// 温度即加到系统温度上会使噪声上升与干扰源相同量的值。 +/// +/// 功率非正,或带宽非正且非有限时返回 `None`。 pub fn equivalent_noise_temperature(interference: Power, bandwidth: f64) -> Option { if !interference.is_valid() || interference.watts() <= 0.0 { return None; @@ -196,6 +269,13 @@ pub fn equivalent_noise_temperature(interference: Power, bandwidth: f64) -> Opti /// /// Returns `None` when the carrier is not positive, when any interferer is /// invalid, or when the total interference is zero. +/// +/// 返回某载波及其干扰的摘要。 +/// +/// 当给出噪声功率时,载波与噪声加干扰之比也一并算出。当只关注干扰时, +/// 噪声功率传 `None`。 +/// +/// 载波非正、任一干扰源无效,或总干扰为零时返回 `None`。 pub fn summarise( carrier: Power, interferers: &[Interferer], diff --git a/crates/rf/apsis-noise/src/cascade.rs b/crates/rf/apsis-noise/src/cascade.rs index 9c689fe..7625498 100644 --- a/crates/rf/apsis-noise/src/cascade.rs +++ b/crates/rf/apsis-noise/src/cascade.rs @@ -10,16 +10,28 @@ use apsis_rf::Gain; /// noise figure; both are converted to a temperature before the cascade is /// evaluated, because temperatures add across the chain while decibel /// figures do not. +/// +/// 接收链的一级。 +/// +/// 一级由其折算到自身输入所加的噪声与其所施加的增益描述。噪声可以温度或 +/// 噪声系数给出;两者都在评估级联之前换算为温度,因为温度在链中相加而 +/// 分贝系数不然。 #[derive(Debug, Clone, Copy, PartialEq)] pub struct Stage { /// The noise temperature added by this stage, referred to its input. + /// + /// 本级折算到其输入所加的噪声温度。 pub temperature: NoiseTemperature, /// The available gain of this stage. + /// + /// 本级的可用增益。 pub gain: Gain, } impl Stage { /// Creates a stage from a noise temperature and a gain. + /// + /// 由噪声温度与增益创建一级。 pub const fn new(temperature: NoiseTemperature, gain: Gain) -> Self { Self { temperature, gain } } @@ -28,6 +40,10 @@ impl Stage { /// decibels. /// /// Returns `None` when either value is not finite. + /// + /// 由以分贝表示的噪声系数与以分贝表示的增益创建一级。 + /// + /// 任一值非有限时返回 `None`。 pub fn from_noise_figure(noise_figure_db: f64, gain_dbi: f64) -> Option { Some(Self { temperature: NoiseTemperature::from_noise_figure_db(noise_figure_db)?, @@ -39,6 +55,10 @@ impl Stage { /// /// An ideal amplifier adds no noise, so it contributes nothing to the /// cascade except its gain. + /// + /// 以给定增益创建无噪声的一级。 + /// + /// 理想放大器不加噪声,故除其增益外它对级联别无贡献。 pub const fn ideal(gain: Gain) -> Self { Self { temperature: NoiseTemperature::from_kelvin(0.0), @@ -47,6 +67,8 @@ impl Stage { } /// Returns `true` when the stage is usable. + /// + /// 当该级可用时返回 `true`。 pub fn is_valid(self) -> bool { self.temperature.is_valid() && self.gain.ratio().is_finite() && self.gain.ratio() > 0.0 } @@ -69,6 +91,19 @@ impl Stage { /// /// Returns `None` when any stage is not usable, which includes a gain ratio /// that is not positive. +/// +/// 返回各级级联的噪声温度,折算到第一级的输入。 +/// +/// Friis 公式按本级之前的增益对每级的贡献加权: +/// +/// ```text +/// T = T_1 + T_2 / G_1 + T_3 / (G_1 G_2) + ... +/// ``` +/// +/// 其结果是第一级占主导:当第一级有增益时,噪声大的第二级影响小得多。 +/// 总温度即整链的温度,故可直接与可用增益比较以求得整链的噪声系数。 +/// +/// 任一级不可用(包括增益比非正)时返回 `None`。 pub fn cascade_temperature(stages: &[Stage]) -> Option { let mut total = NoiseTemperature::from_kelvin(0.0); let mut cumulative_gain = 1.0_f64; @@ -89,6 +124,14 @@ pub fn cascade_temperature(stages: &[Stage]) -> Option { /// [`NoiseTemperature::from_noise_figure_db`](crate::NoiseTemperature::from_noise_figure_db). /// /// Returns `None` when the figure is not finite. +/// +/// 使用标准参考温度,返回与某分贝噪声系数对应的噪声温度。 +/// +/// 这是 +/// [`NoiseTemperature::from_noise_figure_db`](crate::NoiseTemperature::from_noise_figure_db) +/// 的自由函数形式。 +/// +/// 该系数非有限时返回 `None`。 pub fn noise_figure_to_temperature(noise_figure_db: f64) -> Option { NoiseTemperature::from_noise_figure_db(noise_figure_db) } @@ -100,11 +143,20 @@ pub fn noise_figure_to_temperature(noise_figure_db: f64) -> Option Option { cascade_temperature(stages)?.noise_figure_db() } /// Returns the reference temperature used by the noise figure definition. +/// +/// 返回噪声系数定义所用的参考温度。 pub const fn reference_temperature() -> f64 { REFERENCE_TEMPERATURE_K } diff --git a/crates/rf/apsis-noise/src/temperature.rs b/crates/rf/apsis-noise/src/temperature.rs index 3229ced..2f78daf 100644 --- a/crates/rf/apsis-noise/src/temperature.rs +++ b/crates/rf/apsis-noise/src/temperature.rs @@ -10,6 +10,11 @@ use core::fmt; /// IEEE definition of noise figure. It is a convention rather than a /// physical temperature, and the choice affects the noise figure quoted for /// a given noise temperature. +/// +/// 用于定义噪声系数的参考温度,单位为开尔文。 +/// +/// 该值为 290 K,即 IEEE 噪声系数定义的标准参考温度。它是约定而非物理 +/// 温度,这一选择会影响给定噪声温度所对应的噪声系数。 pub const REFERENCE_TEMPERATURE_K: f64 = 290.0; /// A noise temperature in kelvin. @@ -18,14 +23,24 @@ pub const REFERENCE_TEMPERATURE_K: f64 = 290.0; /// the same noise power in the same bandwidth. It is a convenient way to /// express any noise source, including one that is not thermal in origin, /// because temperatures add across a cascade while powers do not. +/// +/// 以开尔文表示的噪声温度。 +/// +/// 噪声温度是在同一带宽内会给出相同噪声功率的电阻的温度。它是表达任何 +/// 噪声源(包括非热起源者)的便利方式,因为温度在级联中相加而功率 +/// 不然。 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)] pub struct NoiseTemperature(f64); impl NoiseTemperature { /// The standard reference temperature of 290 K. + /// + /// 290 K 的标准参考温度。 pub const REFERENCE: Self = Self(REFERENCE_TEMPERATURE_K); /// Creates a noise temperature from a value in kelvin. + /// + /// 由以开尔文表示的值创建噪声温度。 pub const fn from_kelvin(kelvin: f64) -> Self { Self(kelvin) } @@ -36,6 +51,13 @@ impl NoiseTemperature { /// so a noise figure of zero decibels gives a temperature of zero. /// /// Returns `None` when the figure is not finite. + /// + /// 由以分贝表示的噪声系数创建噪声温度。 + /// + /// 关系为 `T = T_0 (F - 1)`,其中 `F` 是线性噪声因子,故零分贝的 + /// 噪声系数给出零温度。 + /// + /// 该系数非有限时返回 `None`。 pub fn from_noise_figure_db(decibels: f64) -> Option { if !decibels.is_finite() { return None; @@ -48,6 +70,10 @@ impl NoiseTemperature { /// /// Returns `None` when the factor is not finite or is below one, which /// would describe a stage that removes noise. + /// + /// 由线性噪声因子创建噪声温度。 + /// + /// 该因子非有限或小于一时返回 `None`,那将描述一个去除噪声的级。 pub fn from_noise_factor(factor: f64) -> Option { if factor.is_finite() && factor >= 1.0 { Some(Self(REFERENCE_TEMPERATURE_K * (factor - 1.0))) @@ -57,6 +83,8 @@ impl NoiseTemperature { } /// Returns this temperature in kelvin. + /// + /// 返回该温度的开尔文值。 pub const fn kelvin(self) -> f64 { self.0 } @@ -64,6 +92,10 @@ impl NoiseTemperature { /// Returns this temperature as a linear noise factor. /// /// The factor is `T / T_0 + 1`, which is one for zero noise. + /// + /// 返回该温度的线性噪声因子。 + /// + /// 该因子为 `T / T_0 + 1`,零噪声时为一。 pub fn noise_factor(self) -> f64 { self.0 / REFERENCE_TEMPERATURE_K + 1.0 } @@ -72,6 +104,10 @@ impl NoiseTemperature { /// /// Returns `None` when the temperature is not finite or is negative, /// which would give a factor below one. + /// + /// 返回该温度的噪声系数,以分贝计。 + /// + /// 温度非有限或为负(会给出小于一的因子)时返回 `None`。 pub fn noise_figure_db(self) -> Option { let factor = self.noise_factor(); if factor > 0.0 && factor.is_finite() && self.0 >= 0.0 { @@ -85,6 +121,10 @@ impl NoiseTemperature { /// /// Noise temperatures of independent sources add, which is the reason /// the quantity is useful. + /// + /// 返回两个温度之和。 + /// + /// 独立源的噪声温度相加,这正是该量有用的原因。 pub const fn plus(self, other: Self) -> Self { Self(self.0 + other.0) } @@ -94,11 +134,18 @@ impl NoiseTemperature { /// A source followed by a gain contributes its temperature divided by /// that gain when referred to the input, so the scaling for a /// contribution referred to the input is the reciprocal. + /// + /// 返回该温度按某增益比缩放后的值。 + /// + /// 某源之后接一增益时,折算到输入其贡献为该温度除以该增益,故折算到 + /// 输入的贡献其缩放取倒数。 pub const fn scaled(self, factor: f64) -> Self { Self(self.0 * factor) } /// Returns `true` when the temperature is finite and not negative. + /// + /// 当该温度有限且非负时返回 `true`。 pub const fn is_valid(self) -> bool { self.0.is_finite() && self.0 >= 0.0 } @@ -126,6 +173,13 @@ impl core::ops::Add for NoiseTemperature { /// /// The bandwidth must be positive. Returns `None` for an invalid /// temperature or bandwidth. +/// +/// 返回某噪声温度下某带宽内的热噪声功率。 +/// +/// 关系为 `P = k T B`,其中 `k` 是玻尔兹曼常量。这是给定温度下的匹配 +/// 电阻在所给带宽内向负载输送的功率。 +/// +/// 带宽必须为正。温度或带宽无效时返回 `None`。 pub fn thermal_noise_power(temperature: NoiseTemperature, bandwidth: f64) -> Option { if !temperature.is_valid() { return None; diff --git a/crates/rf/apsis-rf/src/free_space.rs b/crates/rf/apsis-rf/src/free_space.rs index f8c7cf6..424ceeb 100644 --- a/crates/rf/apsis-rf/src/free_space.rs +++ b/crates/rf/apsis-rf/src/free_space.rs @@ -11,6 +11,12 @@ use core::f64::consts::PI; /// metre. /// /// Returns `None` when the frequency is not positive and finite. +/// +/// 返回某频率在真空中的波长,单位为米。 +/// +/// 关系为 `lambda = c / f`,其中 `c` 依米的定义是精确的。 +/// +/// 频率非正且非有限时返回 `None`。 pub fn wavelength(frequency: f64) -> Option { if frequency > 0.0 && frequency.is_finite() { Some(SPEED_OF_LIGHT / frequency) @@ -41,6 +47,24 @@ pub fn wavelength(frequency: f64) -> Option { /// /// Returns `None` when the distance is not positive, or when either argument /// is not finite. +/// +/// 返回两个各向同性天线之间的自由空间路径损耗,以分贝比值表示。 +/// +/// 该比值为正,故表示一种损耗:接收功率是发射功率除以该比值。关系为 +/// +/// ```text +/// L = (4 pi d / lambda)^2 +/// ``` +/// +/// 它是球面波在距离 `d` 上的扩散损耗与各向同性接收天线有效孔径的 +/// 结合。 +/// +/// 固定距离下损耗随频率增大,因为接收天线的有效孔径按波长的平方下降。 +/// +/// 距离必须为正。零距离不是本式所涵盖的情形:比值会为零,即以分贝计的 +/// 无穷衰减,且其背后的远场假定不成立。 +/// +/// 距离非正,或任一参数非有限时返回 `None`。 pub fn free_space_path_loss(distance: f64, frequency: f64) -> Option { if !distance.is_finite() || distance <= 0.0 { return None; @@ -65,6 +89,20 @@ pub fn free_space_path_loss(distance: f64, frequency: f64) -> Option { /// the two gains exceed the spreading loss. /// /// Returns `None` when the distance or frequency is not usable. +/// +/// 返回自由空间两个天线之间的接收功率比。 +/// +/// 接收功率是发射功率乘以两个天线增益、再除以自由空间路径损耗,以分贝 +/// 表示即 +/// +/// ```text +/// P_r / P_t = G_t G_r / L +/// ``` +/// +/// 结果是分贝比值,故正值意味着接收天线收集到的多于所发射的,这在两个 +/// 增益超过扩散损耗时发生。 +/// +/// 距离或频率不可用时返回 `None`。 pub fn free_space_received_ratio( distance: f64, frequency: f64, diff --git a/crates/rf/apsis-rf/src/gain.rs b/crates/rf/apsis-rf/src/gain.rs index 4c6313f..2f95361 100644 --- a/crates/rf/apsis-rf/src/gain.rs +++ b/crates/rf/apsis-rf/src/gain.rs @@ -162,6 +162,13 @@ impl Gain { /// as it radiates. /// /// Returns `None` when the wavelength is not positive and finite. + /// + /// 返回具有该增益的天线在给定波长处的有效孔径,单位为平方米。 + /// + /// 关系为 `A = G lambda^2 / (4 pi)`。它由热浴中的天线接收功率须等于 + /// 其辐射功率这一要求得出。 + /// + /// 波长非正且非有限时返回 `None`。 pub fn effective_aperture(self, wavelength: f64) -> Option { if wavelength > 0.0 && wavelength.is_finite() && self.0.is_finite() { Some(self.0 * wavelength * wavelength / (4.0 * PI)) @@ -177,6 +184,12 @@ impl Gain { /// /// Returns `None` when the wavelength is not positive and finite, or /// when the aperture is negative. + /// + /// 返回具有该有效孔径的天线在给定波长处的增益。 + /// + /// 它是 [`Gain::effective_aperture`] 的逆。 + /// + /// 波长非正且非有限,或孔径为负时返回 `None`。 pub fn from_effective_aperture(aperture: f64, wavelength: f64) -> Option { if wavelength > 0.0 && wavelength.is_finite() && aperture >= 0.0 && aperture.is_finite() { Some(Self(4.0 * PI * aperture / (wavelength * wavelength)))