feat(core): add shift left/right operators to Signal

This commit is contained in:
Anand Balakrishnan 2023-05-23 13:12:22 -07:00
parent a54ec8a69f
commit 70c5a50d22
No known key found for this signature in database
2 changed files with 63 additions and 0 deletions

View file

@ -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;

View 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(),
}
}
}