You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.4 KiB

  1. //! [Algorithm][1] to compute the [discrete Fourier transform][2] and its
  2. //! inverse.
  3. //!
  4. //! [1]: https://en.wikipedia.org/wiki/Fast_Fourier_transform
  5. //! [2]: https://en.wikipedia.org/wiki/Discrete_Fourier_transform
  6. // The implementation is based on:
  7. // http://www.librow.com/articles/article-10
  8. extern crate complex;
  9. use complex::{Complex, c64};
  10. use std::slice;
  11. /// A means of obtaining a slice of mutable complex numbers.
  12. pub trait AsMutComplex<'l> {
  13. type Complex: Complex + 'l;
  14. fn as_mut_complex(self) -> &'l mut [Self::Complex];
  15. }
  16. macro_rules! implement(
  17. ($complex:ty) => (
  18. impl<'l> AsMutComplex<'l> for &'l mut [$complex] {
  19. type Complex = $complex;
  20. #[inline(always)]
  21. fn as_mut_complex(self) -> &'l mut [Self::Complex] {
  22. self
  23. }
  24. }
  25. impl<'l> AsMutComplex<'l> for &'l mut Vec<$complex> {
  26. type Complex = $complex;
  27. #[inline]
  28. fn as_mut_complex(self) -> &'l mut [Self::Complex] {
  29. <&mut [$complex]>::as_mut_complex(&mut *self)
  30. }
  31. }
  32. );
  33. );
  34. implement!(c64);
  35. macro_rules! implement(
  36. ($complex:ty, $real:ty) => (
  37. impl<'l> AsMutComplex<'l> for &'l mut [$real] {
  38. type Complex = $complex;
  39. /// Treat the slice as a collection of pairs of real and imaginary
  40. /// parts and reinterpret it as a slice of complex numbers.
  41. ///
  42. /// ## Panics
  43. ///
  44. /// The function panics if the number of elements is not even.
  45. #[inline]
  46. fn as_mut_complex(self) -> &'l mut [Self::Complex] {
  47. unsafe {
  48. let length = self.len();
  49. assert!(length % 2 == 0, "the number of elements should be even");
  50. slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, length / 2)
  51. }
  52. }
  53. }
  54. impl<'l> AsMutComplex<'l> for &'l mut Vec<$real> {
  55. type Complex = $complex;
  56. #[inline]
  57. fn as_mut_complex(self) -> &'l mut [Self::Complex] {
  58. <&mut [$real]>::as_mut_complex(&mut *self)
  59. }
  60. }
  61. );
  62. );
  63. implement!(c64, f64);
  64. /// Perform the Fourier transform.
  65. ///
  66. /// The number of points should be a power of two.
  67. pub fn forward<'l, T>(data: T) where T: AsMutComplex<'l, Complex=c64> {
  68. let data = data.as_mut_complex();
  69. let n = data.len();
  70. if n < 1 || n & (n - 1) != 0 {
  71. panic!("expected the number of points to be a power of two");
  72. }
  73. rearrange(data, n);
  74. perform(data, n, false);
  75. }
  76. /// Perform the inverse Fourier transform.
  77. ///
  78. /// The number of points should be a power of two.
  79. pub fn inverse<'l, T>(data: T, scaling: bool) where T: AsMutComplex<'l, Complex=c64> {
  80. let data = data.as_mut_complex();
  81. let n = data.len();
  82. if n < 1 || n & (n - 1) != 0 {
  83. panic!("expected the number of points to be a power of two");
  84. }
  85. rearrange(data, n);
  86. perform(data, n, true);
  87. if scaling {
  88. scale(data, n);
  89. }
  90. }
  91. #[inline(always)]
  92. fn rearrange(data: &mut [c64], n: usize) {
  93. let mut target = 0;
  94. for position in 0..n {
  95. if target > position {
  96. data.swap(position, target);
  97. }
  98. let mut mask = n >> 1;
  99. while target & mask != 0 {
  100. target &= !mask;
  101. mask >>= 1;
  102. }
  103. target |= mask;
  104. }
  105. }
  106. #[inline(always)]
  107. fn perform(data: &mut [c64], n: usize, inverse: bool) {
  108. use std::f64::consts::PI;
  109. let pi = if inverse { PI } else { -PI };
  110. let mut step = 1;
  111. while step < n {
  112. let jump = step << 1;
  113. let delta = pi / step as f64;
  114. let sine = (0.5 * delta).sin();
  115. let multiplier = c64(-2.0 * sine * sine, delta.sin());
  116. let mut factor = c64(1.0, 0.0);
  117. for group in 0..step {
  118. let mut pair = group;
  119. while pair < n {
  120. let match_pair = pair + step;
  121. let product = factor * data[match_pair];
  122. data[match_pair] = data[pair] - product;
  123. data[pair] = data[pair] + product;
  124. pair += jump;
  125. }
  126. factor = multiplier * factor + factor;
  127. }
  128. step <<= 1;
  129. }
  130. }
  131. #[inline(always)]
  132. fn scale(data: &mut [c64], n: usize) {
  133. let factor = 1.0 / n as f64;
  134. for position in 0..n {
  135. data[position] = data[position] * factor;
  136. }
  137. }