python - 如何使用 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:将复数值转换为实数会丢弃虚数部分”,但在简单地执行立体声到单声道的转换和保存时,我也会收到此警告。音频似乎听起来不错,直到我尝试过滤它。我猜这是相关的,但不知道如何解决它。
我过滤的任何音频样本最终听起来像白噪声,而不是其自身的过滤版本。
解决方案
切换到实数到复数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
。
推荐阅读
- google-analytics - Google Analytics(分析)多域跟踪的默认 URL
- excel - 可以匹配单元格,而这两个单元格相等
- python - 检查文本中的单词,如果它与字典键匹配,则添加到该键的值
- json - 如何使用包含已编码值的 Encodable 在 Swift 中编码结构
- verilog - 如何在 Verilog 中初始化一个整数数组?
- amazon-web-services - 在 ECS 中运行的 .Net Core 应用程序的 S3 请求超时
- java - 如何使用 split 和 Array 读取 .txt 文件
- java - 在所有 GridLayout 点中应用相同的 JLabel?
- html - 倾斜按钮,取消倾斜文本
- java - 是否可以将 application.yml 变量放入属性文件?