3、信号处理预备知识:采样定理、傅里叶变换直观理解、滤波器基础概念、信噪比(SNR)计算
好,咱们正式开始啃信号处理这块硬骨头。
说实话,我当年刚接触神经信号时,也被这些概念绕得头晕。采样定理、傅里叶变换、滤波器……每个词都认识,连起来就不知道在说什么。后来做了几个项目,踩了不少坑,才慢慢摸到门道。
这一章,我就用最直白的方式,把这些基础概念给你讲透。你不需要成为信号处理专家,但得知道它们是怎么工作的——毕竟,深度学习模型处理的可都是数字信号,你不懂信号,怎么调模型?
本章核心目标:理解信号处理四大基石——采样定理、傅里叶变换、滤波器、信噪比。掌握它们的基本原理和实际应用场景,为后续深度学习模型处理神经信号打下基础。
3.1 采样定理:别让你的信号“失真”
先问个问题:为什么我们能把连续的脑电波变成电脑能处理的数字信号?
答案就是采样。但采样不是随便采的,有个铁律——奈奎斯特采样定理。
核心内容就一句话:采样频率必须大于信号最高频率的两倍。否则,信号就会“混叠”,也就是高频信号伪装成低频信号,你根本分不清。
举个例子。我做过一个EEG项目,采集的是40Hz的gamma波。当时图省事,用了80Hz采样率,刚好卡在边界上。结果分析时发现波形怪怪的,怎么调模型都不对。后来一查,原来是采样率不够,信号已经混叠了。换成100Hz后,问题立刻解决。
我的经验:实际工程中,采样率一般取信号最高频率的3-5倍。比如你要分析100Hz以内的信号,采样率至少300Hz。留点余量,别卡着边界走。
采样定理的数学表达很简单:
fs ≥ 2 * fmax
其中fs是采样频率,fmax是信号最高频率。
你想想看,如果采样率不够,会发生什么?
- 高频信号被“折叠”到低频区域
- 你看到的波形是假的
- 后续所有分析都是错的
避坑指南:我曾经在采集肌电信号时,因为采样率设置太低,把50Hz的工频干扰当成了有效信号,白白浪费了两周时间。记住:采样前先搞清楚信号的频率范围,再定采样率。
3.2 傅里叶变换:从时域到频域的“翻译器”
傅里叶变换,说白了就是把信号从时间域翻译到频率域。
为什么需要这个翻译?因为很多信号在时域里看着乱糟糟的,但到了频域就一目了然。比如脑电信号,你在时域里看到的是乱七八糟的波形,但用傅里叶变换一看,就能清楚看到alpha波(8-12Hz)、beta波(13-30Hz)的能量分布。
直观理解:傅里叶变换就像一台“频谱分析仪”,告诉你信号里包含哪些频率成分,每个成分的强度有多大。
数学上,连续傅里叶变换长这样:
X(f) = ∫ x(t) * e^(-j2πft) dt
但在实际工程中,我们用的是离散傅里叶变换(DFT),以及它的快速版本FFT。
Python里用FFT超级简单:
import numpy as np
import matplotlib.pyplot as plt
# 生成一个10Hz的正弦波
fs = 1000 # 采样率
t = np.arange(0, 1, 1/fs)
x = np.sin(2 * np.pi * 10 * t)
# 做FFT
X = np.fft.fft(x)
freqs = np.fft.fftfreq(len(x), 1/fs)
# 只取正频率部分
pos_mask = freqs >= 0
plt.plot(freqs[pos_mask], np.abs(X[pos_mask]))
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
这段代码会输出一个频谱图,在10Hz处有一个明显的峰值——那就是你的信号。
重要提醒:FFT的结果是复数,幅度用np.abs()取模,相位用np.angle()取角度。初学者最容易犯的错误是直接拿复数结果画图,画出来全是错的。
3.3 滤波器基础概念:让该过的过,该拦的拦
滤波器,顾名思义,就是过滤信号的“筛子”。
在神经信号处理中,滤波器太重要了。脑电信号里混着肌电噪声、工频干扰、眼动伪迹……你不滤波,模型根本没法用。
四种基本滤波器:
| 类型 | 作用 | 典型应用 |
|---|---|---|
| 低通滤波器 | 保留低频,滤除高频 | 去除肌电噪声(高频) |
| 高通滤波器 | 保留高频,滤除低频 | 去除基线漂移(低频) |
| 带通滤波器 | 保留特定频段 | 提取alpha波(8-12Hz) |
| 带阻滤波器 | 滤除特定频段 | 去除50Hz工频干扰 |
Python里用scipy做滤波器非常方便:
from scipy import signal
# 设计一个带通滤波器,保留8-12Hz
fs = 250 # 采样率
lowcut = 8.0
highcut = 12.0
# 巴特沃斯滤波器
b, a = signal.butter(4, [lowcut/(fs/2), highcut/(fs/2)], btype='band')
# 应用滤波器
filtered_signal = signal.filtfilt(b, a, raw_signal)
我的习惯:用filtfilt而不是lfilter。filtfilt是零相位滤波,不会引入相位偏移,对神经信号分析特别重要。lfilter会延迟信号,导致时间对齐出问题。
嗯,这里要注意:滤波器阶数越高,滤波效果越好,但计算量也越大,而且可能引入振铃效应。我一般用4阶巴特沃斯,平衡效果和效率。
3.4 信噪比(SNR)计算:你的信号到底有多“干净”?
信噪比,就是信号和噪声的功率比值。说白了,就是衡量你的信号质量好不好。
公式很简单:
SNR = 10 * log10(Psignal / Pnoise)
单位是dB。SNR越高,信号越干净。
举个例子:
- SNR = 20dB:信号功率是噪声的100倍,非常好
- SNR = 10dB:信号功率是噪声的10倍,还行
- SNR = 0dB:信号和噪声一样强,基本没法用
实际计算时,怎么区分信号和噪声?
我常用的方法:
- 找一段只有噪声的片段(比如刺激前的基线)
- 找一段包含信号的片段(比如刺激后的响应)
- 分别计算功率,代入公式
import numpy as np
def compute_snr(signal_segment, noise_segment):
"""
计算信噪比
signal_segment: 包含信号的片段
noise_segment: 纯噪声片段
"""
Psignal = np.var(signal_segment)
Pnoise = np.var(noise_segment)
if Pnoise == 0:
return float('inf')
snr = 10 * np.log10(Psignal / Pnoise)
return snr
# 使用示例
snr_value = compute_snr(signal_window, noise_window)
print(f"SNR = {snr_value:.2f} dB")
避坑指南:我曾经在计算SNR时,直接用整个信号段的方差当信号功率,忘了减去噪声功率。结果SNR虚高,模型训练时才发现数据质量其实很差。正确做法是:信号功率 = 总功率 - 噪声功率。
还有一个更实用的指标——信噪比增益。它衡量的是你的预处理流程(滤波、去伪迹等)到底提升了多少信号质量:
SNR_gain = SNR_after - SNR_before
如果增益是负的,说明你的预处理反而把信号搞坏了。我见过不少同学,滤波参数设错了,SNR反而下降。
3.5 本章知识体系
为了让你更直观地理解这些概念之间的关系,我画了一张图:
这张图把本章的知识体系串起来了。你看,从原始神经信号出发,先通过采样定理把它变成数字信号,再用傅里叶变换分析频率成分,然后用滤波器提取你想要的频段,最后用信噪比评估信号质量。每一步都环环相扣。
好了,这一章的内容就到这里。这些概念你可能一次记不住,没关系,后面每一章都会用到它们。等你做完几个项目,自然就熟了。
记住:信号处理不是目的,而是手段。我们的最终目标,是用深度学习从神经信号里挖掘出有价值的信息。打好这个基础,后面的路会顺畅很多。
公众号:蓝海资料掘金营,微信deep3321