我需要优化一个方法,寻找数据峰值的数目在一维阵列。 数据是wav文件振幅的时间序列。
我已经实现了代码:
from scipy.io.wavfile import read
from scipy.signal import find_peaks
_, amplitudes = read('audio1.wav')
indexes, _ = find_peaks(amplitudes, height=80)
print(f'Number of peaks: {len(indexes)}')
绘制时,数据如下所示:
一般刻度
我感兴趣的‘峰’是人眼清楚的--在这个特定的数据集中有23个。
然而,由于阵列如此之大,数据在一般尺度下清晰的峰内是极其不同的(因此有数百个用蓝色十字标记的峰):
放大到一个山峰
找峰的问题以前已经问过很多次了(我已经经历了很多次了!) -但我找不到任何帮助或解释优化参数,只找到我想要的峰值。 我对Python略知一二,但一说到数学分析就瞎了!
根据宽度分析似乎没有用,因为根据第二幅图像,在大尺度上清晰的峰实际上是散布在“无声”范围内的。 距离是没有帮助的,因为我不知道在其他wav文件中峰值会有多近。 突出法被认为是最好的方法,但我不能得到我需要的结果; 阈值也一样。 我还尝试过抽取信号,用Savitzky-Golay滤波器平滑信号,以及参数和值的不同组合,所有这些结果都不准确。
单凭身高就已经很有用了,因为我从图表中可以看到,山峰总是达到80以上。
查看0d持久性同源性以找到一个好的策略,其中您可以为之优化的参数是峰值持久性。 这里有一篇很好的博客文章解释了这些基础知识。
但简而言之,这个想法是想像你的图被水填满,然后慢慢地把水抽干。 每当图上的一片浮出水面,就会有一个新的岛屿诞生。 当两个岛屿紧挨着彼此时,它们会合并,这导致年轻的岛屿(山峰较低的岛屿)死亡。 那么每个数据点都有一个诞生时间和一个死亡时间。 最显著的峰是那些持续时间最长的峰,这就是死亡-出生
。
如果水位以连续的速率下降,那么持久性就用峰高来定义。 另一种可能性是当时间从步骤T
到步骤T+1
时从点到点瞬时地滴水,在这种情况下,持久性以信号样本的峰值宽度来定义。
对你来说,似乎使用原始定义中的峰高>; 70找到所有你感兴趣的峰,尽管可能太多,聚在一起。 您可以通过选择每个簇中的第一个峰或每个簇中的最高峰来限制这一点,或者通过同时采用这两种方法并且只选择具有高度持久性和宽度持久性的峰。