信号与系统课程里频谱分析、频域分析、采样、调制和滤波器几乎总是出现在同一张知识网络里但教材习惯把它们拆在不同章节讲初学者很容易每个术语都认识却串不成一条完整的处理链路。实际上这条主线并不复杂时域信号通过傅里叶变换进入频域频谱告诉我们信号在不同频率上有多少能量采样规定了连续信号变成离散序列后频率成分的边界调制负责把基带频谱搬到适合传输的位置滤波器则是在频域中保留需要的成分、抑制不需要的成分。频谱分析是观察工具采样是数字化的前提调制是信号搬移的手段滤波是频域加工的核心。把这几个概念放到同一条链路上理解再配合一个可运行的实验才能真正把信号与系统的知识变成处理实际问题的能力。这篇文章适合正在学习信号与系统的学生、刚接触数字信号处理的嵌入式开发者以及需要做音频、振动、通信等信号采集和分析的工程师。读完你会理解为什么频谱图要这么看、采样率为什么不能随便设、调制为什么能搬移频率、滤波器为什么不可能做到“完全理想”并能在自己的机器上用 Python 跑通一个从采样到频谱分析再到滤波的完整实验。1. 先建立一条主线时域、频域与频谱分析是什么关系1.1 时域描述过程频域描述构成时域是大多数人先接触的角度。示波器上看到的波形横轴是时间纵轴是幅度它描述的是信号随时间如何变化。这个角度的优点是直观能看到波形起伏、脉冲宽度、周期长短缺点是当信号由多个频率成分叠加时时域波形很难直接告诉我们“这到底包含哪些频率”。频域换了一个观察维度。横轴是频率纵轴是幅度或能量它回答的问题是这个信号由哪些频率成分组成每个成分有多强。用声音来类比时域波形像你听到的一段混合声音频域谱则像把这段声音拆成一个个音符告诉你每个音高占多少音量。齿轮箱振动监测也是一样时域波形可能只是一团乱糟糟的振荡但频谱里某个啮合频率处的谱峰却可以直接指向故障特征。所以时域便于看过程频域便于看构成。信号与系统里反复强调频域分析是因为很多处理操作在频域中描述起来极其简洁滤波是频域乘法调制是频谱搬移采样是频谱周期化。先用频域思维建立整体认识再回来看时域实现很多公式就变得容易接受。1.2 傅里叶变换把信号拆成不同频率的正弦波把信号从时域变到频域的基本工具是傅里叶变换。对连续时间信号傅里叶变换定义为X(f) ∫ x(t) · e^(-j2πft) dt这个积分可以理解为用不同频率的复指数 e^(-j2πft) 去“扫描”信号 x(t)看哪个频率成分和信号最相关。X(f) 是一个复数它的模是幅度谱表示该频率成分的强弱辐角是相位谱表示该频率成分的起始相位。周期信号可以用傅里叶级数拆成离散的谱线而一般非周期信号用傅里叶变换得到连续谱。对于课程学习来说先记住一个最小例子就够了x(t) 2 sin(2π·100t) 1.5 sin(2π·300t π/4)这个信号的时域波形是两个正弦波的叠加而它的频谱会呈现两条清晰的谱线100 Hz 处幅度为 2300 Hz 处幅度为 1.5并带有一个 π/4 的相位信息。容易误解的地方是傅里叶变换并不创造信息它只是把同样一份信息换了一种表示方式。时域和频域是对同一信号的两种观察角度并不存在谁更“真实”的问题。1.3 频谱图怎么读幅度谱、单边谱与功率谱绘制频谱图时最容易犯的错是把负频率当成“不存在的频率”。实际工程信号几乎都是实信号实信号的傅里叶谱是共轭对称的负频率部分只是正频率部分的镜像。既然信息重复通常就画单边谱即只画出频率大于等于 0 的一半并把正频率处的幅度乘以 2保持能量守恒。读频谱图时先看三件事谱峰出现在哪些频率处对应信号的频率成分谱峰高度对应各成分的幅度谱峰宽度和底部裙带反映频谱泄漏和窗函数的影响。FFT 得到的离散幅度谱通常用单边幅度表示幅度计算方法是直流分量取 |X[0]|/N其余正频率分量取 2|X[k]|/N。如果只需要比较成分之间的相对强弱也可以直接画功率谱即幅度谱的平方常用于噪声分析和频谱估计。2. 采样定理离散信号能表示多高频率边界在采样率的一半2.1 从连续信号到离散序列数字信号处理的第一步是把连续信号变成离散序列。ADC 内部完成了两件事采样和量化。采样决定时间上离散x[n] x(n·Ts)其中 Ts 是采样间隔量化决定幅度上离散把连续的幅度值近似到有限个等级。采样率 fs 1/Ts 表示每秒采多少个点。采样后的离散序列包含多少个频率信息取决于采样率。直观上如果信号变化太快采样点太少就无法还原原来的连续波形。这个直觉最终被奈奎斯特采样定理精确地表达出来。采样会造成频谱周期化。连续信号在时域乘以周期冲激串对应频域就是原频谱以 fs 为周期不断复制。如果信号最高频率 fmax 小于 fs/2复制出来的频谱副本彼此不重叠可以无失真恢复一旦 fmax 超过 fs/2副本之间就会重叠产生混叠。2.2 奈奎斯特采样定理到底在说什么奈奎斯特采样定理的标准表述是要无失真地采样一个最高频率为 fmax 的带限信号采样率必须满足 fs ≥ 2·fmax。这里的 fs/2 有一个专门的名字叫折叠频率或奈奎斯特频率。实际工程中很少刚好取 fs 2·fmax。原因在于理论上的临界采样需要理想低通滤波器才能完美重建而理想滤波器物理不可实现。真实系统一般留出设计余量例如振动信号采集常取 fs 3~5 倍的关心最高频率音频 CD 采样率取 44.1 kHz是因为人耳可听上限约 20 kHz还需要考虑抗混叠滤波器的过渡带。数字滤波器的设计参数里也频繁出现归一化频率通常定义为 f / (fs/2)范围是 0 到 1理解这个基准是后面设计滤波器不踩坑的前提。2.3 混叠为什么可怕混叠最直观的后果是高频信号伪装成低频信号。假设采样率 fs 1000 Hz一个 600 Hz 的正弦波采样后频谱上会出现在 400 Hz 处一个 900 Hz 的正弦波会出现在 100 Hz 处。计算公式可以简单记为 f_alias |f - k·fs|取落在 0 到 fs/2 之间的那个结果。真实频率采样率混叠后显示频率说明600 Hz1000 Hz400 Hz超出奈奎斯特频率 100 Hz900 Hz1000 Hz100 Hz折返到低频段1300 Hz1000 Hz300 Hz多次折叠后的结果混叠一旦发生就无法靠后续的数字滤波消除因为你根本不知道这个低频分量到底是真实的还是高频成分折返下来的。正确做法是在 ADC 之前加入模拟低通滤波器把高于 fs/2 的成分在进入采样器之前先抑制掉这就是抗混叠滤波器存在的原因。很多初学者在数字端反复设计滤波器去“提纯”信号却发现始终有莫名低频根因往往在采样前端。注意数字滤波器只能处理采样后频谱里已经存在的信息无法区分真实低频和由混叠产生的伪低频。采样前端留足余量比后端反复滤波更关键。3. 调制本质上是把频谱从基带搬到通带3.1 调制解决的是频谱位置问题通信信道通常工作在特定的通带频率上而语音、视频这类基带信号频率接近零频直流和低频分量无法通过天线有效辐射也无法在信道中直接传输。调制负责把基带信号的频谱整体搬移到载波频率附近。频谱搬移的数学基础是时域乘法对应频域卷积。一个余弦载波 cos(2π·fc·t) 的频谱是两根位于 fc 和 -fc 的冲激信号 m(t) 乘以载波后频谱等价于把 M(f) 复制一份平移到 fc 处再复制一份平移到 -fc 处这就是频谱搬移。通信里常用术语把这些位置称为上边带和下边带统称边带。3.2 用 AM 信号理解调制过程幅度调制 AM 是最直观的调制方式。已调信号写成y(t) (A0 m(t)) · cos(2π·fc·t)其中 A0 是直流偏置m(t) 是基带调制信号fc 是载波频率。若 m(t) Am·cos(2π·fm·t)y(t) 的频谱结构为载波 fc 处一根谱线以及 fc ± fm 处的两根边带谱线。已调信号带宽约为 2·fm是基带信号带宽的两倍。调制深度是 AM 的关键参数定义为 ma Am / A0。ma 小于 1 时包络能完整保留基带形状接收端用包络检波即可解调ma 等于 1 是临界状态包络刚好触零ma 大于 1 时出现过调幅包络发生相位翻转、畸变普通包络检波再也无法恢复原信号。参数含义取值影响A0载波直流偏置决定调制深度的基准Am基带信号幅度决定边带谱线高度ma Am/A0调制深度小于等于 1 可包络检波大于 1 过调幅fc载波频率决定频谱搬移的目标位置fm基带信号频率决定边带与载波的间距3.3 调制、滤波和频谱分析如何配合调制不是孤立操作。发射端在调制后通常要加带通滤波器把已调信号限制在指定信道带宽内防止干扰相邻信道接收端解调后要加低通滤波器把基带信号从高频载波附近恢复出来。调制和滤波始终配对出现。频谱分析在整个链路里是校验工具发射前看基带频谱是否干净调制后看频谱有没有被正确平移到 fc接收端看滤波后高频载波是否被完全抑制。这就是为什么通信系统设计里“先会看频谱、再谈调制解调”是基本顺序。4. 滤波器用频率响应做选择性加工4.1 四类基本滤波器的适用场景滤波器是一个线性时不变系统它的频率响应 H(f) 决定了哪些频率通过、哪些频率被抑制。按通过频段划分最基础的是低通、高通、带通、带阻四类。类型保留频段抑制频段典型应用低通0 ~ fcfc 以上去高频噪声、解调后恢复基带高通fc 以上0 ~ fc去掉直流漂移和低频干扰带通f1 ~ f2其他频段信道选择、提取特定频率分量带阻f1 ~ f2 之外的频段f1 ~ f2抑制 50 Hz 工频干扰设计滤波器时首先要明确三个参数截止频率 fc描述通带与阻带的分界过渡带描述从通带到阻带变化有多快通带纹波和阻带衰减描述幅度误差和抑制能力。任何实际滤波器都是在这些指标之间做取舍。4.2 理想滤波器为什么不可实现理想低通滤波器的频率响应是一块矩形通带内幅度为 1阻带内幅度为 0。这个频率响应对应的时域脉冲响应是无限长的 sinc 函数它从负无穷延伸正无穷意味着输出依赖未来的输入是非因果系统物理上无法实现。实际滤波器用有限阶数去逼近这个理想形状。阶数越高过渡带越窄就越接近理想滤波器但会带来更大的相位延迟、更复杂的数值计算IIR 滤波器阶数过高时还可能出现数值不稳定。常见设计里有最大平坦的巴特沃斯滤波器、允许通带纹波换取更陡过渡带的切比雪夫滤波器、过渡带最陡但纹波更复杂的椭圆滤波器。选型时没有绝对最优要看指标里最不能妥协的是哪一项。4.3 时域卷积与频域乘法是同一件事滤波器对信号的作用在时域是卷积y(t) ∫ h(τ) · x(t - τ) dτ在频域则是乘法Y(f) X(f) · H(f)这是一个极其重要的等价关系。它意味着设计滤波器本质上就是选择 H(f) 的形状想要保留低频就把 H(f) 在低频处设为接近 1高频处设为接近 0。理解了“频域乘法”去看任何滤波器设计工具的文档都会容易很多因为绝大多数参数都是在描述 H(f) 的形状。5. 一个可以动手跑的实验采样、FFT、低通滤波一条龙5.1 环境准备这一步需要 Python 环境以及三个常用库NumPy 负责数组和 FFTSciPy 负责滤波器设计Matplotlib 负责绘图。如果原始环境还没有安装可以在虚拟环境中执行python -m venv venv source venv/bin/activate pip install numpy scipy matplotlib软件包作用安装命令numpy矩阵运算、FFT 函数pip install numpyscipy滤波器设计、信号处理函数pip install scipymatplotlib时域和频谱绘图pip install matplotlib写作时的常见组合是 Python 3.8 以上版本配合较新的 NumPy 和 SciPy具体版本以环境安装结果为准。下面代码用于说明完整流程实际项目中要结合自己的采样率、频率范围和包名调整。5.2 构造一个包含多频率成分的测试信号为了让实验能验证后面每一步构造一个三段正弦叠加再加白噪声的信号5 Hz 幅度 2.050 Hz 幅度 1.5120 Hz 幅度 1.0均匀白噪声标准差 0.3。采样率取 1000 Hz观察时长 1 秒所有频率都远低于奈奎斯特频率 500 Hz。import numpy as np from scipy import signal import matplotlib.pyplot as plt fs 1000 t np.arange(0, 1, 1/fs) np.random.seed(0) x (2.0 * np.sin(2 * np.pi * 5 * t) 1.5 * np.sin(2 * np.pi * 50 * t) 1.0 * np.sin(2 * np.pi * 120 * t) 0.3 * np.random.randn(len(t)))这里设置随机种子是为了让每次运行结果一致便于后续排查。噪声一方面模拟真实采集中的环境干扰另一方面也让频谱图看起来更像实际数据而不是教科书里的纯理想曲线。5.3 用 FFT 做频谱分析对离散序列做傅里叶变换使用 NumPy 的 FFT 函数。关键点有三个频率轴要用 np.fft.fftfreq 生成不能把下标直接当频率幅度谱要做单边归一化绘制时只画正频率部分。N len(x) X np.fft.fft(x) freqs np.fft.fftfreq(N, 1/fs) amp np.abs(X) / N amp_single amp.copy() amp_single[1:N//2] 2 * amp_single[1:N//2] plt.figure(figsize(8, 4)) plt.plot(freqs[:N//2], amp_single[:N//2]) plt.xlabel(frequency (Hz)) plt.ylabel(amplitude) plt.title(single-sided spectrum) plt.xlim(0, 250) plt.grid(True) plt.show()这段代码输出的频谱图应该能看到三根明显的谱线分别位于 5 Hz、50 Hz、120 Hz幅度接近 2.0、1.5、1.0。噪声成分会在整个频带铺开一条低幅度的底。FFT 结果与信号幅度不是直接相等必须经过归一化。对实信号正频率分量取 2|X[k]|/N 才是原信号中对应正弦分量的幅度。频率分辨率由观察时长决定这里是 fs/N 1 Hz意味着两个频率至少相差 1 Hz 才能被区分开。如果想更精细地分辨靠近的频率需要延长观察时间而不是提高采样率。5.4 设计低通滤波器滤除高频目标是把 120 Hz 分量滤掉同时保留 5 Hz 和 50 Hz。取截止频率 80 Hz即通带和阻带的分界放在 50 Hz 与 120 Hz 之间。使用四阶巴特沃斯低通滤波器以 SOS 格式输出再用 sosfilt 滤波。cutoff 80 sos signal.butter(4, cutoff / (fs / 2), btypelow, outputsos) y signal.sosfilt(sos, x) plt.figure(figsize(8, 4)) plt.plot(t, x, alpha0.5, labeloriginal) plt.plot(t, y, labelfiltered) plt.xlabel(time (s)) plt.ylabel(amplitude) plt.legend() plt.xlim(0, 0.4) plt.grid(True) plt.show()设计数字滤波器时截止频率参数必须除以 fs/2 做归一化。cutoff / (fs / 2) 等于 80 / 500 0.16这个无量纲值才是 SciPy 要求的频率单位。如果直接传 80相当于把截止频率设成 80 倍的奈奎斯特频率滤波器会对所有关心频率“全通过”表现为滤波后波形和原信号几乎一样。用 SOS 格式而不是传统的 b、a 系数是因为高阶 IIR 滤波器在 b、a 形式下容易产生数值问题SOS 把高阶滤波器拆成多级二阶节串联数值稳定性更好。这是生产代码里更推荐的做法。5.5 从频谱验证滤波结果滤波后不能只看时域波形还要再做一次 FFT确认 120 Hz 分量确实被抑制。Y np.fft.fft(y) amp_y np.abs(Y) / N amp_y_single amp_y.copy() amp_y_single[1:N//2] 2 * amp_y_single[1:N//2] plt.figure(figsize(8, 4)) plt.plot(freqs[:N//2], amp_y_single[:N//2]) plt.xlabel(frequency (Hz)) plt.ylabel(amplitude) plt.title(spectrum after low-pass filtering) plt.xlim(0, 250) plt.grid(True) plt.show()预期结果是5 Hz 和 50 Hz 的谱线仍然存在幅度略有下降120 Hz 谱线大幅衰减到接近噪声底。时域波形会从原来包含快速振荡的样子变成只有 5 Hz 和 50 Hz 两个慢速成分的叠加曲线明显变光滑。这里要顺带注意滤波瞬态。sosfilt 输出的开头一小段是滤波器初始状态导致的过渡过程频谱验证通常取稳定后的数据段来看。实时系统里这个延迟和瞬态必须纳入设计考虑否则会因为头部数据异常而误判信号质量。注意滤波器是否有校必须用频谱验证而不是只看时域“看起来变好了”。把滤波前后的频谱放在一起对比是最直接的验收方式。6. 频谱分析和滤波的常见问题排查6.1 常见现象排查表实际跑实验或做项目时频谱分析上的问题大多集中在下面几类。问题现象常见原因检查方式处理建议FFT 峰值频率和真实频率对不上频率轴计算错误或 fs 单位不一致检查 fftfreq 的参数和 fs 单位用 np.fft.fftfreq(N, 1/fs) 生成频率轴谱峰很宽、底部出现裙带观察窗口内不是整数个周期频谱泄漏查看信号是否有非整周期截断加汉宁窗或汉明窗后再做 FFT高频分量变成低频假峰采样率不足发生混叠核对 fs 是否大于等于 2 倍信号最高频率提高 fs或在采样前加抗混叠低通滤波器好像没作用butter 的截止频率没除以 fs/2打印 cutoff/(fs/2) 的值确认归一化频率在 0 到 1 之间滤波后信号开头出现明显振荡滤波器初始状态未收敛观察输出前 50 个采样点用 filtfilt 做零相位滤波或丢弃过渡段滤波后信号幅度整体变小通带衰减过大或滤波器设计不当查看滤波器的频率响应改用更高阶数或调整截止频率必要时补增益6.2 三个很容易踩的坑第一个坑是把 FFT 的下标直接当频率。fft 输出数组的第 k 个元素对应频率是 k·fs/N不是“第 k 个就是 k Hz”。不经过 fftfreq 换算绘图时横轴会完全错位。特别是 fs 不是 1 的时候这种错误会非常隐蔽。第二个坑是忽略信号里的带外成分。比如目标信号是 50 Hz但采集到的信号里混有 600 Hz 干扰而 fs 只有 1000 Hz。600 Hz 会被混叠成 400 Hz看起来像低频怎么设计数字滤波器都处理不掉。数字滤波无法区分真实低频和混叠伪低频必须在采样前端加抗混叠滤波。第三个坑是滤波器参数直接传 Hz 给 scipy 的 butter 函数。Wn 是归一化频率必须除以 fs/2。传 80 而不是 0.16等效于截止频率设到了 40 kHz结果滤波器对所有成分全通过初看以为是滤波器无效实际是参数单位理解错了。这类问题非常适合用频率响应图来排查画出 H(f) 就能一眼看见通带和阻带的位置。6.3 一个可直接复用的频谱分析检查清单每次做频谱分析前按下面顺序确认一遍能减少大部分返工确认采样率 fs 和信号最高频率 fmax满足 fs 至少取 3~5 倍 fmax。确认采样前是否有抗混叠处理特别是关心频带接近 fs/2 时。确认观察时长满足频率分辨率需求Δf fs/N。确认 FFT 频率轴用 np.fft.fftfreq 生成单位与 fs 一致。确认是否加窗以及窗函数对谱峰幅度的影响是否已纳入考虑。确认单边谱归一化方式正频率幅度为 2|X[k]|/N直流分量为 |X[0]|/N。确认数字滤波器截止频率已除以 fs/2。确认滤波后是否用频谱对比验证而不是只看时域波形。7. 从课程实验到工程实践还需要补齐哪些能力7.1 学习环境与生产环境的差异Python 脚本里的实验和真实产品里的信号处理之间至少还差一层工程化能力。下表列出最常见的差异。维度学习实验工程实现运行方式Jupyter 或脚本一次性运行实时流处理或嵌入式程序数据格式float64 数组定点数或低精度浮点需考虑溢出滤波器结构sosfilt 直接调用定点系数、状态变量保存、溢出保护频率基准固定 fs时钟漂移、重采样、采样中断错误处理报错重跑日志、看门狗、降级策略资源限制基本不关注内存、算力、实时延迟验证手段画图观察确定性测试用例、在线监测指标学习阶段可以不用关心这些差异但进入项目前必须意识到同一套算法换一个采样平台、换一种数值精度、换一个实时调度环境表现可能完全不同。做嵌入式信号处理时浮点仿真通过只是第一步定点化验证、溢出测试、时序测试一个都不能少。7.2 下一步值得做的方向把本篇文章的主线跑通之后可以按兴趣往四个方向延伸。一是学习加窗谱估计。FFT 直接做功率谱存在统计波动和频谱泄漏问题工程上常用重叠分段加窗的 Welch 方法稳定性更好。二是学习短时傅里叶变换 STFT。实际信号往往是非平稳的频率成分随时间变化STFT 用时间和频率两个维度描述信号是分析语音、机械振动瞬时特征的常用工具。三是深入学习数字滤波器设计。需要线性相位时选 FIR需要低阶高效率时选 IIR理解二者实现结构、相位特性和量化效应才能做选型判断。四是往多速率方向扩展。采样率转换、抽取与插值、CIC 滤波器在软件无线电和音频处理里非常常见它和前端的采样定理有直接关系正好能和本文内容衔接。7.3 三个适合巩固的小练习第一个练习是故意制造混叠。把实验里的 fs 改到 150 Hz奈奎斯特频率变成 75 Hz原本 120 Hz 的分量会出现在 30 Hz 处。先猜测结果再跑代码看频谱能直观记住混叠的后果。第二个练习是把低通滤波器换成带通。设计一个通带 40 Hz 到 60 Hz 的带通滤波器观察滤波后是不是只剩下 50 Hz 分量同时对比它和低通滤波器在频响上的差别。第三个练习是研究频谱泄漏。把 50 Hz 信号改成 49 Hz观察时长仍取 1 秒不用窗函数时谱峰会明显变宽变矮加汉宁窗后谱峰形状改善但幅度也变了。对比这两个结果就能理解窗函数是和频谱分辨率、幅度精度绑定的取舍。这三个练习做完采样、频谱分析、滤波器这三个概念就不再是孤立公式而是可以互相验证的工具链。信号与系统的学习本质是建立这种“每个概念都能解释另一个概念”的关系而不是背下多少条定义。建议把自己机器上的实验跑完再故意改错几个参数观察现象比重新看一遍教材更有效。
