加速MATLAB for Fourier Series For Loop

时间:2015-11-12 17:05:04

标签: performance matlab for-loop sum vectorization

我知道这个话题已被多次访问过,所以请提前道歉。我只是无法解决效率低下的循环操作,并希望得到你的帮助。

我正在实现一个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算法需要分解的某些假设。有谁知道如何将上述总和重写成更有效的格式?我也预先分配了矢量。

2 个答案:

答案 0 :(得分:1)

所以,问题:

  • 循环很慢,但解决了可用内存中的问题;

  • 矢量化很快,但会耗尽你的记忆;

我无法发布代码,因为您提供的关于Fomegatxt的外观的详细信息太少(即确切尺寸和值的范围),但混合解决方案如何:您可以在可以矢量化的频率间隔中分割问题,并在整个频率间隔(块)而不是每个频率上累积部分解。类似的东西:

    %%
    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).';

注意:对于此解决方案Fomegaktxt都应为列向量,那是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矩阵,其中Mtxt的长度。接下来,我们将F(维度1xL)的每一列乘以

Fe = bsxfun(@times, F(k+1), e)

这是另一个MxL矩阵。最后,我们沿着第二维(L)求和以生成Mx1向量

x = x + sum(Fe, 2).'

其中.'用于将Mx1向量转置为1xM向量。