dft/lib.rs
1//! [Discrete Fourier transform][1].
2//!
3//! The `Transform` trait is responsible for performing the transform. The trait
4//! is implemented for both real and complex data. There are three transform
5//! operations available: forward, backward, and inverse. The desired operation
6//! is specified by the `Operation` enumeration passed to the `Plan::new`
7//! function, which precomputes auxiliary information needed for
8//! `Transform::transform`. All the operations are preformed in place.
9//!
10//! When applied to real data, the transform works as follows. If the operation
11//! is forward, the data are replaced by the positive frequency half of their
12//! complex transform. The first and last components of the complex transform,
13//! which are real, are stored in `self[0]` and `self[1]`, respectively. If the
14//! operation is backward or inverse, the data are assumed to be stored
15//! according to the above convention. See the reference below for further
16//! details.
17//!
18//! ## Example
19//!
20//! ```
21//! use dft::{Operation, Plan, c64};
22//!
23//! let plan = Plan::new(Operation::Forward, 512);
24//! let mut data = vec![c64::new(42.0, 69.0); 512];
25//! dft::transform(&mut data, &plan);
26//! ```
27//!
28//! ## References
29//!
30//! 1. W. Press, S. Teukolsky, W. Vetterling, and B. Flannery, “Numerical
31//! Recipes 3rd Edition: The Art of Scientific Computing,” Cambridge University
32//! Press, 2007.
33//!
34//! [1]: https://en.wikipedia.org/wiki/Discrete_Fourier_transform
35
36extern crate num_complex;
37extern crate num_traits;
38
39use num_complex::Complex;
40use num_traits::{Float, FloatConst, One};
41
42/// A complex number with 32-bit parts.
43#[allow(non_camel_case_types)]
44pub type c32 = Complex<f32>;
45
46/// A complex number with 64-bit parts.
47#[allow(non_camel_case_types)]
48pub type c64 = Complex<f64>;
49
50mod complex;
51mod real;
52
53pub use real::unpack;
54
55/// A transform operation.
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub enum Operation {
58 /// The forward transform.
59 Forward,
60 /// The backward transform.
61 Backward,
62 /// The inverse transform.
63 Inverse,
64}
65
66/// A transform plan.
67#[derive(Clone, Debug)]
68pub struct Plan<T> {
69 n: usize,
70 factors: Vec<Complex<T>>,
71 operation: Operation,
72}
73
74/// The transform.
75pub trait Transform<T> {
76 /// Perform the transform.
77 fn transform(&mut self, &Plan<T>);
78}
79
80impl<T> Plan<T>
81where
82 T: Float + FloatConst,
83{
84 /// Create a plan for a specific operation and specific number of points.
85 ///
86 /// The number of points should be a power of two.
87 pub fn new(operation: Operation, n: usize) -> Self {
88 assert!(n.is_power_of_two());
89 let one = T::one();
90 let two = one + one;
91 let mut factors = vec![];
92 let sign = if let Operation::Forward = operation {
93 -one
94 } else {
95 one
96 };
97 let mut step = 1;
98 while step < n {
99 let (multiplier, mut factor) = {
100 let theta = T::PI() / T::from(step).unwrap();
101 let sine = (theta / two).sin();
102 (
103 Complex::new(-two * sine * sine, sign * theta.sin()),
104 Complex::one(),
105 )
106 };
107 for _ in 0..step {
108 factors.push(factor);
109 factor = multiplier * factor + factor;
110 }
111 step <<= 1;
112 }
113 Plan {
114 n: n,
115 factors: factors,
116 operation: operation,
117 }
118 }
119}
120
121/// Perform the transform.
122///
123/// The function is a shortcut for `Transform::transform`.
124#[inline(always)]
125pub fn transform<D: ?Sized, T>(data: &mut D, plan: &Plan<T>)
126where
127 D: Transform<T>,
128{
129 Transform::transform(data, plan);
130}