我有两个信号x1和x2。我试图一次直接使用CONV(x1,X2)进行一次卷积,一次使用fft和ifft进行卷积,并比较两个操作的执行时间。
我不知道为什么fft的执行时间不会比使用conv快。
n = 0: 2^15 ;
x1(n+1) = (0.25).^n ;
x2(n+1) = 1;
tic
Time_Convolution = conv(x1,x2);
toc
Padding = (length(x1)+ length(x2) - 1)-length(x1) ;
x1_before_fft = [ x1 zeros(1, Padding) ];
x2_before_fft = [ x2 zeros(1, Padding)];
tic
Convolution = ifft(fft( x1_before_fft).*fft(x2_before_fft));
toc
这是输出
经过的时间为0.010414秒。 经过的时间是0.017308秒。
答案 0 :(得分:1)
这里的关键是输入信号之一主要包含零,因为您失去了将精度从0.25提高到较大幂的舍入精度。
>> nnz(x1) / numel(x1)
ans =
0.0164
少于2%的第一个输入为非零。卷积的直接实现可以利用它来摆脱很多对结果没有任何贡献的操作。但是,基于FFT的卷积将始终执行几乎相同的工作量,而与所涉及系数的大小无关。
当您将这些系数设为非零时,情况就大不相同了。在我的机器上,我看到:
>> tic; for k = 1:100, conv(x1,x2); end, toc
Elapsed time is 0.291373 seconds.
>> x1 = x1 + eps;
>> tic; for k = 1:100, conv(x1,x2); end, toc
Elapsed time is 3.937819 seconds.
要注意的另一件事是,您正在使用不幸的FFT大小选择来通过FFT进行卷积。任何使用至少length(x1)+length(x2)-1
个点的变换都可以解决问题(如果您有较大的变换,则只需在末尾修剪掉所有额外的系数),因此最好选择一个素数较小的变换。但是,在这种情况下,length(x1)+length(x2)-1
本身就是素数,因此这是最糟糕的选择。只需将长度增加1:即可看到不同之处。
>> N = length(x1)+length(x2)-1; % Original size.
>> tic; for k = 1:100, ifft(fft( x1, N).*fft(x2,N)); end, toc
Elapsed time is 1.036913 seconds.
>> N = length(x1)+length(x2); % Better size.
>> tic; for k = 1:100, ifft(fft( x1, N).*fft(x2,N)); end, toc
Elapsed time is 0.289473 seconds.
当然,如果不断减少N的因素,您甚至可以做得更好:
>> N = length(x1)+length(x2)
N =
65538
>> while max(factor(N)) > 7, N = N + 2; end
>> N
N =
65610
>> tic; for k = 1:100, ifft(fft( x1, N).*fft(x2,N)); end, toc
Elapsed time is 0.250967 seconds.
因此,仅通过选择更好的变换大小,您就能获得4倍的加速,并且即使具有conv
能够针对所有这些零进行优化的能力,您也将获得更好的速度。