Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

fft

快速傅里叶变换

说明

示例

Y = fft(X) 使用快速傅里叶变换 (FFT) 算法计算 X离散傅里叶变换 (DFT)。YX 的大小相同。

  • 如果 X 是向量,则 fft(X) 返回该向量的傅里叶变换。

  • 如果 X 是矩阵,则 fft(X)X 的各列视为向量,并返回每列的傅里叶变换。

  • 如果 X 是一个多维数组,则 fft(X) 将沿大小不等于 1 的第一个数组维度的值视为向量,并返回每个向量的傅里叶变换。

示例

Y = fft(X,n) 返回 n 点 DFT。

  • 如果 X 是向量且 X 的长度小于 n,则为 X 补上尾零以达到长度 n

  • 如果 X 是向量且 X 的长度大于 n,则对 X 进行截断以达到长度 n

  • 如果 X 是矩阵,则每列的处理与在向量情况下相同。

  • 如果 X 为多维数组,则大小不等于 1 的第一个数组维度的处理与在向量情况下相同。

示例

Y = fft(X,n,dim) 返回沿维度 dim 的傅里叶变换。例如,如果 X 是矩阵,则 fft(X,n,2) 返回每行的 n 点傅里叶变换。

示例

全部折叠

通过使用傅里叶变换,求出隐藏在噪声中的信号的频率分量,并求出峰值频率的振幅。

指定信号的参数,采样频率为 1 kHz,信号持续时间为 1.5 秒。

Fs = 1000;            % Sampling frequency                    
T = 1/Fs;             % Sampling period       
L = 1500;             % Length of signal
t = (0:L-1)*T;        % Time vector

构造一个信号,其中包含振幅为 0.8 的 DC 偏移量、振幅为 0.7 的 50 Hz 正弦量和振幅为 1 的 120 Hz 正弦量。

S = 0.8 + 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);

用均值为零、方差为 4 的随机噪声扰乱该信号。

X = S + 2*randn(size(t));

在时域中绘制含噪信号。频率分量在图中显示不明显。

plot(1000*t,X)
title("Signal Corrupted with Zero-Mean Random Noise")
xlabel("t (milliseconds)")
ylabel("X(t)")

Figure contains an axes object. The axes object with title Signal Corrupted with Zero-Mean Random Noise, xlabel t (milliseconds), ylabel X(t) contains an object of type line.

计算信号的傅里叶变换。

Y = fft(X);

由于傅里叶变换涉及复数,因此绘制 fft 频谱的复数模。

plot(Fs/L*(0:L-1),abs(Y),"LineWidth",3)
title("Complex Magnitude of fft Spectrum")
xlabel("f (Hz)")
ylabel("|fft(X)|")

Figure contains an axes object. The axes object with title Complex Magnitude of fft Spectrum, xlabel f (Hz), ylabel |fft(X)| contains an object of type line.

该图显示五个频率峰值,包括 DC 偏移量在 0 Hz 处的峰值。在此示例中,信号预计在 0 Hz、50 Hz 和 120 Hz 处有三个频率峰值。此处,绘图的后半部分是前半部分的镜像,不包括 0 Hz 处的峰值。原因是时域信号的离散傅里叶变换具有周期性,其频谱的前半部分为正频率,后半部分为负频率,第一个元素保留用于零频率。

对于实信号,fft 频谱是双边频谱,其中正频率的频谱是负频率的频谱的复共轭。要显示正负频率的 fft 频谱,可以使用 fftshift。对于偶数长度 L,频域从奈奎斯特频率的负值 -Fs/2 开始,直到 Fs/2-Fs/L,间距或频率分辨率为 Fs/L

plot(Fs/L*(-L/2:L/2-1),abs(fftshift(Y)),"LineWidth",3)
title("fft Spectrum in the Positive and Negative Frequencies")
xlabel("f (Hz)")
ylabel("|fft(X)|")

Figure contains an axes object. The axes object with title fft Spectrum in the Positive and Negative Frequencies, xlabel f (Hz), ylabel |fft(X)| contains an object of type line.

为了找到三个频率峰值的幅值,将 Y 中的 fft 频谱转换为单边振幅频谱。由于 fft 函数包括原始信号和变换信号之间的缩放因子 L,因此通过除以 L 来重新缩放 Y。取 fft 频谱的复数模。双边振幅频谱 P2(其中正频率的频谱是负频率的频谱的复共轭),其峰值振幅是时域信号中对应峰值振幅的一半。要转换为单边频谱,取双边频谱 P2 的前半部分。将正频率的频谱乘以 2。您不需要将 P1(1)P1(end) 乘以 2,因为这些振幅分别对应于零频率和奈奎斯特频率,并且在负频率下没有复共轭对组。

P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);

定义单边频谱的频域 f。绘制单边振幅频谱 P1。与预期相符,振幅接近 0.8、0.7 和 1,但由于增加了噪声,它们并不精确等于这些值。大多数情况下,较长的信号会产生更好的频率逼近值。

f = Fs/L*(0:(L/2));
plot(f,P1,"LineWidth",3) 
title("Single-Sided Amplitude Spectrum of X(t)")
xlabel("f (Hz)")
ylabel("|P1(f)|")

Figure contains an axes object. The axes object with title Single-Sided Amplitude Spectrum of X(t), xlabel f (Hz), ylabel |P1(f)| contains an object of type line.

现在,采用原始的、未破坏信号的傅里叶变换并检索精确振幅在 0.8、0.7 和 1.0 处。

Y = fft(S);
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);

plot(f,P1,"LineWidth",3) 
title("Single-Sided Amplitude Spectrum of S(t)")
xlabel("f (Hz)")
ylabel("|P1(f)|")

Figure contains an axes object. The axes object with title Single-Sided Amplitude Spectrum of S(t), xlabel f (Hz), ylabel |P1(f)| contains an object of type line.

将高斯脉冲从时域转换为频域。

指定信号的参数,采样频率为 44.1 kHz,信号持续时间为 1 秒。创建一倍标准差为 0.1 ms 的高斯脉冲。

Fs = 44100;         % Sampling frequency
T = 1/Fs;           % Sampling period
t = -0.5:T:0.5;     % Time vector
L = length(t);      % Signal length

X = 1/(0.4*sqrt(2*pi))*(exp(-t.^2/(2*(0.1*1e-3)^2)));

在时域中绘制脉冲。

plot(t,X)
title("Gaussian Pulse in Time Domain")
xlabel("Time (t)")
ylabel("X(t)")
axis([-1e-3 1e-3 0 1.1]) 

Figure contains an axes object. The axes object with title Gaussian Pulse in Time Domain, xlabel Time (t), ylabel X(t) contains an object of type line.

fft 的执行时间取决于变换的长度。仅具有小质因数的变换长度比那些具有大质因数的变换长度的执行时间要快得多。

在此示例中,信号长度 L 是 44101,这是非常大的质数。为了改进 fft 的性能,从原始信号长度确定一个是下一个 2 次幂的输入长度。使用此输入长度调用 fft 会将具有尾随零的脉冲 X 填充到指定的变换长度。

n = 2^nextpow2(L);

将高斯脉冲转换为频域。

Y = fft(X,n);

定义频域并绘制唯一频率。

f = Fs*(0:(n/2))/n;
P = abs(Y/sqrt(n)).^2;

plot(f,P(1:n/2+1)) 
title("Gaussian Pulse in Frequency Domain")
xlabel("f (Hz)")
ylabel("|P(f)|")

Figure contains an axes object. The axes object with title Gaussian Pulse in Frequency Domain, xlabel f (Hz), ylabel |P(f)| contains an object of type line.

比较时域和频域中的余弦波。

指定信号的参数,采样频率为 1 kHz,信号持续时间为 1 秒。

Fs = 1000;                    % Sampling frequency
T = 1/Fs;                     % Sampling period
L = 1000;                     % Length of signal
t = (0:L-1)*T;                % Time vector

创建一个矩阵,其中每一行代表一个频率经过缩放的余弦波。结果 X 为 3×1000 矩阵。第一行的波频为 50,第二行的波频为 150,第三行的波频为 300。

x1 = cos(2*pi*50*t);          % First row wave
x2 = cos(2*pi*150*t);         % Second row wave
x3 = cos(2*pi*300*t);         % Third row wave

X = [x1; x2; x3];

在单个图窗中按顺序绘制 X 的每行的前 100 个项,并比较其频率。

for i = 1:3
    subplot(3,1,i)
    plot(t(1:100),X(i,1:100))
    title("Row " + num2str(i) + " in the Time Domain")
end

Figure contains 3 axes objects. Axes object 1 with title Row 1 in the Time Domain contains an object of type line. Axes object 2 with title Row 2 in the Time Domain contains an object of type line. Axes object 3 with title Row 3 in the Time Domain contains an object of type line.

指定 dim 参量沿 X 的行(即对每个信号)使用 fft

dim = 2;

计算信号的傅里叶变换。

Y = fft(X,L,dim);

计算每个信号的双边频谱和单边频谱。

P2 = abs(Y/L);
P1 = P2(:,1:L/2+1);
P1(:,2:end-1) = 2*P1(:,2:end-1);

在频域内,为单个图窗中的每一行绘制单边振幅频谱。

for i=1:3
    subplot(3,1,i)
    plot(0:(Fs/L):(Fs/2-Fs/L),P1(i,1:L/2))
    title("Row " + num2str(i) + " in the Frequency Domain")
end

Figure contains 3 axes objects. Axes object 1 with title Row 1 in the Frequency Domain contains an object of type line. Axes object 2 with title Row 2 in the Frequency Domain contains an object of type line. Axes object 3 with title Row 3 in the Frequency Domain contains an object of type line.

创建一个由频率为 15 Hz 和 40 Hz 的两个正弦波组成的信号。第一个正弦波是相位为 -π/4 的余弦波,第二个正弦波是相位为 π/2 的余弦波。以 100 Hz 的频率对信号进行 1 秒钟的采样。

Fs = 100;
t = 0:1/Fs:1-1/Fs;
x = cos(2*pi*15*t - pi/4) + cos(2*pi*40*t + pi/2);

计算信号的傅里叶变换。将变换幅值绘制为频率函数。

y = fft(x);
z = fftshift(y);

ly = length(y);
f = (-ly/2:ly/2-1)/ly*Fs;
stem(f,abs(z))
title("Double-Sided Amplitude Spectrum of x(t)")
xlabel("Frequency (Hz)")
ylabel("|y|")
grid

Figure contains an axes object. The axes object with title Double-Sided Amplitude Spectrum of x(t), xlabel Frequency (Hz), ylabel |y| contains an object of type stem.

计算变换的相位,删除小幅值变换值。将相位绘制为频率函数。

tol = 1e-6;
z(abs(z) < tol) = 0;

theta = angle(z);

stem(f,theta/pi)
title("Phase Spectrum of x(t)")
xlabel("Frequency (Hz)")
ylabel("Phase/\pi")
grid

Figure contains an axes object. The axes object with title Phase Spectrum of x(t), xlabel Frequency (Hz), ylabel Phase/ pi contains an object of type stem.

通过填充零来对信号的傅里叶变换进行插值。

指定信号的参数,采样频率为 80 Hz,信号持续时间为 0.8 秒。

Fs = 80;
T = 1/Fs;
L = 65;
t = (0:L-1)*T;

创建一个 2 Hz 正弦信号及其高次谐波的叠加。该信号包含一个 2 Hz 余弦波、一个 4 Hz 余弦波和一个 6 Hz 正弦波。

X = 3*cos(2*pi*2*t) + 2*cos(2*pi*4*t) + sin(2*pi*6*t);

在时域中绘制该信号。

plot(t,X)
title("Signal superposition in time domain")
xlabel("t (ms)")
ylabel("X(t)")

Figure contains an axes object. The axes object with title Signal superposition in time domain, xlabel t (ms), ylabel X(t) contains an object of type line.

计算信号的傅里叶变换。

Y = fft(X);

计算信号的单边振幅频谱。

f = Fs*(0:(L-1)/2)/L;
P2 = abs(Y/L);
P1 = P2(1:(L+1)/2);
P1(2:end) = 2*P1(2:end);

在频域中绘制单边频谱。由于信号的时间采样相当短,傅里叶变换的频率分辨率不够精确,不足以显示 4 Hz 附近的峰值频率。

plot(f,P1,"-o") 
title("Single-Sided Spectrum of Original Signal")
xlabel("f (Hz)")
ylabel("|P1(f)|")

Figure contains an axes object. The axes object with title Single-Sided Spectrum of Original Signal, xlabel f (Hz), ylabel |P1(f)| contains an object of type line.

为了更好地评估峰值频率,您可以通过用零填充原始信号来增加分析窗的长度。这种方法以更精确的频率分辨率自动对信号的傅里叶变换进行插值。

从原始信号长度确定是下一个 2 次幂的新输入长度。用尾随零填充信号 X 以扩展其长度。计算填零后的信号的傅里叶变换。

n = 2^nextpow2(L);
Y = fft(X,n);

计算填零后的信号的单边振幅频谱。由于信号长度 n 从 65 增加到 128,频率分辨率变为 Fs/n,即 0.625 Hz。

f = Fs*(0:(n/2))/n;
P2 = abs(Y/L);
P1 = P2(1:n/2+1);
P1(2:end-1) = 2*P1(2:end-1);

绘制填零后的信号的单边频谱。此新频谱在 0.625 Hz 的频率分辨率内显示 2 Hz、4 Hz 和 6 Hz 附近的峰值频率。

plot(f,P1,"-o") 
title("Single-Sided Spectrum of Padded Signal")
xlabel("f (Hz)")
ylabel("|P1(f)|")

Figure contains an axes object. The axes object with title Single-Sided Spectrum of Padded Signal, xlabel f (Hz), ylabel |P1(f)| contains an object of type line.

输入参数

全部折叠

输入数组,指定为向量、矩阵或多维数组。

如果 X 为 0×0 空矩阵,则 fft(X) 返回一个 0×0 空矩阵。

数据类型: double | single | int8 | int16 | int32 | uint8 | uint16 | uint32 | logical
复数支持:

变换长度,指定为 [] 或非负整数标量。为变换长度指定正整数标量可以改进 fft 的性能。通常,长度指定为 2 的幂或可分解为小质数的乘积的值。(质因数不大于 7)。如果 n 小于信号的长度,则 fft 忽略第 n 个条目之后的其余信号值,并返回截断后的结果。如果 n0,则 fft 返回空矩阵。

示例: n = 2^nextpow2(size(X,1))

数据类型: double | single | int8 | int16 | int32 | uint8 | uint16 | uint32 | logical

沿其运算的维度,指定为正整数标量。如果不指定维度,则默认为第一个大于 1 的数组维度。

  • fft(X,[],1) 沿 X 的各列进行运算,并返回每列的傅里叶变换。

    fft(X,[],1) column-wise operation

  • fft(X,[],2) 沿 X 的各行进行运算,并返回每行的傅里叶变换。

    fft(X,[],2) row-wise operation

如果 dim 大于 ndims(X),则 fft(X,[],dim) 返回 X。当指定 n 时,fft(X,n,dim) 将对 X 进行填充或截断,以使维度 dim 的长度为 n

数据类型: double | single | int8 | int16 | int32 | uint8 | uint16 | uint32 | logical

输出参量

全部折叠

频域表示,以向量、矩阵或多维数组形式返回。

如果 X 的类型为 single,则 fft 本身以单精度进行计算,Y 的类型也是 single。否则,Ydouble 类型返回。

Y 的大小如下:

  • 对于 Y = fft(X)Y = fft(X,[],dim)Y 的大小等于 X 的大小。

  • 对于 Y = fft(X,n,dim)size(Y,dim) 的值等于 n,而所有其他维度的大小保持与在 X 中相同。

如果 X 为实数,则 Y 是共轭对称的,且 Y 中特征点的数量为 ceil((n+1)/2)

数据类型: double | single

详细信息

全部折叠

向量的离散傅里叶变换

Y = fft(X)X = ifft(Y) 分别实现傅里叶变换和傅里叶逆变换。对于长度为 nXY,这些变换定义如下:

Y(k)=j=1nX(j)Wn(j1)(k1)X(j)=1nk=1nY(k)Wn(j1)(k1),

其中

Wn=e(2πi)/n

为 n 次单位根之一。

提示

  • fft 的执行时间取决于变换的长度。仅具有小质因数(不大于 7)的变换长度的执行时间明显快于本身是质数或具有较大质因数的变换长度的执行时间。

  • 对于大多数 n 值,实数输入的 DFT 需要的计算时间大致是复数输入的 DFT 计算时间的一半。但是,当 n 有较大的质因数时,速度很少有差别或没有差别。

  • 使用工具函数 fftw 可能会提高 fft 的速度。此函数控制用于计算特殊大小和维度的 FFT 算法优化。

算法

FFT 函数(fftfft2fftnifftifft2ifftn)基于一个称为 FFTW [1] [2] 的库。

参考

[2] Frigo, M., and S. G. Johnson. “FFTW: An Adaptive Software Architecture for the FFT.” Proceedings of the International Conference on Acoustics, Speech, and Signal Processing. Vol. 3, 1998, pp. 1381-1384.

扩展功能

GPU 代码生成
使用 GPU Coder™ 为 NVIDIA® GPU 生成 CUDA® 代码。

版本历史记录

在 R2006a 之前推出