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.

113 lines
3.4 KiB

9 years ago
9 years ago
9 years ago
  1. //! Transformation of real data.
  2. use number::{Complex, c64};
  3. macro_rules! reinterpret(
  4. ($data:ident) => (unsafe {
  5. use std::slice::from_raw_parts_mut;
  6. let n = power_of_two!($data);
  7. (from_raw_parts_mut($data.as_mut_ptr() as *mut _, n / 2), n / 2)
  8. });
  9. );
  10. /// Perform the forward transform.
  11. ///
  12. /// The number of points should be a power of two. The data are replaced by the
  13. /// positive frequency half of their complex Fourier transform. The real-valued
  14. /// first and last components of the complex transform are returned as elements
  15. /// `data[0]` and `data[1]`, respectively.
  16. ///
  17. /// ## References
  18. ///
  19. /// 1. William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P.
  20. /// Flannery, “Numerical Recipes 3rd Edition: The Art of Scientific
  21. /// Computing,” Cambridge University Press, 2007.
  22. pub fn forward(data: &mut [f64]) {
  23. let (data, n) = reinterpret!(data);
  24. ::complex::forward(data);
  25. compose(data, n, false);
  26. }
  27. /// Perform the backward transform.
  28. ///
  29. /// The number of points should be a power of two. The data should be packed as
  30. /// described in `real::forward`.
  31. pub fn backward(data: &mut [f64]) {
  32. let (data, n) = reinterpret!(data);
  33. compose(data, n, true);
  34. ::complex::backward(data);
  35. }
  36. /// Perform the inverse transform.
  37. ///
  38. /// The number of points should be a power of two. The data should be packed as
  39. /// described in `real::forward`.
  40. pub fn inverse(data: &mut [f64]) {
  41. let (data, n) = reinterpret!(data);
  42. compose(data, n, true);
  43. ::complex::inverse(data);
  44. }
  45. /// Unpack a compressed representation produced by `real::forward`.
  46. pub fn unpack(data: &[f64]) -> Vec<c64> {
  47. let n = power_of_two!(data);
  48. let mut cdata = Vec::with_capacity(n);
  49. unsafe { cdata.set_len(n) };
  50. cdata[0] = c64(data[0], 0.0);
  51. for i in 1..(n / 2) {
  52. cdata[i] = c64(data[2 * i], data[2 * i + 1]);
  53. }
  54. cdata[n / 2] = c64(data[1], 0.0);
  55. for i in (n / 2 + 1)..n {
  56. cdata[i] = cdata[n - i].conj();
  57. }
  58. cdata
  59. }
  60. pub fn compose(data: &mut [c64], n: usize, inverse: bool) {
  61. data[0] = c64(data[0].re() + data[0].im(), data[0].re() - data[0].im());
  62. if inverse {
  63. data[0] = data[0] * 0.5;
  64. }
  65. let sign = if inverse { 1.0 } else { -1.0 };
  66. let (multiplier, mut factor) = {
  67. use std::f64::consts::PI;
  68. let theta = sign * PI / n as f64;
  69. let sine = (0.5 * theta).sin();
  70. (c64(-2.0 * sine * sine, theta.sin()), c64(1.0, 0.0))
  71. };
  72. for i in 1..(n / 2) {
  73. let j = n - i;
  74. factor = multiplier * factor + factor;
  75. let part1 = (data[i] + data[j].conj()) * 0.5;
  76. let part2 = (data[i] - data[j].conj()) * 0.5;
  77. let product = c64(0.0, sign) * factor * part2;
  78. data[i] = part1 + product;
  79. data[j] = (part1 - product).conj();
  80. }
  81. data[n / 2] = data[n / 2].conj();
  82. }
  83. #[cfg(test)]
  84. mod tests {
  85. use number::c64;
  86. #[test]
  87. fn unpack() {
  88. let data = (0..4).map(|i| (i + 1) as f64).collect::<Vec<_>>();
  89. assert_eq!(super::unpack(&data), vec![
  90. c64(1.0, 0.0), c64(3.0, 4.0), c64(2.0, 0.0), c64(3.0, -4.0),
  91. ]);
  92. let data = (0..8).map(|i| (i + 1) as f64).collect::<Vec<_>>();
  93. assert_eq!(super::unpack(&data), vec![
  94. c64(1.0, 0.0), c64(3.0, 4.0), c64(5.0, 6.0), c64(7.0, 8.0),
  95. c64(2.0, 0.0), c64(7.0, -8.0), c64(5.0, -6.0), c64(3.0, -4.0),
  96. ]);
  97. }
  98. }