Audio 缩小FFT频谱范围

Audio 缩小FFT频谱范围,audio,numpy,fft,spectrum,nyquist,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。无论如何,我不在乎比这更重要的事。这将把我的工作频谱减

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

我希望我的措辞足够清楚。让我知道如果我需要调整我的解释或术语。

将FFT的大小加倍将是显而易见的事情,但是如果有一个很好的理由你不能做到这一点,那么在FFT之前考虑2x下采样以使有效的采样率降到22050赫兹:

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

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

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


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

如果您不想在相邻的频率峰值或噪声之间进行解析,那么,在频率间隔为一半的情况下,您可以将数据归零以使FFT长度加倍,而无需等待更多数据。然后,如果您只需要频率范围0..Fs/2的下半部分,只需扔掉FFT结果向量的中半部分(这通常比通过非FFT方法计算频率范围的下半部分要有效得多)


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

我刚刚添加了代码,用于获取从采样创建到fft转换的传入音频。你能告诉我你的三个台阶在哪里吗?我不确定您是否在使用python,但我无法访问此项目的Scipy库。我无法将FFT加倍,因为我的样本的时间窗口需要尽可能紧(128块就可以了)。另外,我假设如果我想要所有的频率在11025到22050之间,那么我只应用一个从11024Hz开始的高通滤波器,对吗?啊-你运气不好-你不能从稀薄的空气中获得信息-在采样窗口持续时间和频率分辨率之间有一个折衷(见海森堡)。下采样(或其他任何事情)对你没有帮助-你唯一的选择就是增加你的样本窗口大小。嗯,我想可能是这样的。我希望我能在样本采集上设置一个窗口,集中精力采集一定范围内的样本。感谢您提供的信息,非常感谢。没问题-为了将来的参考,关于DSP理论的问题(与实际编程问题相反)通常会得到更好的回答。这是在python中动态设计过滤器的起点。若你们认为带通中心频率和采样率是恒定的,那个么这个代码是不必要的。然而,这可能是有见地的。如果您查看BPF的代码分支,您将看到它在给定其他输入参数的情况下最终生成一组称为a和b的系数。这些系数随后将在实现中使用。我找不到Python例子,但是看看C++代码中的进程函数,你会得到一个想法:A.WyLi-DigiCyoTo:你的问题是什么?我只是把我的LinkedIn链接到我的配置文件中,这样你也可以在那里联系我。如果我只想要上半部呢?Fs/2到22050?你是指Fs/4到Fs/2吗?(11025到22050)这是在44.1ksps下使用基带采样时正频率的上半部分。然后只保留FFT结果的中间部分(N/4到3N/4)。当然,对于严格的实输入,其中一半,其余的只是一个复共轭镜。