我正在使用scipy peakfinder scipy.signal.find_peaks_cwt来查找信号中的峰值。可靠地找到所有峰值,但我总是得到额外的结果(到目前为止所有峰值都在信号的末尾),这些峰值不是峰值。我想知道为什么会这样......
以下是合成数据的完整示例:
from scipy.signal import find_peaks_cwt
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline # for jupyter notebooks
x = np.arange(0, 15, 0.1)
y = np.sin(x)
plt.plot(y)
peakinds = find_peaks_cwt(y, np.arange(1, 5))
plt.plot(peakinds, y[peakinds], 'o')
(要在普通的python shell中运行,请注释%matplotlib inline
并在末尾添加plt.show()
)
绘制标有点的峰:
(最后三个点不应该在那里)
凭借我的真实数据,同样的事情发生了:
(这里最后一个点错了)
为什么会这样?
答案 0 :(得分:2)
widths
中的find_peaks_cwt
参数是问题所在。
from scipy.signal import find_peaks_cwt
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 15, 0.1)
y = np.sin(x)
fig0 = plt.figure()
ax0 = fig0.add_subplot(111)
ax0.plot(y)
peakinds = find_peaks_cwt(y, np.arange(1, 10)) # Here changed 5 to 10
ax0.plot(peakinds, y[peakinds], 'o')
plt.axis([0, 160, -1.1, 1.1])
宽度:序列 用于计算CWT矩阵的1-D宽度数组。一般而言,该范围应涵盖目标峰的预期宽度。
修改强>
使用的默认小波是Ricker小波。基本上,在所有指定的widths
处通过调用ricker(width[i])
在信号和小波之间执行卷积。因此,您给出的范围必须从小(到精确定位峰值)到足够大(用于检测感兴趣的峰值)但不要太大(以避免混淆 - 让我们记住小波在频域工作)。
文档摘录:算法如下:1 - 对矢量执行连续小波变换,以获得所提供的宽度。这是矢量的卷积,其宽度为每个宽度的小波(宽度)。
如果您将widths
更改为np.arange(10, 20)
,您会发现已检测到峰值,但其最大值未得到很好的本地化(我们缺少精细比例)。如果您再次使用np.arange(1, 20)
,则可以更好地定位峰值。
另外,如果您想要显示ricker wavelet:
from scipy.signal import ricker
vec = ricker(100, 10) # (nb_of_points, frequency)
fig0 = plt.figure()
ax0 = fig0.add_subplot(111)
ax0.plot(vec)
编辑2:
至于在信号结束时错误检测到的额外峰值,这很可能是由于边界效应。基本上,卷积的窗口超出了信号的最后一个样本。通常,对信号进行填充(零填充,信号包装......),但是根据它的完成方式(或根本不进行),可能会发生这种错误。在使用这些类型的方法时,丢弃前几个和最后一个点通常是合适的。