scipy.signal.

find_peaks#

scipy.signal.find_peaks(x, height=None, threshold=None, distance=None, prominence=None, width=None, wlen=None, rel_height=0.5, plateau_size=None)[源代码][源代码]#

根据峰值属性在信号内寻找峰值。

此函数接受一个一维数组,并通过简单比较相邻值来找到所有局部最大值。可选地,可以通过指定峰值属性的条件来选择这些峰值的子集。

参数:
x序列

一个带有峰值的信号。

高度数字或 ndarray 或序列,可选

所需的山峰高度。可以是一个数字、None、与 x 匹配的数组或前者的两元素序列。第一个元素总是被解释为最小值,第二个元素(如果提供)则被解释为最大所需高度。

阈值数字或 ndarray 或序列,可选

所需的峰值阈值,即与其相邻样本的垂直距离。可以是一个数字、None、与 x 匹配的数组或前者的两元素序列。第一个元素总是被解释为最小阈值,第二个元素(如果提供)则被解释为最大所需阈值。

距离数字,可选

相邻峰值之间所需的最小水平距离(>= 1),以样本为单位。首先移除较小的峰值,直到所有剩余峰值都满足条件。

突出数字或 ndarray 或序列,可选

所需的峰突出度。可以是一个数字、None、与 x 匹配的数组或前者的2元素序列。第一个元素总是被解释为最小所需突出度,第二个元素(如果提供)则被解释为最大所需突出度。

宽度数字或 ndarray 或序列,可选

峰值所需的样本宽度。可以是一个数字、None、与 x 匹配的数组或前者的 2 元素序列。第一个元素总是被解释为最小宽度,第二个元素(如果提供)则被解释为最大所需宽度。

wlenint, 可选

用于计算峰的显著性,因此仅在给定参数 prominencewidth 时使用。有关其效果的完整描述,请参见 peak_prominences 中的参数 wlen

rel_heightfloat, 可选

用于计算峰宽,因此仅在给出 width 时使用。有关其效果的完整描述,请参见 peak_widths 中的参数 rel_height

plateau_size数字或 ndarray 或序列,可选

峰顶平坦部分在样本中的所需大小。可以是一个数字、None、与 x 匹配的数组或前述内容的 2 元素序列。第一个元素总是被解释为最小值,第二个元素(如果提供)则被解释为最大所需平台大小。

Added in version 1.2.0.

返回:
ndarray

满足所有给定条件的 x 中的峰值索引。

属性dict

包含返回峰值属性的字典,这些属性是在评估指定条件期间作为中间结果计算的:

  • ‘peak_heights’

    如果给出了 height,则为 x 中每个峰值的高度。

  • ‘left_thresholds’, ‘right_thresholds’

    如果给出了 threshold ,这些键包含一个峰值与其相邻样本之间的垂直距离。

  • ‘prominences’, ‘right_bases’, ‘left_bases’

    如果给出了 prominence,这些键是可访问的。有关其内容的描述,请参见 peak_prominences

  • ‘width_heights’, ‘left_ips’, ‘right_ips’

    如果给出了 width,这些键是可访问的。有关其内容的描述,请参见 peak_widths

  • ‘plateau_sizes’, ‘left_edges’, ‘right_edges’

    如果给出了 plateau_size,这些键是可访问的,并且包含一个峰值边缘的索引(边缘仍然是高原的一部分)以及计算出的高原大小。

    Added in version 1.2.0.

要计算并返回属性而不排除峰值,请将开区间 (None, None) 作为适当参数的值(不包括 distance)。

警告:
PeakPropertyWarning

如果一个峰的属性具有意外的值,则会引发此异常(参见 peak_prominencespeak_widths)。

警告

对于包含 NaN 的数据,此函数可能会返回意外结果。为了避免这种情况,应删除或替换 NaN。

参见

find_peaks_cwt

使用小波变换寻找峰值。

peak_prominences

直接计算山峰的突出度。

peak_widths

直接计算峰的宽度。

注释

在这个函数的上下文中,峰值或局部最大值被定义为任何其两个直接相邻样本的振幅较小的样本。对于平坦的峰值(宽度超过一个等振幅样本),返回中间样本的索引(如果样本数为偶数则向下取整)。对于噪声信号,峰值位置可能会有偏差,因为噪声可能会改变局部最大值的位置。在这种情况下,考虑在寻找峰值之前平滑信号,或者使用其他峰值查找和拟合方法(如 find_peaks_cwt)。

关于指定条件的其他注释:

  • 几乎所有条件(不包括 distance)都可以指定为半开区间或闭区间,例如,1(1, None) 定义了半开区间 \([1, \infty]\),而 (None, 1) 定义了区间 \([-\infty, 1]\)。开区间 (None, None) 也可以指定,这将返回匹配的属性而不排除峰值。

  • 边界总是包含在用于选择有效峰值的区间内。

  • 对于几种条件,区间边界可以用与 x 形状匹配的数组来指定,这使得可以根据样本位置动态设置约束。

  • 条件按以下顺序评估:plateau_sizeheightthresholddistanceprominencewidth。在大多数情况下,这个顺序是最快的,因为首先应用更快的操作来减少需要稍后评估的峰值数量。

  • 虽然 peaks 中的索引保证至少相隔 distance 个样本,但平坦峰值的边缘可能比允许的 distance 更接近。

  • 使用 wlen 来减少评估 prominencewidth 条件所需的时间,如果 x 很大或有很多局部最大值(参见 peak_prominences)。

Added in version 1.1.0.

示例

为了演示此功能的用法,我们使用 SciPy 提供的信号 x`(参见 `scipy.datasets.electrocardiogram)。让我们找出 x 中所有振幅高于 0 的峰值(局部最大值)。

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.datasets import electrocardiogram
>>> from scipy.signal import find_peaks
>>> x = electrocardiogram()[2000:4000]
>>> peaks, _ = find_peaks(x, height=0)
>>> plt.plot(x)
>>> plt.plot(peaks, x[peaks], "x")
>>> plt.plot(np.zeros_like(x), "--", color="gray")
>>> plt.show()
../../_images/scipy-signal-find_peaks-1_00_00.png

我们可以选择高度低于0的峰值,使用 height=(None, 0) 或者使用与 x 大小匹配的数组来反映信号不同部分的改变条件。

>>> border = np.sin(np.linspace(0, 3 * np.pi, x.size))
>>> peaks, _ = find_peaks(x, height=(-border, border))
>>> plt.plot(x)
>>> plt.plot(-border, "--", color="gray")
>>> plt.plot(border, ":", color="gray")
>>> plt.plot(peaks, x[peaks], "x")
>>> plt.show()
../../_images/scipy-signal-find_peaks-1_01_00.png

周期信号的另一个有用条件可以通过 distance 参数给出。在这种情况下,我们可以通过要求至少150个样本的距离,轻松选择心电图(ECG)中QRS复合波的位置。

>>> peaks, _ = find_peaks(x, distance=150)
>>> np.diff(peaks)
array([186, 180, 177, 171, 177, 169, 167, 164, 158, 162, 172])
>>> plt.plot(x)
>>> plt.plot(peaks, x[peaks], "x")
>>> plt.show()
../../_images/scipy-signal-find_peaks-1_02_00.png

特别是对于噪声信号,峰值可以通过它们的显著性轻松分组(参见 peak_prominences)。例如,我们可以通过将允许的显著性限制在0.6来选择所有峰值,除了提到的QRS复合波。

>>> peaks, properties = find_peaks(x, prominence=(None, 0.6))
>>> properties["prominences"].max()
0.5049999999999999
>>> plt.plot(x)
>>> plt.plot(peaks, x[peaks], "x")
>>> plt.show()
../../_images/scipy-signal-find_peaks-1_03_00.png

最后,让我们检查心电图的不同部分,其中包含不同形状的心跳形式。为了仅选择非典型的心跳,我们结合了两个条件:最小突出度为1,宽度至少为20个样本。

>>> x = electrocardiogram()[17000:18000]
>>> peaks, properties = find_peaks(x, prominence=1, width=20)
>>> properties["prominences"], properties["widths"]
(array([1.495, 2.3  ]), array([36.93773946, 39.32723577]))
>>> plt.plot(x)
>>> plt.plot(peaks, x[peaks], "x")
>>> plt.vlines(x=peaks, ymin=x[peaks] - properties["prominences"],
...            ymax = x[peaks], color = "C1")
>>> plt.hlines(y=properties["width_heights"], xmin=properties["left_ips"],
...            xmax=properties["right_ips"], color = "C1")
>>> plt.show()
../../_images/scipy-signal-find_peaks-1_04_00.png