Current section
Files
Jump to
Current section
Files
lib/fft.ex
defmodule FFT do
@moduledoc """
FFT - Fast Fourier Transform
Algorithm for fast fourier transform, which is widely used in the treatment of signals.
The fast fourier transform picks up the signal input in a given time period and divides it into its frequency components.
"""
require Integer
import :math
@doc """
Transform
List (With length power of 2) -> Complex List
Input list and return the fft-list.
## Example
```
iex> a = [1,1,1,1,0,0,0,0]
[1, 1, 1, 1, 0, 0, 0, 0]
iex> FFT.transform a
[#ComplexNum (Cartesian) <4.0 + 0.0Β·π>,
#ComplexNum (Cartesian) <1.0 + -2.414213562373095Β·π>,
#ComplexNum (Cartesian) <0.0 + 0.0Β·π>,
#ComplexNum (Cartesian) <1.0 + -0.4142135623730949Β·π>,
#ComplexNum (Cartesian) <0.0 + 0.0Β·π>,
#ComplexNum (Cartesian) <0.9999999999999999 + 0.4142135623730949Β·π>,
#ComplexNum (Cartesian) <0.0 + 0.0Β·π>,
#ComplexNum (Cartesian) <0.9999999999999997 + 2.414213562373095Β·π>]
```
"""
def transform (a) do
test_var = a |> length |> :math.log2
if (test_var / round(test_var) == 1), do: solve(a), else: raise(ArgumentError, "The list length is not a power of 2.")
end
defp solve(a, i \\ -1, s \\ 1, k \\ 0, j \\ 1) do
unless i >= (length(a)) || i == -1 do
b = butterfly(Enum.at(a, i), Enum.at(a, i+1), k, pow(2, s))
if j >= (length(a) / pow(2, s)) do
a |> List.update_at(i, &(&1 = Enum.at(b, 0)))
|> List.update_at((i + 1), &(&1 = Enum.at(b, 1)))
|> solve(i + 2, s, k + 1)
else
a |> List.update_at(i, &(&1 = Enum.at(b, 0)))
|> List.update_at((i + 1), &(&1 = Enum.at(b, 1)))
|> solve(i + 2, s, k, j + 1)
end
else
if i == -1 do
a |> bit_reverse |> solve(i + 1)
else
unless s >= log2(length(a))do
a |> even_odd |> solve(0, s + 1)
else
even_odd(a)
end
end
end
end
@doc """
Bit-reverse.
List -> List
input a list and returns a list with the reassembled elements using bit-reverse.
## Example
```
iex> a = [0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7]
iex> FFT.bit_reverse a
[0, 4, 2, 6, 1, 5, 3, 7]
```
"""
def bit_reverse(array, reverse \\ [], n \\ 0) do
unless n == length(array) do
ind = n |> Integer.digits(2)
|> zeros(array)
|> inverter
|> Integer.undigits(2)
bit_reverse(array, reverse ++ [Enum.at(array, ind)], n + 1)
else
reverse
end
end
defp butterfly(h, g, k, n) do
w = ComplexNum.new(1, (-2 * pi() * k / n), :polar)
t = ComplexNum.mult(w, g)
[ComplexNum.add(h, t), ComplexNum.sub(h, t)]
end
@doc """
"""
def modulus_vector(a) do
Enum.map(a, fn x -> ComplexNum.magnitude(x) end )
end
defp zeros(bin, a) do
len = length(bin)
unless len == :math.log2(length(a)), do: zeros([0] ++ bin, a), else: bin
end
defp inverter(bin, resp \\[]) do
[h | t] = bin
unless t == [], do: inverter(t, [h] ++ resp), else: [h] ++ resp
end
defp even_odd(a, rec \\ -1, e \\ [], o \\ [], n \\ 0) do
unless n >= length(a) do
if Integer.is_even(n),
do: even_odd(a, rec, e ++ [Enum.at(a, n)], o ,n + 1), else: even_odd(a,rec , e, o ++ [Enum.at(a, n)],n + 1)
else
if rec > 0 do
even_odd(e++o, rec - 1)
else
e++o
end
end
end
end