提高 MATLAB 中分段函数的速度

Improve Speed of Piecewise Function in MATLAB

我有一个小的分段函数,分析显示它占用了程序运行时间的 60%。它经常被调用,因为它包含在我的代码中经常执行的一些积分中。

根据分析,它被调用了 213560 次,总共耗时 47.786 秒,相当于每次调用约 220 微秒。

我想给它传递一个数组,它应该return一个数组,明智地操作元素。

我知道在 Matlab 中使用循环非常慢,应该避免,但我不确定如何向量化这种函数。

function bottleradius = aux_bottle_radius(z_array)
%AUXBOTTLERADIUS Radius of aux bottle
%   This returns the radius of the aux bottle as a function of z. It works for all
%   heights of aux bottle, just remember to integrate over the right height
%   range
    bottleradius = zeros(size(z_array));
    for i = 1 : max(size(z_array))
        if z_array(i)<-30e-3
            %door cavity
            bottleradius(i) = 34e-3;
        elseif z_array(i)>=-30e-3 && z_array(i)<-20e-3
            %radiussing door cavity
            bottleradius(i) = 34e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(i)+30e-3).^2);
        elseif z_array(i)>=-20e-3 && z_array(i)<-10e-3
            %aluminium plate
            bottleradius(i) = 46e-3;
        elseif z_array(i)>=-10e-3 && z_array(i)<0e-3
            %radiussing aluminium plate to main bottle
            bottleradius(i) = 46e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(i)+10e-3).^2);
        elseif z_array(i)>=0e-3
            %top of Al plate, bottom of main bottle
            bottleradius(i) = 185e-3;
        else
            bottleradius(i) = 0;
        end
    end
end

您可以使用 logical 运算符完全矢量化。您基本上可以将该代码替换为:

function bottleradius = aux_bottle_radius(z_array)

%// Declare initial output array of all zeroes
bottleradius = zeros(size(z_array));

%// Condition #1 - Check for all values < -30e-3 and set accordingly
bottleradius(z_array < -30e-3) = 34e-3;

%// Condition #2 - Check for all values >= -30e-3 and < -20e-3 and set accordingly
ind = z_array >= -30e-3 & z_array < -20e-3;
bottleradius(ind) = 34e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(ind)+30e-3).^2);

%// Condition #3 - Check for all values >= -20e-3 and < -10e-3 and set accordingly
bottleradius(z_array >=-20e-3 & z_array < -10e-3) = 46e-3;

%// Condition #4 - Check for all values >= -10e-3 and < 0 and set accordingly
ind = z_array >=-10e-3 & z_array < 0;
bottleradius(ind) = 46e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(ind)+10e-3).^2);

%// Condition #5 - Check for all values >= 0 and set accordingly
bottleradius(z_array >= 0) = 185e-3;
end

小评论

  1. 0e-3 在精确度方面没有任何意义。这与 0 基本相同,我已经在您的代码中进行了更改。
  2. 请注意,对于条件 #2 和 #4,我预先计算了一个 logical 数组,该数组指示我们需要在何处访问 z_array 中的相应值以简化操作并设置相同的位置在 bottleradius 中成为所需的计算输出。我不会对其他条件执行此操作,因为您只是将它们设置为一个常量。
  3. 幸运的是,您对条件 #2 和 #4 使用了逐元素运算符,因此无需更改这些条件的表达式。