做信号处理这些年,傅里叶变换几乎是每天打照面的老朋友。但说句实话,公式背得再熟,真要问一句“为什么积分核是e的负jωt次方”“那个1/2π到底从哪冒出来的”“三角脉冲的频谱怎么记最不容易忘”,很多做了两三年的工程师也得愣一下。这篇博文我想把傅里叶变换从头到尾捋一遍:先建立直观图景,再把定义和公式整理成一套能直接查的表格,接着用欧拉公式把推导走通,最后把三角脉冲的傅里叶变换这个经典记忆难点掰开揉碎。适合刚学信号与系统的大学生、需要用FFT做分析的工程师,以及所有想把傅里叶变换从“会背”升级成“会用”的人。
1. 先把话说清楚:傅里叶变换到底在做什么
1.1 时域与频域:同一信号的两张面孔
我从最简单的现象说起。你在示波器上看到一条随时间起伏的电压波形,这是信号的“时域”面孔,横轴是时间,纵轴是幅度。但你换个角度想,任何一条复杂的波形,是不是都可以看成很多个不同频率、不同幅度、不同相位的正弦波叠加在一起的结果?当你用频谱仪看它时,横轴变成了频率,纵轴变成了该频率成分的强度,这就是信号的“频域”面孔。
傅里叶变换就是在这两张面孔之间来回切换的数学工具。正变换把时域信号变成频域函数,逆变换把频域函数还原成时域信号。两个方向都不丢信息,这一点很重要。
我经常用一个调音师听和弦的比喻来理解这件事。一段钢琴和弦,在时域上是十几个键同时按下产生的复杂振动波形;但调音师耳朵能分辨出其中哪几个音高了、哪几个音低了,还能告诉你每个音的响度比例。调音师做的事,本质上就是一次人肉傅里叶变换。他听到的不是“波形长什么样”,而是“由哪些频率成分构成、各占多少”。
所以傅里叶变换回答的问题很朴素:这一段信号里,包含了哪些频率的振动?每个频率的振动有多强?初相位是什么?仅此而已。但这个“仅此而已”的视角,几乎重构了现代工程学。无论是音频均衡器、图像JPEG压缩、通信里的OFDM,还是机械故障诊断里的频谱分析,底层都是同一套傅里叶思想。
1.2 从傅里叶级数到傅里叶变换:周期和非周期如何统一
大学教材通常先讲傅里叶级数,再讲傅里叶变换,这个顺序有它的道理。任何满足狄利克雷条件的周期信号,都可以分解成基频及其整数倍频率的正弦波之和,这就是傅里叶级数。换句话说,周期信号有离散的频谱,一根根谱线,间隔就是基频。
问题来了:现实世界里我们处理的信号往往不是周期的,比如一段语音、一次冲击、一段随机振动。它没有重复的周期,怎么办?傅里叶本人的处理思路非常聪明:把非周期信号看成周期趋于无穷大的周期信号。周期趋于无穷大,基频就趋于无穷小,离散的谱线间距就趋于无穷小,原本一根根离散的线,最后连成了一片连续的频谱面。求和也就变成了积分——傅里叶级数就这样升级成了傅里叶变换。
顺着这个思路走一遍,你会对“频谱密度”这个词有更本质的理解。连续信号的频谱不是一个点一个点给出幅度,而是给出“单位频率上的密度”,所以连续频谱函数叫频谱密度函数(spectral density)。离散谱线和连续谱密度之间差着一个因子,这个因子最后就体现在1/2π的系数上。这些细节很多教材直接带过,导致很多人公式背得很熟,却不明白系数从何而来,后面我会用完整推导把它补上。
2. 公式整理:连续、离散与常用性质一网打尽
2.1 连续傅里叶变换的定义公式体系
先摆出最标准的定义。若x(t)是时域连续信号,其傅里叶变换(频谱密度函数)定义为:
$$X(f)=\int_{-\infty}^{\infty}x(t)e^{-j2\pi f t}dt$$
对应的傅里叶逆变换为:
$$x(t)=\int_{-\infty}^{\infty}X(f)e^{j2\pi f t}df$$
注意,这里我用的频率变量是f(Hz),而不是角频率ω。如果用角频率,公式会变成:
$$X(\omega)=\int_{-\infty}^{\infty}x(t)e^{-j\omega t}dt$$
$$x(t)=\frac{1}{2\pi}\int_{-\infty}^{\infty}X(\omega)e^{j\omega t}d\omega$$
很多初学者在这里被坑过:为什么用f的形式,正反变换对称,都没有1/2π;换成ω,逆变换前面就多出了1/2π。这不是因为定义不统一,而是因为dω=2πdf,积分变量换掉以后,系数自然跟着变。两种写法本质完全一样,你习惯用哪种都行,但看文献时一定要先看清对方用的是f还是ω,否则很容易差出一个2π来。
进一步说,工程中还有一组常用的频域约定:单边谱与双边谱。上述公式得到的是双边谱,频率从负无穷取到正无穷,负频率纯粹是数学工具带来的,没有物理意义。实际做频谱分析时,我们通常只看正频率部分,并把负频率部分的能量折算到正频率上,所以幅度会乘以2(直流分量除外)。这个细节后面讲FFT工程实践时还会再提到。
2.2 离散傅里叶变换与工程版公式
计算机没法处理无穷积分,只能处理有限长的离散采样点。于是有了离散傅里叶变换(DFT)。对长度为N的序列x[n],它的DFT定义为:
$$X[k]=\sum_{n=0}^{N-1}x[n]e^{-j\frac{2\pi}{N}kn},\quad k=0,1,\dots,N-1$$
逆变换为:
$$x[n]=\frac{1}{N}\sum_{k=0}^{N-1}X[k]e^{j\frac{2\pi}{N}kn},\quad n=0,1,\dots,N-1$$
这里的k不是频率本身,而是频率索引,对应实际频率f_k = k·fs/N,其中fs是采样率。也就是说,第k根谱线代表的真实频率等于k乘以频率分辨率fs/N。FFT只是DFT的一种快速算法,不改变DFT的数学本质,但因为太常用,很多人直接把FFT当成了DFT本身,其实是不严谨的。
2.3 常用性质速查表,边用边查
傅里叶变换的性质非常丰富,实际工程中有一半的工作是在“利用性质偷懒”。我把最常用的几条整理成表格:
| 性质 | 时域表达式 | 频域表达式 | 用途 |
|---|---|---|---|
| 线性 | a·x(t)+b·y(t) | a·X(f)+b·Y(f) | 多分量信号分解 |
| 时移 | x(t-t0) | X(f)·e^{-j2πft0} | 延时系统分析 |
| 频移 | x(t)·e^{j2πf0t} | X(f-f0) | 调制解调 |
| 尺度变换 | x(at) | (1/ | a |
| 卷积定理 | x(t)∗y(t) | X(f)·Y(f) | 线性系统输出频谱 |
| 相乘 | x(t)·y(t) | X(f)∗Y(f) | 加窗、混频 |
| 帕萨瓦尔 | ∫ | x(t) | ²dt |
| 对偶性 | X(t) | x(-f) | 快速推导新变换对 |
这几条性质里,卷积定理在工程中地位极高。一个线性时不变系统的输出,等于输入与冲激响应的卷积。直接算卷积很费劲,但变换到频域后,卷积变成了乘法,算完再逆变换回来,计算量大减。FIR滤波器、通信里的匹配滤波,全是建立在这个性质上的。
帕萨瓦尔定理也值得单独说一句,它相当于说信号在时域的总能量,等于频域各个频率成分的能量之和。这条性质常用来验证数值计算有没有出错:在MATLAB或Python里做完FFT之后,把频域幅值的平方累加一下,再和时域信号平方累加对比,如果数量级不一致,说明某个环节有问题。
3. 推导一遍:欧拉公式、正交基与那个1/2π
3.1 为什么积分核是e的负jωt次方
很多人背公式时疑惑:为什么傅里叶变换的积分核偏偏是e^{-jωt},而不是别的什么函数?这个问题的答案藏在“正交分解”里。
线性代数里,把一个向量投影到正交基上,就得到该基方向上的坐标。求坐标的公式是内积。信号也可以看成无穷维空间里的一个“向量”,傅里叶变换做的就是把它投影到一组完备正交基{e^{jωt}}上。投影公式就是内积:
$$X(\omega)=\langle x(t), e^{j\omega t}\rangle=\int_{-\infty}^{\infty}x(t)e^{-j\omega t}dt$$
注意内积中第二个向量要取共轭,所以e^{jωt}变成e^{-jωt},这就是负号的来源。为什么选e^{jωt}做基?因为不同频率的复指数函数是相互正交的,它们之间没有重叠,任何一个信号都能唯一地分解成它们的线性组合。这组基确实是信号分解的最优选择。
这里还要补充一点:e^{jωt}=cos(ωt)+j·sin(ωt),所以复指数基里天然包含了正弦和余弦两种成分。用复指数而不是单独用正弦或余弦,好处是把相位信息统一放在复数里,推导和计算都简便得多。频谱X(ω)是复数,它的模表示该频率分量的幅度,辐角表示相位,一次变换把幅度谱和相位谱全部拿到了。
3.2 逆变换前的1/2π到底从何而来
我见过不少人把1/2π当成“规定”草草背过,但其实它完全可以推出来。核心思路从傅里叶级数出发看连续化的过程。
一个周期为T的信号x(t),傅里叶级数系数为:
$$c_n=\frac{1}{T}\int_{-T/2}^{T/2}x(t)e^{-j\frac{2\pi n}{T}t}dt$$
当T→∞时,令ω0=2π/T为基频,随着T增大,ω0变得越来越小。此时相邻谱线的间隔Δω=2π/T→0,离散的c_n就趋向于连续的X(ω)。但要注意,c_n本身趋于0,因为能量被无限多根谱线平分了,所以不能直接用c_n定义X(ω),而是用密度T·c_n来定义:
$$X(\omega)=\lim_{T\to\infty}T\cdot c_n$$
代入c_n的表达式,得到X(ω)=∫x(t)e^{-jωt}dt,这正是不带系数的正变换。反过来,由c_n重构x(t)的傅里叶级数求和:
$$x(t)=\sum_{n=-\infty}^{\infty}c_n e^{j\frac{2\pi}{T}nt}$$
把c_n=T^{-1}X(ω)代进去,并用Δω=2π/T替换,原和式变为:
$$x(t)=\frac{1}{2\pi}\sum_{n=-\infty}^{\infty}X(\omega)e^{j\omega t}\Delta\omega$$
当T→∞、Δω→0时,上式变成积分:
$$x(t)=\frac{1}{2\pi}\int_{-\infty}^{\infty}X(\omega)e^{j\omega t}d\omega$$
1/2π就这样自然出现了。它本质是离散谱线间隔Δω在连续化过程中留下的“历史痕迹”,相当于把单位弧度频率内的谱线密度做一个换算。这个过程也让我彻底理解了为什么逆变换要带系数而正变换不带:因为是“谱密度”重构原函数,密度就必须乘以一个无穷小的区间再求和,系数用来保证量纲和幅度的正确。
3.3 用矩形脉冲走一遍完整计算
定义很抽象,必须演算一题才能落地。我选矩形脉冲,因为它是后续所有脉冲波形频谱推导的基础。设宽度为τ、幅度为1的矩形脉冲:
$$x(t)=\begin{cases}1,& |t|\le \tau/2\0,& |t|>\tau/2\end{cases}$$
代入X(f)的定义:
$$X(f)=\int_{-\tau/2}^{\tau/2}1\cdot e^{-j2\pi f t}dt$$
这是一个标准复指数积分,直接算:
$$X(f)=\frac{e^{-j2\pi f\tau/2}-e^{j2\pi f\tau/2}}{-j2\pi f}$$
分子是两个共轭复指数之差,等于-2j·sin(πfτ),于是:
$$X(f)=\frac{-2j\sin(\pi f\tau)}{-j2\pi f}=\tau\cdot\frac{\sin(\pi f\tau)}{\pi f\tau}=\tau\cdot\operatorname{sinc}(\pi f\tau)$$
这里用到了归一化sinc函数的定义:sinc(x)=sin(πx)/(πx)。结论就一句话:矩形脉冲的频谱是sinc函数,第一零点出现在f=1/τ处。脉宽τ越宽,频谱主瓣越窄;脉宽τ越窄,频谱铺得越开。这个“时间越短频带越宽”的结论,就是通信系统带宽设计的根本矛盾。这个例题做完后,整个推导体系和计算套路基本就掌握了。
4. 三角脉冲的傅里叶变换:一种忘不掉的记忆方法
4.1 图形法:先看卷积再看频谱,记住“卷积变相乘”
三角脉冲是信号处理、光学和数值分析里经常遇到的波形。表面积分去算当然可以,但更容易记、也不容易出错的方法,是利用卷积定理从图形出发。
关键观察:把一个宽度为τ的矩形脉冲和自己做卷积,得到的就是一个底宽2τ、峰值为τ的三角形。为什么?矩形脉冲卷积的几何意义是“平移、翻转、相乘、积分”,两个宽度相同的矩形卷积,重叠面积从0线性增加到τ,再线性下降到0,形成的正是三角形。这是卷积里最经典的入门图形。
时域卷积对应频域相乘。矩形脉冲的傅里叶变换刚才算过,是τ·sinc(fτ),那么三角脉冲的频谱就是它的平方:
$$X_{\Delta}(f)=\left[\tau\operatorname{sinc}(f\tau)\right]^2=\tau^2\operatorname{sinc}^2(f\tau)$$
这个结论本身简洁得惊人:矩形脉冲的频谱是sinc,三角形脉冲的频谱就是sinc的平方。零点还在同样的位置f=k/τ处,但旁瓣的衰减速度从1/f变成1/f²,明显快得多。这种“时域一次卷积,频域一次平方”的规律,整个信号处理中用得极多,从采样保持器的孔径效应分析,到图像处理里的双线性插值,都能看到它的影子。
4.2 从积分定义硬推一遍,加深理解
图形法快,但心里总归要有一遍严格推导才踏实。设三角脉冲:
$$x(t)=\begin{cases}1-\frac{2|t|}{\tau},& |t|\le \tau/2\0,& |t|>\tau/2\end{cases}$$
以τ/2为界,把积分拆成t<0和t>0两段,考虑到函数是偶函数,频谱可以直接化简为:
$$X(f)=2\int_{0}^{\tau/2}\left(1-\frac{2t}{\tau}\right)\cos(2\pi f t),dt$$
这个积分是“多项式乘三角”的标准形式,用分部积分法处理。第一步令u=1-2t/τ,dv=cos(2πft)dt,计算后整理,最终会得到:
$$X(f)=\frac{4(1-\cos 2\pi f\tau)}{(2\pi f)^2\tau}$$
再用三角恒等式1-cosθ=2sin²(θ/2),就得到:
$$X(f)=\frac{4\cdot2\sin^2(\pi f\tau)}{4\pi^2 f^2\tau}=\tau^2\left(\frac{\sin(\pi f\tau)}{\pi f\tau}\right)^2=\tau^2\operatorname{sinc}^2(f\tau)$$
和卷积定理的结果完全一致。两条路殊途同归,但图形法更容易记住最终形式,积分推导帮你建立信任感,两个都走一遍就不会再虚了。
4.3 记忆口诀、常见误区与工程直觉
我自己记三角脉冲频谱时,用的口诀只有一句话:“矩形出sinc,卷积变三角,频谱是平方。”每次都从矩形脉冲出发推,哪怕一时间忘了公式,也能在三秒钟之内重新得到结果。
但有几个误区需要特别提醒。第一,三角脉冲的频谱是sinc²,不是sinc(2fτ)之类的别的东西。sinc²比sinc看起来相似,旁瓣衰减完全不同。第二,主瓣带宽:矩形脉冲第一零点在f=1/τ,三角脉冲第一零点也在1/τ,但三角脉冲如果用底宽2τ来定义,第一零点就会变成2/T往上的位置,计算前一定要先确认时域表达式的定义,否则零点位置差着倍数。第三,三角脉冲不等于升余弦脉冲,升余弦频谱是连续解析表达式,比sinc²衰减更快,工程上常用来做脉冲整形,不能混为一谈。
从工程角度看,三角脉冲频谱旁瓣低、收敛快,做窗函数时能有效抑制频谱泄漏,但主瓣比矩形窗宽,频率分辨能力稍差。这个“主瓣宽度”和“旁瓣电平”的权衡,几乎贯穿所有窗函数设计,三角窗只是最简单的一档。
5. 工程实战:那些公式书上不写,但一定会踩的坑
5.1 选公式之前,先分清你的信号是什么类型
拿到一个信号,先用三秒钟判断它是周期信号、非周期连续信号,还是有限长离散采样序列。判断错了,公式用得再熟也是白搭。周期信号直接用傅里叶级数,得到的是离散谱线;非周期连续信号用傅里叶变换,得到的是连续谱密度;计算机里能处理的只有DFT/FFT,对应的是离散化的频谱采样值。
一个常见的困惑:周期信号也能做FFT吗?当然能,但FFT默认输入是有限长序列,相当于给周期信号先截断了。截断会带来频谱泄漏(spectral leakage),原本一根细谱线变成了一片带旁瓣的形状。缓解手段是加窗,但加窗也有副作用,主瓣变宽,两个频率很近的分量可能会糊在一起分不开。这就是为什么做频谱分析时,你要在“频率分辨率”和“旁瓣泄漏”之间做权衡。
实际测试中,我建议先做一次不加窗的FFT看全局谱形,确定关注频段后,再针对性地加汉宁窗或平顶窗进一步精细化。汉宁窗的旁瓣衰减快,适合宽频带分析;平顶窗的幅度精度高,适合校准测试;矩形窗频率分辨率最好,但泄漏最严重。
5.2 FFT分析绕不开的三个高频坑
第一坑:采样率不够导致频谱混叠。奈奎斯特定理告诉我们,采样率必须大于信号最高频率的两倍,否则高频成分会折叠到低频区,伪装成不存在的低频信号。这里的“最高频率”指模拟信号本身的带宽,不是你关心的带宽,最好在采样前加抗混叠低通滤波器。我见过有同学在数据采集卡前端没有滤波,结果FFT里出现一堆莫名其妙的谱峰,折腾好久才发现是混叠。
第二坑:补零不等于提高分辨率。FFT点数N不够,频谱看起来“很粗”,有人把序列末尾补一堆零再做更长点数的FFT,看起来谱线变密了,心里很爽。但补零只相当于对原频谱做插值,它不会改变真实的物理分辨率,真实分辨率只取决于数据持续时长T:Δf=1/T。也就是说,你想分辨两个相差只有0.1Hz的信号,至少得采10秒的数据,补再多零也救不了你。这个坑在工程应用中出现频率极高,一定要记住根本公式。
第三坑:幅度修正。做FFT后直接取模得到的幅度,跟真实幅度往往对不上。矩形窗时,单频正弦的FFT峰值幅度大约为A·N/2,其中A是真实幅度,N是采样点数,所以要把峰值乘以2/N才大致还原出幅度。换了汉宁窗,主瓣幅度还会进一步损失约一半,需要乘以相应的窗恢复系数。实际测量中,最好的做法是用已知幅度的标准信号去校准系统增益,而不是从理论上死抠系数。
下面给一段Python示例,演示一次完整的FFT频谱分析流程,用来校准幅度并画单边频谱:
import numpy as np import matplotlib.pyplot as plt fs = 1000 # 采样率 1000 Hz T = 2.0 # 采样时长 2 s N = int(fs * T) # 采样点数 t = np.arange(N) / fs # 合成信号:50Hz幅度1.0,120Hz幅度0.5,加一点噪声 x = 1.0 * np.sin(2*np.pi*50*t) + 0.5*np.sin(2*np.pi*120*t) x += 0.1 * np.random.randn(N) win = np.hanning(N) xw = x * win X = np.fft.rfft(xw, n=N) * 2 / np.sum(win) # 窗函数幅度恢复 freq = np.fft.rfftfreq(N, d=1/fs) mag = np.abs(X) plt.plot(freq, mag) plt.xlabel('Frequency (Hz)') plt.ylabel('Amplitude') plt.title('Windowed FFT Spectrum') plt.xlim(0, 200) plt.grid(True) plt.show()注意这里用了rfft,只算正频率部分,节省一半计算量。乘以2/N的修正已经考虑了窗函数的能量损失,用的是窗函数求和值np.sum(win)来代替N,这样换窗函数时修正也相对准确。
5.3 实测下来的几个心得,帮你少走弯路
最后分享几个我用频谱分析做工程排查时沉淀下来的经验。
第一,分析前先看时域波形。先确认信号是干净的还是有毛刺、有直流偏置、有趋势项,再做FFT。很多人一上来就FFT,结果频谱里一大片零频附近的高能量,其实只是直流偏置在作怪。此时先减去均值或做高通滤波,就能露出真正关心的中高频细节。
第二,频谱分辨率的需求要一次性算明白。例如做电机轴承故障诊断,需要区分转速频率的多次谐波,分辨率可能要到0.1Hz,那采集时长就必须在10秒以上。合理安排采样时长和采样率,往往比事后加窗、插值更能彻底解决问题。
第三,不要把FFT的结果直接当“真值”。频谱泄漏、栅栏效应、窗函数幅度修正误差、传感器本身的频响不平坦,每一项都会给最终幅值带来偏差。重要的测试,一定要用已知信号源做一次全链路校准,把误差修正到可接受范围内。
第四,如果频谱中出现了幅度随时间变化的情况,单纯FFT可能不够,要改用短时傅里叶变换(STFT)或小波分析。例如声音信号里的变频特征,就看得出“什么时候出现什么频率”,而不是只能看到“整个时间段里有哪些频率”。
傅里叶变换难学,难不在四则运算,难在建立“换一个角度看信号”的思维方式。我当年也是被那堆积分符号折磨得够呛,后来靠一遍遍画矩形脉冲、画三角脉冲、套卷积定理,才慢慢把那些公式从纸面变成了直觉。现在你把这几个经典例子跟着推一遍,再打开MATLAB或Python动手跑几个信号的FFT,那些原本像是天书一样的符号,就能真正变成你工具箱里顺手的东西了。