如何正确使用fftshift?MATLAB中FFT频谱分析的实用技巧

1. 从一次“诡异”的频谱图说起:fftshift到底在解决什么问题?

我记得刚接触MATLAB做信号处理那会儿,被一张频谱图搞懵了。我用一个100Hz的正弦波做FFT,采样率是1000Hz,理论上看,频谱图上100Hz的位置应该有个尖峰。但当我兴冲冲地画出图时,却发现尖峰不在100Hz,而是对称地出现在了900Hz的位置。我当时的第一反应是:“代码写错了?还是MATLAB的FFT有bug?”

折腾了半天,我才意识到问题出在对FFT输出结果的理解上。MATLAB内置的fft函数,它输出的频谱数据顺序,和我们人类习惯看的“从负频率到正频率”或者“从零频到正频率再到负频率”的顺序是不一样的。它默认的输出是从零频(DC分量)开始,到最高正频率,然后紧接着是最负频率,再到接近零的负频率。如果你直接把这个结果对应到0到采样频率(fs)的横坐标去画图,对于实信号,你就会看到频谱在中间“折叠”了一下,高频部分看起来像是“镜像”到了后半段。

这就是fftshift出场的时候了。它的核心工作就一句话:把FFT输出数组的左右两半交换一下。更具体地说,它把零频分量从数组的第一个位置(索引1),搬到了数组的物理中心位置。经过这么一“挪”,整个频谱数据在顺序上就变成了:从最负的频率,到零频,再到最正的频率。这时候你再配上从-fs/2fs/2的频率横轴,频谱图看起来就无比直观和“正确”了——100Hz的峰就老老实实地待在100Hz的位置。

所以,fftshift本身并不改变频谱的任何数值,它只是重新排列了数据的顺序,目的是为了方便我们以更符合认知习惯的方式将频谱可视化。理解这一点,是决定你何时需要用它、何时可以省掉它的关键。

2. 庖丁解牛:fftshift在实信号与复信号中的不同境遇

为什么有时候需要fftshift,有时候又不需要?这完全取决于你处理的信号类型和你想要观察的频谱视角。这里面的门道,我们可以从实信号和复信号的根本区别讲起。

2.1 实信号的频谱:天生自带“镜像”的对称美

我们生活中采集到的绝大多数信号,比如声音、振动、温度,都是实信号。实信号在频域有一个非常重要的特性:其频谱是共轭对称的。也就是说,幅度谱关于零频(直流分量)对称,相位谱关于零频奇对称。

这背后是数学的必然。因为时域信号的值全是实数,经过傅里叶变换后,必须满足这个对称性条件。这个对称性导致了一个直接后果:实信号的频谱,其负频率部分并不携带新的信息,它只是正频率部分的“镜像”

现在,我们结合采样定理来想。假设我们有一个最高频率为B的实信号,为了避免混叠,采样频率fs必须至少是2B(即fs >= 2B)。当我们对这个采样后的序列做N点FFT时,MATLAB的fft函数默认输出的是从0到fs(更精确地说是从0到(N-1)/N * fs)频率区间的N个频谱点。

关键来了!由于频谱的周期性(以fs为周期)和实信号的共轭对称性,频率区间[fs/2, fs]上的频谱,实际上就是负频率区间[-fs/2, 0]的频谱,经过周期延拓后呈现出来的。所以,直接画出的[0, fs]频谱,在fs/2处会发生一个“折叠”。

如果你想看到以零频为中心的、符合我们数学课本上描述的对称频谱(即[-fs/2, fs/2]),你就必须使用fftshift,把数据顺序调整过来。 这是实信号分析中最常使用fftshift的场景。

让我们看一个具体的代码例子,感受一下区别:

%% 实信号频谱对比:使用与不使用fftshift
clear; clc; close all;

% 参数设置
fs = 500;               % 采样频率 500 Hz
t = 0:1/fs:1-1/fs;     % 1秒时间向量,共500个点
f1 = 50;                % 信号1频率 50 Hz
f2 = 120;               % 信号2频率 120 Hz

% 生成一个包含两个频率分量的实信号
x = 0.7*sin(2*pi*f1*t) + cos(2*pi*f2*t);

% 计算FFT
N = length(x);          % 序列长度
X = fft(x);             % 直接FFT

% 构建两种频率轴
f_axis_0_fs = (0:N-1)*(fs/N);          % 对应[0, fs)的频率轴
f_axis_neg_pos = (-N/2:N/2-1)*(fs/N); % 对应[-fs/2, fs/2)的频率轴

% 绘图:直接FFT的结果
figure(‘Position‘, [100 100 1200 500])
subplot(1,2,1)
plot(f_axis_0_fs, abs(X), ‘b-‘, ‘LineWidth‘, 1.2)
xlabel(‘频率 (Hz)‘)
ylabel(‘幅度‘)
title(‘直接FFT幅度谱 ([0, fs])‘)
grid on
xlim([0, fs])
% 标记两个频率点
hold on
plot([f1, f1], [0, max(abs(X))], ‘r--‘)
plot([fs-f1, fs-f1], [0, max(abs(X))], ‘r--‘) % 注意镜像峰
plot([f2, f2], [0, max(abs(X))], ‘g--‘)
pl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值