Python寻找音频的频率和振幅随时间变化的方法

6
这是我想要做的事情:我想在一个.wav文件中每1毫秒找到音频频率和振幅,并将其保存到文件中。我已经绘制了频率与振幅的图形,也绘制了随时间变化的振幅图形,但我无法解决随时间变化的频率问题。我的最终目标是能够读取该文件并使用振幅来调整变量,使用频率来触发哪些变量正在被使用,这似乎是容易的部分。我一直在使用numpy、audiolab、matplotlib等工具,使用FFT算法,但我就是无法解决这个问题,非常需要帮助!谢谢!

2
一个声音文件在任何给定的时间都不只有一个“频率”,除非它只是一个纯正弦波音调的录音。你可能需要做的是定期捕获功率谱并存储它,或者可能对功率谱进行某种处理,例如识别最大的N个峰值并将其存储。 - Paul R
https://dev59.com/IXRB5IYBdhLWcg3wgHar - sylvanaar
1个回答

7
使用重叠窗口的STFT来估算频谱图。为了避免自己麻烦,您可以使用Matplotlib的mlab的specgram方法。重要的是使用足够小的窗口使音频近似静止,并且缓冲区大小应该是2的幂以有效地使用常见的基数2 fft。512个样本(在48 ksps下约10.67毫秒;或每个bin 93.75 Hz)应该足够。对于48 ksps的采样率,重叠464个样本以在每1毫秒(即移位48个样本)评估滑动窗口。

编辑:

这是一个例子,使用mlab.specgram处理一个8秒的信号,其中每秒有1个音调从2kHz到16kHz。请注意瞬态响应。我已经在第4秒放大显示了响应的更多细节。频率在精确的第4秒发生变化,但需要一个缓冲区长度(512个样本; 约+/-5毫秒)才能通过瞬态。这说明了非平稳过渡通过缓冲区时产生的一种谱/时间模糊。此外,即使信号是平稳的,也存在由于对数据进行窗口处理而导致的谱泄漏问题。使用Hamming 窗函数来最小化泄漏的旁瓣,但这也会加宽主瓣。

spectrogram

import numpy as np
from matplotlib import mlab, pyplot

#Python 2.x:
#from __future__ import division

Fs = 48000
N = 512
f = np.arange(1, 9) * 2000
t = np.arange(8 * Fs) / Fs 
x = np.empty(t.shape)
for i in range(8):
    x[i*Fs:(i+1)*Fs] = np.cos(2*np.pi * f[i] * t[i*Fs:(i+1)*Fs])

w = np.hamming(N)
ov = N - Fs // 1000 # e.g. 512 - 48000 // 1000 == 464
Pxx, freqs, bins = mlab.specgram(x, NFFT=N, Fs=Fs, window=w, 
                                 noverlap=ov)

#plot the spectrogram in dB

Pxx_dB = np.log10(Pxx)
pyplot.subplots_adjust(hspace=0.4)

pyplot.subplot(211)
ex1 = bins[0], bins[-1], freqs[0], freqs[-1]
pyplot.imshow(np.flipud(Pxx_dB), extent=ex1)
pyplot.axis('auto')
pyplot.axis(ex1)
pyplot.xlabel('time (s)')
pyplot.ylabel('freq (Hz)')

#zoom in at t=4s to show transient

pyplot.subplot(212)
n1, n2 = int(3.991/8*len(bins)), int(4.009/8*len(bins))
ex2 = bins[n1], bins[n2], freqs[0], freqs[-1]
pyplot.imshow(np.flipud(Pxx_dB[:,n1:n2]), extent=ex2)
pyplot.axis('auto')
pyplot.axis(ex2)
pyplot.xlabel('time (s)')
pyplot.ylabel('freq (Hz)')

pyplot.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接