关于算法:测量信号的峰值检测

Peak detection of measured signal

我们使用一个数据采集卡从一个设备中获取读数,这个设备将信号增加到一个峰值,然后再降低到接近原始值。为了找到峰值,我们目前搜索数组中的最高读数,并使用索引来确定计算中使用的峰值时间。

如果最高值是我们正在寻找的峰值,这就可以很好地工作,但是如果设备工作不正常,我们可以看到第二个峰值,它可以高于初始峰值。我们在90秒内从16台设备上每秒读取10个读数。

我最初的想法是在读数中循环,检查前面和后面的点是否小于电流,以找到一个峰值并构造一组峰值。也许我们应该在当前位置的每一侧平均观察几个点,以考虑系统中的噪声。这是最好的方法还是有更好的技术?

我们确实使用了LabVIEW,我已经查看了Lava论坛,这里有许多有趣的例子。这是我们测试软件的一部分,我们试图避免使用太多的非标准vi库,所以我希望得到有关所涉及的过程/算法的反馈,而不是特定代码。


有很多经典的峰值检测方法,其中任何一种都可以工作。您必须了解数据质量的界限,尤其是。以下是基本说明:

  • 在您的数据中的任意两点之间,(x(0), y(0))(x(n), y(n))加上y(i + 1) - y(i)表示0 <= i < n并称之为T(旅行),将R设为y(n) - y(0) + k表示合适的小kT/R > 1表示峰值。如果噪音不太可能导致大行程,或者噪音在基本曲线形状周围对称分布,则此功能正常。对于您的应用程序,接受分数高于给定阈值的最早峰值,或者分析每个上升值的行程曲线以获得更有趣的特性。

  • 使用匹配的过滤器对标准峰值形状的相似性进行评分(本质上,使用针对某个形状的标准化点积来获得相似性的余弦度量)

  • 对标准峰值形状进行反卷积,并检查是否有高值(尽管对于简单的仪器输出,我经常发现2对噪声不太敏感)。

  • 平滑数据并检查等距点的三联体,如果是x0 < x1 < x2, y1 > 0.5 * (y0 + y2),或检查这样的欧几里得距离:D((x0, y0), (x1, y1)) + D((x1, y1), (x2, y2)) > D((x0, y0),(x2, y2)),它依赖于三角形不等式。使用简单的比率将再次为您提供评分机制。

  • 将一个非常简单的2高斯混合模型适合您的数据(例如,数字配方有一个很好的现成代码块)。以较早的高峰为例。这将正确处理重叠的峰值。

  • 在数据中找到与简单高斯、柯西、泊松或你曲线的最佳匹配。在大范围内评估该曲线,并在记录其峰值位置后从数据副本中减去该曲线。重复。以最早的峰值为例,其模型参数(可能是标准偏差,但某些应用可能关心峰度或其他特征)满足某些标准。当心从数据中减去峰值后留下的伪影。最佳匹配可能由上述2中建议的匹配得分类型决定。

  • 我以前做过这样的工作:在DNA序列数据中找到峰值,在根据测量曲线估计的导数中找到峰值,在柱状图中找到峰值。

    我鼓励你认真考虑适当的底线。维纳滤波或其他滤波或简单的柱状图分析通常是在有噪声的情况下基线的一种简单方法。

    最后,如果您的数据通常是嘈杂的,并且您将数据从卡上取下来作为未引用的单端输出(甚至是引用的,只是不是差分的),并且如果您将许多观测平均到每个数据点,请尝试对这些观测进行排序,并丢弃第一个和最后一个四分位数,然后对剩余的数据进行平均。有很多这样的离群值消除策略是非常有用的。


    您可以尝试信号平均,即对每个点,用周围3个或更多点平均值。如果噪声点很大,那么即使这样也没有帮助。

    我知道这是语言不可知论者,但是假设你正在使用LabVIEW,LabVIEW附带了许多预打包的信号处理VIS,你可以使用它们来进行平滑和降噪。NI论坛是一个很好的地方,可以在这类事情上获得更专业的帮助。


    我想为这个线程贡献一个我自己开发的算法:

    它是基于离散原理:如果一个新的数据点是一个给定的x个标准差,远离某个移动平均值,算法信号(也称为z-得分)。该算法具有很强的鲁棒性,因为它构造了一个独立的移动平均值和偏差,这样信号就不会破坏阈值。因此,未来信号的识别精度大致相同,而与先前信号的数量无关。该算法接受3个输入:lag = the lag of the moving windowthreshold = the z-score at which the algorithm signalsinfluence = the influence (between 0 and 1) of new signals on the mean and standard deviation。例如,一个5的lag将使用最后5个观察来平滑数据。如果数据点与移动平均值的标准偏差为3.5,则3.5的threshold将发出信号。0.5的influence给出了正常数据点影响的一半信号。同样,0的influence完全忽略了重新计算新阈值的信号:因此,0的影响是最可靠的选择。

    其工作原理如下:

    伪代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    # Let y be a vector of timeseries data of at least length lag+2
    # Let mean() be a function that calculates the mean
    # Let std() be a function that calculates the standard deviaton
    # Let absolute() be the absolute value function

    # Settings (the ones below are examples: choose what is best for your data)
    set lag to 5;          # lag 5 for the smoothing functions
    set threshold to 3.5;  # 3.5 standard deviations for signal
    set influence to 0.5;  # between 0 and 1, where 1 is normal influence, 0.5 is half

    # Initialise variables
    set signals to vector 0,...,0 of length of y;   # Initialise signal results
    set filteredY to y(1,...,lag)                   # Initialise filtered series
    set avgFilter to null;                          # Initialise average filter
    set stdFilter to null;                          # Initialise std. filter
    set avgFilter(lag) to mean(y(1,...,lag));       # Initialise first value
    set stdFilter(lag) to std(y(1,...,lag));        # Initialise first value

    for i=lag+1,...,t do
      if absolute(y(i) - avgFilter(i-1)) > threshold*stdFilter(i-1) then
        if y(i) > avgFilter(i-1)
          set signals(i) to +1;                     # Positive signal
        else
          set signals(i) to -1;                     # Negative signal
        end
        # Adjust the filters
        set filteredY(i) to influence*y(i) + (1-influence)*filteredY(i-1);
        set avgFilter(i) to mean(filteredY(i-lag,i),lag);
        set stdFilter(i) to std(filteredY(i-lag,i),lag);
      else
        set signals(i) to 0;                        # No signal
        # Adjust the filters
        set filteredY(i) to y(i);
        set avgFilter(i) to mean(filteredY(i-lag,i),lag);
        set stdFilter(i) to std(filteredY(i-lag,i),lag);
      end
    end

    演示

    Demonstration of robust thresholding algorithm

    >原始答案


    对这个问题作了一些详细的研究。

    TSpectrum*类中有一组非常新的实现,这些类是a href="http://root.cern.ch/"rel="noreferrer">root/aa(核/粒子物理分析工具)。代码在一维到三维数据中工作。

    根源代码是可用的,因此如果需要,可以获取此实现。

    从a href="http://root.cern.ch/root/html/tsspectrum.html"rel="noreferrer">tsspectrum/aa类文档:

    此类中使用的算法已在以下参考文献中发布:

    [1] M.Morhac et al.: Background
    elimination methods for
    multidimensional coincidence gamma-ray
    spectra. Nuclear Instruments and
    Methods in Physics Research A 401
    (1997) 113-
    132.

    [2] M.Morhac et al.: Efficient one- and two-dimensional Gold
    deconvolution and its application to
    gamma-ray spectra decomposition.
    Nuclear Instruments and Methods in
    Physics Research A 401 (1997) 385-408.

    [3] M.Morhac et al.: Identification of peaks in
    multidimensional coincidence gamma-ray
    spectra. Nuclear Instruments and
    Methods in Research Physics A
    443(2000), 108-125.

    这些论文是从类文档链接到那些没有NIM在线订阅的人。

    所做的工作的简短版本是将直方图展平以消除噪声,然后在展平的直方图中使用蛮力检测局部最大值。


    这种方法基本上是从大卫·马尔的《视觉》一书中得出的。

    高斯模糊您的信号与预期宽度的峰值。这样可以消除噪声峰值,并且相位数据没有损坏。

    然后边缘检测(日志将执行此操作)

    然后你的边缘就是特征的边缘(像峰)。在边缘之间寻找峰值,按大小对峰值进行排序,这样就完成了。

    我在这个问题上使用了变体,它们工作得很好。


    我认为你想把你的信号与一个预期的、典型的信号交叉关联起来。但是,从我学习信号处理到现在已经有很长一段时间了,即使在那时我也没有太多的注意。


    所需峰值和不需要的第二峰值之间是否存在质量差异?如果这两个峰值都是"尖峰"——即持续时间短——当你在频域中观察信号时(通过做FFT),你将在大多数波段获得能量。但是,如果"好"峰的能量确实存在于"坏"峰不存在的频率上,或者相反,你可以自动地用这种方式区分它们。


    我对仪器不太了解,所以这可能完全不切实际,但这可能是一个有帮助的不同方向。如果你知道读数是如何失效的,并且在给定失效的情况下,峰值之间有一定的间隔,为什么不在每个间隔处进行梯度下降呢?如果下降带你回到你以前搜索过的区域,你可以放弃它。根据采样表面的形状,这也可能有助于比搜索更快地找到峰值。


    您可以对逻辑应用一些标准偏差,并注意超过x%的峰值。