本文算法的原始论文出处:Algorithms | Free Full-Text | An Efficient Algorithm for Automatic Peak Detection in Noisy Periodic and Quasi-Periodic Signals | HTML (mdpi.com)

在数字信号处理中,经常涉及到波峰(或波谷)查找算法,比如心率测量、步数计数等。对于周期信号或者准周期信号,有一种称之为Automatic multiscale-based peak detection (AMPD),即自动多尺度峰值查找算法。其优势是:

(1)算法本身(几乎)没有超参数,无需调参,对信号具有良好的自适应性,唯一的假设是信号是周期的或者准周期的;

(2)抗噪能力强,后面可以看到,对周期性的要求也不是很高。就是用一个多尺度的滑动窗口去两侧进行比较,寻找局部最大值。

import numpy as np

def AMPD(data):
    """
    实现AMPD算法
    :param data: 1-D numpy.ndarray 
    :return: 波峰所在索引值的列表
    """
    p_data = np.zeros_like(data, dtype=np.int32)
    count = data.shape[0]
    arr_rowsum = []
    for k in range(1, count // 2 + 1):
        row_sum = 0
        for i in range(k, count - k):
            if data[i] > data[i - k] and data[i] > data[i + k]:
                row_sum -= 1
        arr_rowsum.append(row_sum)
    min_index = np.argmin(arr_rowsum)
    max_window_length = min_index
    for k in range(1, max_window_length + 1):
        for i in range(k, count - k):
            if data[i] > data[i - k] and data[i] > data[i + k]:
                p_data[i] += 1
    return np.where(p_data == max_window_length)[0]

我们先来合成一段数据看看效果:

import matplotlib.pyplot as plt

def sim_data():
    N = 1000
    x = np.linspace(0, 200, N)
    y = 2 * np.cos(2 * np.pi * 300 * x) \
        + 5 * np.sin(2 * np.pi * 100 * x) \
        + 4 * np.random.randn(N)
    return y

def vis():
    y = sim_data()
    plt.plot(range(len(y)), y)
    px = AMPD(y)
    plt.scatter(px, y[px], color="red")

    plt.show()

vis()

波谷的计算方式只需要把数据乘以-1反转一下就可以了。

数据的噪声还是比较大的,但是AMPD的效果很好。

原始文献中还给出了很多检测例子,比如:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐