Raspberry Pi 上的声音激活录音和高级过滤

信息处理 过滤器 声音的 Python 过滤 音频处理
2022-01-23 15:01:25

我正在使用USB 供电的超声波麦克风制作 Raspberry Pi 蝙蝠探测器。我希望能够在排除昆虫和其他非蝙蝠噪音的同时记录蝙蝠。录音需要声音触发以避免过快填充 SD 卡并帮助分析。该网站解释了如何使用 SoX 执行此操作:

rec - c1 -r 192000 record.wav sinc 10k silence 1 0.1 1% trim 0 5

这会在至少 0.1 秒的触发声音后记录 5 秒,并包含一个 10kHz 高通滤波器。这是一个好的开始,但我真正想要的是一个高级过滤器,它可以排除蟋蟀和其他非蝙蝠噪音。昆虫和蝙蝠的叫声在频率上重叠,因此高通或带状滤波器不起作用。

Elekon Batlogger通过分析过零的周期触发器来执行此操作。从蝙蝠记录器网站:

蝙蝠(声带)和昆虫(颤音)的声音产生差异会影响周期的连续性。期间触发器利用了这一点: 在此处输入图像描述

当 ProdVal 和 DivVal 低于设置的限制时触发触发器,因此如果值在黄色范围内。(数值表示默认值):ProdVal = 8,数值越大触发越容易 DivVal = 20,数值越大越容易触发

图片中的翻译文本:

蝙蝠:音调信号

周期常数 => 过零 / 时间 = 稳定

昆虫:抓挠

周期常数 => 过零 / 时间 = 不同

MN => 每个测量间隔的周期数的平均值

SD => 周期数的标准差

较高的值即使在低频下也能更好地触发(还有昆虫!)反之亦然

有没有办法在 Raspberry Pi OS 中实现这个(或具有相同效果的东西)?我最熟悉的语言是 R。根据对这个问题的回答, R 似乎适合这个问题,尽管如果 R 不是最佳选择,那么我愿意接受其他建议。

我真的很感激一些用于录制音频和过滤的工作代码,如上所述。我想要的输出是包含蝙蝠呼叫的 5 秒文件,而不是昆虫或噪音。在 CPU / 电源使用方面需要高效,并且需要即时工作。

蝙蝠和昆虫的示例记录在这里


更新:

我有一个在 Python 中工作的基本声音激活脚本(基于此答案),但我不确定如何在其中包含高级过滤器:

import pyaudio
import wave
from array import array
 import time
 
FORMAT=pyaudio.paInt16
CHANNELS=1
RATE=44100
CHUNK=1024
RECORD_SECONDS=5

audio=pyaudio.PyAudio() 

stream=audio.open(format=FORMAT,channels=CHANNELS, 
                  rate=RATE,
                  input=True,
                  frames_per_buffer=CHUNK)

nighttime=True # I will expand this later

while nighttime:
     data=stream.read(CHUNK)
     data_chunk=array('h',data)
     vol=max(data_chunk)
     if(vol>=3000):
         print("recording triggered")
         frames=[]
         for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
             data = stream.read(CHUNK)
             frames.append(data)
         print("recording saved")
         # write to file
         words = ["RECORDING-", time.strftime("%Y%m%d-%H%M%S"), ".wav"]
         FILE_NAME= "".join(words) 
         wavfile=wave.open(FILE_NAME,'wb')
         wavfile.setnchannels(CHANNELS)
         wavfile.setsampwidth(audio.get_sample_size(FORMAT))
         wavfile.setframerate(RATE)
         wavfile.writeframes(b''.join(frames))
         wavfile.close()
     # check if still nighttime
     nighttime=True # I will expand this later
 
 stream.stop_stream()
 stream.close()
 audio.terminate()
1个回答

首先——文件名以 .wav 结尾的事实表明这是一个未压缩的文件。这是浪费存储的好方法!

有无损压缩格式(主要是:FLAC)应该在蝙蝠声音上做得非常好(这意味着它们不需要太多空间)并且相对优雅地处理通常的背景噪音。这很可能已经解决了您的问题!FLAC 允许高达 655350 Hz 的采样率,因此您的 384000 Hz 数字化音频应该可以正常工作。

然后:是的,过零检测是一种测量频率的方法,但是在存在多个音调或宽带噪声的情况下,它不是一个好的选择。

一个简单的带通滤波器,它只允许您假设蝙蝠使用的频率(主要是专门的),然后是一个功率检测器(取平方根并平滑结果)会更好 - 这正是 sox call 正在做的,似乎(只是使用高通滤波器,即它假设蝙蝠不在频带中,但所有高于 10 kHz 的都是蝙蝠)。

现在,实现这一点并不难,但老实说,R 只是错误的工具选择。事后它是一种很好的数据分析语言,但对于在线分析/过滤来说,它几乎就是一件麻烦事(我什至根本不知道如何使用它)。另外,我认为在声音片段上反复运行 R 绝不是计算效率高的,但我对 R 解释器的了解还不够深入,无法用事实真正支持这一说法。

幸运的是,这并不难。有数据流建模语言允许您在没有硬编码的情况下实现这一点,例如语言“处理”或GNU Radio ¹。

我将留下一个快速的GNU Radio 伴侣实现的流程图作为说明(我更改了一些参数以使其适合您的用例):

GNU Radio 配套流程图

请注意,在检测到蝙蝠活动时将任何未发生的信号归零会产生一个几乎压缩为“无”的信号,因此您会得到一个连续文件(具有正确的时间!),该文件仅在某些时间使用大量存储空间实际发生了。


现在,正如您所说,您正在寻找比您引用的 sox 命令行更先进的东西(这实际上基本上是相同的:高通滤波器,检测电源,如果低于阈值则切断)。

我对蝙蝠的声音没有经验(我假设你是chiropterist,在这里),所以更好的设计必须留给你。但从这个想法开始:

首先,你使用一个简单的高通或带通滤波器来抑制所有明显不合时宜的东西。然后,您可以使用诸如 PLL(锁相环,一种跟踪正弦相位随时间变化的速度的设备,即正弦在其周期中的哪个点)来检测是否存在主导频率在信号; 如果该 PLL 检测到的频率没有“跳来跳去”,您可能会听到类似单音的声音。然后,您可以使用它来检测单音及其频率的存在!然后,您可以分析频率“轨迹”等。很可能,您甚至可以找出蝙蝠运动的多普勒特征。

但是:这有点“靠运气”,还有鸟类和昆虫也会在相似的频率范围内发出单音。这可能表明这实际上是使用神经网络学习检测器可以正常工作的情况之一(并且这些情况不一定是树莓派无法实时运行分类的那么重,但可能没有什么理由,因为归零绝对非 bat-times 加上音频压缩将使存储问题可能消失)。


¹我是 GNU Radio 项目的一部分。我有偏见。