AMPD峰值提取算法

方法一:ampdlib和pyampd

一个直接实现原始AMPD算法的库

复制代码
pip install ampdlib

import ampdlib
# 假设 your_signal 是你的信号数据 (NumPy数组或列表)
peaks = ampdlib.ampd(your_signal)

注意 :该库对内存消耗可能较高,对于长信号,可以考虑使用ampd_fast进行分窗处理

复制代码
pip install pyampd

from pyampd.ampd import find_peaks
# 基础用法
peaks = find_peaks(your_signal)
# 指定最大尺度以优化性能
peaks = find_peaks(your_signal, scale=100)

pyampd :一个进行了性能优化的实现,支持指定最大尺度(scale)来提升速度,并提供了能适应信号特征变化的自适应版本

方法二:手动实现算法(自己编写)

复制代码
import numpy as np
import matplotlib.pyplot as plt

def ampd_algorithm(signal):
    """
    AMPD(自动多尺度峰值检测)算法的Python实现。
    参考: Scholkmann et al. 2012
    """
    n = len(signal)
    # 1. 线性去趋势
    t = np.arange(n)
    p = np.polyfit(t, signal, 1)
    detrended_signal = signal - np.polyval(p, t)

    # 2. 计算局部极大值刻度图 (LMS)
    # 最大尺度 L = floor(N/2) - 1
    L = n // 2 - 1
    # 初始化LMS矩阵,M[k, i] 表示在尺度k下,点i是否为局部极大值
    M = np.ones((L, n), dtype=float) * np.random.rand() 
    for k in range(1, L + 1):
        window_size = k + 1
        for i in range(k, n - k):
            # 检查点i是否在窗口 [i-k, i+k] 内为最大值
            if detrended_signal[i] > detrended_signal[i - k] and detrended_signal[i] > detrended_signal[i + k]:
                M[k-1, i] = 0

    # 3. 确定最佳尺度 lambda
    gamma = np.sum(M, axis=1) # 对LMS矩阵逐行求和
    lambda_ = np.argmin(gamma) # 行和最小的索引即为最佳尺度

    # 4. 峰值检测:裁剪LMS矩阵并计算列标准差
    # 只保留尺度 1 到 lambda_ 的行
    M_reduced = M[:lambda_ + 1, :]
    # 计算裁剪后矩阵的列标准差
    sigma = np.std(M_reduced, axis=0)
    # 标准差为0的列索引即为检测到的峰值位置
    peaks = np.where(sigma == 0)[0]

    return peaks, detrended_signal

# --- 使用示例 ---
if __name__ == '__main__':
    # 生成一个含噪声的模拟信号
    np.random.seed(42)
    x = np.arange(1000)
    base_signal = np.sin(0.2 * x) + 2 * np.sin(0.4 * x)
    noise = 0.8 * np.random.randn(len(x))
    y = base_signal + noise

    # 执行峰值检测
    detected_peaks, detrended_y = ampd_algorithm(y)

    # 可视化结果
    plt.figure(figsize=(14, 6))
    plt.plot(x, y, 'b-', label='原始信号', alpha=0.7)
    plt.plot(x, detrended_y, 'g-', label='去趋势信号', alpha=0.5)
    plt.scatter(detected_peaks, y[detected_peaks], color='red', s=40, zorder=5, label='检测到的峰值')
    plt.title("AMPD 峰值检测结果")
    plt.xlabel("数据点索引")
    plt.ylabel("信号值")
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

    print(f"检测到峰值数量: {len(detected_peaks)}")
    # print(f"峰值位置索引: {detected_peaks}")

关键注意事项

  • 信号预处理 :强烈建议在使用AMPD之前,对信号进行带通滤波,以去除与目标峰值无关的高频噪声和低频漂移,这能显著提升检测准确率。

  • 内存与计算 :AMPD算法的复杂度为O(N²),处理非常长的信号(如数百万个数据点)时可能较慢或占用大量内存。可考虑使用ampdlib的分窗功能或pyampd的限制尺度功能。

  • 参数调整 :虽然算法号称"无参",但部分实现允许你指定最大尺度 (scale)。对于周期明显的信号,限制此参数可大幅提升速度。

  • 边缘与重叠峰 :原始算法在信号起点和终点附近可能检测不佳,对非常接近的重叠峰也可能分辨困难。使用pyampdfind_peaks_original或最新库可改善边缘问题。