Numpy 与实空间卷积相比,FFT卷积的缺点是什么?

Numpy 与实空间卷积相比,FFT卷积的缺点是什么?,numpy,scipy,signal-processing,fft,convolution,Numpy,Scipy,Signal Processing,Fft,Convolution,所以我知道FFT卷积比实空间卷积的计算复杂度要低。但是FFT卷积的缺点是什么 内核大小是否总是必须与映像大小相匹配,或者是否有函数处理此问题,例如在pythonnumpy和scipy包中?那么抗锯齿效果呢 FFT卷积基于,其中规定给定两个函数f和g,如果Fd()和Fi()表示直接和反向傅里叶变换,*和卷积和乘法,则: f*g = Fi(Fd(d).Fd(g)) 要将此应用于信号f和内核g,需要注意以下几点: f和g必须具有相同的大小,才能实现乘法步骤,因此需要对内核进行零填充(或者输入,如果

所以我知道FFT卷积比实空间卷积的计算复杂度要低。但是FFT卷积的缺点是什么


内核大小是否总是必须与映像大小相匹配,或者是否有函数处理此问题,例如在pythonnumpy和scipy包中?那么抗锯齿效果呢

FFT卷积基于,其中规定给定两个函数
f
g
,如果
Fd()
Fi()
表示直接和反向傅里叶变换,
*
卷积和乘法,则:

f*g = Fi(Fd(d).Fd(g))
要将此应用于信号
f
和内核
g
,需要注意以下几点:

  • f
    g
    必须具有相同的大小,才能实现乘法步骤,因此需要对内核进行零填充(或者输入,如果内核比它长)
  • 当进行DFT时(FFT就是这样做的),函数的频域表示结果是周期性的。这意味着,默认情况下,在进行卷积时,内核会环绕边缘。如果你想要这个,那么一切都很好。但是如果没有,您必须添加一个额外的零填充来避免内核的大小
  • 大多数(全部?)FFT软件包只在没有任何大的基本因子的情况下工作良好(性能方面)。将信号和内核大小四舍五入到下一个二次方是一种常见做法,可能会导致(非常)显著的速度提升
如果您的信号和内核大小是
f_l
g_l
,则在时域中进行直接卷积需要
g_l*(f_l-g_l+1)
乘法和
(g_l-1)*(f_l-g_l+1)
加法

对于FFT方法,您必须至少进行3次大小为
f_l+g_l
的FFT,以及
f_l+g_l
乘法

对于大尺寸的
f
g
,FFT的
n*log(n)
复杂度明显优越。对于小内核,直接方法可能更快


scipy.signal
有两种方法供您使用。并且
fftconvolve
为您透明地处理上述所有填充。

而快速卷积比直接形式卷积具有更好的“大O”复杂度;有一些缺点或警告。我对这个话题做了一些思考,因为我之前写过

  • 更好的“大O”复杂性并不总是更好。对于小于一定尺寸的滤波器,直接形式卷积比使用FFT更快。具体大小取决于所使用的平台和实现。交叉点通常在10-40系数范围内

  • 延迟。快速卷积本质上是一种分块算法。对于某些实时应用程序来说,在转换之前一次将数百或数千个样本排队可能是不可接受的

  • 实现复杂性。直接形式在内存、代码空间和编写/维护人员的理论背景方面更简单

  • 在定点DSP平台上(不是通用CPU):定点FFT的有限字长考虑使得大型定点FFT几乎无用。在尺寸谱的另一端,这些芯片具有专门的MAC指令,这些指令是为执行直接形式FIR计算而精心设计的,增加了O(N^2)直接形式比O(NlogN)快的范围。这些因素倾向于创建一个有限的“最佳点”,其中定点FFT对于快速卷积非常有用


  • 请注意,只有当内核超过一定大小时,频域中的卷积才更有效。对于相对较小的内核,直接卷积更为有效。“大多数(全部?)FFT包只适用于没有任何大的素数因子的大小。”:确切地说,你所说的只是速度,计算本身没有问题(至少在numpy和scipy中)。是的,在我的回答中添加了一个注释。典型的FFT算法递归地将大小为
    N=a*b
    的DFT分解为大小为
    b
    的FFT。如果
    N
    是prime,则需要加快速度。在我的电脑上:
    %timeit numpy.fft.fft(np.random.rand(1024));10000个回路,最好为3个:每个回路36.2 us;%timeit numpy.fft.fft(np.rand.rand(1021));100个循环,每个循环最好3:2.15毫秒
    ,一个x100的减速,这似乎表明质数大小的DFT是直接计算的,没有加速度。看起来FFTW有加速度:“质数因子小的尺寸是最好的,但FFTW使用O(N log N)算法,即使对于质数大小也是如此。”。Is也支持多处理。它可以从python与pyfftw一起使用。请注意,如果使用“重叠添加”或“重叠保存”方法(将输入信号分割为多个片段进行处理),内核不必进行零填充,以使其与信号大小相同。