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)[source]#

根據峰值屬性在訊號中尋找峰值。

此函數接受一維陣列,並透過簡單比較相鄰值來尋找所有局部最大值。選擇性地,可以透過指定峰值屬性的條件來選擇這些峰值的子集。

參數:
x序列

具有峰值的訊號。

height數字或 ndarray 或序列,選填

峰值的必要高度。可以是數字、None、與 x 相符的陣列,或是前述項目的 2 元素序列。第一個元素始終被解釋為最小必要高度,而第二個元素(如果提供)則為最大必要高度。

threshold數字或 ndarray 或序列,選填

峰值的必要閾值,即與相鄰樣本的垂直距離。可以是數字、None、與 x 相符的陣列,或是前述項目的 2 元素序列。第一個元素始終被解釋為最小必要閾值,而第二個元素(如果提供)則為最大必要閾值。

distance數字,選填

相鄰峰值之間樣本的必要最小水平距離(>= 1)。較小的峰值會先被移除,直到所有剩餘峰值都滿足條件為止。

prominence數字或 ndarray 或序列,選填

峰值的必要顯著性。可以是數字、None、與 x 相符的陣列,或是前述項目的 2 元素序列。第一個元素始終被解釋為最小必要顯著性,而第二個元素(如果提供)則為最大必要顯著性。

width數字或 ndarray 或序列,選填

峰值在樣本中的必要寬度。可以是數字、None、與 x 相符的陣列,或是前述項目的 2 元素序列。第一個元素始終被解釋為最小必要寬度,而第二個元素(如果提供)則為最大必要寬度。

wlen整數,選填

用於計算峰值顯著性,因此僅當給定參數 prominencewidth 之一時才使用。請參閱 peak_prominences 中的參數 wlen,以取得其效果的完整描述。

rel_height浮點數,選填

用於計算峰值寬度,因此僅當給定 width 時才使用。請參閱 peak_widths 中的參數 rel_height,以取得其效果的完整描述。

plateau_size數字或 ndarray 或序列,選填

峰值平坦頂部的必要大小,以樣本為單位。可以是數字、None、與 x 相符的陣列,或是前述項目的 2 元素序列。第一個元素始終被解釋為最小必要平坦區大小,而第二個元素(如果提供)則為最大必要平坦區大小。

在 1.2.0 版本中新增。

回傳:
peaksndarray

滿足所有給定條件的 x 中峰值的索引。

properties字典

包含回傳峰值屬性的字典,這些屬性是在評估指定條件期間作為中間結果計算的

  • ‘peak_heights’

    如果給定 height,則為 x 中每個峰值的高度。

  • ‘left_thresholds’, ‘right_thresholds’

    如果給定 threshold,這些鍵包含峰值到其相鄰樣本的垂直距離。

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

    如果給定 prominence,則可以存取這些鍵。請參閱 peak_prominences 以取得其內容的描述。

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

    如果給定 width,則可以存取這些鍵。請參閱 peak_widths 以取得其內容的描述。

  • ‘plateau_sizes’, left_edges’, ‘right_edges’

    如果給定 plateau_size,則可以存取這些鍵,並且包含峰值邊緣的索引(邊緣仍然是平坦區的一部分)以及計算出的平坦區大小。

    在 1.2.0 版本中新增。

若要在不排除峰值的情況下計算並回傳屬性,請將開區間 (None, None) 作為值提供給適當的參數(不包括 distance)。

警告:
PeakPropertyWarning

如果峰值的屬性具有非預期的值時引發(請參閱 peak_prominencespeak_widths)。

Warning

此函數對於包含 NaNs 的資料可能會回傳非預期的結果。為了避免這種情況,應移除或替換 NaNs。

另請參閱

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 更接近。

  • 如果 x 很大或有很多局部最大值,請使用 wlen 來減少評估 prominencewidth 條件所需的時間(請參閱 peak_prominences)。

在 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

我們可以使用 height=(None, 0) 選擇低於 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 參數給定。在這種情況下,我們可以輕鬆地選擇心電圖 (ECG) 中 QRS 波群的位置,方法是要求至少 150 個樣本的距離。

>>> 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

最後,讓我們檢查 ECG 的另一個區段,其中包含不同形狀的搏動形式。為了僅選擇非典型心跳,我們結合了兩個條件:最小顯著性為 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