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.

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