Используйте STFT с перекрывающимися окнами для оценки спектрограммы. Чтобы избавить себя от необходимости кататься самостоятельно, вы можете использовать метод mlab Matplotlib. Важно использовать достаточно маленькое окно, для которого звук приблизительно неподвижен, а размер буфера должен быть степенью 2, чтобы эффективно использовать обычное значение radix-2 fft. 512 выборок (около 10,67 мс при 48 к / с; или 93,75 Гц на ячейку) должно быть достаточно. При частоте дискретизации 48 кбит / с наложение на 464 выборки для оценки скользящего окна каждые 1 мс (т.е. сдвиг на 48 выборок).
Редактировать:
Вот пример, который использует mlab.specgram
для 8-секундного сигнала, который имеет 1 тон в секунду от 2 кГц до 16 кГц. Обратите внимание на ответ на переходных процессах. Я увеличил масштаб в 4 секунды, чтобы показать ответ более подробно. Частота сдвигается ровно через 4 секунды, но для прохождения переходного процесса требуется длина буфера (512 выборок; приблизительно +/- 5 мс). Это иллюстрирует вид спектрального / временного размытия, вызванного нестационарными переходами, когда они проходят через буфер. Кроме того, вы можете видеть, что даже когда сигнал является стационарным, существует проблема спектральной утечки, вызванной окном данных. Оконная функция Хэмминга была использована для минимизации боковых лепестков утечки, но это также расширяет основной лепесток.
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()