1. 先从标题说起:为什么是“【Math】”和“信号处理”
看到“【Math】2.0 信号处理——目录”这个标题时,我第一反应是:整理这份目录的人,大概率已经把信号处理相关的资料翻过一轮了。因为“2.0”意味着前面可能有过1.0版本,而“Math”放在最前面,说明作者清醒地知道,信号处理不是会调用几个库函数就行,它本质上是一层层建在数学砖块上的工程学科。这份目录如果拆开来看,基本就是一条从数学原理到工程落地的信号处理学习路线图。
我这些年做过雷达回波分析,也处理过ECG、PPG这类生理信号,偶尔还会碰音频降噪和阵列测向。说实话,每次换一个领域,最怕的不是新算法不会用,而是基础知识不牢导致问题定位困难。比如一个滤波器参数设错,可能整个心率检测都会被噪声带偏;窗函数没选好,频谱里的峰值会“长胖”;阵列间距没算对,波束就会形成栅瓣。这些问题如果只会“调用现成代码”,那你只能一直复制粘贴。只有把数学和信号处理的地图刻在脑子里,才能迅速判断问题出在哪个环节。
所以我打算从这份“目录”切入,把它展开成一份可执行的信号处理学习与实战地图。你不需要一次读完,但可以用它来定位自己在哪里、下一步该补什么。无论是刚入门的在校学生,还是想转行做音频、雷达、生物医学信号的工程师,这份内容都能给你一个相对清晰的坐标系。
1.1 这真的只是一份目录吗
目录的本质是知识框架。很多人收藏了一大堆资料,却从来没有梳理过主线,信号处理这门学科尤其容易这样。因为它的概念太多了:傅里叶变换、Z变换、数字滤波器、功率谱密度、小波变换、自适应滤波、阵列流型……如果不靠目录把知识点挂起来,学完后面就会忘记前面。
我更愿意把目录当成一张作战地图。地图本身不解决战斗,但能告诉你现在站在哪、下一个据点在哪、哪些路径可以绕开。比如你只做音频降噪,就没必要一上来死磕MUSIC算法;你如果做雷达目标检测,那FFT加窗、CFAR、多普勒处理就是必经之路。目录帮你做筛选,也帮你建立“这个知识点属于哪棵树”的感觉,后续遇到问题时能快速找到对应的工具箱。
1.2 信号处理领域的“数学地图”到底长什么样
信号处理里要用到的数学,看起来很多,但工程上主要就四大块:微积分、线性代数、概率统计、复变函数。如果方向再偏理论一点,还会碰到泛函分析的一些皮毛,但大多数工程师用不到那么深。
我习惯把数学和信号处理的对应关系列出表来:
| 数学工具 | 典型信号处理场景 |
|---|---|
| 微积分与积分变换 | 傅里叶变换、拉普拉斯变换、Z变换的基础 |
| 线性代数 | 滤波器组、子空间算法、阵列信号处理中的矩阵特征分解 |
| 概率统计 | 随机信号分析、噪声建模、参数估计、目标检测 |
| 复变函数 | 解析信号分析、Hilbert变换、系统稳定性判定 |
举个例子,阵列信号处理里的MUSIC算法,本质上是计算协方差矩阵的特征分解,完全依赖线性代数;雷达测距,本质上是发射信号与回波做相关运算,再通过傅里叶变换转到频域找峰值;PPG信号处理中最头疼的运动伪迹消除,往往要用到随机信号估计里的自适应滤波。你会发现,数学工具并不是孤立存在的,它们在具体应用里互相配合。
1.3 用数学视角看信号处理的三个阶段
我习惯把一个信号处理系统拆成三段:感知、表示、决策。感知是传感器把物理量变成电信号,表示是选择某个变换域让信息浮现出来,决策是估计参数或判断类别。
感知阶段,你需要建立噪声模型。比如雷达回波里的热噪声通常建模为高斯白噪声,ECG里常见的工频干扰是正弦信号加谐波,PPG的运动伪迹是低频随机扰动。表示阶段,你需要理解基函数和变换。傅里叶变换把信号分解成正弦波,小波变换把信号分解成不同时间和频率的局部波形。决策阶段,则是估计和检测问题,用概率理论判定哪个假设更可信。
有了这三个阶段的框架,学任何一个算法都不容易迷路。比如卡尔曼滤波,表面上是状态方程和观测方程,本质上是在“表示”阶段建模,在“决策”阶段做最优估计。这个视角是很多教材不会专门讲的,但真到工程里非常管用。
2. 基础篇:目录里必须先放下的几块基石
信号处理的东西虽然多,但不管哪个方向,基础模块绕不开时域、频域、采样、滤波这几座山。别觉得它们简单,很多看起来很高端的工程问题,最后都会回到这些基础概念上。
2.1 时域与频域:傅里叶变换不是终点,而是起点
很多人把傅里叶变换背得滚瓜烂熟,但真到工程里,却容易被采样率、频谱泄漏这种“基本功”绊住。傅里叶变换的核心思想并不复杂:把信号分解成一系列复指数信号的叠加。连续信号的公式是积分,离散信号就是累加。你需要建立一些关键直觉,尤其是频率分辨率。
频率分辨率有一个特别实用的经验公式:Δf ≈ 1/T,这里的T是信号时长。也就是说,你想在频谱上区分两个间隔为1Hz的频率分量,至少要采1秒;想做到0.1Hz分辨率,就要采10秒。这个式子会在雷达、音频、生物医学信号处理中反复出现。
我举个例子:采样率是1000Hz,你采集了1秒数据,做1024点FFT,频率分辨率大约是1Hz。这时你看到频谱里有一个峰,你需要习惯性问自己一句:这个峰到底是真实信号,还是窗函数泄漏或者短数据处理带来的假象?如果你能带着这个问题去看频谱,很多误判都能提前避免。
2.2 采样定理与混叠:很多工程问题的根因
奈奎斯特定理说,采样率必须大于信号最高频率的两倍,才能无失真重建。但实际工程里,问题比这句话复杂得多。抗混叠滤波器怎么放?采样率选择是否留了余量?如果采样率不够,高频信号会折叠到低频,形成一个根本不存在的“幽灵频率”。
举例来说,ECG信号里经常有50Hz工频干扰。如果你的采样率只有100Hz,那么50Hz信号采样后会变成直流分量,想滤都滤不掉。正确的做法是采样前加低通滤波器,把50Hz以上的成分压下去,再进入ADC。
我自己在定采样率时,通常取最高关心频率的5到10倍,而不是理论上的2倍。因为真实系统里的滤波器都有过渡带,采样率太低,过渡带里的噪声就会混叠到目标频带内。这个经验可能有点保守,但能省掉很多后续处理上的麻烦。
2.3 滤波器设计:从理想响应到可实现系统
理想滤波器有矩形的频率响应,可惜物理可实现系统都会有过渡带和纹波。设计一个数字滤波器,本质上是在指标之间做折中:通带纹波、阻带衰减、过渡带宽度,这三者不可能同时做到完美。
FIR和IIR滤波器的选择是一个经典问题。FIR滤波器容易实现线性相位,也不会因为反馈导致不稳定,但同样的过渡带要求下阶数往往很高,计算量大。IIR滤波器效率高,计算量小,但相位响应是非线性的,可能造成波形畸变。
我调试滤波器时有一个习惯:先确定过渡带宽度,再用经验公式估算阶数,最后仿真验证。比如用窗函数法设计FIR滤波器时,过渡带宽度大约等于窗函数主瓣宽度,阶数越高过渡带越窄。当你发现滤波器实际效果和预期不符时,十有八九是阶数不够或者截止频率选在了过渡带边缘。
3. 进阶篇:经典与现代算法怎么排进目录
基础模块搭好之后,目录就需要放进更多有挑战的算法。这里我会从频谱分析、统计信号处理、非平稳信号处理三个角度来展开,它们是很多高级应用的地基。
3.1 频谱分析中的窗函数与泄漏抑制
现实世界里,我们只能截取有限长的一段数据来做频谱分析。这个截断操作相当于把原始信号乘以一个矩形窗,频谱会与矩形窗的频谱卷积,导致能量泄漏到主瓣以外的频率上。于是我们引入各种窗函数,比如汉宁窗、汉明窗、布莱克曼窗,来抑制旁瓣。
但窗函数不是白给的。主瓣越窄,频率分辨能力越强;旁瓣越低,泄漏越少,但通常主瓣会变宽。比如汉宁窗旁瓣抑制能力比矩形窗好很多,但主瓣宽度变为原来的大约两倍,会让两个相近频率的峰变得难以分辨。
我的建议是,先明确你更在意频率分辨还是旁瓣抑制,再选窗函数。如果做雷达测距,目标速度连续变化,你通常希望主瓣窄一点;如果做音频频谱显示,你会更在意旁瓣低、看起来干净。工程里没有免费的午餐,参数选择就是取舍。
3.2 随机信号与统计信号处理:为什么绕不开概率
很多信号并不是确定性信号,比如雷达杂波、脑电、背景噪声。描述它们需要用随机过程的概念,而不是简简单单一个函数。随机信号处理的核心工具是自相关函数和功率谱密度,Wiener-Khinchin定理把它们联系起来:自相关函数的傅里叶变换就是功率谱密度。
在实际估计功率谱时,经典方法是周期图,但周期图的方差很大,估计结果很不稳定。所以工程上常用Welch平均法,把长信号切段、加窗、做FFT,再对多个段求平均,以方差换偏差,得到更平滑的功率谱估计。这个“以偏差换方差”的思想,是统计信号处理的精髓之一。
说到统计信号处理,很多人在读Kay的《统计信号处理基础——估计与检测理论》时,会对第二章的习题感到头疼。那一章讲的是最小均方误差估计、贝叶斯估计和BLUE,核心是理解“估计误差的准则”到底是什么。我建议不要急着找答案,而是亲自动手推一遍“高斯噪声中估计直流电平”的例子,你会发现样本均值其实是一个极大似然估计,也是某个条件下的BLUE。这样一遍推导下来,比看十遍PPT都有用。
3.3 从自适应滤波到小波变换:非平稳信号的解药
传统滤波器假设信号和噪声是平稳的,但真实信号往往不是。ECG里的肌电干扰是突发的,雷达杂波随时变,音频里经常有人声和背景噪声交叠。这时候就需要自适应滤波或时频分析。
LMS自适应滤波器的原理很直观:根据误差信号自动调整权向量,让滤波器输出逼近期望信号。核心参数是步长。步长太大,算法发散;步长太小,收敛速度慢。实际使用中我更推荐归一化LMS(NLMS),它把步长除以输入信号的功率,不同信号幅度下稳定性更好。
小波变换则是另一种思路。它用一组可变时宽和频宽的基函数去分解信号,低频部分用长的时间窗,高频部分用短的时间窗。这在处理ECG时特别有用:QRS波群是高频突变,基线漂移是低频慢变,用小波包分别处理后重组,可以同时抑制漂移和保留波形细节。
4. 应用篇:雷达、ECG、PPG、音频、阵列信号处理各有各的脾气
学完基础,你可能会想:这些算法到底用在哪?信号处理的分支很多,我分别聊聊我接触过的几个典型领域,希望能帮你在目录里找到更具体的定位。
4.1 ECG/PPG生物医学信号:从噪声里捞救命信息
ECG是心电信号,PPG是光电容积脉搏波,两者都是强噪声背景下提取微弱生理信息。ECG最关键的任务是QRS波群检测,然后通过RR间期算出心率;PPG则是从光学传感器捕捉到的血管容积变化中,估计心率和血氧。
ECG的预处理链路通常包括带通滤波(5-25Hz左右)、基线漂移校正、工频陷波,之后才能做R峰检测。PPG比ECG更容易受到运动伪迹影响,很多手环和智能手表里的PPG心率算法,都会引入加速度计信号作为参考,做自适应滤波。
有一次我在实测手环的PPG数据时,运动伪迹几乎把脉搏波形完全淹没。我试过固定截止频率的滤波器,发现没法同时保留脉搏谐波和滤除运动干扰。后来把加速度信号作为参考,用LMS自适应滤波才恢复出可用的波形。这个经历让我明白,生物医学信号处理里,了解噪声来源比调算法参数更重要。
4.2 雷达信号处理:从回波里提取距离和速度
雷达的原理是发射电磁波,接收目标反射回波。脉冲雷达通过计算发射脉冲到回波的延迟来测距,公式是R = cτ/2,其中c是光速,τ是延迟时间。调频连续波(FMCW)雷达则更现代,它通过发射频率随时间线性变化的信号,把距离信息转换成拍频频率,再通过FFT提取。
FMCW雷达做距离-速度估计时,会先沿快时间维做一次FFT,得到距离维,再沿多个chirp组成的慢时间维做第二次FFT,得到多普勒维。这两个维度的FFT组合起来,就是“距离-多普勒图”。如果再加上阵列天线,还可以在第三个维度做角度估计,这就进入了阵列信号处理的范畴。
雷达处理中有个东西很关键:CFAR检测。目标是否存在的判断不是简单超过阈值,而要结合周围噪声水平自适应调整阈值,否则虚警率会很高。做雷达实验时,窗函数也是常态,加窗可以抑制旁瓣,但会牺牲一点分辨率。这就是工程里的常态:每个参数都有代价。
4.3 音频信号处理:算法要懂“耳朵”的容忍度
音频信号处理包括降噪、回声消除、增益控制、音频编码等。和雷达、医学信号不太一样的是,音频最终是给人听的,所以算法的好坏很大程度上取决于人的听觉感受。心理声学里的掩蔽效应非常重要:一个频率上的强音可以掩盖邻近频率的弱音,所以降噪算法可以只在听觉上感知不到的区域做处理。
我在做音频降噪时,最常用的算法之一是谱减法。它先估计噪声谱,再从带噪信号谱中减去噪声谱。听起来很简单,但如果不加谱下限(spectral floor),结果会出现一种叫“音乐噪声”的伪迹,听着像流水声一样令人烦躁。
我踩过几次坑之后,总结出一个心得:音频降噪宁可保守一点,也不要追求“干净到诡异”的输出。因为人耳对残留噪声的适应能力其实很强,但讨厌骤变和人工伪迹。好的降噪应该让人感觉“背景安静了”,而不是“声音变形了”。
4.4 阵列信号处理:空间维度的信号增强与测向
阵列信号处理利用多个传感器在空间上的位置差异,把接收信号按方向区分开。波束形成本质上是一个空域滤波器,可以让阵列主瓣对准目标方向、把零陷对准干扰方向,从而提升信噪比。
更高阶的方向估计算法,比如MUSIC和ESPRIT,利用协方差矩阵的特征分解来分辨方向近似的信号源。MUSIC算法的核心步骤是:先估计接收信号的协方差矩阵,再做特征分解,把特征向量分成信号子空间和噪声子空间,最后在角度维度上搜索使方向向量与噪声子空间正交的峰值。
设计阵列时有一个重要原则:阵元间距通常要小于等于半波长。这可以理解为空间域的采样定理,间距太大就会出现栅瓣,就像时间域采样率不足会混叠一样。实际系统中,阵列通道之间的幅相误差也必须校正,否则再高分辨的算法也会失效。很多人以为MUSIC算法很“高级”,但在实际硬件上做时,最麻烦的往往不是算法本身,而是校准。
5. 实战篇:用一份可维护的目录来推动学习落地
说了这么多,最终还是要落到操作上。既然标题里写着“目录”,那我就分享一下我是怎么把目录变成学习工具,以及如何用一个小实验验证自己是否真的理解了这些概念。
5.1 搭建自己的Markdown学习目录(附模板)
我是那种离开笔记就不会学习的人。但我不太喜欢把所有内容堆在一个巨大的笔记里,而是用Markdown维护一棵目录树。每个模块一个文件,文件里记录三件事:核心概念、解决的实际问题、我踩过的坑。这样目录不只是清单,而是真的能用的“工程索引”。
下面是我常用的目录结构,你可以直接参考:
signal-processing/ ├── 00-math-basics.md ├── 01-fourier-z-transform/ │ ├── 01-1-fourier.md │ └── 01-2-z-transform.md ├── 02-filter-design/ │ ├── 02-1-fir-iir.md │ └── 02-2-window-method.md ├── 03-random-signal/ │ ├── 03-1-spectrum-estimation.md │ └── 03-2-kalman-filter.md ├── 04-applications/ │ ├── 04-1-ecg-ppg.md │ ├── 04-2-radar.md │ ├── 04-3-audio.md │ └── 04-4-array.md └── 05-experiments/ └── ecg-heart-rate.ipynb建目录的时候有个小技巧:文件命名前面加上数字序号,这样排序就是你的学习顺序。不要试图让目录一次到位,它应该随着你的学习不断调整。我经常翻旧文件,看到哪个知识点现在有了新的理解,就回头改一版,这个过程本身就是学习。
5.2 推荐书单与工具链(Oppenheim/Kay/SciPy/Matlab)
如果你不知道从哪里入手,我列一个最小书单,够用很久:
| 书名 | 定位 |
|---|---|
| Oppenheim《信号与系统》 | 连续与离散时间信号基础 |
| Oppenheim《离散时间信号处理》 | DFT、Z变换、滤波器设计的系统参考 |
| Kay《统计信号处理基础》 | 估计理论和检测理论入门 |
| Haykin《自适应滤波器原理》 | 自适应滤波的经典教材 |
工具方面,Python配合NumPy、SciPy、Matplotlib可以覆盖绝大多数学习实验。SciPy的signal模块里封装了滤波器设计、频谱估计、峰值检测等常用函数。Matlab的优势在于工具箱完善,尤其在做阵列信号处理和雷达仿真时,很多专门函数能帮你少写不少代码。
有人会问,用现成库算不算“偷懒”?我的观点是,学习阶段还是要把底层原理亲手推一遍,比如自己实现一个FFT或者一个LMS滤波器。但工程阶段,只要理解背后逻辑,用库反而更稳定。关键是别把库函数当成黑盒,至少你要知道‘改变这个参数会影响什么’。
5.3 一个入门级ECG信号处理小实验
与其一直看公式,不如跑一个最小实验。下面的代码生成一段带噪声的仿真ECG信号,用带通滤波器清除工频干扰和高频噪声,再通过峰值检测估计心率。它不长,但麻雀虽小五脏俱全。
import numpy as np from scipy import signal import matplotlib.pyplot as plt fs = 250 t = np.arange(0, 10, 1/fs) # 用高斯峰模拟QRS波群 ecg = np.zeros_like(t) for beat_start in range(0, 10): beat_time = beat_start * 0.8 idx = np.abs(t - beat_time) < 0.1 local_t = t[idx] - beat_time ecg[idx] += np.exp(-local_t**2 / (2 * 0.008**2)) \ - 0.5 * np.exp(-local_t**2 / (2 * 0.02**2)) # 加入工频噪声和白噪声 noise = 0.05 * np.random.randn(len(t)) powerline = 0.1 * np.sin(2 * np.pi * 50 * t) x = ecg + noise + powerline # 带通滤波,保留5~25Hz的QRS能量 b, a = signal.butter(2, [5, 25], btype='bandpass', fs=fs) y = signal.filtfilt(b, a, x) # R峰检测 peaks, _ = signal.find_peaks(y, distance=int(0.2 * fs), height=0.5) rr = np.diff(peaks) / fs heart_rate = 60 / np.mean(rr) print(f"Estimated HR: {heart_rate:.1f} bpm") plt.figure(figsize=(10, 4)) plt.plot(t, x, alpha=0.5, label='noisy') plt.plot(t, y, label='filtered') plt.plot(peaks / fs, y[peaks], 'x', label='peaks') plt.legend() plt.show()代码里有三个关键点。第一,我用了filtfilt而不是lfilter,这样能避免IIR滤波器带来的相位偏移。第二,find_peaks里的distance=0.2秒对应R峰之间最小间隔,防止将一个大R峰误检成两个。第三,带通范围选5-25Hz,是为了抑制基线漂移和部分肌电干扰,同时保留QRS波群的主要能量。
如果你自己跑这个实验,建议动手改几个参数:把滤波范围改成1-40Hz,或者把filtfilt换成lfilter,观察波形和心率估计值的变化。这种对比实验会让你很快建立起“参数敏感度”的直觉,比死记硬背公式有用得多。
5.4 信号处理中的常见坑与排查心得
最后分享几个高频问题的排查思路,这些都是我踩过坑之后总结的。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 频谱中出现不存在的低频分量 | 采样率不足,发生混叠 | 检查采样率是否足够,是否加抗混叠滤波 |
| 频谱峰周围有大量拖尾 | 频率泄漏 | 换窗函数,调整信号截断长度 |
| 滤波后QRS波群位置偏移 | IIR滤波器相位非线性 | 改用filtfilt,或者直接用FIR |
| 自适应滤波不收敛或发散 | 步长设置不当 | 改用NLMS,或归一化输入信号幅度 |
| 信号基线漂移严重 | 高通截止频率太低 | 适当提高高通频率,比如ECG选0.5-1Hz |
我排查问题的习惯是,不急着调算法,先把数据“看懂”。画原始波形、频谱、时频图,绝大部分问题在预处理阶段就能找到答案。比如看到ECG波形整体上下飘,你该想到的是基线漂移,而不是R峰检测算法不够高级。看到频谱里50Hz有尖峰,你该先做陷波或者带通滤波,而不是改检测阈值。很多时候,问题本身并不复杂,只是被噪声和干扰藏住了。
一个小技巧:当你觉得某个算法“玄学”时,把它换成最简单的替代方案,比如用固定阈值代替自适应阈值,看效果差多少。这样你能直观感受到复杂算法到底帮你解决了什么问题,而不是盲目堆模型。
6. 写在最后:我的一些真实体会
说实话,信号处理不是学完全部公式才会上手,而是边做边补目录。就像健身一样,今天为雷达测距补FFT,明天为ECG补滤波器设计,后天为PPG补自适应滤波,大后天为音频降噪补心理声学。目录的最大价值,不是让你一次性掌握所有内容,而是让你知道每一个新问题该挂在知识树的哪个枝干上。
到目前为止,我自己的笔记里已经有近千条信号处理相关的记录,很多都是从“项目标题”这样的目录延展出来的。那些最初看起来陌生的概念,比如MUSIC、CFAR、Welch等等,如今都成了工具箱里随手可用的工具。这个过程没有捷径,但目录能让你少走很多弯路。
如果你正准备开始学信号处理,我的建议是:先建一个属于自己的目录,哪怕一开始只有几行字,然后按最小实验驱动学习。遇到经典教材的习题,比如Kay第二章,不要急着找答案,亲自推一遍,远比看十遍答案有用。希望这份拆解能成为你目录里的第一块拼图。