查找样本之间的局部峰值

信息处理 平滑 插值 峰值检测
2022-01-10 12:33:10

我有的离散样本ny[n]在此处输入图像描述

我想在信号中找到局部最大值。

是否为最大值的简单测试是: y[n]

y[n]:maxima if y[n]>y[n1] and y[n]>y[n+1]

然而,最大值可能位于样本之间,例如在处可能存在最大值。i=4.25

为了找到样本之间的最大值,我相信我需要插值y[n]

  • 如何使用插值找到最大值?
  • 我应该使用什么形式的插值?

如您所见,我的信号不是很嘈杂,但是如果该方法还进行了一些过滤以使最大值超过阈值并具有一定的宽度(没有尖峰),那就太好了。

然而,我最大的问题是在样本之间找到峰值。有什么好的方法可以做到这一点吗?

提前感谢您的任何答案!

3个回答

获得子样本分辨率

一个非常便宜(就代码大小而言)的解决方案就是对信号进行上采样。在 matlab 中,这可以用interp(y ,ratio). 一个稍微复杂一点的解决方案是简单地检测峰值;对于每个峰值,通过 y[peak - 1], y[peak], y[peak + 1] 拟合抛物线;然后使用该抛物线最大的点作为真正的峰值位置。

关于峰值检测

一堆帮助的技术:

  • 正如 Hilmar 所建议的,通过高斯或汉恩窗口对信号进行卷积,其宽度大致等于您希望在检测到的峰之间看到的最小间隔的一半。由于时间精度似乎对您的应用程序至关重要,但请确保您考虑到过滤引入的时间延迟!
  • 减去您的信号本身的中值滤波版本(具有相当大的观察窗口);并将结果除以自身的标准差过滤版本。这摆脱了趋势并允许以标准偏差为单位表示阈值。
  • 对于峰值选择,我使用“顶帽”过滤器来制定它。将信号的顶帽滤波版本定义为 yt[n] = max(y[n - W], y[n - W + 1], ..., y[n + W - 1], y[n + W]) ; 并将 y[n] == yt[n] 和 y[n] > 阈值的点用作峰值。

所有这些都可以在 Matlab 中通过几次 nlfilter 非常有效地实现。

尝试有损峰值检测器:

y[n] = max(abs(x[n]),a*y[n-1]);

其中“a”是一个小于 1 的数字,用于控制检测器衰减的速度。它决定了相邻峰之间的距离,而不会平滑成一个峰。然后进行阈值检测。

您还可以使用均值偏移算法使用核函数来细化峰值。

如果您关心的峰值与信号大小相比非常少,这将特别有用和高效,因此您不必对整个信号进行上采样(这可能非常昂贵)。

例如,这里是一个简化的 MATLAB 或 GNU Octave 实现:

function peak = meanshift(y, sigma, peak_guess)
    peak = peak_guess;
    x = 1:size(y, 2);

    for iter = 1:10
        %TODO: ignore areas more than 3 sigma away
        %      since those don't affect the output
        weights = exp(-(x - peak).^2 / sigma^2) .* y;
        off = sum(weights .* x) / sum(weights);
        peak = off;
    end
endfunction

尽管我必须强调您必须实现“TODO”中描述的内容才能使其高效。