Python 中复数的 FFT 滤波器

FFT Filter on Complex Numbers in Python

我的问题与 A. Levy 的解释有关: Analyze audio using Fast Fourier Transform

如何在这些复数上生成 带通滤波器...

[-636.00000000 +0.00000000e+00j  -47.84161618 -2.80509841e+02j
30.69754505 -1.30624718e+01j -109.94022791 +7.58155488e+00j
-3.18538186 +1.44880882e+01j -120.36687555 +5.45225425e+00j
50.48671763 +1.69504204e+01j   31.56751791 -7.22728042e+01j
-17.96079093 -3.17853727e+01j  -19.25527276 +5.08151876e+00j
18.38143611 -2.60879726e+01j  -27.15617871 -4.39789289e+01j...

... 已经知道我将使用 ifft 将复数数组转换回时域。我的带通应该只允许 18500Hz 到 19500Hz 通过(超音速,我知道。我专门寻找那些从房间另一头的音调发生器传来的音调)。我的采样率是 44100Hz,我的 FFT 中的点数是 128。

然后我将在这里使用频率检测代码(它已经在我的非过滤样本上工作)Python frequency detection以便在它到达时给我音频音高。如果在 19000HZ 没有播放音调(例如),那么音调检测函数的输出应该 return 0.

我当前的过滤器代码(没有给我正确的结果):

samp = [-10 -16 -15 -11 -8 -10 -9  -12 -7 -13 -4 -10 
        -1  -4  -11 -6 -8 -8 -10 -6 -9 -7 -16 -11 5 -14   
        -9 -3 -9 -7 -7 -6 -3 -11 -13 -9 -10 -4 -6 -7 
        -11 -15 -15 -3 -5 -15 -11 -8 -13 -9 -12 -10 -8 -16  
        -13 -5 -4 -12 -14 -8 -14 -6 -7 -7 -4 -6 -9 -4 -4  
        -4  1 -10 -3 -9 -9  -1 -5 -2 -5 -3 -3  2 -3  2  
        -5 -4 -6  1 -2 -6 -8  -3 -10 -11 -6 -2 -5  -3   
         0  3  0  1  1 -1 -3 -3  1  3 -3 -3  3 -3 -1  
        -3  -1  2  1  0 -8  0  6 -3 -4 -7 -5 -10 -4 -4]

sample_time = 0.000022675   # 1/44100

low_cut = 18500
high_cut = 19500

float_samp = np.float32(samp)
fft_spectrum = np.fft.fft(float_samp)

freqs = np.fft.fftfreq(len(fft_spectrum), d=sample_time)

### wrong approach ###
for i in range(len(freqs)): # (H-red)

    if abs(freqs[i]) >= high or abs(freqs[i]) <= low:
        fft_spectrum[i] = 0.0 
### -------------- ###

time_domain = np.fft.ifft(fft_spectrum)
converted = np.int16(time_domain)

目前 return在音调检测后在 18500Hz 和 19500Hz 之间计算值,无论音调是否存在。我相信是这种情况,因为我从我的 fft_spectrum 列表中删除了所有信息,除了那些包含在我的过滤器值中的信息。即使音调不存在,唯一留下的信息就是那个频段内的信息,所以这就是音调检测器正在读取的内容。这是我的假设。

请注意: 我无法使用 Scipy,因为我正在 Android 上部署它,并且该库在该平台上不可用。我希望有一种方法可以通过 Numpy 做到这一点。

您链接的频率检测代码正在执行 FFT,然后找到幅度最大的 bin。它要 return 为零的唯一方法是最大幅度位于第 0 个 bin 中。即使您可能不会以您感兴趣的频率发出音调,但那里肯定有能量,因此是最大的候选者。要执行您所要求的操作,您需要修改引用的代码以提供所需的行为。例如,您可以应用某种最小阈值。

which = fftData[1:].argmax() + 1
if (fftData[which] < threshold)
    return -1; // no peak found

当你这样做的时候:我不明白你为什么要经历带通滤波信号的过程,而你只能限制频率检测来搜索感兴趣的箱子:

binMin = floor(low_cut / 22050.0 * 128)
binMax = ceil(high_cut / 22050.0 * 128)
which = fftData[binMin:binMax].argmax() + 1