我希望有人可以查看下面的代码并提供提示如何加快tic和toc之间的部分。下面的函数试图比Matlab的内置函数更快地执行IFFT,因为(1)几乎所有的fft系数区间都是零(即10
到1000
区间10M
to 300M
bin是非零的),以及(2)只保留IFFT结果的中心三分之一(丢弃第一个和后三个 - 所以不需要首先计算它们)。
输入变量是:
fftcoef = complex fft-coef 1D array (10 to 1000 pts long)
bins = index of fft coefficients corresponding to fftcoef (10 to 1000 pts long)
DATAn = # of pts in data before zero padding and fft (in range of 10M to 260M)
FFTn = DATAn + # of pts used to zero pad before taking fft (in range of 16M to 268M) (e.g. FFTn = 2^nextpow2(DATAn))
目前,此代码比Matlab的ifft
函数方法要长几个数量级,后者计算整个频谱然后丢弃它的2/3
。例如,如果fftcoef和bin的输入数据是9x1
数组(即每个边带只有9
个复数fft系数;考虑两个边带时18
pts),DATAn=32781534
,FFTn=33554432
(即2^25
),然后ifft方法需要1.6
秒,而下面的循环需要700
秒。
我避免使用矩阵来矢量化nn循环,因为有时fftcoef和bin的数组大小可能长达1000
个pts,而260Mx1K
矩阵对于内存来说太大了除非它能以某种方式被打破。
非常感谢任何建议!提前谢谢。
function fn_fft_v1p0(fftcoef, bins, DATAn, FFTn)
fftcoef = [fftcoef; (conj(flipud(fftcoef)))]; % fft coefficients
bins = [bins; (FFTn - flipud(bins) +2)]; % corresponding fft indices for fftcoef array
ttrend = zeros( (round(2*DATAn/3) - round(DATAn/3) + 1), 1); % preallocate
start = round(DATAn/3)-1;
tic;
for nn = start+1 : round(2*DATAn/3) % loop over desired time indices
% sum over all fft indices having non-zero coefficients
arg = 2*pi*(bins-1)*(nn-1)/FFTn;
ttrend(nn-start) = sum( fftcoef.*( cos(arg) + 1j*sin(arg));
end
toc;
end
答案 0 :(得分:3)
你必须记住,Matlab使用编译的fft库(http://www.fftw.org/)来实现其fft函数,除了比Matlab脚本运行速度快得多之外,它还针对许多用例进行了优化。因此,第一步可能是用c / c ++编写代码并将其编译为可在Matlab中使用的mex文件。这肯定会使你的代码加速至少一个数量级(可能更多)。
除此之外,您可以做的一个简单优化是考虑两件事:
这两点转换为以下循环:
nn=(start+1 : round(2*DATAn/3))';
ttrend2 = zeros( (round(2*DATAn/3) - round(DATAn/3) + 1), 1);
tic;
for bn = 1:length(bins)
arg = 2*pi*(bins(bn)-1)*(nn-1)/FFTn;
ttrend2 = ttrend2 + 2*real(fftcoef(bn) * exp(i*arg));
end
toc;
请注意,在展开bins
和fftcoef
之前,必须先使用 这个循环,因为已经考虑了对称性。使用您问题中的参数运行此循环需要8.3秒,而使用您的代码运行我的pc需要141.3秒。
答案 1 :(得分:0)
我在Accelerating FFTW pruning to avoid massive zero padding发布了一个问题/答案,它解决了使用FFTW的C ++案例的问题。您可以通过利用mex
- 文件来使用此解决方案。