☰
信号处理核心概念解析:自相关、互相关、卷积与相干性
2026/10/5 12:32:26 网站建设 项目流程

做信号处理这些年,被问得最多的一个问题不是“FFT怎么实现”,而是“两个信号到底像不像”。你要是查资料,会发现答案一会儿是相关性,一会儿是相干性,中间还夹着一个怎么都绕不开的卷积。自相关、互相关、卷积、相关性、相干性,五个词长得像亲戚,实际的关系却经常让人一脸懵。这篇东西我想用一个工程师的习惯,把这几个概念摆在一起讲清楚:它们分别是干什么的,公式怎么来的,实际操作中怎么用,以及我踩过哪些坑。

不管你是刚接触信号处理的学生,还是在用Python做数据分析、跑深度学习时遇到卷积和相关的名词,这篇文章都适用。我会尽量避开教科书式的推导,用“生活类比 + 代码示例 + 踩坑记录”的组合,把这块硬骨头啃下来。

1. 从“像不像”到“有多像”:相关性到底在算什么

1.1 皮尔逊相关系数:用一条直线解释所有相似

先看最简单的场景。两个数组 x 和 y,长度都是 N,你想知道它们之间有没有线性关系。最常用的就是皮尔逊相关系数 r:

r = Σ(x_i - x̄)(y_i - ȳ) / sqrt(Σ(x_i - x̄)² · Σ(y_i - ȳ)²)

这个公式干的事情,就是先分别把两个序列减去各自的均值,让它们都变成“零均值”序列,然后算两个零均值序列的“内积”,再除以各自能量的乘积开根号。最终结果被限制在 [-1, 1] 之间。

r=1 表示完全正线性相关,r=-1 表示完全负线性相关,r=0 表示没有线性相关。这句“没有线性相关”很关键,因为两个变量完全可能是非线性关系,比如正弦和它的平方,r 可能算出来很小,但它们显然有关。

实际操作中,很多人直接拿原始数据算 r,忘了先去均值。虽然公式里已经减了均值,但如果你在写代码时用 np.corrcoef 就会自动去均值,可一旦你手写公式或者用互相关函数去模拟相关系数,就很容易漏掉这一步。我见过不少人用 np.correlate(x, y, mode='valid') 算出来一个巨大的数值,然后直接当相关系数解读,这就是没做零均值和归一化导致的结果。

1.2 相关性和“相干性”别急着混为一谈

第一次接触“相干性”这个词,我以为是相关性的高级叫法。后来做振动台数据分析时才明白,相关性和相干性虽然中文只差两个字,管的东西完全不同。

相关性是在时域或样本空间里,两个序列整体的线性关联强度。它给你的是一个“总账”:这两个信号,在整个时间范围内,整体上是不是一起变化。

相干性则是在频域里,两个信号在每个频率分量上的线性关联强度。它给你的是“明细账”:在 20Hz 这个频率上,这两个信号的线性关系有多强;在 40Hz 上,可能完全没关系。

如果你把两个信号想象成两个乐队,相关性回答的是“这两个乐队整场演出的节奏是不是同步”,相干性回答的是“吉他手在哪个频段上跟鼓手配合得最默契”。一个是总体,一个是分布。这个区分在工程应用里非常重要,尤其是在故障诊断、脑电信号分析、声学测量这些场合,只看总账会漏掉太多信息。

2. 自相关:让信号和过去的自己对话

2.1 自相关函数怎么计算

自相关函数描述的是一个信号与它自身在不同延迟时刻的相似程度。对于离散序列 x[n],自相关的定义是:

Rxx[m] = Σ_n x[n] · x[n - m]

这里的 m 就是延迟量,通常叫 lag。如果 m=0,那就是信号和自身完全不延迟地相乘求和,结果就是信号的能量。如果 m 不等于 0,就是在问“我把信号往左挪了 m 个点,它和自己原来的形态还有多像”。

在 Python 里,通常用 np.correlate 一步到位:

import numpy as np import matplotlib.pyplot as plt fs = 1000 t = np.arange(0, 1, 1/fs) # 10Hz正弦 + 噪声 x = np.sin(2 * np.pi * 10 * t) + 0.5 * np.random.randn(len(t)) # 自相关前先去均值 x = x - np.mean(x) rxx = np.correlate(x, x, mode='full') lags = np.arange(-(len(x) - 1), len(x)) plt.figure(figsize=(10, 4)) plt.plot(lags, rxx) plt.xlabel('lag (samples)') plt.ylabel('Rxx') plt.title('Autocorrelation') plt.grid(True) plt.show()

注意,mode='full' 返回的长度是 2N-1,对应的 lag 范围是 -(N-1) 到 N-1。这样做的好处是能同时看到正延迟和负延迟。如果你只需要单边信息,可以取 lags >= 0 的部分。

2.2 用自相关看周期:顺手就检测出隐藏的规律

自相关最经典的用途是检测周期性。假设信号是一个纯正弦,那么自相关函数会是一个同周期的余弦函数,在 lag 等于信号周期的整数倍时出现峰值。如果信号里混着噪声,噪声的自相关在非零延迟处会迅速衰减到 0,而周期成分的自相关却会一直保持峰值。这就是为什么自相关能从强噪声里把微弱周期信号“扒”出来。

拿上面那个例子,10Hz 正弦,采样率 1000Hz,一个周期是 100 个采样点。算完自相关后,你会在 lag=100、200、300……处看到明显的峰值。哪怕信噪比很低,这些峰值依然清晰。实际做振动诊断和转速测量时,这个方法非常常用,不需要做复杂的频谱分析,看一眼自相关就能知道大致周期。

要注意的是,如果信号本身不是平稳信号,比如带有明显趋势或缓慢漂移,直接做自相关会被趋势项干扰。我的习惯是先做去趋势,再用自相关分析周期。

2.3 自相关和功率谱:维纳-辛钦定理的实用意义

自相关和功率谱密度是一对傅里叶变换对,这就是维纳-辛钦定理。中文说得很绕,但实际含义非常实用:一个信号的自相关函数做傅里叶变换,就得到它的功率谱密度;反过来,功率谱密度做逆傅里叶变换,也能得到自相关函数。

这意味着,如果你想用 FFT 快速计算自相关,不需要真的去循环卷积。可以这样做:

n = len(x) Xf = np.fft.rfft(x, n=2*n) # 补零到2N,避免循环卷积 psd = np.abs(Xf) ** 2 rxx_fft = np.fft.irfft(psd, n=2*n)

补零是必须的,因为 FFT 本身会带来循环卷积效应,不补零的话,自相关的后半部分会叠加尾部的值。这个技巧在长信号分析里能省下大量时间,而且 FFT 方法比直接时域卷积快得多。

3. 互相关:两个信号的时差定位器

3.1 互相关的计算与归一化

互相关和自相关几乎一样,区别是它比较的是两个不同信号。定义是:

Rxy[m] = Σ_n x[n] · y[n - m]

它回答的问题是:当我让 y 信号相对于 x 延迟 m 个点后,两个信号的相似度有多高。互相关最常见的应用就是时延估计,也就是找出两个传感器接收到同一个信号的时间差。

裸算出来的 Rxy 是未归一化的,它的大小同时受到两个信号能量影响。如果想要一个类似于相关系数那样的值,需要做归一化,变成:

ρxy[m] = Rxy[m] / sqrt(Rxx[0] · Ryy[0])

这样得到的结果在 [-1, 1] 之间。不过实际做时延估计时,我们通常不关心这个归一化值,只关心 Rxy 峰值位置对应的 lag。

3.2 实操案例:用互相关测两个麦克风的时延

假设有两个麦克风,放在不同位置录制同一个声源。声源到两个麦克风的距离不同,所以两个信号之间存在一个时间延迟 τ。用互相关就能估计这个 τ。

我写一个最小例子:

import numpy as np fs = 16000 t = np.arange(0, 0.1, 1/fs) # 一个400Hz的短音 signal = np.sin(2 * np.pi * 400 * t) * np.exp(-50 * t) # 模拟第二个麦克风比第一个晚接收到100个采样点 delay = 100 y = np.concatenate([np.zeros(delay), signal])[:len(t)] # 去均值 x = signal - np.mean(signal) y = y - np.mean(y) # 互相关 corr = np.correlate(x, y, mode='full') lags = np.arange(-(len(x) - 1), len(x)) # 峰值对应的lag est_delay = lags[np.argmax(corr)] print(f"真实延迟: {delay} 采样点,估计延迟: {est_delay} 采样点")

这里 mode='full' 很关键,因为 y 比 x 延迟了 100 个点,互相关的峰值会出现在正 lag 方向。如果 mode='same',输出长度虽然和输入一样,但 lag 坐标不是从 -(N-1) 开始,很容易搞错索引。我一般在做互相关时都默认用 mode='full',再用 lags 数组去对应。

延迟时间就是 est_delay / fs。如果两个麦克风之间的距离已知,还能进一步算出声源的方向,这就是声阵列定位的基础原理。

3.3 互相关峰值不是越高越好:注意边界和噪声

很多人第一次做互相关,看到峰值很高就欢呼“找到时延了”。实际上,互相关峰值的高度受信号能量影响很大,两个不同幅度的信号之间的互相关峰值可能非常高,但线性关系却没那么强。如果只做时延估计,峰值高度其实不重要,重要的是峰值位置。

另外一个容易忽略的问题是窄带信号。如果信号是单一频率的正弦波,互相关会呈现出周期性振荡,峰值不止一个,而是每隔一个周期出现一个峰。这时你直接取全局最大,很可能取到某个假的周期峰。解决办法是先对信号做包络解调,或者用广义互相关(GCC-PHAT)对频谱进行白化,让尖峰更尖锐。

边界效应也很讨厌。截断信号的边缘会造成不真实的低相关性,尤其在 lag 很大的时候,重叠的有效数据变少,估计方差变大。我的习惯是只在 lag 绝对值不超过信号长度的三分之一时取峰值,这样可以避开大部分边界误差。

4. 卷积与相关:一对被名字误导的亲戚

4.1 卷积的本质:翻转、滑动、相乘、求和

卷积在信号处理里的定义是:

y(t) = ∫ x(τ) h(t - τ) dτ

换成离散形式就是:

y[n] = Σ_k x[k] · h[n - k]

它的操作可以拆成四步:翻转、滑动、相乘、求和。h 必须先沿纵轴翻转成 h[-k],然后跟 x 对齐,从负无穷滑到正无穷,每一步做逐点相乘再累加。

为什么要翻转?因为卷积描述的是系统对输入的因果响应。h 可以理解为系统的脉冲响应,翻转保证了“过去的输入影响现在的输出,而不是未来的输入影响现在的输出”。这和你做相关时的操作有本质区别。

生活化类比:卷积就像工厂流水线,每个产品经过多个工位,每个工位的加工效果叠加在一起;而“相关”更像两个人做手势猜谜,不翻转任何一方,只看当前动作和另一个动作像不像。

4.2 相关与卷积的数学换算:一句话记牢

互相关和卷积的关系,可以用一句话记牢:互相关等于把其中一个信号时间反转后,再与另一个信号做卷积。

公式是这样的:

Rxy[m] = Σ_n x[n] · y[n - m]

令 k = n - m,则 n = k + m,代入可得:

Rxy[m] = Σ_k x[k + m] · y[k] = Σ_k x[-(-k - m)]? 写起来绕。

更直接的是用符号表示:

Rxy[m] = (x[-n] * y[n])[m]

也就是说,把 x 的时域序列绕原点反转,变成 x[-n],再跟 y 做卷积,得到的结果就是互相关。如果你只有卷积函数,没有相关函数,就用这个等式来算相关。反过来,如果你只有相关函数,也可以用相关实现卷积:把 y 反转后做互相关,再反转结果。

我在代码里这样做过多次,尤其在嵌入式平台上没有现成相关函数时,直接用 FFT 卷积来实现互相关,速度很快。

4.3 顺带聊聊CNN里的“卷积”其实是相关

既然提到卷积,就不得不说说卷积神经网络(CNN)里的“卷积层”。很多做深度学习的人第一次接触信号处理里的卷积,会疑惑:深度学习框架里的卷积怎么不翻转卷积核?

事实是:CNN 里的卷积层严格说应该叫“互相关层”。它做的事情就是把卷积核和输入图像的区域做点积,这个操作没有翻转卷积核。所以从数学定义看,CNN 卷积核和图像块计算的是互相关,而不是经典卷积。

这个区别在工程上影响不大,因为网络可以通过学习自动适应是否翻转;但对理解公式的人来说,这是个值得知道的坑。如果你用信号处理的眼光去看 CNN,很多操作就变得亲切了:转置卷积、膨胀卷积、深度可分离卷积,本质都是在“相关/卷积”这个框架上做变形。

5. 相干性:频域里的相关系数

5.1 从自功率谱到相干函数:公式与直觉

相干性(Coherence)的定义是幅值平方相干函数:

Cxy(f) = |Sxy(f)|² / (Sxx(f) · Syy(f))

其中 Sxx(f) 是 x 的自功率谱密度,Syy(f) 是 y 的自功率谱密度,Sxy(f) 是 x 和 y 的互功率谱密度。结果是一个关于频率 f 的函数,取值范围在 0 到 1 之间。

直觉上,可以把它理解为“在频率 f 处,y 的功率有多少比例是由 x 的线性变换贡献的”。如果两个信号在某个频率上完全同步变化,只是幅度和相位有差异,相干性就接近 1;如果它们在该频率上的分量是独立的,相干性接近 0。

一个典型的例子:x 是电机振动信号,y 是电机附近的噪声信号。如果电机以 50Hz 旋转,那么 x 和 y 在 50Hz 处都会出现较强的频率成分,但除了 50Hz,y 可能还有大量气流噪声。这时候看相干谱,50Hz 处会出现一个尖峰,说明两者在这个频率上有共同的振源。这就是相干分析在故障诊断里的核心用途。

5.2 相干性估计的实操要点:加窗、分段、平均

相干性估计最容易犯的错误是:只用一段数据算功率谱,然后套公式,结果会发现所有频率的相干性都等于 1。这不是真实结果,而是数学恒等式在作怪——单段数据的互功率谱和自功率谱之间存在固有的代数关系,直接除必然得到 1。

要得到有意义的相干估计,必须做分段平均,也就是 Welch 方法。把信号分成若干小段,每段加窗(常用汉宁窗),分别计算功率谱,然后对多段的功率谱取平均,最后再用平均后的 Sxx、Syy、Sxy 求相干。分段的数目越多,相干估计的方差越低,但频率分辨率会下降。

我常用的参数是:

from scipy.signal import coherence import numpy as np fs = 1000 t = np.arange(0, 10, 1/fs) x = np.sin(2 * np.pi * 20 * t) + 0.3 * np.random.randn(len(t)) y = np.sin(2 * np.pi * 20 * t + 0.5) + 0.5 * np.random.randn(len(t)) f, Cxy = coherence(x, y, fs=fs, nperseg=1024, noverlap=512, window='hann')

nperseg 是每段长度,noverlap 是重叠采样数。我一般会保证至少有 8 到 16 段做平均,这样相干谱才比较稳定。如果分段太少,相干值会普遍偏高,看上去像噪声也有很强的相干。

5.3 相干谱读法:一个实际例子

还是用上面那个代码,x 和 y 都包含 20Hz 的正弦分量,但各自混入不同噪声。算出来的相干谱在 20Hz 处会有一个明显的峰值,接近 1,其他频率则比较低。这就是想要的结果:两个信号在 20Hz 存在强线性关系,其他频率没有关系。

读相干谱时还要注意一个坑:峰值宽度。峰值越尖锐,说明两个信号共同成分的频率越稳定;如果峰值宽而起伏,可能是信号频率漂移,也可能是分段长度太短导致频率分辨率不足。

如果相干谱整体都很高,比如达到 0.8 以上,那要先检查是不是两个信号本身是同一个源的不同幅度版本,或者是不是数据分段数太少。如果整体都很低,但你知道它们应该有某个频率的联系,可以适当增大 nperseg 提高频率分辨率,再看对应频率附近有没有尖峰。

6. 常见问题与排查技巧:那些年我踩过的坑

6.1 相关值异常高?先查数据是否去均值

这是一个极其常见的坑。两个完全无关的序列,如果都带有缓慢上升趋势,直接用皮尔逊相关算出来的系数可能接近 1。原因很简单:趋势项在协方差计算中占据了主导地位,掩盖了随机部分的真实关系。

处理方法是先对数据去均值,再做一次线性去趋势,通常用 np.polyfit 拟合一次项后减掉拟合线。更严格的做法是,如果你关心的是高频成分的相关性,可以再做一个高通滤波。在我做振动台数据分析时,这个习惯救了我很多次。

6.2 互相关峰值找错?小心周期信号和边界效应

周期信号互相关会出现多个等间隔的峰值,这时全局最大不一定代表真实时延。比如两个麦克风接收同一个正弦声源,由于信号是周期的,互相关峰在每个周期处都会出现,而真实时延对应的峰不一定就是最高的那个。

我的解决方案是结合信号包络再做互相关,而不是直接用原始信号。先取信号的包络(用希尔伯特变换求解析信号的幅值),再对包络做互相关,包络是缓慢变化的,不会产生周期性的假峰。另外,在时延估计之前先检查信号的频谱,如果频谱是窄带的,就要对 GCC-PHAT 这类加权方法多一点了解。

6.3 相干谱全是1?平均次数不够

看到相干谱全为 1,第一个反应不是数据有问题,而是估计方法有问题。分段数太少甚至单段,必然导致近似 1 的相干值。解决方法是减小 nperseg 以增加段数,或者增大 noverlap 增加重叠率。

不过,nperseg 也不能无限减小,因为分段越短,频率分辨率越差。如果信号频率相近,比如 49Hz 和 51Hz,nperseg 太短就分不开这两个峰。所以在使用 Welch 相关估计前,先想清楚你的频率分辨率需求。经验值是让每段时长至少包含 10 个目标频率周期。

6.4 自相关、互相关、卷积、相干:一张速查表

名称域核心定义(实信号)典型用途常见坑
自相关时域Rxx[m] = Σ x[n]x[n-m]检测周期、估计频谱未去均值/趋势项干扰
互相关时域Rxy[m] = Σ x[n]y[n-m]时延估计、信号匹配周期信号多峰、边界效应
卷积时域y[n] = Σ x[k]h[n-k]线性系统响应、滤波容易和相关混淆
相干性频域Cxy(f)=Sxy(f)²/(SxxSyy)
皮尔逊相关样本空间r = cov(x,y)/(σxσy)线性关联总览虚假相关、非线性关系

我在实际处理数据时,通常会先问自己三个问题:这个问题关心的是整体关系还是频率分布?关心的是时延还是相似度?数据是不是平稳的?这三个问题基本能决定应该用哪个工具,而不是哪个公式好看用哪个。

我记得自己最早做振动台数据分析时,就是把自相关和互相关当成同一个东西,结果花了两天时间才找到问题出在没去均值。后来养成一个习惯:凡是算相关,第一步永远先画时域图,看均值、趋势和边缘是否异常;第二步才套公式。这个习惯帮我躲过了无数个“看似正确”的坑。如果你也想把这几个概念印在脑子里,可以把速查表存下来,下次遇到相关、相干、卷积中的任何一个,先问自己一句:现在这个场景,我需要的是总账、明细账,还是翻转滑动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询