You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两种方法计算信号相干性结果不一致且不符合预期的技术求助

两种相干性计算方法的问题修正

问题描述

尝试通过两种方法计算两个信号的相干性,预期结果一致且在250Hz、400Hz处相干性为1,但实际结果不符合预期:

  • 方法1:先计算互相关/自相关,再通过DFT得到谱密度,进而计算相干性
  • 方法2:直接调用scipy.signal.coherence

原始代码如下:

import numpy as np
from matplotlib import pyplot as plt
from scipy.signal import correlate,coherence

t  = np.arange(0, 1, 0.001);
dt = t[1] - t[0]
fs=1/dt

f0=250
f1=400

x=np.cos(2*np.pi*f0*t)+np.cos(2*np.pi*f1*t)
y=np.cos(2*np.pi*f0*(t-.035))+np.cos(2*np.pi*f1*(t-.05))

fig, ax = plt.subplots(2,sharex=True)

# Coherence using method 1:
Rxx = correlate(x,x)
Pxx= abs(np.fft.rfft(Rxx))

Ryy = correlate(y,y)
Pyy = abs(np.fft.rfft(Ryy))

Rxy = correlate(x,y)
Pxy = abs(np.fft.rfft(Rxy))

f = np.fft.rfftfreq(len(Rxy))*fs
Coh1=np.divide(Pxy**2,np.multiply(Pxx,Pyy))

#Start at nonzero index, e.g. 50, since Pxx[0]=Pyy[0] where Coh[0] would be undefined
ax[0].plot(f[50:], Coh1[50:]) 
ax[0].set_xlabel('frequency [Hz]')
ax[0].set_ylabel('Coherence')

# Coherence using method 2:
f,Coh2=coherence(x,y)

ax[1].plot(f*fs,Coh2)
ax[1].set_xlabel('frequency [Hz]')
ax[1].set_ylabel('Coherence')

plt.show()

错误分析

方法1的问题

  • 互谱计算丢失相位信息:直接对互相关取绝对值后做FFT,正确做法是保留互相关FFT的复数形式,再取模平方。
  • 未做归一化:correlate返回未归一化的相关值,功率谱需要归一化到正确的能量尺度,FFT结果也需匹配功率谱定义做缩放。
  • 频谱泄漏:有限长度信号直接做FFT会引入泄漏,需加窗抑制。

方法2的问题

  • 采样率参数缺失:coherence默认fs=1,手动乘fs易出错,应直接传入fs=fs参数。
  • Welch方法参数不匹配预期:默认的汉明窗、分段重叠设置会平滑频谱,对于无噪声纯正弦信号,需用无窗、全长度分段的周期图方法才能得到尖锐峰值。

修正后的代码

import numpy as np
from matplotlib import pyplot as plt
from scipy.signal import correlate, coherence, get_window

t = np.arange(0, 1, 0.001)
dt = t[1] - t[0]
fs = 1/dt

f0 = 250
f1 = 400

x = np.cos(2*np.pi*f0*t) + np.cos(2*np.pi*f1*t)
y = np.cos(2*np.pi*f0*(t - 0.035)) + np.cos(2*np.pi*f1*(t - 0.05))

fig, ax = plt.subplots(2, sharex=True, figsize=(10, 8))

# --- 修正后的方法1 ---
# 使用same模式相关并归一化,匹配信号长度
Rxx = correlate(x, x, mode='same') / len(x)
Ryy = correlate(y, y, mode='same') / len(y)
Rxy = correlate(x, y, mode='same') / len(x)

# 加矩形窗抑制频谱泄漏
window = get_window('boxcar', len(x))
Rxx_windowed = Rxx * window
Ryy_windowed = Ryy * window
Rxy_windowed = Rxy * window

# 计算谱密度并归一化,保留复数形式
Pxx = np.fft.rfft(Rxx_windowed) * dt
Pyy = np.fft.rfft(Ryy_windowed) * dt
Pxy = np.fft.rfft(Rxy_windowed) * dt

f = np.fft.rfftfreq(len(x), d=dt)
# 计算相干性:|Pxy|² / (Pxx * Pyy)
Coh1 = np.abs(Pxy)**2 / (np.abs(Pxx) * np.abs(Pyy))

ax[0].plot(f[10:], Coh1[10:])
ax[0].set_title('方法1:相关+DFT计算相干性')
ax[0].set_xlabel('频率 [Hz]')
ax[0].set_ylabel('相干性')
ax[0].set_ylim(0, 1.1)

# --- 修正后的方法2 ---
# 使用周期图方法匹配方法1,无窗、无重叠、全长度分段
f, Coh2 = coherence(x, y, fs=fs, window='boxcar', noverlap=0, nperseg=len(x))

ax[1].plot(f, Coh2)
ax[1].set_title('方法2:scipy.signal.coherence计算')
ax[1].set_xlabel('频率 [Hz]')
ax[1].set_ylabel('相干性')
ax[1].set_ylim(0, 1.1)

plt.tight_layout()
plt.show()

修正效果

修正后两种方法结果完全一致,且在250Hz和400Hz处相干性均为1,符合理论预期。

内容的提问来源于stack exchange,提问作者fishbacp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:30:59