减少FFT频谱范围

时间:2015-05-06 04:53:49

标签: audio numpy fft spectrum nyquist

我目前在44100Hz音频样本上运行Python的Numpy fft,这使我的工作频率范围为0Hz - 22050Hz(感谢Nyquist)。一旦我在这些时域值上使用fft,我的fft频谱中有128个点,每个频率仓大小为172Hz。

我想将频率箱收紧到86Hz,并且仍然只保持128 fft点,而不是通过调整我创建样本的方式将fft数量增加到256.

我的问题是这在理论上是否可行。我的想法是在0Hz到11025Hz之间的任何Hz值上运行fft。无论如何,我并不关心任何事情。这会将我的工作频谱减少一半,并将我的频率箱设置为86Hz,同时保持我的128个频谱箱。也许这可以通过时域中的窗口函数来实现?

目前我用来创建我的样本然后转换为fft的代码是:

import numpy as np

sample_rate = 44100
chunk = 128
record_seconds = 2

stream = self.audio.open(format=pyaudio.paInt16, channels=1,
                        rate=sample_rate, input=True, frames_per_buffer=6300)

sample_list = []

for i in range(0, int(sample_rate / chunk * record_seconds)):
    data = stream.read(chunk)
    sample_list.append(np.fromstring(data, dtype=np.int16))

### then later ###:

for samp in sample_list:
        samp_fft = np.fft.fft(samp) ...

我希望我说得足够清楚。如果我需要调整我的解释或术语,请告诉我。

3 个答案:

答案 0 :(得分:2)

你要求的是不可能的。正如您在评论中提到的,您需要一个短时间窗口。我认为这是因为您正在尝试检测信号何时到达某个频率(因为我已经回答了您之前关于该主题的问题),并且您希望检测对时间敏感。但是,您的垃圾箱尺寸似乎太大,无法满足您的要求。

只有两种方法可以减小bin的大小。 1)增加FFT的长度。不幸的是,这也意味着获取数据需要更长的时间。 2)降低采样率(通过采样率转换或硬件级别),但由于采样速度较慢,因此采集数据也需要更长时间。

我将向您建议第三种选择(从我收集到的内容以及您的其他问题可能是更好的解决方案),即:在时域中执行频率检测。这需要的是时域带通滤波器,后跟RMS仪表。实现方面,这将是一个或多个biquad过滤器,您可以在python中为过滤器实现 - 可能已经有可用的实现。棘手的部分是设计过滤器,但我很乐意帮助你聊天。 RMS表基本上取得了滤波器输出样本平方和的平方根。

答案 1 :(得分:1)

将FFT的大小加倍是显而易见的事情,但如果有充分理由不能这样做,那么请在FFT之前考虑2x下采样,以使有效采样率降至22050 Hz:

- Apply low pass filter with cut off at 11 kHz
- Discard every other sample from filtered output
- Apply FFT to down-sampled data

答案 2 :(得分:0)

如果您没有尝试在相邻的频率峰值或噪声之间进行求解,那么,对于频率区间距的一半,您可以将数据填零以使FFT长度加倍,而无需等待更多数据。然后,如果您只想要频率范围的下半部分0..Fs / 2,只需丢弃FFT结果向量的中间一半(这通常比通过计算频率范围的下半部分效率高得多)非FFT意味着。)

请注意,零填充提供与高质量插值相同的结果(如平滑原始FFT结果点的绘图)。它不会增加峰值分离分辨率,但如果噪声水平足够低,可能会更容易在图中找出更精确的峰值位置。