docs: bilingual comments for the access finder and pass summary
This commit is contained in:
parent
5857c44492
commit
295ba16d0d
|
|
@ -11,6 +11,11 @@ use apsis_math::Vec3;
|
||||||
/// in seconds from the caller's origin. The caller supplies a sequence of
|
/// in seconds from the caller's origin. The caller supplies a sequence of
|
||||||
/// these, which decouples the finder from the propagation and the frame
|
/// these, which decouples the finder from the propagation and the frame
|
||||||
/// transformation.
|
/// transformation.
|
||||||
|
///
|
||||||
|
/// 卫星轨迹的一个样本,按其被查找器消费的形式。
|
||||||
|
///
|
||||||
|
/// 位置在地固系中,单位为千米;时间以距调用方原点的秒数表示。调用方
|
||||||
|
/// 提供这样的一串样本,使查找器与传播及坐标系变换解耦。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct OrbitSample {
|
pub struct OrbitSample {
|
||||||
/// The time of the sample, in seconds from the caller's origin.
|
/// The time of the sample, in seconds from the caller's origin.
|
||||||
|
|
@ -18,11 +23,15 @@ pub struct OrbitSample {
|
||||||
/// 样本时刻,单位为自调用方原点起的秒数。
|
/// 样本时刻,单位为自调用方原点起的秒数。
|
||||||
pub seconds: f64,
|
pub seconds: f64,
|
||||||
/// The satellite position in the Earth-fixed frame, in kilometers.
|
/// The satellite position in the Earth-fixed frame, in kilometers.
|
||||||
|
///
|
||||||
|
/// 地固系中的卫星位置,单位为千米。
|
||||||
pub position_ecef_km: Vec3,
|
pub position_ecef_km: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrbitSample {
|
impl OrbitSample {
|
||||||
/// Creates a sample from a time and a position.
|
/// Creates a sample from a time and a position.
|
||||||
|
///
|
||||||
|
/// 由时间与位置创建样本。
|
||||||
pub const fn new(seconds: f64, position_ecef_km: Vec3) -> Self {
|
pub const fn new(seconds: f64, position_ecef_km: Vec3) -> Self {
|
||||||
Self {
|
Self {
|
||||||
seconds,
|
seconds,
|
||||||
|
|
@ -31,6 +40,8 @@ impl OrbitSample {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` when the sample is usable.
|
/// Returns `true` when the sample is usable.
|
||||||
|
///
|
||||||
|
/// 当该样本可用时返回 `true`。
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
self.seconds.is_finite() && self.position_ecef_km.is_finite()
|
self.seconds.is_finite() && self.position_ecef_km.is_finite()
|
||||||
}
|
}
|
||||||
|
|
@ -41,25 +52,43 @@ impl OrbitSample {
|
||||||
/// The finder holds the station and the numerical settings of the search.
|
/// The finder holds the station and the numerical settings of the search.
|
||||||
/// The settings are separated from the search so that the same finder can be
|
/// The settings are separated from the search so that the same finder can be
|
||||||
/// applied to many satellites.
|
/// applied to many satellites.
|
||||||
|
///
|
||||||
|
/// 为一个地面站查找可见性窗口。
|
||||||
|
///
|
||||||
|
/// 查找器保存地面站与搜索的数值设置。设置与搜索分开,使同一个查找器可
|
||||||
|
/// 应用于许多卫星。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct AccessFinder {
|
pub struct AccessFinder {
|
||||||
/// The station and its elevation mask.
|
/// The station and its elevation mask.
|
||||||
|
///
|
||||||
|
/// 地面站及其仰角遮蔽。
|
||||||
pub station: GroundPoint,
|
pub station: GroundPoint,
|
||||||
/// The interval between samples of the satellite track, in seconds.
|
/// The interval between samples of the satellite track, in seconds.
|
||||||
///
|
///
|
||||||
/// A smaller step finds shorter passes but costs proportionally more
|
/// A smaller step finds shorter passes but costs proportionally more
|
||||||
/// evaluations. A step of one minute resolves any pass a low Earth
|
/// evaluations. A step of one minute resolves any pass a low Earth
|
||||||
/// satellite makes, since such a pass lasts several minutes.
|
/// satellite makes, since such a pass lasts several minutes.
|
||||||
|
///
|
||||||
|
/// 卫星轨迹样本之间的间隔,单位为秒。
|
||||||
|
///
|
||||||
|
/// 更小的步长能发现更短的过境,但求值次数成比例增加。一分钟的步长
|
||||||
|
/// 能分辨低轨卫星的任何过境,因为这样的过境持续数分钟。
|
||||||
pub sample_step_seconds: f64,
|
pub sample_step_seconds: f64,
|
||||||
/// The tolerance on a crossing time, in seconds.
|
/// The tolerance on a crossing time, in seconds.
|
||||||
///
|
///
|
||||||
/// The refinement of a rise or set continues until the interval
|
/// The refinement of a rise or set continues until the interval
|
||||||
/// containing the crossing is this narrow.
|
/// containing the crossing is this narrow.
|
||||||
|
///
|
||||||
|
/// 穿越时刻的容差,单位为秒。
|
||||||
|
///
|
||||||
|
/// 对升起或降落的细化持续到包含该穿越的区间窄于该值为止。
|
||||||
pub crossing_tolerance_seconds: f64,
|
pub crossing_tolerance_seconds: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccessFinder {
|
impl AccessFinder {
|
||||||
/// Returns `true` when the finder settings are usable.
|
/// Returns `true` when the finder settings are usable.
|
||||||
|
///
|
||||||
|
/// 当查找器设置可用时返回 `true`。
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
self.station.is_valid()
|
self.station.is_valid()
|
||||||
&& self.sample_step_seconds.is_finite()
|
&& self.sample_step_seconds.is_finite()
|
||||||
|
|
@ -71,6 +100,8 @@ impl AccessFinder {
|
||||||
|
|
||||||
/// Validates the settings, returning the reason when they are not
|
/// Validates the settings, returning the reason when they are not
|
||||||
/// usable.
|
/// usable.
|
||||||
|
///
|
||||||
|
/// 校验设置,不可用时返回原因。
|
||||||
fn validate(&self) -> Result<(), AccessError> {
|
fn validate(&self) -> Result<(), AccessError> {
|
||||||
if !self.station.is_valid() {
|
if !self.station.is_valid() {
|
||||||
return Err(AccessError::new(AccessErrorKind::InvalidStation));
|
return Err(AccessError::new(AccessErrorKind::InvalidStation));
|
||||||
|
|
@ -93,6 +124,10 @@ impl AccessFinder {
|
||||||
/// Returns the elevation of a sample, in radians.
|
/// Returns the elevation of a sample, in radians.
|
||||||
///
|
///
|
||||||
/// Returns `None` when the sample or the station is not usable.
|
/// Returns `None` when the sample or the station is not usable.
|
||||||
|
///
|
||||||
|
/// 返回某样本的仰角,单位为弧度。
|
||||||
|
///
|
||||||
|
/// 样本或地面站不可用时返回 `None`。
|
||||||
pub fn elevation_of(&self, sample: &OrbitSample) -> Option<f64> {
|
pub fn elevation_of(&self, sample: &OrbitSample) -> Option<f64> {
|
||||||
if !sample.is_valid() {
|
if !sample.is_valid() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -129,11 +164,34 @@ impl AccessFinder {
|
||||||
/// checked rather than assumed, because the interpolation between two
|
/// checked rather than assumed, because the interpolation between two
|
||||||
/// samples binary searches the sequence and a binary search over an
|
/// samples binary searches the sequence and a binary search over an
|
||||||
/// unordered list returns a wrong index without failing.
|
/// unordered list returns a wrong index without failing.
|
||||||
|
///
|
||||||
|
/// 在有序的样本序列中查找可见性窗口。
|
||||||
|
///
|
||||||
|
/// 各样本必须按时间排序并覆盖所关注的区间。查找器假定仰角在样本
|
||||||
|
/// 之间连续,故步长必须短到卫星不会在一个步长内升起又降落。低轨
|
||||||
|
/// 卫星在十度遮蔽以上持续数分钟,故一分钟或更短的步长即满足。
|
||||||
|
///
|
||||||
|
/// 穿越时刻通过在跨越该穿越的两个样本之间线性插值卫星位置求得。
|
||||||
|
/// 两样本之间的弦与真实弧的偏差为步长的二阶量,故十秒步长给出的
|
||||||
|
/// 穿越精度约为十分之一秒,一秒步长约为毫秒。当传播器可用且希望
|
||||||
|
/// 穿越达到完整容差时,用 [`AccessFinder::find_with`]。
|
||||||
|
///
|
||||||
|
/// 在第一个样本处已进行中的过境,其升起时刻报告为第一个样本时间;
|
||||||
|
/// 在最后一个样本处仍在进行中的过境,其降落时刻报告为最后一个
|
||||||
|
/// 样本时间。该约定意味着过境被裁剪到所搜索的区间,而不外推超出
|
||||||
|
/// 它。
|
||||||
|
///
|
||||||
|
/// 设置不可用、样本序列少于两项、某样本不可用,或序列未按时间
|
||||||
|
/// 递增排列时返回错误。次序是被检查而非假定的,因为两样本之间的
|
||||||
|
/// 插值会对序列做二分查找,而对无序列表的二分查找会返回错误的下标
|
||||||
|
/// 而不报错。
|
||||||
pub fn find(&self, samples: &[OrbitSample]) -> Result<PassSummary, AccessError> {
|
pub fn find(&self, samples: &[OrbitSample]) -> Result<PassSummary, AccessError> {
|
||||||
self.find_internal(samples, |seconds| {
|
self.find_internal(samples, |seconds| {
|
||||||
// Interpolate the position between the bracketing samples. The
|
// Interpolate the position between the bracketing samples. The
|
||||||
// order of the sequence is checked by `find_internal` before
|
// order of the sequence is checked by `find_internal` before
|
||||||
// this closure runs, and the step is the caller's to choose.
|
// this closure runs, and the step is the caller's to choose.
|
||||||
|
// 在夹逼的两个样本之间插值位置。序列的次序在该闭包运行前由
|
||||||
|
// `find_internal` 检查,步长由调用方选择。
|
||||||
let index = match samples.binary_search_by(|sample| {
|
let index = match samples.binary_search_by(|sample| {
|
||||||
sample
|
sample
|
||||||
.seconds
|
.seconds
|
||||||
|
|
@ -164,6 +222,11 @@ impl AccessFinder {
|
||||||
/// The function must be defined over the whole interval and must be
|
/// The function must be defined over the whole interval and must be
|
||||||
/// continuous, and the sample sequence must be ordered by time. The
|
/// continuous, and the sample sequence must be ordered by time. The
|
||||||
/// closure returns `None` when the position at that time is not usable.
|
/// closure returns `None` when the position at that time is not usable.
|
||||||
|
///
|
||||||
|
/// 在给定返回某时刻仰角的函数下运行搜索。
|
||||||
|
///
|
||||||
|
/// 该函数必须定义在整个区间上且必须连续,样本序列必须按时间排序。
|
||||||
|
/// 当该时刻的位置不可用时,该闭包返回 `None`。
|
||||||
fn find_internal<F>(
|
fn find_internal<F>(
|
||||||
&self,
|
&self,
|
||||||
samples: &[OrbitSample],
|
samples: &[OrbitSample],
|
||||||
|
|
@ -185,10 +248,17 @@ impl AccessFinder {
|
||||||
// crossing against the wrong pair of positions and report a pass that
|
// crossing against the wrong pair of positions and report a pass that
|
||||||
// never happened. Checking only the ends, as this once did, let that
|
// never happened. Checking only the ends, as this once did, let that
|
||||||
// through silently.
|
// through silently.
|
||||||
|
// 整个序列必须严格按时间递增,而不只是其两端。两样本之间的插值
|
||||||
|
// 会对该列表做二分查找,而对无序列表的二分查找会返回错误的下标
|
||||||
|
// 而不报错,故无序序列会针对错误的位置对细化穿越,并报告一个
|
||||||
|
// 从未发生过的过境。只检查两端(如本代码过去所做的)会使其无声
|
||||||
|
// 通过。
|
||||||
for (index, pair) in samples.windows(2).enumerate() {
|
for (index, pair) in samples.windows(2).enumerate() {
|
||||||
// The test is written out rather than as `!(a < b)` so that it
|
// The test is written out rather than as `!(a < b)` so that it
|
||||||
// also rejects a pair whose times are not finite, and so that a
|
// also rejects a pair whose times are not finite, and so that a
|
||||||
// reader can see that equality and disorder are both refused.
|
// reader can see that equality and disorder are both refused.
|
||||||
|
// 该测试是写开的而非写成 `!(a < b)`,使它也拒绝时间非有限的
|
||||||
|
// 点对,并使读者能看出相等与失序都被拒绝。
|
||||||
let ordered = pair[0].seconds.is_finite()
|
let ordered = pair[0].seconds.is_finite()
|
||||||
&& pair[1].seconds.is_finite()
|
&& pair[1].seconds.is_finite()
|
||||||
&& pair[0].seconds < pair[1].seconds;
|
&& pair[0].seconds < pair[1].seconds;
|
||||||
|
|
@ -229,6 +299,8 @@ impl AccessFinder {
|
||||||
let mut rise: Option<f64> = None;
|
let mut rise: Option<f64> = None;
|
||||||
// Track the highest elevation seen inside the current pass so that
|
// Track the highest elevation seen inside the current pass so that
|
||||||
// the peak is known without a second pass over the samples.
|
// the peak is known without a second pass over the samples.
|
||||||
|
// 跟踪当前过境内所见的最大仰角,使峰值无需再遍历一遍样本即可
|
||||||
|
// 得知。
|
||||||
let mut peak = f64::NEG_INFINITY;
|
let mut peak = f64::NEG_INFINITY;
|
||||||
let mut peak_seconds = first;
|
let mut peak_seconds = first;
|
||||||
let mut peak_position = samples[0].position_ecef_km;
|
let mut peak_position = samples[0].position_ecef_km;
|
||||||
|
|
@ -240,6 +312,8 @@ impl AccessFinder {
|
||||||
rise = Some(if index == 0 {
|
rise = Some(if index == 0 {
|
||||||
// The pass was already open at the start of the
|
// The pass was already open at the start of the
|
||||||
// window, so it is clipped to the first sample.
|
// window, so it is clipped to the first sample.
|
||||||
|
// 该过境在窗口开始时就已打开,故被裁剪到第一个
|
||||||
|
// 样本。
|
||||||
samples[0].seconds
|
samples[0].seconds
|
||||||
} else {
|
} else {
|
||||||
self.refine_crossing(samples, index, true, &mut elevation_at)
|
self.refine_crossing(samples, index, true, &mut elevation_at)
|
||||||
|
|
@ -266,6 +340,7 @@ impl AccessFinder {
|
||||||
|
|
||||||
// A pass still open at the end of the sequence is clipped to the
|
// A pass still open at the end of the sequence is clipped to the
|
||||||
// last sample.
|
// last sample.
|
||||||
|
// 在序列末尾仍打开的过境被裁剪到最后一个样本。
|
||||||
if let Some(rise_seconds) = rise {
|
if let Some(rise_seconds) = rise {
|
||||||
passes.push(Pass {
|
passes.push(Pass {
|
||||||
rise_seconds,
|
rise_seconds,
|
||||||
|
|
@ -290,6 +365,14 @@ impl AccessFinder {
|
||||||
/// increases through the mask; otherwise it is a set. The flag selects
|
/// increases through the mask; otherwise it is a set. The flag selects
|
||||||
/// which side of the crossing is above the mask, which keeps the search
|
/// which side of the crossing is above the mask, which keeps the search
|
||||||
/// bracket correct.
|
/// bracket correct.
|
||||||
|
///
|
||||||
|
/// 细化仰角穿越遮蔽的时刻。
|
||||||
|
///
|
||||||
|
/// 该穿越位于下标 `index` 处的样本与其前一个之间,两者夹逼遮蔽。
|
||||||
|
/// 二分法把区间减半直到它窄于容差。
|
||||||
|
///
|
||||||
|
/// 当 `rising` 为真时该穿越是升起,即仰角递增地穿过遮蔽;否则是
|
||||||
|
/// 降落。该标志选择穿越的哪一侧在遮蔽之上,从而保持搜索夹逼正确。
|
||||||
fn refine_crossing<F>(
|
fn refine_crossing<F>(
|
||||||
&self,
|
&self,
|
||||||
samples: &[OrbitSample],
|
samples: &[OrbitSample],
|
||||||
|
|
@ -306,6 +389,8 @@ impl AccessFinder {
|
||||||
|
|
||||||
// The elevation difference from the mask, with the sign arranged so
|
// The elevation difference from the mask, with the sign arranged so
|
||||||
// that the function is negative at `low` and positive at `high`.
|
// that the function is negative at `low` and positive at `high`.
|
||||||
|
// 相对遮蔽的仰角差,其符号被安排为使该函数在 `low` 处为负、在
|
||||||
|
// `high` 处为正。
|
||||||
let sign = if rising { 1.0 } else { -1.0 };
|
let sign = if rising { 1.0 } else { -1.0 };
|
||||||
let mut difference = |seconds: f64| {
|
let mut difference = |seconds: f64| {
|
||||||
let elevation = elevation_at(seconds).unwrap_or(mask);
|
let elevation = elevation_at(seconds).unwrap_or(mask);
|
||||||
|
|
@ -342,6 +427,13 @@ impl AccessFinder {
|
||||||
///
|
///
|
||||||
/// Returns an error when the settings are not usable, when the interval
|
/// Returns an error when the settings are not usable, when the interval
|
||||||
/// is not ordered, or when the propagator fails at a sample.
|
/// is not ordered, or when the propagator fails at a sample.
|
||||||
|
///
|
||||||
|
/// 在某个区间上查找可见性窗口,对每个样本调用一次传播器。
|
||||||
|
///
|
||||||
|
/// 传播器接收以距搜索原点的秒数表示的时间,返回地固系中的卫星
|
||||||
|
/// 位置。这使查找器可适配任何轨道来源,而本 crate 不依赖于其一。
|
||||||
|
///
|
||||||
|
/// 设置不可用、区间次序不对,或传播器在某样本处失败时返回错误。
|
||||||
pub fn find_with<F>(
|
pub fn find_with<F>(
|
||||||
&self,
|
&self,
|
||||||
start_seconds: f64,
|
start_seconds: f64,
|
||||||
|
|
@ -361,6 +453,7 @@ impl AccessFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the sample sequence, including the end point.
|
// Build the sample sequence, including the end point.
|
||||||
|
// 构建样本序列,包含端点。
|
||||||
let step = self.sample_step_seconds;
|
let step = self.sample_step_seconds;
|
||||||
let count = ((end_seconds - start_seconds) / step).ceil() as usize + 1;
|
let count = ((end_seconds - start_seconds) / step).ceil() as usize + 1;
|
||||||
let mut samples = Vec::with_capacity(count);
|
let mut samples = Vec::with_capacity(count);
|
||||||
|
|
@ -375,6 +468,8 @@ impl AccessFinder {
|
||||||
// The loop above may append the end point twice when the interval is
|
// The loop above may append the end point twice when the interval is
|
||||||
// an exact multiple of the step, so the last sample is replaced when
|
// an exact multiple of the step, so the last sample is replaced when
|
||||||
// it duplicates the end.
|
// it duplicates the end.
|
||||||
|
// 当区间是步长的精确整数倍时,上面的循环可能把端点追加两次,故
|
||||||
|
// 当最后一个样本与端点重复时将其替换。
|
||||||
if let Some(last) = samples.last_mut() {
|
if let Some(last) = samples.last_mut() {
|
||||||
if last.seconds != end_seconds {
|
if last.seconds != end_seconds {
|
||||||
let position = propagator(end_seconds).ok_or_else(|| {
|
let position = propagator(end_seconds).ok_or_else(|| {
|
||||||
|
|
@ -390,6 +485,8 @@ impl AccessFinder {
|
||||||
// The refinement calls the propagator at each bisection point, so
|
// The refinement calls the propagator at each bisection point, so
|
||||||
// the crossing is found to the tolerance rather than to the
|
// the crossing is found to the tolerance rather than to the
|
||||||
// accuracy of a chord between two samples.
|
// accuracy of a chord between two samples.
|
||||||
|
// 细化在每个二分点调用传播器,故穿越是按容差求得,而非按两样本
|
||||||
|
// 之间弦的精度求得。
|
||||||
let mut failure = None;
|
let mut failure = None;
|
||||||
let summary = self.find_internal(&samples, |seconds| match propagator(seconds) {
|
let summary = self.find_internal(&samples, |seconds| match propagator(seconds) {
|
||||||
Some(position) if position.is_finite() => elevation_angle(position, &self.station),
|
Some(position) if position.is_finite() => elevation_angle(position, &self.station),
|
||||||
|
|
|
||||||
|
|
@ -8,34 +8,58 @@ use apsis_math::Vec3;
|
||||||
/// Times are seconds from an origin chosen by the caller, so the same
|
/// Times are seconds from an origin chosen by the caller, so the same
|
||||||
/// structure serves a search over a scenario clock and one over elapsed
|
/// structure serves a search over a scenario clock and one over elapsed
|
||||||
/// time.
|
/// time.
|
||||||
|
///
|
||||||
|
/// 卫星高于某地面站仰角遮蔽的一个连续区间。
|
||||||
|
///
|
||||||
|
/// 时间是以距调用方所选原点的秒数表示,故同一结构既服务于按场景时钟的
|
||||||
|
/// 搜索,也服务于按流逝时间的搜索。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Pass {
|
pub struct Pass {
|
||||||
/// The time the satellite rises above the mask, in seconds from the
|
/// The time the satellite rises above the mask, in seconds from the
|
||||||
/// caller's origin.
|
/// caller's origin.
|
||||||
|
///
|
||||||
|
/// 卫星升到遮蔽之上的时间,以距调用方原点的秒数表示。
|
||||||
pub rise_seconds: f64,
|
pub rise_seconds: f64,
|
||||||
/// The time the satellite falls below the mask.
|
/// The time the satellite falls below the mask.
|
||||||
|
///
|
||||||
|
/// 卫星降到遮蔽以下的时间。
|
||||||
pub set_seconds: f64,
|
pub set_seconds: f64,
|
||||||
/// The time of greatest elevation.
|
/// The time of greatest elevation.
|
||||||
|
///
|
||||||
|
/// 仰角最大时的时间。
|
||||||
pub peak_seconds: f64,
|
pub peak_seconds: f64,
|
||||||
/// The greatest elevation during the pass, in radians.
|
/// The greatest elevation during the pass, in radians.
|
||||||
|
///
|
||||||
|
/// 该过境期间的最大仰角,单位为弧度。
|
||||||
pub peak_elevation: f64,
|
pub peak_elevation: f64,
|
||||||
/// The elevation at which the satellite crossed the mask, in radians.
|
/// The elevation at which the satellite crossed the mask, in radians.
|
||||||
///
|
///
|
||||||
/// This is the station's mask, recorded so that a pass carries the
|
/// This is the station's mask, recorded so that a pass carries the
|
||||||
/// geometry it was found under.
|
/// geometry it was found under.
|
||||||
|
///
|
||||||
|
/// 卫星穿越遮蔽时的仰角,单位为弧度。
|
||||||
|
///
|
||||||
|
/// 这是地面站的遮蔽,记录它是为了使过境携带其被发现时所依据的
|
||||||
|
/// 几何。
|
||||||
pub mask_elevation: f64,
|
pub mask_elevation: f64,
|
||||||
/// The satellite position in the Earth-fixed frame at the peak, in
|
/// The satellite position in the Earth-fixed frame at the peak, in
|
||||||
/// kilometers.
|
/// kilometers.
|
||||||
|
///
|
||||||
|
/// 峰值处地固系中的卫星位置,单位为千米。
|
||||||
pub peak_position: Vec3,
|
pub peak_position: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pass {
|
impl Pass {
|
||||||
/// Returns the duration of the pass, in seconds.
|
/// Returns the duration of the pass, in seconds.
|
||||||
|
///
|
||||||
|
/// 返回该过境的时长,单位为秒。
|
||||||
pub fn duration(&self) -> f64 {
|
pub fn duration(&self) -> f64 {
|
||||||
self.set_seconds - self.rise_seconds
|
self.set_seconds - self.rise_seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the time from the rise to the peak, in seconds.
|
/// Returns the time from the rise to the peak, in seconds.
|
||||||
|
///
|
||||||
|
/// 返回从升起到峰值的时间,单位为秒。
|
||||||
pub fn rise_to_peak(&self) -> f64 {
|
pub fn rise_to_peak(&self) -> f64 {
|
||||||
self.peak_seconds - self.rise_seconds
|
self.peak_seconds - self.rise_seconds
|
||||||
}
|
}
|
||||||
|
|
@ -46,6 +70,11 @@ impl Pass {
|
||||||
/// The pass stores only the peak, so this helper reports the stored
|
/// The pass stores only the peak, so this helper reports the stored
|
||||||
/// values at the three defining times and defers to the caller's
|
/// values at the three defining times and defers to the caller's
|
||||||
/// elevation function otherwise.
|
/// elevation function otherwise.
|
||||||
|
///
|
||||||
|
/// 返回过境内某时刻的仰角,当调用方能提供它时。
|
||||||
|
///
|
||||||
|
/// 过境只保存峰值,故该辅助函数在三个界定时刻报告所存的值,其余
|
||||||
|
/// 情形交由调用方的仰角函数。
|
||||||
pub fn contains(&self, seconds: f64) -> bool {
|
pub fn contains(&self, seconds: f64) -> bool {
|
||||||
seconds >= self.rise_seconds && seconds <= self.set_seconds
|
seconds >= self.rise_seconds && seconds <= self.set_seconds
|
||||||
}
|
}
|
||||||
|
|
@ -54,22 +83,34 @@ impl Pass {
|
||||||
///
|
///
|
||||||
/// This is the same as the peak elevation, named for readability at a
|
/// This is the same as the peak elevation, named for readability at a
|
||||||
/// call site that compares passes.
|
/// call site that compares passes.
|
||||||
|
///
|
||||||
|
/// 返回该过境的最大仰角,单位为弧度。
|
||||||
|
///
|
||||||
|
/// 这与峰值仰角相同,其命名是为在比较过境的调用处更具可读性。
|
||||||
pub fn maximum_elevation(&self) -> f64 {
|
pub fn maximum_elevation(&self) -> f64 {
|
||||||
self.peak_elevation
|
self.peak_elevation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A summary of the access windows over an interval.
|
/// A summary of the access windows over an interval.
|
||||||
|
///
|
||||||
|
/// 某区间上可见性窗口的汇总。
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct PassSummary {
|
pub struct PassSummary {
|
||||||
/// The passes, in time order.
|
/// The passes, in time order.
|
||||||
|
///
|
||||||
|
/// 按时序排列的各过境。
|
||||||
pub passes: Vec<Pass>,
|
pub passes: Vec<Pass>,
|
||||||
/// The length of the interval searched, in seconds.
|
/// The length of the interval searched, in seconds.
|
||||||
|
///
|
||||||
|
/// 所搜索区间的长度,单位为秒。
|
||||||
pub interval_seconds: f64,
|
pub interval_seconds: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PassSummary {
|
impl PassSummary {
|
||||||
/// Creates a summary from a list of passes and the interval length.
|
/// Creates a summary from a list of passes and the interval length.
|
||||||
|
///
|
||||||
|
/// 由过境列表与区间长度创建汇总。
|
||||||
pub fn new(passes: Vec<Pass>, interval_seconds: f64) -> Self {
|
pub fn new(passes: Vec<Pass>, interval_seconds: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
passes,
|
passes,
|
||||||
|
|
@ -78,6 +119,8 @@ impl PassSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of passes.
|
/// Returns the number of passes.
|
||||||
|
///
|
||||||
|
/// 返回过境的数量。
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.passes.len()
|
self.passes.len()
|
||||||
}
|
}
|
||||||
|
|
@ -85,6 +128,10 @@ impl PassSummary {
|
||||||
/// Returns the total access time, in seconds.
|
/// Returns the total access time, in seconds.
|
||||||
///
|
///
|
||||||
/// The passes are disjoint, so the durations add.
|
/// The passes are disjoint, so the durations add.
|
||||||
|
///
|
||||||
|
/// 返回总可见时间,单位为秒。
|
||||||
|
///
|
||||||
|
/// 各过境互不相交,故时长相加。
|
||||||
pub fn total_access_seconds(&self) -> f64 {
|
pub fn total_access_seconds(&self) -> f64 {
|
||||||
self.passes.iter().map(Pass::duration).sum()
|
self.passes.iter().map(Pass::duration).sum()
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +140,10 @@ impl PassSummary {
|
||||||
/// accessible.
|
/// accessible.
|
||||||
///
|
///
|
||||||
/// Returns `None` when the interval length is not positive.
|
/// Returns `None` when the interval length is not positive.
|
||||||
|
///
|
||||||
|
/// 返回卫星可见所占该区间的比例。
|
||||||
|
///
|
||||||
|
/// 区间长度非正时返回 `None`。
|
||||||
pub fn access_fraction(&self) -> Option<f64> {
|
pub fn access_fraction(&self) -> Option<f64> {
|
||||||
if self.interval_seconds > 0.0 && self.interval_seconds.is_finite() {
|
if self.interval_seconds > 0.0 && self.interval_seconds.is_finite() {
|
||||||
Some(self.total_access_seconds() / self.interval_seconds)
|
Some(self.total_access_seconds() / self.interval_seconds)
|
||||||
|
|
@ -104,6 +155,10 @@ impl PassSummary {
|
||||||
/// Returns the mean pass duration, in seconds.
|
/// Returns the mean pass duration, in seconds.
|
||||||
///
|
///
|
||||||
/// Returns `None` when there are no passes.
|
/// Returns `None` when there are no passes.
|
||||||
|
///
|
||||||
|
/// 返回过境的平均时长,单位为秒。
|
||||||
|
///
|
||||||
|
/// 没有过境时返回 `None`。
|
||||||
pub fn mean_duration_seconds(&self) -> Option<f64> {
|
pub fn mean_duration_seconds(&self) -> Option<f64> {
|
||||||
if self.passes.is_empty() {
|
if self.passes.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -112,6 +167,8 @@ impl PassSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the longest pass, if there is one.
|
/// Returns the longest pass, if there is one.
|
||||||
|
///
|
||||||
|
/// 返回最长的过境(若存在)。
|
||||||
pub fn longest(&self) -> Option<&Pass> {
|
pub fn longest(&self) -> Option<&Pass> {
|
||||||
self.passes.iter().max_by(|first, second| {
|
self.passes.iter().max_by(|first, second| {
|
||||||
first
|
first
|
||||||
|
|
@ -122,6 +179,8 @@ impl PassSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the highest pass, if there is one.
|
/// Returns the highest pass, if there is one.
|
||||||
|
///
|
||||||
|
/// 返回仰角最高的过境(若存在)。
|
||||||
pub fn highest(&self) -> Option<&Pass> {
|
pub fn highest(&self) -> Option<&Pass> {
|
||||||
self.passes.iter().max_by(|first, second| {
|
self.passes.iter().max_by(|first, second| {
|
||||||
first
|
first
|
||||||
|
|
@ -135,6 +194,10 @@ impl PassSummary {
|
||||||
///
|
///
|
||||||
/// Returns `None` when either index is out of range or the two indices
|
/// Returns `None` when either index is out of range or the two indices
|
||||||
/// are not consecutive and increasing.
|
/// are not consecutive and increasing.
|
||||||
|
///
|
||||||
|
/// 返回两个相邻过境之间的间隙,单位为秒。
|
||||||
|
///
|
||||||
|
/// 任一下标越界,或两个下标不相邻且递增时返回 `None`。
|
||||||
pub fn gap_seconds(&self, first: usize, second: usize) -> Option<f64> {
|
pub fn gap_seconds(&self, first: usize, second: usize) -> Option<f64> {
|
||||||
if second != first + 1 {
|
if second != first + 1 {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -148,6 +211,11 @@ impl PassSummary {
|
||||||
///
|
///
|
||||||
/// This is the longest time a station waits between contacts.
|
/// This is the longest time a station waits between contacts.
|
||||||
/// Returns `None` when there are fewer than two passes.
|
/// Returns `None` when there are fewer than two passes.
|
||||||
|
///
|
||||||
|
/// 返回相邻过境之间的最大间隙,单位为秒。
|
||||||
|
///
|
||||||
|
/// 这是一个地面站在两次通信之间等待的最长时间。过境少于两个时返回
|
||||||
|
/// `None`。
|
||||||
pub fn longest_gap_seconds(&self) -> Option<f64> {
|
pub fn longest_gap_seconds(&self) -> Option<f64> {
|
||||||
if self.passes.len() < 2 {
|
if self.passes.len() < 2 {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue