|
| 1 | +use super::GeneralCosine; |
| 2 | +use super::{extend, len_guard, truncate}; |
| 3 | +use nalgebra::RealField; |
| 4 | +use num_traits::{real::Real, Float}; |
| 5 | + |
| 6 | +#[cfg(feature = "alloc")] |
| 7 | +use super::GetWindow; |
| 8 | +#[cfg(feature = "alloc")] |
| 9 | +use alloc::{vec, vec::Vec}; |
| 10 | + |
| 11 | +/// Collection of arguments for window `Blackman` for use in [GetWindow]. |
| 12 | +#[derive(Debug, Clone, PartialEq)] |
| 13 | +pub struct Blackman { |
| 14 | + /// Number of points in the output window. If zero, an empty array is returned in [GetWindow]. |
| 15 | + pub m: usize, |
| 16 | + /// Whether the window is symmetric. |
| 17 | + /// |
| 18 | + /// When true, generates a symmetric window, for use in filter design. |
| 19 | + /// When false, generates a periodic window, for use in spectral analysis. |
| 20 | + pub sym: bool, |
| 21 | +} |
| 22 | + |
| 23 | +impl Blackman { |
| 24 | + /// Returns a Blackman struct. |
| 25 | + /// |
| 26 | + /// # Parameters |
| 27 | + /// * `m`: |
| 28 | + /// Number of points in the output window. If zero, an empty array is returned. |
| 29 | + /// * `sym`: |
| 30 | + /// When true, generates a symmetric window, for use in filter design. |
| 31 | + /// When false, generates a periodic window, for use in spectral analysis. |
| 32 | + pub fn new(m: usize, sym: bool) -> Self { |
| 33 | + Blackman { m, sym } |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +#[cfg(feature = "alloc")] |
| 38 | +impl GetWindow for Blackman { |
| 39 | + /// Return a window of type: Blackman. |
| 40 | + /// |
| 41 | + /// The Blackman window is a taper formed by using the first three terms of a summation of |
| 42 | + /// cosines. It was designed to have close to the minimal leakage possible. It is close to |
| 43 | + /// optimal, only slightly worse than a Kaiser window. |
| 44 | + /// |
| 45 | + /// # Parameters |
| 46 | + /// `self`: [Blackman] |
| 47 | + /// |
| 48 | + /// # Returns |
| 49 | + /// `w`: `vec<F>` |
| 50 | + /// The window, with the maximum value normalized to 1 (though the value 1 does not appear |
| 51 | + /// if `M` is even and `sym` is True). |
| 52 | + /// |
| 53 | + /// # Example |
| 54 | + /// ``` |
| 55 | + /// use sci_rs::signal::windows::{Blackman, GetWindow}; |
| 56 | + /// |
| 57 | + /// let nx = 8; |
| 58 | + /// let b = Blackman::new(nx, true); |
| 59 | + /// ``` |
| 60 | + /// |
| 61 | + /// # References |
| 62 | + /// <https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.windows.blackman.html> |
| 63 | + #[cfg(feature = "alloc")] |
| 64 | + fn get_window<F>(&self) -> Vec<F> |
| 65 | + where |
| 66 | + F: Real + Float + RealField, |
| 67 | + { |
| 68 | + GeneralCosine::new( |
| 69 | + self.m, |
| 70 | + [0.42, 0.50, 0.08] |
| 71 | + .into_iter() |
| 72 | + .map(|n| F::from(n).unwrap()) |
| 73 | + .collect(), |
| 74 | + self.sym, |
| 75 | + ) |
| 76 | + .get_window() |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +#[cfg(test)] |
| 81 | +mod tests { |
| 82 | + use super::*; |
| 83 | + use approx::assert_abs_diff_eq; |
| 84 | + |
| 85 | + #[test] |
| 86 | + fn blackman_20() { |
| 87 | + // Created with |
| 88 | + // >>> from scipy.signal.windows import blackman |
| 89 | + // >>> blackman(20) |
| 90 | + let expected = vec![ |
| 91 | + -1.38777878e-17, |
| 92 | + 1.02226199e-02, |
| 93 | + 4.50685843e-02, |
| 94 | + 1.14390287e-01, |
| 95 | + 2.26899356e-01, |
| 96 | + 3.82380768e-01, |
| 97 | + 5.66665187e-01, |
| 98 | + 7.52034438e-01, |
| 99 | + 9.03492728e-01, |
| 100 | + 9.88846031e-01, |
| 101 | + 9.88846031e-01, |
| 102 | + 9.03492728e-01, |
| 103 | + 7.52034438e-01, |
| 104 | + 5.66665187e-01, |
| 105 | + 3.82380768e-01, |
| 106 | + 2.26899356e-01, |
| 107 | + 1.14390287e-01, |
| 108 | + 4.50685843e-02, |
| 109 | + 1.02226199e-02, |
| 110 | + -1.38777878e-17, |
| 111 | + ]; |
| 112 | + assert_vec_eq(expected, Blackman::new(20, true).get_window()); |
| 113 | + } |
| 114 | + |
| 115 | + #[track_caller] |
| 116 | + fn assert_vec_eq(a: Vec<f64>, b: Vec<f64>) { |
| 117 | + for (a, b) in a.into_iter().zip(b) { |
| 118 | + assert_abs_diff_eq!(a, b, epsilon = 1e-6); |
| 119 | + } |
| 120 | + } |
| 121 | +} |
0 commit comments