我知道这个话题已被多次访问过,所以请提前道歉。我只是无法解决效率低下的循环操作,并希望得到你的帮助。
我正在实现一个for循环,它对时域周期数据求和。我使用从先前FFT获得的傅里叶系数。我的问题是我需要在周期信息中添加额外的时域数据,所以我不能简单地使用逆FFT运算。我基本上编辑标准的离散傅立叶变换(DFT)和,即:
for k = 1:L
x = x + F(k+1)*exp(1j*(omega(k+1)*t));
end
在这个系列中,F是我的傅立叶系数,omega是频率向量,t是时间向量。我必须改变总和,使它看起来像这样:
for k = 1:L
x = x + F(k+1)*exp(1j*(omega(k+1)*t)+1j*k*xt);
end
唯一的变化是我现在包括一个向量,它是一个时域函数(例如正弦波),我称之为xt。问题是时域信息必须具有极其精细的分辨率(10秒记录大约5e6长)。我无法缩短时间长度,因为我需要高频分辨率。这导致我的机器上的单个功能评估大约7小时(我必须承认,这不是最好的)。我需要在优化设置中评估函数,因此7小时的函数评估时间是不可行的。
我试图对操作进行矢量化,但是矩阵变得太大而我的计算机无法处理,并且MATLAB已经更新以便更有效地处理循环。我曾尝试编写自己的快速傅里叶变换版本,但是因为我在每一步编辑频率信息,Cooley和Tukey算法需要分解的某些假设。有谁知道如何将上述总和重写成更有效的格式?我也预先分配了矢量。
答案 0 :(得分:1)
所以,问题:
循环很慢,但解决了可用内存中的问题;
矢量化很快,但会耗尽你的记忆;
我无法发布代码,因为您提供的关于但混合解决方案如何:您可以在可以矢量化的频率间隔中分割问题,并在整个频率间隔(块)而不是每个频率上累积部分解。类似的东西:F
,omega
,t
和xt
的外观的详细信息太少(即确切尺寸和值的范围),
%%
clear all; % [!] BEWARE BEFORE EXECUTING, IT DELETES STUFF!!!
N = 1016419;
R = 524288;
t = linspace(1,10,N);
F = 400*rand(1,R) + 200i*rand(1,R);
omega = 1./(1:R);
xt = sin(0.23*t);
x = zeros(size(xt));
U = 10;
% ck1 = repmat(1i*t, U, 1); % trying to be extra clever is
% ck2 = repmat(1i*xt, U, 1); % not always good for the health
ck1 = 1i*t;
ck2 = 1i*xt;
u0 = 1;
tic;
while u0 < R
u1 = min(u0+U-1,R);
% x = x + sum(bsxfun( ...
% @times, ...
% F(u0+1:u1+1).', ...
% exp(omega(u0+1:u1+1).' * ck1 ...
% + (u0+1:u1+1).' * ck2 ...
% ) ...
% ));
x = x + sum(bsxfun( ...
@times, ...
F(u0+1:u1+1).', ...
exp(bsxfun(@times, ck1, omega(u0+1:u1+1).') ...
+ bsxfun(@times, ck2, (u0+1:u1+1).') ...
) ...
));
u0 = u1 + 1;
fprintf('%d iterations: %.0f sec.\n', u1, toc);
end;
U
的值应该足够小,因此xu
贡献的矢量化版本适合内存,并且足够大以使矢量化成为重要因素。所以你需要进行一些实验。
答案 1 :(得分:1)
我认为这可能是一种使用bsxfun
执行所需内容的矢量化方法。
k = 1:L;
x = x + sum(bsxfun(@times, F(k+1), exp(1j*(bsxfun(@times, omega(k+1), permute(t, [2 1])) + bsxfun(@times, k, permute(xt, [2 1]))))), 2).';
注意:对于此解决方案F
,omega
,k
,t
和xt
都应为列向量,那是1x?
。
首先使用
计算指数exp(1j*(omega(k+1)*t)+1j*k*xt)
e = exp(1j*(bsxfun(@times, omega(k+1), permute(t, [2 1])) + bsxfun(@times, k, permute(xt, [2 1]))))
生成MxL
矩阵,其中M
是t
和xt
的长度。接下来,我们将F
(维度1xL
)的每一列乘以
Fe = bsxfun(@times, F(k+1), e)
这是另一个MxL
矩阵。最后,我们沿着第二维(L
)求和以生成Mx1
向量
x = x + sum(Fe, 2).'
其中.'
用于将Mx1
向量转置为1xM
向量。