Python/SciPy 的寻峰算法

新手上路,请多包涵

我可以通过找到一阶导数的零交叉点或其他东西来自己编写一些东西,但它似乎是一个足够常见的函数,可以包含在标准库中。有人知道吗?

我的特定应用程序是一个二维数组,但通常它会用于查找 FFT 等中的峰值。

具体来说,在这类问题中,有多个强峰,然后是许多较小的“峰”,这些峰是由噪声引起的,应该被忽略。这些只是例子;不是我的实际数据:

一维峰:

带峰值的 FFT 输出

二维峰:

带有圆形峰的氡变换输出

峰值查找算法会找到这些峰值的位置(而不仅仅是它们的值),并且理想情况下会找到真正的样本间峰值,而不仅仅是具有最大值的索引,可能使用 二次插值 或其他方法。

通常你只关心几个强峰,所以它们要么是因为它们高于某个阈值,要么是因为它们是有序列表的前 n 个 峰,按振幅排名。

正如我所说,我自己知道如何写这样的东西。我只是问是否有已知运行良好的预先存在的功能或包。

更新:

翻译了一个 MATLAB 脚本,它适用于一维情况,但可能会更好。

更新更新:

sixtenbe 为一维案例 创建了一个更好的版本

原文由 endolith 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.8k
2 个回答

顾名思义,函数 scipy.signal.find_peaks 对此很有用。 But it’s important to understand well its parameters width , threshold , distance and above all prominence to get a good peak extraction.

根据我的测试和文档, 突出 的概念是“有用的概念”,可以保留好的峰值,并丢弃嘈杂的峰值。

什么是 (地形)突出?它是 “从山顶下降到任何更高地形所需的最小高度” ,如下所示:

在此处输入图像描述

这个想法是:

突出度越高,峰值越“重要”。

测试:

在此处输入图像描述

我故意使用(嘈杂的)频率变化的正弦波,因为它显示出很多困难。我们可以看到 width 参数在这里不是很有用,因为如果你设置最小值 width 太高,那么它将无法跟踪高频中非常接近的峰值部分。如果您将 width 设置得太低,您将在信号的左侧部分出现许多不需要的峰值。与 distance 相同的问题。 threshold 只与直接邻居比较,在这里没有用。 prominence 是提供最佳解决方案的解决方案。请注意,您可以组合其中的许多参数!

代码:

 import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks

x = np.sin(2*np.pi*(2**np.linspace(2,10,1000))*np.arange(1000)/48000) + np.random.normal(0, 1, 1000) * 0.15
peaks, _ = find_peaks(x, distance=20)
peaks2, _ = find_peaks(x, prominence=1)      # BEST!
peaks3, _ = find_peaks(x, width=20)
peaks4, _ = find_peaks(x, threshold=0.4)     # Required vertical distance to its direct neighbouring samples, pretty useless
plt.subplot(2, 2, 1)
plt.plot(peaks, x[peaks], "xr"); plt.plot(x); plt.legend(['distance'])
plt.subplot(2, 2, 2)
plt.plot(peaks2, x[peaks2], "ob"); plt.plot(x); plt.legend(['prominence'])
plt.subplot(2, 2, 3)
plt.plot(peaks3, x[peaks3], "vg"); plt.plot(x); plt.legend(['width'])
plt.subplot(2, 2, 4)
plt.plot(peaks4, x[peaks4], "xk"); plt.plot(x); plt.legend(['threshold'])
plt.show()

原文由 Basj 发布,翻译遵循 CC BY-SA 4.0 许可协议

我正在研究一个类似的问题,我发现一些最好的参考来自化学(来自质谱数据中的峰值)。要全面了解峰值查找算法,请阅读 内容。这是我遇到过的最清晰的寻峰技术评论之一。 (小波最适合在嘈杂的数据中寻找此类峰值。)

看起来您的峰值清晰可见,没有隐藏在噪音中。在这种情况下,我建议使用平滑的 savtizky-golay 导数来找到峰值(如果你只是区分上面的数据,你会得到一堆误报。)。这是一种非常有效的技术并且很容易实现(您确实需要一个带有基本操作的矩阵类)。如果您只是找到第一个 SG 导数的零交叉,我想您会很高兴。

原文由 Paul 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏