Python NumPy - FFT和逆FFT?

7
我一直在使用FFT技术,目前我正在尝试使用FFT从文件中获取声音波形(并最终修改它),然后输出已修改的波形到文件。我已经得到了声波的FFT,然后对其使用了一个反向FFT函数,但是输出文件听起来一点也不对。我还没有对波形进行任何滤波-我只是测试一下如何获取频率数据,然后将其放回文件中-它应该听起来相同,但是听起来完全不同。
我之后一直在努力,但是还没有得到想要的结果。输出的声音文件很嘈杂(更响亮,并且存在原始文件中不存在的额外噪声),并且一个声道中的声音泄漏到另一个声道中(先前是静音的)。输入的声音文件是立体声2通道文件,只有一个声道有声音。以下是我的代码:
import scipy
import wave
import struct
import numpy
import pylab

from scipy.io import wavfile

rate, data = wavfile.read('./TriLeftChannel.wav')

filtereddata = numpy.fft.rfft(data, axis=0)
print(data)

filteredwrite = numpy.fft.irfft(filtereddata, axis=0)
print(filteredwrite)

wavfile.write('TestFiltered.wav', rate, filteredwrite)

我不太明白为什么这不起作用。
我已将问题.py文件和音频文件压缩,如果有帮助解决问题可以从这里下载。

3
在保存之前尝试添加filteredwrite = numpy.round(filteredwrite).astype('int16') - Bi Rico
@Bago - 非常感谢!问题完全解决了。我在想,将过滤后的ifft强制转换为'int16'是否意味着它将成为一个16位深度的声音文件? - SolarLune
我对wav文件不是很了解,我一直认为它们是原始的、未压缩的数据,但你需要阅读wav格式规范才能确定。 - Bi Rico
4个回答

7
  1. 您似乎没有应用任何过滤器。
  2. 您可能希望对fft(后处理过滤)而不是输入波形进行ifft

5
>>> import numpy as np
>>> a = np.vstack([np.ones(11), np.arange(11)])

# We have two channels along axis 0, the signals are along axis 1
>>> a
array([[  1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.],
       [  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.]])
>>> np.fft.irfft(np.fft.rfft(a, axis=1), axis=1)
array([[  1.1       ,   1.1       ,   1.1       ,   1.1       ,
          1.1       ,   1.1       ,   1.1       ,   1.1       ,
          1.1       ,   1.1       ],
       [  0.55      ,   1.01836542,   2.51904294,   3.57565618,
          4.86463721,   6.05      ,   7.23536279,   8.52434382,
          9.58095706,  11.08163458]])
# irfft returns an even number along axis=1, even though a was (2, 11)

# When a is even along axis 1, we get a back after the irfft.
>>> a = np.vstack([np.ones(10), np.arange(10)])
>>> np.fft.irfft(np.fft.rfft(a, axis=1), axis=1)
array([[  1.00000000e+00,   1.00000000e+00,   1.00000000e+00,
          1.00000000e+00,   1.00000000e+00,   1.00000000e+00,
          1.00000000e+00,   1.00000000e+00,   1.00000000e+00,
          1.00000000e+00],
       [  7.10542736e-16,   1.00000000e+00,   2.00000000e+00,
          3.00000000e+00,   4.00000000e+00,   5.00000000e+00,
          6.00000000e+00,   7.00000000e+00,   8.00000000e+00,
          9.00000000e+00]])

# It seems like you signals are along axis 0, here is an example where the signals are on axis 0
>>> a = np.vstack([np.ones(10), np.arange(10)]).T
>>> a
array([[ 1.,  0.],
       [ 1.,  1.],
       [ 1.,  2.],
       [ 1.,  3.],
       [ 1.,  4.],
       [ 1.,  5.],
       [ 1.,  6.],
       [ 1.,  7.],
       [ 1.,  8.],
       [ 1.,  9.]])
>>> np.fft.irfft(np.fft.rfft(a, axis=0), axis=0)
array([[  1.00000000e+00,   7.10542736e-16],
       [  1.00000000e+00,   1.00000000e+00],
       [  1.00000000e+00,   2.00000000e+00],
       [  1.00000000e+00,   3.00000000e+00],
       [  1.00000000e+00,   4.00000000e+00],
       [  1.00000000e+00,   5.00000000e+00],
       [  1.00000000e+00,   6.00000000e+00],
       [  1.00000000e+00,   7.00000000e+00],
       [  1.00000000e+00,   8.00000000e+00],
       [  1.00000000e+00,   9.00000000e+00]])

5
"这句话应该更像这样吗?"
filtereddata = numpy.fft.fft(data)
# do fft stuff to filtereddata
filteredwrite = numpy.fft.ifft(filtereddata)
wavfile.write('TestFiltered.wav', rate, filteredwrite)

@wim - 对此很抱歉 - 我编辑了原始帖子以提供更多信息。 - SolarLune

2

存在两个问题。

您正在对2通道数据进行FFT。为了使FFT结果有意义,您应该仅对单声道数据的1个通道进行FFT处理。如果要处理2个通道的立体声数据,则应分别对每个通道进行IFFT(FFT())。

您正在使用实际的FFT,这会丢弃信息,从而使FFT不可逆。

如果您想要反演,您将需要使用产生复数结果的FFT,然后将此复杂频域向量IFFT回到时间域。如果您修改频域向量,请确保它保持共轭对称,如果您想要一个严格的实际结果(减去数值噪声)。


你可以对多通道数据进行FFT,只需要使用一个二维数组,并确保轴关键字设置正确(默认为-1),而irfft(rfft(n))应该返回n(在机器精度范围内)。 - Bi Rico
如果 n.shape[axis] 是偶数,那么 irfft(rfft(n)) 似乎表现最佳。 - Bi Rico
@Bago - 很抱歉这么晚才开始处理,但你能详细解释一下你的意思吗?你说的“使用一个二维数组”是什么意思?你是指使用NumPy数组,对吗? - SolarLune
@Bago - 我认为我做得正确,但很难确定。数组是通过wavfile.read('./TriLeftChannel.wav')读入的,但形状为(x, 2),其中x是大量样本。因此,它已经是一个二维数组。我在使用FFT和IFFT时指定了轴,但输出没有改变... - SolarLune
@SolarLune,在这种情况下,提供一个简短的示例会非常有帮助。我认为如果你在SO上提供足够的信息来帮助其他人重现你的问题,你会得到更多的反馈。 - Bi Rico
@Bago - 你说得对。我已经在上面发布了我的问题代码,并制作了一个包含.py文件和音频文件的压缩包,以便有帮助。 - SolarLune

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接