当前位置: 首页 > 面试题库 >

从麦克风产生光谱图

公孙涵育
2023-03-14
问题内容

下面的代码将从麦克风获取输入,如果当音频块通过某个阈值时,它将产生
音频块(30毫秒长)。

从我所看到的来看,这和我所期望的完全不同
频谱图看起来像给定的音频和它的环境。我在期待
类似于以下内容(为了保留空间而进行了换位):

我录制的麦克风是我的Macbook上的默认麦克风
关于哪里出了问题的建议?

record.py:

import pyaudio
import struct
import math
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt


THRESHOLD = 40 # dB
RATE = 44100
INPUT_BLOCK_TIME = 0.03 # 30 ms
INPUT_FRAMES_PER_BLOCK = int(RATE * INPUT_BLOCK_TIME)

def get_rms(block):
    return np.sqrt(np.mean(np.square(block)))

class AudioHandler(object):
    def __init__(self):
        self.pa = pyaudio.PyAudio()
        self.stream = self.open_mic_stream()
        self.threshold = THRESHOLD
        self.plot_counter = 0

    def stop(self):
        self.stream.close()

    def find_input_device(self):
        device_index = None
        for i in range( self.pa.get_device_count() ):
            devinfo = self.pa.get_device_info_by_index(i)
            print('Device %{}: %{}'.format(i, devinfo['name']))

            for keyword in ['mic','input']:
                if keyword in devinfo['name'].lower():
                    print('Found an input: device {} - {}'.format(i, devinfo['name']))
                    device_index = i
                    return device_index

        if device_index == None:
            print('No preferred input found; using default input device.')

        return device_index

    def open_mic_stream( self ):
        device_index = self.find_input_device()

        stream = self.pa.open(  format = pyaudio.paInt16,
                                channels = 1,
                                rate = RATE,
                                input = True,
                                input_device_index = device_index,
                                frames_per_buffer = INPUT_FRAMES_PER_BLOCK)

        return stream

    def processBlock(self, snd_block):
        f, t, Sxx = signal.spectrogram(snd_block, RATE)
        plt.pcolormesh(t, f, Sxx)
        plt.ylabel('Frequency [Hz]')
        plt.xlabel('Time [sec]')
        plt.savefig('data/spec{}.png'.format(self.plot_counter), bbox_inches='tight')
        self.plot_counter += 1

    def listen(self):
        try:
            raw_block = self.stream.read(INPUT_FRAMES_PER_BLOCK, exception_on_overflow = False)
            count = len(raw_block) / 2
            format = '%dh' % (count)
            snd_block = np.array(struct.unpack(format, raw_block))
        except Exception as e:
            print('Error recording: {}'.format(e))
            return

        amplitude = get_rms(snd_block)
        if amplitude > self.threshold:
            self.processBlock(snd_block)
        else:
            pass

if __name__ == '__main__':
    audio = AudioHandler()
    for i in range(0,100):
        audio.listen()

基于评论的编辑:
如果我们把频率限制在16000赫兹,用对数标度表示colormap,这是用于在麦克风附近轻敲的输出:
这在我看来还是有点奇怪,但也似乎是正确的一步方向。


问题答案:

首先,请注意,您的代码最多绘制100个光谱图(ifprocessBlock)
被多次调用),你只能看到最后一个。
你可能想解决这个问题。此外,我想你知道你为什么要工作
有30毫秒的录音。就我个人而言,我想不出一个切实可行的办法
使用笔记本电脑麦克风录制30毫秒的应用程序可以提供有趣的
洞察力。它取决于你正在录制的内容以及你如何触发
录音,但这个问题与实际问题相切。
否则代码工作得很好。只需要在
processBlock函数,应用一些背景知识,可以得到
信息丰富且美观的光谱图。
我们来谈谈实际的光谱图。我将把SoX的输出作为
参考文献。colorbar注释说它是“dBFS”1,这是一个
对数测度(dB是

    f, t, Sxx = signal.spectrogram(snd_block, RATE)   
    dBS = 10 * np.log10(Sxx)  # convert to dB
    plt.pcolormesh(t, f, dBS)

这提高了色阶。现在我们看到了高频段的噪声
那是以前藏起来的。接下来,让我们讨论时间分辨率。光谱图
将信号分成若干段(默认长度为256)并计算
每个的光谱。这意味着我们有很好的频率分辨率,但非常
时间分辨率差,因为只有少数这样的片段适合信号
窗口(约1300个样本长)。两者之间总是有权衡的
时间和频率分辨率。这与[不确定性]有关
原则. 所以让我们
通过分割信号,用频率分辨率换取时间分辨率
分成较短的部分:

f, t, Sxx = signal.spectrogram(snd_block, RATE, nperseg=64)

太好了!现在我们在两个轴上得到了相对平衡的分辨率-但是等等!
为什么结果如此像素化?!实际上,这就是所有的信息
在30毫秒的短时间内。只有这么多方法可以
以二维分布。不过,我们可以作弊一点,用更高的
FFT分辨率和重叠段。这会使结果更平滑
尽管它没有提供额外的信息:

f, t, Sxx = signal.spectrogram(snd_block, RATE, nperseg=64, nfft=256, noverlap=60)

请看漂亮的光谱干涉图。(这些模式取决于
使用了window函数,但我们不要在这里讨论细节。看到了吗
windowspectrogram函数的参数来处理这些结果
看起来不错,但实际上不包含比
上一个图像。
为了使结果更接近SoX-lixe,我们观察到SoX谱图相当复杂
涂抹在时间轴上。你通过使用原始的低时间获得这种效果
分辨率(长线段),但为了平滑,让它们重叠:

f, t, Sxx = signal.spectrogram(snd_block, RATE, noverlap=250)

我个人更喜欢第三种解决方案,但你需要找到自己的解决方案
首选时间/频率权衡。
最后,让我们使用更像SoX的颜色图:

plt.pcolormesh(t, f, dBS, cmap='inferno')

下面一行的简短评论:

THRESHOLD = 40 # dB

将阈值与输入信号的均方根值进行比较,均方根值不是_测量单位为dB,但为原始振幅单位。

1 FS是满标度的缩写。dBFS意味着dB度量是相对于最大范围。0分贝是世界上最响亮的信号
当前表示,因此实际值必须<=0 dB。



 类似资料:
  • 我想直播Android麦克风,可以使用VLC播放器等听到。 Playstore主要提供IP摄像头应用,但这些应用是通过内部网络实现的。我想在互联网上播放流媒体。 可能吗? 我尝试了以下代码片段,但目前不起作用: 在VLC播放器前,我试着听(媒体)- 还有别的办法吗?

  • 播放音符 播放声音 录制 文字转语音

  • 我已经在python中安装和安装了pocketsphinx和sphinxbase包。我还为github获取了语音识别代码,并根据需要更改了数据和模式目录,但当我试图通过“python test.py”运行它时,它仍然无法通过语音进行流式传输。下面是代码: 请告诉我如何执行它。

  • 问题内容: 我正在尝试通过Java访问麦克风的级别。我不需要录制任何东西,我只想知道声音水平的相对范围。 这可以实时吗? 如果这是不可能的,那么这可能会起作用:当电平超过某个值时开始记录,当电平下降到一定水平以下一段时间后停止录制四分之一秒的位并读取它的音量,如果它在阈值以下停止录音。 提前致谢 问题答案: 您可以通过Sound API访问麦克风,但不会给您简单的响度级别。您只需要捕获数据并就其声

  • 问题内容: 我已经读了几天的Java声音API了,我无法理解。我是一个体面的程序员,只是很难理解API。 我一直在尝试从麦克风捕获音频并实时显示波形图。 我在捕捉音频时遇到麻烦,他们在教程中说要这样做,但是我似乎无法使它正常工作。 任何建议和帮助将不胜感激,逐行回答将是理想的。 谢谢,麻烦您了。 问题答案: 这将为您提供操作系统默认的设置。 要选择特定的输入设备(TargetDataLine),最

  • 更新时间:2018-09-17 11:37:10 功能说明 高感度麦克风模块。rf13 是一款高感度麦克风模块,这里我们用该模块采集周围环境声音的大小。 硬件资源 1.ESP32Kit 开发板 2.RF13 模块 3.接线 rf13 GND 引脚接 esp32Kit GND 引脚 rf13 VCC 引脚接 esp32Kit 3.3V 引脚 rf13 AO 引脚接 esp32Kit IO34 引脚

  • 问题内容: 我有一个应用程序可以点击麦克风,还可以根据麦克风输入播放声音(不必同时通过tho)。下面的代码有效。但是一个问题是输出在小型顶部扬声器而不是底部真实扬声器上播放。我可以通过 在播放器开始播放之前 将3行放在下面来奇怪地解决此问题,然后我可以听到扬声器上的声音。 但是,麦克风停止收听 !即使在播放器停止播放之后。基本上麦克风不喜欢 .defaultToSpeaker 任何想法? 这里也记

  • 使用光环板制作一个音量检测计,通过光环板的麦克风检测音量大小,并通过可视化的形式呈现出来,音量越大,LED灯环亮起的灯就越多。 1. 从事件类积木拖取一个 当按钮被按下时 积木。 2. 从控制类积木拖取一个 重复执行 积木。 3. 从灯光类积木拖取一个 显示LED环形图()% 积木,再添加一个传感器类积木 麦克风 响度。 4. 试着拍下桌子,看光环板LED环形图的变化吧! 下载代码