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:信号和噪声一样强,基本没法用

实际计算时,怎么区分信号和噪声?

我常用的方法:

  1. 找一段只有噪声的片段(比如刺激前的基线)
  2. 找一段包含信号的片段(比如刺激后的响应)
  3. 分别计算功率,代入公式
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 本章知识体系

为了让你更直观地理解这些概念之间的关系,我画了一张图:

信号处理预备知识体系 神经信号处理 采样定理 傅里叶变换 滤波器 信噪比(SNR) 奈奎斯特频率 混叠效应 时域→频域 FFT实现 低通/高通/带通/带阻 零相位滤波(filtfilt) SNR = 10*log10(Ps/Pn) 信噪比增益 四大基石:采样→变换→滤波→评估

这张图把本章的知识体系串起来了。你看,从原始神经信号出发,先通过采样定理把它变成数字信号,再用傅里叶变换分析频率成分,然后用滤波器提取你想要的频段,最后用信噪比评估信号质量。每一步都环环相扣。

好了,这一章的内容就到这里。这些概念你可能一次记不住,没关系,后面每一章都会用到它们。等你做完几个项目,自然就熟了。

记住:信号处理不是目的,而是手段。我们的最终目标,是用深度学习从神经信号里挖掘出有价值的信息。打好这个基础,后面的路会顺畅很多。


公众号:蓝海资料掘金营,微信deep3321