自学,获得优质频谱图

信息处理 声音的 Python 频谱图
2022-02-12 00:10:04

所以我一直在自学信号处理,并一直在尝试使用 Python 来获得高质量的频谱图,质量频谱图就像会大胆地产生的频谱图等。我所做的步骤是:

  1. 我说“计算机”,以 .m4a 格式记录在我的 mac 上,然后我使用 ffmpeg 将其转换为 .wav

    $ ffmpeg -i computer.m4a -acodec pcm_s16le -ac 1 -ar 16000 computer.wav

  2. 通过以下方式导入 Python:

    sample_rate, samples = wavfile.read('/path/to/computer.wav')

  3. 现在我只是快速绘制样本图:

    plt.plot(samples)

    我得到这样的图表:

    音频样本图

    为什么我的峰被封顶?

  4. 无论如何,我继续,据我所知,我执行傅里叶变换,将我的信号分解为不同幅度和频率的正弦波,然后得到生成的复数的实部:

    样本_fft = np.fft.rfft(样本)
    频率 = np.abs(samples_fft)

  5. 我现在绘制频率图:

    音频频率图

    这就是我猜想的样子,因为人声频率通常在 100 到 1000 之间,对吧?

  6. 频谱图是将我的样本分成一定数量的窗口,然后对每个窗口进行傅里叶变换,从而得到一个时间频率图。

    最后风 = 0
    windows = np.linspace(0,len(samples),1000)
    频谱图 = []
    对于窗口中的窗口:
        如果窗口!= 0:
            samples_in_range = samples[last_wind:int(window)]
            samples_in_range_fft = np.fft.rfft(samples_in_range)
            频率_in_range = np.abs(samples_in_range_fft)
            spectrogram.append(list(frequencies_in_range))
            last_wind = int(窗口)
    谱图2 = np.asarray(谱图).T

  7. 绘制频谱图:

    audio_length = len(samples)/sample_rate
    audio_time_intervals = np.linspace(0,audio_length,999)
    tempfreq = np.linspace(0,1,19)
    plt.pcolormesh(audio_time_intervals,tempfreq,spectrogram2)

音频数据的频谱图

所以现在我有一个频谱图,但质量很差。但我一直在看 youtube 视频,比如这个,我如何获得更好的分辨率和清晰度以便阅读元音中的共振峰等内容,我尝试改变分区的大小,但仍然得到非常相似的结果,更多的窗口在每个窗口中获得较少的频率数据,并且较少的窗口获得较差的时间分辨率。

我对信号处理非常陌生,因此将不胜感激任何帮助,例如正确方向的点或关于我做错了什么的指针,以便获得清晰的频谱图以便研究。

注意,我已经尝试过这样的 python 包signal.spectrogram,但结果也很差。另外,我宁愿了解细节,这样我才能真正了解发生了什么。

2个回答

为什么我的峰被封顶?

您的放大增益设置得太高,或者您离麦克风太近。放大器被驱动到它的极限,它会限制输出。保留这个录音,然后在离麦克风稍远一点的地方再做一个录音,以便稍后比较频谱图中的差异。看看这种削波如何在频谱中表现出来将会很有趣。

...我如何获得更好的分辨率和清晰度以便读取元音中的共振峰等内容,我尝试更改分区的大小,但仍然得到非常相似的结果,更多的窗口在每个窗口中获得更少的频率数据,并且较少的窗口得到较差的时间分辨率。

在第 6 点的第 7 行,您使用了numpy.fft.rfft

从文档中......输出的转换轴的长度因此是n//2 + 1.

您的信号在 16kHz 的采样频率 (Fs) 下长约 2 秒,您将其划分为 1000 个样本的窗口,这些窗口由 965 个样本重叠。这大约是 97% 的重叠。

这 97% 的重叠是非常高的时间分辨率。您缺少的是频率分辨率,而增加频率分辨率的唯一方法是增加窗口大小。这将使快速傅里叶变换 (FFT) 有机会解析更多频率。

这些是 Audacity 用于导出频谱图的参数:

在此处输入图像描述

在此处输入图像描述

这里有两点需要注意:

  1. Audacity 的所有窗口大小都是 2 的幂。这样做是为了利用计算 FT 的计算结构并执行 F(ast)

  2. 窗口大小与 FFT 的分辨率成反比。大小为 8 的窗口被标记为“最宽带”,大小为 32768 的窗口被标记为“最窄带”。当然,您的窗口大小与您的采样频率无关,并且考虑到在采样时已经捕获的数据,它可以解析多少频率分量是有限的。因此,更高的真实频率分辨率意味着捕获更多数据,这意味着增加采样频率。使用 16kHz,您可以(理论上)解析高达 8kHz。

因此,除了这里和那里的一些细节和优化之外,你的代码是正确的。

你错过了:

  1. 窗口功能(与您在代码中应用的滑动窗口长度(1000)无关)。如果您想解决诸如共振峰之类的问题,这将在以后变得很重要。

  2. “正确”绘图将绘图的 x 和 y 轴设置为解释频谱图所需的时间和频率尺度。这并不是一件非常困难的事情,但是您会发现自己需要它,否则每次您想从绘图中读取频率和偏移量时,您都会进行“信封背面”计算。

最终,您也会将这些添加到您的代码中,并且您将在很大程度上复制scipy.signal.spectrogram的功能。

因此,我建议您将精力集中在频谱图的细节上,以了解它的工作原理以及每个参数对其输出质量的影响。

对频谱图本身的一个很好的介绍就是这个当然,它并不是唯一的。

scipy.signal.spectrogram包括所有关键参数,它将让您舒适地探索频谱图。

最后,如果您对音频分析感兴趣,那么 Python 空间中有一些非常好的库,它们实现了您需要的许多功能。一些例子是pyAudioAnalysislibrosa这里更接近你的要求)。这里有更多可用的指针

希望这可以帮助。

除了其他人所说的之外,让我添加一些我认为对于创建详细的频谱图很重要的内容(此信息不针对 Python 或任何特定的音频库)

  1. FFT 帧(窗口)重叠--您的 FFT 帧应重叠至少 50%。这意味着如果您的 FFT 帧长度为 1024,则您的帧将从 0、512、1024、1536 等开始(对于 50% 的重叠)为了计算幅度,您将从 3 个连续帧的结果中取平均值(除了平均 2 帧的第一帧和最后一帧)。然后将这些平均幅度用于实际的频谱图显示。

    上面描述的重叠补偿了由于窗口(嗯,在一定程度上)导致的信息丢失,并且它增加了时间分辨率

  2. FFT bin 的数量由用于 FFT 的帧长度决定。如果您的帧长度为 1024,您将获得 512 个 bin(实际上是 1024,但只使用了前半部分)。实际的频谱图高度可能小于 512(箱数),在这种情况下,您显然无法显示每个箱。您应该使用峰值幅度,因为这最有意义(尤其是对于共振峰等)。如果您只是平均几个 bin,甚至随机跳过一些 bin,您的频谱图可能会丢失(不显示)重要信息。