使用智能手机从音频捕获中计算心跳

信息处理 声音的 音频处理
2022-02-16 18:44:38

我正在做一个项目,我需要从使用智能手机麦克风/免提设备捕获的音频信号中执行心率 BPM 计算。约束是不要使用 ML。所以我只能玩过滤器和香农。

我很难清除信号中的噪音。

这是我到目前为止所拥有的。

[read audiofile] -> [decimate signal by factor 5] -> [low-pass filter butterworth 350 Hz Order 6] -> [normalize] -> [signal^2 (convolution in TD)] 

使用平方信号来锻炼阈值并从原始信号中衰减低于阈值的任何信号,使用香农能量包络。

虽然此管道适用于环境相对安静的大多数情况。但当有接地噪音或其他尖锐噪音时,它会失效。

我正在为任何愿意提供帮助的人附上样品。音频样本 https://app.box.com/s/jli6dut9v4ttrqnmuzjqhkxy701izh2q

我需要 a) 消除接地噪音 b) 消除噼啪声 c) 增强节拍或消除一般本底噪声的帮助。

1个回答

这将是一个很长的答案。

我将首先分析您的文件以及您可以采取哪些措施来改善音频。我还将在我设计用于检测心跳的算法上试用您的文件。在那之后,我将描述设计我的算法的内容以及它是如何工作的。然后,我将对如何开始使用您自己的算法提出一些一般性建议。

现有文件分析

我将您的每个文件加载到Audacity中以收听它们并查看频率内容的样子。通常,您不仅会遇到静态(白)噪声问题。来自您所在地区的交流电源频率(50Hz 和谐波)的持续干扰会给您带来很多麻烦。

从最差到最好:

文件: static_with_beats_doesnt_evaluate.wav

电力线噪声的严重干扰。我可以看到那里有一个心跳信号。但是,它被干扰掩盖了太多,无法检测到。没有什么可以保存这段录音。50Hz 干扰太接近实际信号而无法分离。

在此处输入图像描述

文件: in_accurate_with_noise.png 最大的问题还是来自 50Hz 电源线的干扰。在某些时候,信号足够干净,可以识别出心跳。如果我通过一个非常尖锐的 45Hz 低通滤波器运行它,我使用的算法可以挑选出个别的节拍,但即使这样,也有一些心跳是根本听不见的。

在此处输入图像描述

文件: accuracy.wav

这个文件没有电源线干扰,可能是在户外录制的。它可以比其他人更好地破译,尽管仍然有一些部分根本没有检测到信号。一个截止频率为 45 Hz 的陡峭低通滤波器从我的算法中得到了几乎完美的结果。有一小段信号太弱,无法从剩余的噪声中挑选出来。

在此处输入图像描述

文件: accuracy_72bpm.wav

该文件也缺少电源线干扰。偶尔的干扰会导致一个节拍在这里和那里丢失,但除此之外是非常好的录音。

在此处输入图像描述

检测心跳所涉及的问题

检测心跳涉及几个基本问​​题:

  1. 什么是心跳?心跳由多种声音组成,其中大部分声音很难与背景噪音和干扰区分开来。您必须选择一个“功能”,而不是从垃圾中可靠地挑选出来。简单地检测声音的音量是行不通的(太多其他的东西也可能很响。)我发现“lub dub”声音是大约 30Hz 到 40Hz 之间的短脉冲频率。这就是我的算法所要寻找的。
  2. 阈值 - 你什么时候真正检测到你的特征说有心跳?音量不断变化,噪音和干扰的音量也随之变化。因为固定阈值不行。您的阈值必须适应背景和心跳的变化量。心跳的音量随着每次呼吸而变化,并且随着麦克风在胸部周围移动而变化。对于阈值问题,我有一个非常奇怪的解决方案。
  3. 噪声 - 该算法必须在相当广泛的噪声条件下工作。您寻找的功能应该相当简单,几乎可以从任何噪音中挑选出来。我使用的算法可以达到大约 20dB 的信噪比。它对心跳信号的绝对电平不敏感,但需要相当干净的信号。
  4. 硬件——如果算法依赖于麦克风的灵敏度和频率响应,那么它对你没有好处。无论您做什么,都需要在任何手机上使用任何麦克风。我使用的算法对硬件几乎完全不敏感。如果有心跳,就会被发现。

第 3 点确实是最重要的。大声不重要,绝对水平不重要。整个事情的生死取决于你的信号有多干净。无论您使用什么算法,干净的信号都是必须的。

  1. 没有干扰。如果您正在拾取电源线嗡嗡声,请修复它。这通常是电气问题,可以通过适当的接线和接地来解决。
  2. 减少运动噪音。在我的实验中,我使用松紧带将麦克风固定在胸前。
  3. 减少背景噪音。我在麦克风和松紧带之间使用了一块塞满棉花的小纸板“饼干”。它由几圈带有塑料覆盖物的硬纸板制成。背面也是硬纸板。面向我胸部的那一面,棉球和麦克风之间只有一层塑料。这大大降低了背景噪音。

我如何检测心跳

我最终想出的方法是建立在对一些(真正)干净的心跳记录的观察之上。我发现,心跳的每一次“砰砰”都有一种“突发”的频率。如果您过滤掉除了突发内容之外的所有内容,那么您将获得一个相当可靠的心跳检测器。我使用 24 到 44 Hz 的带通滤波器。这似乎提供了最好的结果。范围可能取决于人——我没有足够的样本来比较。

在带通之后,我使用希尔伯特变换来连续估计突发频率的响度。希尔伯特函数给出两个彼此旋转 90 度的输出。每个平方,求和的平方根,你就有一个连续的信号,代表“突发”频率的幅度。对其应用低通滤波器以消除疯狂的变化。

获得正确的阈值是真正的问题,我尝试了几种方法。我从手动调整阈值开始,但当然它会随着您的呼吸和移动而改变,因此效果不佳。我尝试了自动校准,这有帮助,但必须在麦克风移动时重复。我尝试了各种自适应阈值,但由于各种原因都失败了。

最终效果很好的东西看起来非常愚蠢。

取幅值信号绝对值的对数。是的,取振幅的对数(无论您使用什么底数对数都没有关系。)将其通过高通滤波器,并将固定阈值应用于输出。该固定阈值并未设置信号的绝对电平。它正在设置信噪比。较低的值意味着“以较低的信噪比工作”,而较高的值意味着“需要更高的信噪比”。最终效果是“如果存在 24Hz 和 44Hz 之间的频率并且它比当前噪音水平响亮某个固定比率,则触发”。

这种设置对输入信号的绝对电平非常不敏感。麦克风和放大器的频率响应几乎无关紧要。当呼吸和麦克风改变位置时,它会自动适应运动。

此图显示了该过程的核心部分:

在此处输入图像描述

这是我为开发算法而放在一起 的纯数据补丁的片段。GitHub 上提供了整个内容以及一些示例文件。 如果您想试用它,您将需要Pure Data Extended 0.43才能使用该补丁 - 它依赖于 PD Extended 包含但其他版本不包含的几个外部库。

概括

无论您选择如何实现您的算法,您都必须从查看录音中的可用信号开始。

在时域(示波器视图)和频域 (FFT) 中查看它们。找出您的噪声和干扰的样子。

查看干净的录音,找出与噪音和干扰不同的特征。找到可以用某种过滤器挑选出来的东西。

设计一个可以将特性与噪声分离的滤波器。

设计一种使阈值适应当前噪声水平和信号水平的方法。


当然,我的方法有缺点。最大的问题是,如果没有心跳,它会“想象”它正在听到心跳并开始传递错误的脉冲。独立于绝对电平和硬件变化的代价是必须保证一定的最小信噪比。