为何用FFT乘积对一维数组做卷积时结果值存在差异?
为什么FFT逐元素相乘的逆变换与直接卷积结果存在差异?
你观察到的差异核心原因是循环卷积和线性卷积的区别:
scipy.fft.fft默认对输入序列做长度等于原序列长度的FFT,此时逐元素相乘再逆FFT得到的是循环卷积,结果长度和输入序列一致(这里是4)。np.convolve默认计算的是线性卷积,结果长度为len(A) + len(B) - 1(这里是4+4-1=7)。
循环卷积的本质
循环卷积会把线性卷积的结果进行“循环折叠”:将线性卷积中超出输入长度的部分,循环加到前面的对应位置上。以你的例子来说:
线性卷积结果是 [6,23,34,52,50,17,18],循环卷积长度为4,所以每个位置的值是:
- 第0位:
6 + 50 = 56(线性卷积第0位 + 第4位) - 第1位:
23 + 17 = 40(线性卷积第1位 + 第5位) - 第2位:
34 + 18 = 52(线性卷积第2位 + 第6位) - 第3位:
52 + 0 = 52(线性卷积第3位,无对应循环位)
这正好和你得到的逆FFT结果[56.+0.j, 40.+0.j, 52.+0.j, 52.-0.j]完全对应。
如何用FFT得到线性卷积的结果
要让FFT方法等价于线性卷积,需要先对两个序列补零填充,让长度至少为 len(A)+len(B)-1(或者更高效的下一个2的幂长度),此时循环卷积就等同于线性卷积。修正后的代码如下:
import numpy as np from scipy.fft import fft, ifft a = [3, 4, 1, 2] b = [2, 5, 4, 9] # 计算线性卷积需要的最小长度 min_length = len(a) + len(b) - 1 # 对序列补零到最小长度 a_padded = np.pad(a, (0, min_length - len(a)), mode='constant') b_padded = np.pad(b, (0, min_length - len(b)), mode='constant') # 执行FFT、逐元素相乘、逆FFT fft_a = fft(a_padded) fft_b = fft(b_padded) result_fft = ifft(fft_a * fft_b).real.round() # 取实部并消除浮点误差 print(result_fft) # 输出:[ 6. 23. 34. 52. 50. 17. 18.] # 对比线性卷积结果 result_conv = np.convolve(a, b) print(result_conv) # 输出:[ 6 23 34 52 50 17 18]
这样两种方法的结果就完全一致了。
内容的提问来源于stack exchange,提问作者Linear Algebra fans
相关产品推荐
相关产品推荐

