diff --git a/src/interop_facade/facade32.rs b/src/interop_facade/facade32.rs index 751122074..75a44a3ce 100644 --- a/src/interop_facade/facade32.rs +++ b/src/interop_facade/facade32.rs @@ -470,4 +470,36 @@ pub extern fn sifft32(vector: Box, even_odd: i32) -> VectorResult< pub extern fn mirror32(vector: Box, even_odd: i32) -> VectorResult { let even_odd = translate_to_even_odd(even_odd); convert_vec!(vector.mirror(even_odd)) +} + +#[no_mangle] +pub extern fn apply_window32(vector: Box, window: i32) -> VectorResult { + let window = translate_to_window_function(window); + convert_vec!(vector.apply_window(window.as_ref())) +} + +#[no_mangle] +pub extern fn unapply_window32(vector: Box, window: i32) -> VectorResult { + let window = translate_to_window_function(window); + convert_vec!(vector.unapply_window(window.as_ref())) +} + + +#[no_mangle] +pub extern fn windowed_fft32(vector: Box, window: i32) -> VectorResult { + let window = translate_to_window_function(window); + convert_vec!(vector.windowed_fft(window.as_ref())) +} + +#[no_mangle] +pub extern fn windowed_ifft32(vector: Box, window: i32) -> VectorResult { + let window = translate_to_window_function(window); + convert_vec!(vector.windowed_ifft(window.as_ref())) +} + +#[no_mangle] +pub extern fn windowed_sifft32(vector: Box, even_odd: i32, window: i32) -> VectorResult { + let even_odd = translate_to_even_odd(even_odd); + let window = translate_to_window_function(window); + convert_vec!(vector.windowed_sifft(even_odd, window.as_ref())) } \ No newline at end of file diff --git a/src/interop_facade/mod.rs b/src/interop_facade/mod.rs index 18dd2d402..85176f7fd 100644 --- a/src/interop_facade/mod.rs +++ b/src/interop_facade/mod.rs @@ -41,6 +41,8 @@ pub mod facade64; use vector_types::{ ErrorReason, EvenOdd}; +use window_functions::*; +use RealNumber; pub fn translate_error(reason: ErrorReason) -> i32 { match reason { @@ -58,6 +60,15 @@ pub fn translate_to_even_odd(value: i32) -> EvenOdd { if value != 0 { EvenOdd::Odd } else { EvenOdd::Even } } +pub fn translate_to_window_function(value: i32) -> Box> + where T: RealNumber { + if value == 0 { + Box::new(TriangularWindow) + } else { + Box::new(TriangularWindow) + } +} + /// Result of a vector operation. Check the ```result_code```. #[repr(C)] pub struct VectorResult { diff --git a/src/vector_types/time_freq_impl.rs b/src/vector_types/time_freq_impl.rs index 0d51ea97a..620dd3b90 100644 --- a/src/vector_types/time_freq_impl.rs +++ b/src/vector_types/time_freq_impl.rs @@ -78,13 +78,13 @@ pub trait TimeDomainOperations : DataVector /// Applies a FFT window and performs a Fast Fourier Transformation transforming a time domain vector /// into a frequency domain vector. - fn windowed_fft(self, window: W) -> VecResult where W: WindowFunction; + fn windowed_fft(self, window: &WindowFunction) -> VecResult; /// Applies a window to the data vector. - fn apply_window(self, window: W) -> VecResult where W: WindowFunction; + fn apply_window(self, window: &WindowFunction) -> VecResult; /// Removes a window from the data vector. - fn unapply_window(self, window: W) -> VecResult where W: WindowFunction; + fn unapply_window(self, window: &WindowFunction) -> VecResult; } /// Defines all operations which are valid on `DataVectors` containing complex data. @@ -170,7 +170,7 @@ pub trait FrequencyDomainOperations : DataVector /// Performs an Inverse Fast Fourier Transformation transforming a frequency domain vector /// into a time domain vector and removes the FFT window. - fn windowed_ifft(self, window: W) -> VecResult where W: WindowFunction; + fn windowed_ifft(self, window: &WindowFunction) -> VecResult; /// Performs a Symmetric Inverse Fast Fourier Transformation (SIFFT) and removes the FFT window. /// The SIFFT is performed under the assumption that `self` @@ -181,7 +181,7 @@ pub trait FrequencyDomainOperations : DataVector /// The argument indicates whether the resulting real vector should have `2*N` or `2*N-1` points. /// # Unstable /// Symmetric IFFTs are unstable and may only work under certain conditions. - fn windowed_sifft(self, even_odd: EvenOdd, window: W) -> VecResult where W: WindowFunction; + fn windowed_sifft(self, even_odd: EvenOdd, window: &WindowFunction) -> VecResult; } macro_rules! define_time_domain_forward { @@ -193,11 +193,11 @@ macro_rules! define_time_domain_forward { Self::FreqPartner::from_genres(self.to_gen().plain_fft()) } - fn apply_window(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn apply_window(self, window: &WindowFunction<$data_type>) -> VecResult { Self::from_genres(self.to_gen().apply_window(window)) } - fn unapply_window(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn unapply_window(self, window: &WindowFunction<$data_type>) -> VecResult { Self::from_genres(self.to_gen().unapply_window(window)) } @@ -205,7 +205,7 @@ macro_rules! define_time_domain_forward { Self::FreqPartner::from_genres(self.to_gen().fft()) } - fn windowed_fft(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_fft(self, window: &WindowFunction<$data_type>) -> VecResult { Self::FreqPartner::from_genres(self.to_gen().windowed_fft(window)) } } @@ -216,7 +216,7 @@ macro_rules! define_time_domain_forward { macro_rules! implement_window_function { ($($name:ident, $data_type:ident, $operation: ident);*) => { $( - fn $name(mut self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn $name(mut self, window: &WindowFunction<$data_type>) -> VecResult { assert_time!(self); if self.is_complex { let len = self.len(); @@ -284,7 +284,7 @@ macro_rules! add_time_freq_impl { .and_then(|v|v.swap_halves()) } - fn windowed_fft(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_fft(self, window: &WindowFunction<$data_type>) -> VecResult { self.apply_window(window) .and_then(|v|v.plain_fft()) .and_then(|v|v.swap_halves()) @@ -374,7 +374,7 @@ macro_rules! add_time_freq_impl { .and_then(|v| v.plain_sifft(even_odd)) } - fn windowed_ifft(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_ifft(self, window: &WindowFunction<$data_type>) -> VecResult { let points = self.points(); self.real_scale(1.0 / points as $data_type) .and_then(|v| v.swap_halves()) @@ -382,7 +382,7 @@ macro_rules! add_time_freq_impl { .and_then(|v|v.unapply_window(window)) } - fn windowed_sifft(self, even_odd: EvenOdd, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_sifft(self, even_odd: EvenOdd, window: &WindowFunction<$data_type>) -> VecResult { let points = self.points(); self.real_scale(1.0 / points as $data_type) .and_then(|v| v.swap_halves()) @@ -414,11 +414,11 @@ macro_rules! add_time_freq_impl { Self::RealTimePartner::from_genres(self.to_gen().sifft(even_odd)) } - fn windowed_ifft(self, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_ifft(self, window: &WindowFunction<$data_type>) -> VecResult { Self::ComplexTimePartner::from_genres(self.to_gen().windowed_ifft(window)) } - fn windowed_sifft(self, even_odd: EvenOdd, window: W) -> VecResult where W: WindowFunction<$data_type> { + fn windowed_sifft(self, even_odd: EvenOdd, window: &WindowFunction<$data_type>) -> VecResult { Self::RealTimePartner::from_genres(self.to_gen().windowed_sifft(even_odd, window)) } } diff --git a/src/window_functions.rs b/src/window_functions.rs index 1c308ad01..f117e93f8 100644 --- a/src/window_functions.rs +++ b/src/window_functions.rs @@ -11,7 +11,7 @@ use super::RealNumber; /// 1. The second argument is of the function is always `self.points()` and the possible values for the first argument ranges from `0..self.points()`. /// 2. A window function must be symmetric about the y-axis. /// 3. All real return values are allowed -pub trait WindowFunction : Sized +pub trait WindowFunction where T: RealNumber { /// Calculates a point of the window function fn window(&self, n: usize, length: usize) -> T; diff --git a/tests/time_freq_test.rs b/tests/time_freq_test.rs index 85897d74c..c0aa2bdc6 100644 --- a/tests/time_freq_test.rs +++ b/tests/time_freq_test.rs @@ -34,8 +34,8 @@ mod slow_test { fn window_real_vs_complex_vector64() { let vector = new_sinusoid_vector(); let complex = vector.clone().to_complex().unwrap(); - let complex_windowed = complex.apply_window(HammingWindow::default()).unwrap(); - let real_windowed = vector.apply_window(HammingWindow::default()).unwrap(); + let complex_windowed = complex.apply_window(&HammingWindow::default()).unwrap(); + let real_windowed = vector.apply_window(&HammingWindow::default()).unwrap(); assert_eq!(real_windowed.data(), complex_windowed.to_real().unwrap().data()); } @@ -62,7 +62,7 @@ mod slow_test { fn windowed_fft_vector64() { let vector = new_sinusoid_vector(); let complex = vector.to_complex().unwrap(); - let fft = complex.windowed_fft(HammingWindow::default()).unwrap().magnitude().unwrap(); + let fft = complex.windowed_fft(&HammingWindow::default()).unwrap().magnitude().unwrap(); // Expected data has been created with GNU Octave let expected: &[f64] = &[0.07411808515197066, 0.07422272322333621, 0.07453841468679659, 0.07506988195440296, 0.07582541343880053, 0.07681696328361777, 0.07806061998281554, 0.07957802869766938, 0.08139483126598358, 0.08354572044699357, 0.0860733404576818, @@ -91,8 +91,8 @@ mod slow_test { fn windowed_fft_windowed_ifft_vector64() { let vector = new_sinusoid_vector(); let complex = vector.clone().to_complex().unwrap(); - let fft = complex.windowed_fft(HammingWindow::default()).unwrap(); - let ifft = fft.windowed_ifft(HammingWindow::default()).unwrap().to_real().unwrap(); + let fft = complex.windowed_fft(&HammingWindow::default()).unwrap(); + let ifft = fft.windowed_ifft(&HammingWindow::default()).unwrap().to_real().unwrap(); assert_vector_eq(vector.data(), ifft.data()); }