首页 > 解决方案 > 如何使用 fft 为音频创建低通滤波器

问题描述

我试图为 aiff 文件创建一个低通滤波器,但发出的声音是白噪声。我只了解 FFT 如何工作的广泛概述,所以我猜我的问题与此有关。

基本上,我打开音频文件(比如说钢琴循环),将其转换为单声道,然后对样本执行 FFT,然后我尝试通过将它们设置为零来去除高频。最后我执行 IFTT 并将结果保存到一个新文件中。

import aifc
import struct
import numpy as np

def getMonoSamples(fileName):
    enter code here`obj = aifc.open(fileName,'r')
    obj.setpos(0)
    numFrames = obj.getnframes()
    myFrames = obj.readframes(numFrames)
    samplingRate = obj.getframerate()
    data = struct.unpack('{n}h'.format(n=numFrames*2), myFrames)
    data = np.array(data)
    dataLeft =[]
    for i,x in enumerate(data):
        if i%2==1:
            dataLeft.append(x)
    obj.close()
    return dataLeft,numFrames,samplingRate

def writeMonoFile(fileName,samples,nframes):
    mono_file=aifc.open(file, 'w')
    comptype="NONE"
    compname="not compressed"
    nchannels=1
    sampwidth=2
    mono_file.setparams((nchannels, sampwidth, int(sampling_rate), nframes, comptype, compname))
    print "writing sample aif..."
    for s in samples:
       mono_file.writeframes(struct.pack('h', s))
    mono_file.close()

def lpFilter(dataFft):
    new =[None]*len(dataFft)
    for i,x in enumerate(dataFft):
        #if the frequency is above 5000, remove it
        if i>5000:
            new[i]=0
        else:
            new[i]=x
    return new
# get audio samples from a function that converts stereo to mono
sampleData,numFrames,samplingRate = getMonoSamples('beetP2.aif') 
dataFft = np.fft.fft(sampleData)
filtered = lpFilter(dataFft)
invFft = np.fft.ifft(filtered)
invFft = [int(x) for x in invFft]
file = "test.aif"
writeMonoFile(file,invFft,numFrames)

我确实收到了警告:“ComplexWarning:将复数值转换为实数会丢弃虚数部分”,但在简单地执行立体声到单声道的转换和保存时,我也会收到此警告。音频似乎听起来不错,直到我尝试过滤它。我猜这是相关的,但不知道如何解决它。

我过滤的任何音频样本最终听起来像白噪声,而不是其自身的过滤版本。

标签: pythonaudiofilteringfft

解决方案


切换到实数到复数numpy.fft.rfft及其倒数numpy.fft.irfft可能会解决问题。

由于复数到复数的 DFT 变换应用于实数数组sampleData,因此输出数组是dataFft相同大小的复数数组。该数组的第一项对应于 DC 分量,第二项对应于频率 1/N,第三项对应于 2/N……然而,数组的后半部分应该被描述为负频率分量。因此,数组最后一项的频率是 -1/N,-2/N 之前的项目...如FFTW 真正计算的内容中所述

对于那些喜欢考虑正频率和负频率的人来说,这意味着正频率存储在输出的前半部分,负频率按倒序存储在输出的后半部分。(频率 -k/n 与频率 (nk)/n 相同。)

由于信号是实数,频率 -k/N 的分量必须是频率 k/N 的分量的复共轭。例如,频率为 k/N 的余弦波会产生频率为 k/N 和 -k/N 的两个相等的实数分量。

通过将阵列的后半部分归零,具有低负频率的分量被丢弃,并且阵列不再对应于实际阵列的 DFT。它不是低通滤波器,可以解释产生的白噪声。当应用逆 DFT 时invFft = np.fft.ifft(filtered),它的结果invFft是复杂的,具有与原始数组相同的大小sampleData

使用从实数到复数的 DFT 会将实数数组sampleData转换为大约一半大小的复数数组dataFft。将该阵列的一个分量归零意味着将正频率和负频率都归零,确保该阵列仍然可以被视为真实阵列的 DFT。这个真实的数组最终可以通过应用逆变换来恢复irfft


推荐阅读