2026/4/5 22:38:33
网站建设
项目流程
1. 为什么我们需要频谱分析想象一下你正在调试一段音频听到里面有奇怪的嗡嗡声。作为工程师你不仅想知道有杂音更想知道这个杂音具体是哪个频率成分。这就是频谱分析的用武之地——它像是一把声音的显微镜能把混合在一起的频率成分拆解开来让我们看清每个频率的强度。在MATLAB中做频谱分析最基础的工具就是fft快速傅里叶变换。但很多初学者直接看fft结果时会困惑为什么频谱图看起来不对称那些出现在后半部分的频率点代表什么这时候就需要fftshift出场了。我第一次用fft分析振动传感器数据时盯着那个奇怪的频谱图看了半天直到用了fftshift才恍然大悟。2. 理解fft的本质2.1 fft到底输出了什么当我们对一个时域信号做fft时MATLAB会返回一个复数数组。这个数组的长度和输入信号长度相同除非你指定了fft点数每个元素对应一个频率点的复数表示。关键点在于这个数组的前半部分代表的是正频率而后半部分实际上是负频率举个例子假设我们采样率是1000Hz信号长度是1000点。那么fft结果的前500点对应0-500Hz后500点对应-500Hz到-1Hz。这个设计源于傅里叶变换的数学定义但在实际观察频谱时这种排列方式很不直观。% 生成一个简单信号示例 fs 1000; % 采样率1kHz t 0:1/fs:1-1/fs; % 1秒时间向量 f1 50; % 50Hz正弦波 f2 120; % 120Hz正弦波 signal 0.7*sin(2*pi*f1*t) sin(2*pi*f2*t); % 计算fft N length(signal); fft_result fft(signal); f_axis (0:N-1)*(fs/N); % 对应的频率轴 figure; plot(f_axis, abs(fft_result)/N); title(直接FFT结果); xlabel(频率(Hz)); ylabel(幅度);运行这段代码你会看到在50Hz和120Hz处有峰值但在880Hz和950Hz处也有对称的峰值——这就是负频率成分的表现。2.2 频率分辨率与补零技巧频率分辨率Δffs/N其中fs是采样率N是fft点数。提高分辨率有两种方法增加采样时间增大N或者降低采样率。实际中我们常用补零(zero-padding)来增加N% 原始信号长度1000点 N_original 1000; signal 0.7*sin(2*pi*50*(0:N_original-1)/fs); % 补零到2000点 N_padded 2000; fft_padded fft(signal, N_padded); f_padded (0:N_padded-1)*(fs/N_padded); figure; subplot(2,1,1); plot(f_axis(1:N_original/2), abs(fft_result(1:N_original/2))/N_original); title(原始FFT); subplot(2,1,2); plot(f_padded(1:N_padded/2), abs(fft_padded(1:N_padded/2))/N_original); title(补零后的FFT);补零不会增加真实的信息量但可以让频谱曲线看起来更平滑也便于观察频率细节。3. fftshift的魔法3.1 为什么要中心化直接fft的结果把负频率放在了频谱的后半部分这在数学上完全正确但不符合人类的观察习惯。fftshift的作用就是把零频率分量移到频谱中心负频率在左正频率在右就像我们常见的对称频谱图那样。我第一次分析电机振动数据时没使用fftshift差点误判了故障特征频率。后来导师指出应该把频谱中心化才发现了隐藏在负频率区域的异常峰值。3.2 实际操作演示让我们用实际代码看看fftshift的效果% 使用之前的信号 fft_magnitude abs(fft_result)/N; f_shifted (-N/2:N/2-1)*(fs/N); % 中心化的频率轴 fft_shifted fftshift(fft_magnitude); figure; subplot(1,2,1); plot(f_axis, fft_magnitude); title(原始FFT); xlabel(频率(Hz)); ylabel(幅度); subplot(1,2,2); plot(f_shifted, fft_shifted); title(fftshift后的FFT); xlabel(频率(Hz)); ylabel(幅度);运行后你会看到右边的图对称地展示了正负频率50Hz和-50Hz的峰值清晰可见。这对于识别信号中的对称频率成分特别有用。3.3 实际工程中的注意事项在工业振动分析中我们经常需要观察非常接近的频峰。这时候fftshift能帮我们更直观地比较正负频率成分。但要注意对于实数信号频谱总是对称的正负频率幅度相同对于复数信号如通信中的IQ信号正负频率可能不同使用fftshift后频率轴也需要相应调整一个常见错误是只对幅度做fftshift却忘了调整频率轴导致频率标签错误。我在第一次做雷达信号处理时就犯过这个错误结果误判了目标速度。4. 完整实战案例音频信号分析4.1 案例背景设定假设我们有一段录音里面混合了440Hz的A4标准音和880Hz的A5音现在需要分析它们的频谱特性。采样率为8kHz录音时长0.5秒。fs 8000; % 8kHz采样率 t 0:1/fs:0.5-1/fs; % 0.5秒 f1 440; f2 880; audio 0.5*sin(2*pi*f1*t) 0.3*sin(2*pi*f2*t); % 添加一些随机噪声模拟真实环境 noise 0.1*randn(size(t)); audio_noisy audio noise;4.2 频谱分析全流程现在我们来完整走一遍分析流程首先观察时域信号计算原始fft应用fftshift对比分析结果N length(audio_noisy); f_axis (0:N-1)*(fs/N); f_shifted (-N/2:N/2-1)*(fs/N); % 计算频谱 fft_raw fft(audio_noisy); fft_mag abs(fft_raw)/N; fft_shifted fftshift(fft_mag); % 绘图 figure; subplot(3,1,1); plot(t, audio_noisy); title(含噪声的音频信号); xlabel(时间(s)); ylabel(幅度); subplot(3,1,2); plot(f_axis(1:N/2), fft_mag(1:N/2)); title(原始FFT (仅显示正频率)); xlabel(频率(Hz)); ylabel(幅度); subplot(3,1,3); plot(f_shifted, fft_shifted); title(fftshift后的完整频谱); xlabel(频率(Hz)); ylabel(幅度);4.3 结果解读技巧在最后的图中我们可以看到原始FFT显示了440Hz和880Hz处的峰值fftshift后的图则对称地展示了正负频率成分噪声表现为整个频带内的小幅度波动实际工程中我们通常会结合两种视图用原始FFT查看主要频率成分用fftshift后的视图检查对称性和潜在的干扰信号。5. 常见问题与调试技巧5.1 频谱泄露与加窗当信号频率不是频率分辨率的整数倍时会发生频谱泄露。我第一次分析电力系统谐波时就遇到过这个问题——50Hz的基波能量泄露到了相邻频点。解决方法是对信号加窗如汉宁窗window hann(N); % 生成汉宁窗 signal_windowed audio_noisy .* window; % 计算加窗后的fft fft_windowed fft(signal_windowed); fft_windowed_shifted fftshift(abs(fft_windowed)/N); figure; plot(f_shifted, fft_windowed_shifted); title(加窗后的fftshift频谱);加窗会降低频谱泄露但会加宽主瓣需要在分辨率和泄露之间权衡。5.2 幅度校正问题使用fftshift后很多人会困惑幅度值是否正确。其实fftshift只是重新排列数据不影响幅度值。但要注意对于双边频谱每个频率成分的幅度是单边频谱的一半直流分量0Hz不需要除以2如果只关心正频率可以只看前半部分并乘以2除直流外5.3 复数信号的特殊处理对于通信系统中的复数信号如IQ数据fftshift的处理稍有不同% 生成复数信号 t 0:1/fs:1-1/fs; fc 1000; % 载波1kHz complex_signal exp(1j*2*pi*fc*t); % fft处理 N length(complex_signal); fft_complex fft(complex_signal); fft_complex_shifted fftshift(fft_complex); % 频率轴 f_axis (-N/2:N/2-1)*(fs/N); figure; plot(f_axis, abs(fft_complex_shifted)/N); title(复数信号的fftshift频谱);复数信号的频谱不再对称正负频率可能包含不同信息。在软件定义无线电(SDR)等应用中这种不对称性携带了重要信息。