feat(core): add shift left/right operators to Signal
This commit is contained in:
parent
a54ec8a69f
commit
70c5a50d22
2 changed files with 63 additions and 0 deletions
|
|
@ -4,6 +4,7 @@ mod cast;
|
||||||
mod cmp_ops;
|
mod cmp_ops;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
mod num_ops;
|
mod num_ops;
|
||||||
|
mod shift_ops;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
|
@ -16,6 +17,7 @@ pub use cmp_ops::*;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
pub use num_ops::*;
|
pub use num_ops::*;
|
||||||
use num_traits::{Num, NumCast};
|
use num_traits::{Num, NumCast};
|
||||||
|
pub use shift_ops::*;
|
||||||
pub use traits::*;
|
pub use traits::*;
|
||||||
use utils::intersect_bounds;
|
use utils::intersect_bounds;
|
||||||
|
|
||||||
|
|
|
||||||
61
argus-core/src/signals/shift_ops.rs
Normal file
61
argus-core/src/signals/shift_ops.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
use core::iter::zip;
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use itertools::{enumerate, Itertools};
|
||||||
|
|
||||||
|
use super::traits::LinearInterpolatable;
|
||||||
|
use super::{InterpolationMethod, Signal};
|
||||||
|
|
||||||
|
impl<T> Signal<T>
|
||||||
|
where
|
||||||
|
T: Copy + LinearInterpolatable,
|
||||||
|
{
|
||||||
|
/// Shift all samples in the signal by `delta` amount to the left.
|
||||||
|
///
|
||||||
|
/// This essentially filters out all samples with time points greater than `delta`,
|
||||||
|
/// and subtracts `delta` from the rest of the time points.
|
||||||
|
pub fn shift_left(&self, delta: Duration) -> Self {
|
||||||
|
match self {
|
||||||
|
Signal::Sampled { values, time_points } => {
|
||||||
|
// We want to skip any time points < delta, and subtract the rest.
|
||||||
|
// Moreover, if the signal doesn't start at 0 after the shift, we may
|
||||||
|
// want to interpolate from the previous value.
|
||||||
|
|
||||||
|
// Find the first index that satisfies `t >= delta` while also checking
|
||||||
|
// if we need to interpolate
|
||||||
|
let Some((idx, first_t)) = time_points.into_iter().find_position(|&t| t >= &delta)
|
||||||
|
else {
|
||||||
|
// Return an empty signal (we exhauseted all samples).
|
||||||
|
return Signal::Empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new_samples: Vec<(Duration, T)> = Vec::with_capacity(time_points.len() - idx);
|
||||||
|
// Let's see if we need to find a new sample
|
||||||
|
if idx > 0 && first_t != &delta {
|
||||||
|
// The shifted signal will not start at 0, and we have a previous
|
||||||
|
// index to interpolate from.
|
||||||
|
let v = self.interpolate_at(delta, InterpolationMethod::Linear).unwrap();
|
||||||
|
new_samples.push((Duration::ZERO, v));
|
||||||
|
}
|
||||||
|
// Shift the rest of the samples
|
||||||
|
new_samples.extend(zip(&time_points[idx..], &values[idx..]).map(|(&t, &v)| (t - delta, v)));
|
||||||
|
new_samples.into_iter().collect()
|
||||||
|
}
|
||||||
|
// Empty and constant signals can't really be changed
|
||||||
|
sig => sig.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shift all samples in the signal by `delta` amount to the right.
|
||||||
|
///
|
||||||
|
/// This essentially adds `delta` to all time points.
|
||||||
|
pub fn shift_right(&self, delta: Duration) -> Self {
|
||||||
|
match self {
|
||||||
|
Signal::Sampled { values, time_points } => {
|
||||||
|
zip(time_points, values).map(|(&t, &v)| (t + delta, v)).collect()
|
||||||
|
}
|
||||||
|
// Empty and constant signals can't really be changed
|
||||||
|
sig => sig.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue