Engee 文档
Notebook

傅立叶方法

信号处理中常用的一种方法是傅立叶变换。这种方法可以在时域和频域之间变换信号。Julia 使用 FFTW 库实现了高效的快速傅立叶变换(FFT)算法。

In [ ]:
using FFTW

一维傅立叶变换

我们先来看看一维的傅立叶变换。我们将使用宽矩形函数创建时域测试数据。

In [ ]:
f = [abs(x) <= 1 ? 1 : 0 for x in -5:0.1:5];
plot(real(f))
Out[0]:

现在,让我们使用 fft() 将数据转换到频域,并使用复数模块绘制信号频谱。

In [ ]:
FFT = fft(f);
typeof(FFT)
Out[0]:
Vector{ComplexF64} (alias for Array{Complex{Float64}, 1})
In [ ]:
abs_FFT = sqrt.(real(FFT).^2+imag(FFT).^2)
plot(abs_FFT)
Out[0]:

频域数据是一个复数类型的数组,长度与时域数据相同。

由于每个复数都由两部分组成(实数和虚数),我们似乎在某种程度上将信号的信息量增加了一倍。其实不然:一半的频域数据是多余的。fftshift()函数可以方便地重新排列频域数据,使负频位于左侧。

In [ ]:
F = fftshift(FFT);
abs_F = sqrt.(real(F).^2+imag(F).^2)
plot(abs_F)
Out[0]:

矩形函数的解析傅里叶变换是函数 sinc,它与上图中的数值数据非常吻合。

二维傅里叶变换

让我们考虑一个类似的二维问题。但这次我们将反其道而行之,从二维函数 sinc 开始,求其傅里叶变换。

使用列表生成器很容易建立一个 sinc 数据数组。

In [ ]:
f = [(r = sqrt(x^2 + y^2); sinc(r)) for x in -6:0.125:6, y in -6:0.125:6];
plot(f)
Out[0]:

在时域中考虑二维函数并没有什么意义。但傅里叶变换可以同时处理时间信号和空间信号(或几乎任何其他域的信号)。因此,假设我们的二维数据在空间域。

In [ ]:
heatmap(f)
Out[0]:

还可使用 fft() 生成多维信号的傅立叶变换。

In [ ]:
F = fft(f);
F = fftshift(F);
abs_F = sqrt.(real(F).^2+imag(F).^2)
heatmap(abs_F)
Out[0]:

输出

除上述之外,将 FFT 应用于高维数据也很方便。

FFTW 库的大部分功能都在 Julia 接口中实现。

具体如何实现呢? 1.使用 plan_fft() 生成优化的 FFT 计划; 2; 2. 使用 dct() 使用离散余弦变换; 3. 使用 rfft() 在实变换中使用共轭对称性; 您还可以通过 FFTW.set_num_threads() 运行多个线程。