
第一次看到傅里叶级数的时候我其实挺抵触的——信号在时域里明明画得清清楚楚为什么非要拆成一大堆正弦波和余弦波直到后来做音频处理、振动监测和滤波器设计被一堆时域里根本看不明白的问题折腾到怀疑人生才意识到“傅里叶级数展开”和“傅里叶变换”这套东西才是打开频域视角的第一把钥匙。这篇先聊傅里叶级数展开顺带把傅里叶变换是怎么被引出来的讲透。内容适合刚接触信号处理、公式能背但用不利索的初学者也适合想重建频域直觉的工程师。我不打算堆一堆严谨到催眠的推导而是用工程直觉加上可以动手运行的小实验把关键概念串起来。1. 先别急着套公式傅里叶级数到底在拆什么东西1.1 时域里的信号藏着一层看不到的频谱我们平时看到的波形绝大多数都是时间轴上的“混叠体”。举个例子蜂鸣器发声听起来比纯音要“亮”要“刺耳”为什么因为蜂鸣器产生的往往不是单一正弦波而是类似方波的周期信号。把方波拆开你会看到它其实是若干个正弦波叠在一起频率1倍基频的正弦波、3倍基频的正弦波、5倍基频的正弦波……幅度按1、1/3、1/5的规律逐级衰减。方波之所以听起来低沉又带金属感就是这些奇次谐波叠加出来的结果。这在工程上特别常见。做设备故障诊断的工程师都知道某台旋转机械的振动信号不会是干净的单频正弦而是包含“转频”以及转频的2倍、3倍、甚至更高倍数谐波。把振动波形做傅里叶级数展开找到哪几个频率位置的幅度突然变大了才能反过来推断是哪根轴、哪个轴承出了问题。如果你一直只看时域波形几路谐波叠在一起会糊成一团根本分不清谁是谁一旦切到频域每个频率分量就像排队点名一样清清楚楚。所以傅里叶级数干的第一件事就是把一个周期信号从“时间上的总效果”还原成“一个个频率上的独立成分”。这种拆解不是方便看热闹而是为了让我们能在某个具体频率上做手脚比如把某个特定谐波滤掉或者单独测量某阶谐波的强度。1.2 为什么选正弦波当地基而不选方波或三角波很多人会问把信号拆成一堆分量为什么偏偏是正弦波用方波拆方波不是更省事吗这个问题我当年也问过答案其实很朴素正弦波在物理和数学上有不可替代的地位。对线性时不变系统来说输入一个正弦波输出仍然是相同频率的正弦波只是幅度和相位变了。换句话说正弦波是这类系统的“特征函数”。为什么要强调这一点因为电子电路、机械振动、声音传播等大量实际系统在正常工作范围内都可以近似看成线性时不变系统。如果选择方波作为“地基分量”信号经过一个低通滤波器之后方波会变成另一副模样连形状都不保拆解就会变得没有意义。再从数学工具的角度看正弦函数和余弦函数构成一组正交基微积分之后还是同族的正弦、余弦不引入新的函数类型。同时欧拉公式又把正弦、余弦和复指数函数联系到一起而复数形式让后续傅里叶变换的计算方便得多。你可以把正弦波想象成“红、绿、蓝”三原色其他波形都是混出来的颜色而方波、三角波这些本身就是若干种正弦波按特定比例混合出来的“混合色”。用混合色当原色肯定越拆越乱。2. 傅里叶级数的数学骨架正交基、系数公式与复指数表达2.1 正交性到底意味着什么傅里叶级数能成立最核心的底层逻辑是“三角函数系的正交性”。很多教材把这个性质直接扔出来然后就开始推公式看得人云里雾里。我换个说法解释一下。普通三维空间里我们说x轴和y轴垂直意味着沿x轴的向量在y轴上投影为零两个方向互不影响。把这种思想推广到函数空间两个函数也可以定义“内积”就是在一个周期内把它们相乘再积分。如果这个积分为零就称这两个函数正交。正交的意义是它们之间没有交叉能量彼此独立。具体来说对周期为T、基频ω02π/T的函数有以下几个常用结论∫0T cos(nω0t)·cos(mω0t)dt 0当n≠m∫0T sin(nω0t)·sin(mω0t)dt 0当n≠m∫0T cos(nω0t)·sin(mω0t)dt 0不管n、m取什么都成立当nm时∫0T cos²(nω0t)dt T/2sin²同理。这些式子看起来只是积分公式实际含义非常强不同频率的正弦波之间是“垂直”的互不污染。正因如此我们才可以把一个复杂信号投影到某一根“频率轴”上得到该频率分量的贡献而不会被其他分量的影子干扰。如果三角函数不正交那系数的计算就会变成解一个巨大的联立方程组而不是现在这样直接套积分公式。2.2 系数公式是“投影”不是天外飞仙周期信号f(t)的傅里叶级数通常写作f(t) a0/2 Σ_{n1}^{∞}[a_n·cos(nω0t) b_n·sin(nω0t)]其中系数公式a0 (1/T)·∫0T f(t)dta_n (2/T)·∫0T f(t)·cos(nω0t)dtb_n (2/T)·∫0T f(t)·sin(nω0t)dt很多人背下公式但不知道来历。其实系数公式的本质就是“投影”。回忆坐标系里的做法想求某个向量在x轴方向的分量就把这个向量和x轴单位向量做点积。同理a_n就是函数f(t)在“n次余弦基”方向上的投影分子∫0T f(t)·cos(nω0t)dt是投影计算分母T/2则是对基向量自身长度平方的归一化。为什么积分就能滤出对应频率的分量因为当f(t)里混着其他频率成分时它们与当前cos(nω0t)相乘后再积分根据正交性会变成0只有与当前基频相同的分量会留下常数积累。这个原理其实和锁相放大器的思路一模一样用参考频率与信号相乘再取直流项就能把特定频率“捞”出来。工程上很多数字锁相算法就是这么干的。实际操作中还有个小技巧如果原信号是奇函数比如标准方波、三角波的中心对称类型那所有余弦项的a_n都会为0只需要算b_n如果信号是偶函数则b_n全部为0。先判断奇偶性能省掉一半计算量。我早期手动算级数的时候就是因为没注意这个浪费了不少时间。2.3 复指数形式与“负频率”的疑问傅里叶级数还可以改写为复指数形式。用欧拉公式把正弦、余弦替换掉之后级数变成f(t) Σ_{n-∞}^{∞} c_n·e^{i·nω0t}这里的系数c_n (1/T)·∫0T f(t)·e^{-i·nω0t}dt很多初学者看到n取负整数就以为信号里存在“负频率”这种物理概念被绕晕。实际上负频率是配对用的数学概念。对实信号来说c_n和c_{-n}是共轭对称的正负频率合在一起才能还原出实数的正弦或余弦。你可以把一对e^{iωt}和e^{-iωt}理解成两个反向旋转的向量它们叠加之后虚部正好抵消留下实部的波形。单独谈“负频率的能量”没有物理意义因为实信号的双边谱必须成对看待。我以前看频谱图看到左右对称的两根谱线还纳闷“怎么会有负频率”后来才明白那只是一种表示方式。工程中如果只关心实际功率通常会看单边谱把负频率一侧的幅度合并过来。3. 从周期到非周期傅里叶变换引入的那一步3.1 周期无限拉长谱线间距不断变密傅里叶级数只适用于周期信号。但现实中大量信号根本不是周期的比如一段语音、一次震动冲击或者某个突然弹出的瞬态噪声。这些信号怎么分析频率答案就是让周期T趋向无穷大把非周期信号看成“周期无穷大的周期信号”。周期信号的频谱是离散谱相邻谱线的频率间隔Δω2π/T。T越大间隔越小。想象一个方波周期从1秒变成10秒、100秒基频从2π缓慢地靠近0各次谐波的频率点不断变密。当T真正趋向无穷大时离散的谱线之间没有间隙了变成一条连续曲线。此时再用“某个频率点的幅度有多大”来描述已经不合适因为每个点附近的能量会越来越薄直观上就是每条谱线的幅度都在变小。为了描述这种连续分布我们需要引入“频谱密度”的概念即单位频率宽度上分布的幅度这就是傅里叶变换F(ω)的物理意义。这一步理解特别关键。我一直觉得直接从“级数公式”跳到“变换公式”而不讲这个极限过程是很多初学者觉得傅里叶变换“玄学”的原因。其实它就是级数公式的一种连续化改写求和符号Σ变成积分符号∫离散频率点nω0变成连续变量ω级数系数c_n变成频谱密度函数F(ω)。3.2 傅里叶变换公式只是级数公式的极限写法连续傅里叶变换的正反变换写成常用形式F(ω) ∫_{-∞}^{∞} f(t)·e^{-iωt}dtf(t) (1/2π)·∫_{-∞}^{∞} F(ω)·e^{iωt}dω注意正变换没有前面的1/2π逆变换有。有些教材或工具库会把2π放在正变换那边甚至正反变换各放1/√(2π)这纯粹是定义习惯问题使用时保持一致就行。从直观上看正变换把时间函数变成频谱密度逆变换又能把频谱密度还原成时间函数。理解了这个对应关系后面再学离散傅里叶变换DFT、快速傅里叶变换FFT就会容易得多FFT就是把这里的连续积分替换为有限采样点上的离散求和。举一个经典例子单个矩形脉冲的傅里叶变换是Sa函数也就是sin(x)/x的形状。脉冲越窄频谱主瓣越宽这正是时域越短、频域越宽的体现。而周期性方波如果只看单个周期其频谱包络线同样是Sa函数但因为有周期重复频谱只在基频整数倍处存在离散谱线。换言之离散谱外面罩着一个连续包络线包络由脉冲形状决定谱线位置由重复频率决定。这个关系在通信里的脉冲成型和采样定理中反复出现。4. 实操用Python把方波一层层拼出来4.1 最小代码框架从零开始叠谐波理论讲再多不如亲手跑一遍。我推荐用Python的NumPy和Matplotlib做可视化几十行代码就能看到傅里叶级数逼近方波的过程。下面这段代码生成一个周期为2π的标准方波并叠加前若干项奇次谐波import numpy as np import matplotlib.pyplot as plt # 在[-pi, pi]之间取足够密的点避免绘图锯齿 t np.linspace(-np.pi, np.pi, 4000, endpointTrue) # 标准方波在(0, pi)为正在(-pi, 0)为负 x np.sign(np.sin(t)) # 叠加傅里叶级数方波只含奇次谐波 N 9 # 最大谐波次数 approx np.zeros_like(t) for k in range(1, N 1, 2): approx (4.0 / (np.pi * k)) * np.sin(k * t) plt.figure(figsize(10, 4)) plt.plot(t, x, k--, label原方波) plt.plot(t, approx, r-, labelf前{ (N1)//2 }项谐波叠加) plt.legend() plt.tight_layout() plt.show()代码里range(1, N1, 2)取的是1、3、5、7、9这些奇数正好对应方波级数中sin(kt)/k的项。(N1)//2用来计算实际叠加项数因为N9时实际只选了5项。这里的核心参数是采样点数4000它决定绘图曲线的平滑程度如果只取几十个点叠加出来的曲线会变成锯齿状这其实是绘图欠采样不是傅里叶级数本身的问题。4.2 不同N的叠合效果与Gibbs现象把N分别设成1、5、15、99运行上面的代码你会看到很有意思的变化N1时只有一根基频正弦近似结果就是一个大波浪只在整体趋势上贴近方波N5时边缘开始出现陡峭的过渡带中间平台明显“变平”N15时边沿更锐利平台上的波纹更密集N99时几乎看不出和方波的区别但如果你把图像局部放大到跳变沿附近依然能看到小幅度的过冲振荡。这个“边缘过冲”就是著名的Gibbs现象。它不是数值误差也不是代码写错了而是有限项截断本身的数学特性。在方波的跳变点附近不论叠加多少项过冲幅度大约保持在跳变幅度9%左右不会因为N继续增大而消失N越大过冲振荡越向跳变点压缩宽度越来越窄但峰的高度不会降下来。很多人第一次看到这个现象会怀疑程序算错了甚至有同学以为多叠几千项就能消除过冲。实际不会。在处理真实信号时如果关心的是跳变边的位置9%的过冲可能影响阈值判断这需要用窗函数或者不完全用傅里叶基来缓解。这个话题到离散傅里叶变换那篇再细说。4.3 顺手记录一个采样点选择的坑写代码时最容易踩的坑是直接取整个周期的点做循环叠加然后发现绘制出来的波形在边界处有明显跳变。原因是方波的周期是2π如果你取t np.linspace(0, 2*np.pi, 100)最后一个点正好是2π而sin(2π)等于0数值上没问题但如果你的方波定义成“在0到π为正、π到2π为负”最后一个点到底算正还是负需要注意。更稳妥的做法是用np.sign(np.sin(t))定义让方波自动在零点处理为零绘制时不至于出现错误的平台。另外如果你打算用数值积分去求a_n和b_n而不是套标准系数千万不要在方波的不连续点上直接采样。数值积分在跳变处会引入难以忽略的偏差最好把积分区间从0到2π改成分段积分先积0到π再积π到2π这样可以得到精确的系数。这个细节在写算法时很关键因为实际采集信号中不会存在理想的不连续点但分段量化误差仍是真实存在的。5. 常见理解误区与排查技巧实录5.1 不是所有周期函数都能随手展开傅里叶级数不是什么时候都成立。严格来说周期函数需要满足狄利克雷条件一个周期内只有有限个间断点只有有限个极大值和极小值并且函数绝对可积。工程上常见的方波、锯齿波、三角波都满足所以大部分时候我们不需要纠结。但有一个点容易被忽略在不连续点处傅里叶级数收敛到的是左右极限的平均值而不是函数本身的取值。例如方波在跳变点左边为1、右边为-1那级数在该点收敛到0。所以不要用级数重构结果去精确读取跳变点的值否则你看到的永远是0而不是原来的±1。这个特性在实际设计控制系统时会影响阈值比较逻辑尤其当你拿重构波形判断边沿位置时要预留这个偏差。5.2 相位被丢掉之后波形会面目全非频率分析里人们经常只盯着幅度忽略了相位。我见过不少初学者做信号重构时只保留幅度谱把相位直接置零再逆变换回来发现波形完全不是原信号然后一头雾水。原因很简单不同频率分量的相对时间对齐关系完全由相位决定。你把每一根正弦波的起点都挪到一起叠加结果自然完全不同。举个例子同样一个脉冲串如果所有谐波相位对齐会在时域形成一个很尖锐的峰如果相位随机化能量就铺开成类似噪声的波形。幅度谱可能看起来一模一样但时域形态天差地别。所以做频域滤波时除非是做离线零相位滤波否则相位响应同样重要。很多入门教材为了先建立频域直觉故意忽略相位这可以理解但实战里真不能完全无视它。5.3 画频谱图时容易搞混的几个单位和量纲最后记录一个绘图时很常见的问题。傅里叶级数系数a_n、b_n的幅频图线性纵轴直接画|C_n|但工程上为了观察动态范围常用20log10(|C_n|)画成dB。两者差别很大线性图上看起来不起眼的小分量在dB图上可能已经是有影响的旁瓣。再一个容易搞混的是单边谱和双边谱。用复指数形式展开时n从负无穷取到正无穷所以画出来正负频率各有一半对称分布。有人看到负频率有数值就疑惑“负频率哪里来的能量”其实实信号的负频率项和正频率项是共轭配合的实际能量要算单边谱即把正频率侧的功率加倍而直流分量保持原样。这个规则在做功率谱估计时特别重要很多算法库默认返回双边谱如果直接画图或积分算功率数值上会差一倍。另一个容易懵的点是连续傅里叶变换的纵轴到底代表什么。很多人把它当成“幅度”看到矩形脉冲的频谱最大峰值不是1就以为算错了。实际上连续频谱F(ω)是频谱密度量纲是“幅度×时间”不能直接和傅里叶级数的离散谱线幅度画等号。只有当信号变成周期信号时谱线幅度和密度之间才有简单换算关系这一点我在做仿真时也栽过跟头。按我自己的经验傅里叶级数最值得花时间的地方不是把公式背到滚瓜烂熟而是亲手凑一次方波。你在屏幕上看到前5次谐波叠加出来的轮廓开始出现就会真正相信“任意周期信号都能拆成正弦波”这句话。等这一步顺了再往傅里叶变换、采样定理走会省力很多。下一篇我会重点展开连续傅里叶变换的反变换、能量守恒关系以及离散化之后怎么用FFT处理实际问题先把引子放在这儿。