1

我目前在 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) ...

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

4

3 回答 3

2

你所要求的是不可能的。正如您在评论中提到的,您需要一个较短的时间窗口。我认为这是因为您试图检测信号何时以特定频率到达(正如我已经回答了您之前关于该主题的问题),并且您希望检测对时间敏感。但是,您的 bin 大小似乎对您的要求来说太大了。

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

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

于 2015-05-06T08:00:24.163 回答
1

将 FFT 的大小加倍是显而易见的事情,但如果有充分的理由不能这样做,那么请考虑在 FFT 之前进行 2 倍下采样,以将有效采样率降至 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
于 2015-05-06T06:09:36.183 回答
0

如果您不尝试解决相邻频率峰值或噪声之间的问题,那么,将频率仓间距减半,您可以将数据补零以使 FFT 长度加倍,而无需等待更多数据。然后,如果您只想要频率范围的下半部分 0..Fs/2,只需丢弃 FFT 结果向量的中半部分(这通常比尝试通过以下方式计算频率范围的下半部分要高效得多非 FFT 表示)。

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

于 2015-05-06T18:02:16.857 回答