测试信号是否包含特定的先前记录的信号

信息处理 声音的 信号检测
2022-02-04 08:06:31

我正在开展一个项目,该项目将无线电数据转换为文本,以寻找特定类型的无线电聊天。在大多数情况下,无线电信号是死气沉沉的。会定期对特定类型的市政事件(火灾、医疗、警察)进行标注。每个标注都有独特的一系列声音,用于识别类型的呼叫。在耳朵里,它们听起来是一样的。但由于噪声/失真、音量,信号每次都不完全相同。

我正在尝试做的是确定一种方法,根据前面的声音按市政类型自动对每个标注进行分类。我目前使用的技术是首先在 15 分钟的 mp3 数据剪辑中获取原始信号数据。我通过消除沉默将它剪成片段。然后我拍摄剪辑的前 4 秒,使用 imagemagick 将其转换为频谱图,然后使用 imagemagick 的compare -metric phash技工将其与之前保存的已知有效信号记录的频谱图进行比较。该解决方案工作正常,但不是很好。它会导致误报到耳朵甚至不靠近。如果我减少允许的汉明距离,则会导致我对有效标注进行错误分类。如果我增加汉明距离,我会得到误报。另一个问题是它需要大量处理(原始 -> 删除静音 -> 每个剪辑 -> 获取 4s 剪辑 -> 频谱图 -> 比较 -> 如果匹配 -> 保存剪辑)。最终,方法似乎有缺陷……必须有更好的方法。

这是一个示例文件https://drive.google.com/file/d/1GcU6zQDr2G39a5Szpr-A6rPBYjv9Zrch/view?usp=sharing. 这是 15 分钟的信号数据。如果您跳到 1:52,您会听到医疗呼叫的声音,这是一个音量逐渐增大的单音调,每次都是相同的音调。另一个医疗电话发生在 2:07。如果您跳到 3:44,您将听到前面的火灾报警声音。这是一种奇怪的声音,几乎听起来像一个老式的调制解调器,但每次火灾都是一样的。5 点 35 分又有一场火灾。火灾呼叫的波形相似但不完全相同。在这个项目之前,我对信号处理的了解完全为零,我仍然知道略高于零。我的直觉告诉我必须有某种方法来平滑波形,然后做某种机制来比较波形的形状,而不是确切的高度(所以如果一个标注只是稍微响亮或安静,它们就会匹配)。类似于正则表达式的东西,但用于信号数据,但我不知道这是否有意义,或者是否没有更好的方法。当我在网上查看时,很多都是像音频指纹这样的东西,但这对我来说没有意义,因为我不是要识别整个文件,而是查看我的原始文件是否包含此音频文件。它似乎与Shazam中使用的算法相似,但我在那篇论文中找不到实际的算法,它似乎只是在谈论生成星座,而不是关于如何实际生成星座的细节。

我的担忧归结为两个主要问题。首先,什么是正确的算法,其次我如何实际执行它。我有使用 python、node 和 golang 的经验/访问权限。如果我知道正确的算法,我想我可以找出其余的,但如果有一个众所周知的库已经解决了这个问题,那就更好了。

编辑:

根据 Max 的回答,我取得了一些进展。但我仍然陷入僵局。

testFile, sr = librosa.load("/app/src/1601317821107.mp3")
matchFile, sr = librosa.load("/app/src/medicSound3.wav")
corr = scipy.signal.correlate(testFile, matchFile, mode="full", method="fft")

如果我绘图corr,我会得到下图。

在此处输入图像描述

这清楚地显示了给定文件中的 4 个匹配项,这是完全正确的。如果我对一个没有实际匹配的文件运行它,那么该图永远不会有任何高于 10 的峰值。所以下一个挑战是如何定位每个峰值的起点。我已经尝试过scipy.signal.find_peaks,但这给了我很多高峰,而不仅仅是我寻求的 4 个。我试过摆弄prominence, width,height参数,但没有一个真正找到我要找的东西。在这种情况下,我正在寻找每场主要比赛的开始。如果我知道起始索引,我相信我可以简单地将其除以采样率 (22050) 以获得以秒为单位的位置。另一个问题是corr数组的长度是 thetestFilematchFile数组的总和。这导致我的索引corr数组不完全匹配它们在testFile数组中的位置。

想法?

1个回答

这听起来确实像是互相关的工作。它非常强大,对阈值进行一些调整应该会给你你正在寻找的结果。它是在时域中计算的,因此无需调整频谱或频谱图。基本上,您只需在录制的音频上“滑动”您的样本并对重叠部分进行卷积。当正弦音在播放时,它会有几个峰值,但通常,最高峰会给你你正在寻找的信号的确切位置。如果您只需要知道它是否发生,您可以通过某种阈值而不是样本,而是在整个相关分析的总和上使其更加稳健。

编辑:当然,有一个有据可查的,广泛使用的python库:numpy

编辑 2:我将通过传递"same"给函数而不是"full". 这将产生与测试信号长度相同的信号。接下来,我会对abs信号进行处理,然后在scipy.signal.medfilt其上运行一个kernel_size匹配信号的长度。这应该为您提供每次出现的清晰峰值,然后您可以像之前尝试过的那样识别它。