Python中的峰值检测算法

时间:2018-06-08 08:49:19

标签: python function detection detect

我在Python中实现了一个峰值检测算法,只检测那些高于阈值幅度的峰值。我不想使用内置函数,因为我必须将此模拟扩展到硬件实现。

from math import sin,isnan
from pylab import *

def peakdet(v, delta,thresh,x):
    delta=abs(delta)
    maxtab = []
    mintab = []

    v = asarray(v)

    mn, mx = v[0], v[0]
    mnpos, mxpos = NaN, NaN

    lookformax = True

    for i in arange(len(v)):
        this = v[i]
        if abs(this)>thresh:
            if this > mx:
                mx = this
                mxpos = x[i]
            if this < mn:
                mn = this
                mnpos = x[i]
            if lookformax:
                if (this < mx-delta):
                    if (mx>abs(thresh)) and not isnan(mxpos):
                        maxtab.append((mxpos, mx))
                    mn = this
                    mnpos = x[i]
                    lookformax = False
            else:
                if (this > mn+delta):
                    if (mn<-abs(thresh)) and not isnan(mnpos):
                        mintab.append((mnpos, mn))
                    mx = this
                    mxpos = x[i]
                    lookformax = True
    return array(maxtab), array(mintab)

#Input Signal
t=array(range(100))
series=0.3*sin(t)+0.7*cos(2*t)-0.5*sin(1.2*t)

thresh=0.95 #Threshold value
delta=0.0 #

a=zeros(len(t)) #
a[:]=thresh #

maxtab, mintab = peakdet(series,delta,thresh,t)

#Plotting output
scatter(array(maxtab)[:,0], array(maxtab)[:,1], color='red')
scatter(array(mintab)[:,0], array(mintab)[:,1], color='blue')
xlim([0,t[-1]])
title('Peak Detector')
grid(True)
plot(t,a,color='green',linestyle='--',dashes=(5,3))
plot(t,-a,color='green',linestyle='--',dashes=(5,3))
annotate('Threshold',xy=(t[-1],thresh),fontsize=9)
plot(t,series,'k')
show()

该程序的问题在于即使它们高于阈值也无法检测到某些峰值。 这是我得到的输出:

Peak Detection Output

我看到其他帖子有峰值检测问题,但无法找到任何解决方案。请帮助并建议更正。

4 个答案:

答案 0 :(得分:1)

你的功能使用了很多参数。您可以将问题分解为几个步骤:

  1. 首先检测高于阈值的所有点。将这些积分添加到maxthreshminthresh列表。
  2. 遍历maxthresh列表,如果该点之前的y值小于该点,并且该点之后的y值小于该点,则该点为峰值。
  3. 遍历minthresh列表,如果该点之前的y值大于该点,并且该点之后的y值大于该点,则该点为峰值。
  4. 代码实施:

    from math import sin
    from matplotlib import pylab
    from pylab import *
    
    def peakdet(v, thresh):
        maxthresh = []
        minthresh = []
        peaks = []
        valleys = []
    
        for x, y in v:
            if y > thresh:
                maxthresh.append((x, y))
            elif y < -thresh:
                minthresh.append((x, y))
    
        for x, y in maxthresh:
            try:
                if (v[x - 1][1] < y) & (v[x + 1][1] < y):
                    peaks.append((x, y))
            except Exception:
                pass
    
        for x, y in minthresh:
            try:
                if (v[x - 1][1] > y) & (v[x + 1][1] > y):
                    valleys.append((x, y))
            except Exception:
                pass
    
        return peaks, valleys
    

    测试代码:

    # input signal
    t = array(range(100))
    series = 0.3 * sin(t) + 0.7 * cos(2 * t) - 0.5 * sin(1.2 * t)
    
    arr = [*zip(t, series)]  # create a list of tuples where the tuples represent the (x, y) values of the function
    thresh = 0.95
    
    peaks, valleys = peakdet(arr, thresh)
    
    scatter([x for x, y in peaks], [y for x, y in peaks], color = 'red')
    scatter([x for x, y in valleys], [y for x, y in valleys], color = 'blue')
    plot(t, 100 * [thresh], color='green', linestyle='--', dashes=(5, 3))
    plot(t, 100 * [-thresh], color='green', linestyle='--', dashes=(5, 3))
    plot(t, series, 'k')
    show()
    

    enter image description here

    进一步测试以确保在超过阈值的多个点时检测到峰值:

    # input signal
    t = array(range(100))
    series = 6.3 * sin(t) + 4.7 * cos(2 * t) - 3.5 * sin(1.2 * t)
    
    arr = [*zip(t, series)]
    thresh = 0.95
    
    peaks, valleys = peakdet(arr, thresh)
    
    scatter([x for x, y in peaks], [y for x, y in peaks], color = 'red')
    scatter([x for x, y in valleys], [y for x, y in valleys], color = 'blue')
    plot(t, 100 * [thresh], color='green', linestyle='--', dashes=(5, 3))
    plot(t, 100 * [-thresh], color='green', linestyle='--', dashes=(5, 3))
    plot(t, series, 'k')
    show()
    

    enter image description here

答案 1 :(得分:1)

所以,在这里你有一个numpythonic解决方案(比明确的循环好得多)。

我使用roll函数来移动位置中的数字+1或-1。也是一个&#34;峰值&#34;被定义为局部最大值,其中前一个和后一个数字小于中心值。

完整代码如上:

Month   sum
Jan.    5
Feb.    0
Mar.    5
Apr.    3
May.    0
June.   0
July.   1
Aug.    0
Sept.   4
Oct.    0
Nov.    15
Dec.    12

如果你绘制它,你得到:

enter image description here

答案 2 :(得分:0)

使用find_peaks中的scipy.signal解决方案

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

# Input signal
t = np.arange(100)
series = 0.3*np.sin(t)+0.7*np.cos(2*t)-0.5*np.sin(1.2*t)

# Threshold value (for height of peaks and valleys)
thresh = 0.95

# Find indices of peaks
peak_idx, _ = find_peaks(series, height=thresh)

# Find indices of valleys (from inverting the signal)
valley_idx, _ = find_peaks(-series, height=thresh)

# Plot signal
plt.plot(t, series)

# Plot threshold
plt.plot([min(t), max(t)], [thresh, thresh], '--')
plt.plot([min(t), max(t)], [-thresh, -thresh], '--')

# Plot peaks (red) and valleys (blue)
plt.plot(t[peak_idx], series[peak_idx], 'r.')
plt.plot(t[valley_idx], series[valley_idx], 'b.')

plt.show()

结果图如下所示。

enter image description here

请注意,find_peaks有一个参数height,在这里我们称之为thresh。它还有一个名为threshold的参数,它正在执行其他操作。

Documentation for find_peaks

答案 3 :(得分:-1)

这些代码

        if lookformax:
            if (this < mx-delta):
                if (mx>abs(thresh)) and not isnan(mxpos):
                    maxtab.append((mxpos, mx))
                mn = this
                mnpos = x[i]
                lookformax = False
        else:
            if (this > mn+delta):
                if (mn<-abs(thresh)) and not isnan(mnpos):
                    mintab.append((mnpos, mn))
                mx = this
                mxpos = x[i]
                lookformax = True

仅在

条件下运行
    if abs(this)>thresh:

所以只有当thresh上方的下一个点小于它时,你才能找到一个峰值。

说出条件