Matlab:if语句和abs()函数在变步长ODE求解器中

时间:2013-05-16 08:45:54

标签: matlab if-statement ode absolute-value

我正在网上阅读这篇文章,其中提到使用“if语句”和“abs()”函数会在MATLAB的变步长ODE求解器(如ODE45)中产生负面影响。根据OP,它可以显着影响时间步长(需要太低的时间步长),并且当微分方程最终被积分时给出差的结果。我想知道这是否属实,如果是,为什么。此外,如果不诉诸固定步骤求解器,如何减轻这个问题。我在下面给出了一个示例代码,我的意思是:

function [Z,Y] = sauters(We,Re,rhos,nu_G,Uinj,Dinj,theta,ts,SMDs0,Uzs0,...
Uts0,Vzs0,zspan,K)

Y0 = [SMDs0;Uzs0;Uts0;Vzs0]; %Initial Conditions
options = odeset('RelTol',1e-7,'AbsTol',1e-7); %Tolerance Levels
[Z,Y] = ode45(@func,zspan,Y0,options);

function DY = func(z,y)

    DY = zeros(4,1);

    %Calculate Local Droplet Reynolds Numbers
    Rez = y(1)*abs(y(2)-y(4))*Dinj*Uinj/nu_G;
    Ret = y(1)*abs(y(3))*Dinj*Uinj/nu_G;

    %Calculate Droplet Drag Coefficient
    Cdz = dragcof(Rez);
    Cdt = dragcof(Ret);

    %Calculate Total Relative Velocity and Droplet Reynolds Number
    Utot = sqrt((y(2)-y(4))^2 + y(3)^2);
    Red = y(1)*abs(Utot)*Dinj*Uinj/nu_G;

    %Calculate Derivatives
    %SMD
    if(Red > 1)
        DY(1) = -(We/8)*rhos*y(1)*(Utot*Utot/y(2))*(Cdz*(y(2)-y(4)) + ...
            Cdt*y(3)) + (We/6)*y(1)*y(1)*(y(2)*DY(2) + y(3)*DY(3)) + ...
            (We/Re)*K*(Red^0.5)*Utot*Utot/y(2);
    elseif(Red < 1)
        DY(1) = -(We/8)*rhos*y(1)*(Utot*Utot/y(2))*(Cdz*(y(2)-y(4)) + ...
        Cdt*y(3)) + (We/6)*y(1)*y(1)*(y(2)*DY(2) + y(3)*DY(3)) + ...
        (We/Re)*K*(Red)*Utot*Utot/y(2);
    end
    %Axial Droplet Velocity
    DY(2) = -(3/4)*rhos*(Cdz/y(1))*Utot*(1 - y(4)/y(2));
    %Tangential Droplet Velocity
    DY(3) = -(3/4)*rhos*(Cdt/y(1))*Utot*(y(3)/y(2));
    %Axial Gas Velocity
    DY(4) = (3/8)*((ts - ts^2)/(z^2))*(cos(theta)/(tan(theta)^2))*...
        (Cdz/y(1))*(Utot/y(4))*(1 - y(4)/y(2)) - y(4)/z;

end

end

以下给出“dragcof”函数:

function Cd = dragcof(Re)    
if(Re <= 0.01)

    Cd = (0.1875) + (24.0/Re);

elseif(Re > 0.01 && Re <= 260.0)

    Cd = (24.0/Re)*(1.0 + 0.1315*Re^(0.32 - 0.05*log10(Re)));

else

    Cd = (24.0/Re)*(1.0 + 0.1935*Re^0.6305);
end
end

2 个答案:

答案 0 :(得分:4)

这是因为使用if - 语句,模数运算(abs())计算的导数,或者单位阶跃函数,dirac delta等等,将会导致价值的不连续性。解或其衍生物,导致扭结,跳跃,拐点等。

这意味着ODE的解决方案在相关时间的行为发生了彻底的变化。变量步进积分器将做什么

  • 检测到此
  • 认识到他们无法直接使用“问题点”之外的信息
  • 减少步骤,并从顶部重复,直到问题点满足精度要求

因此,在问题点附近会有许多失败的步骤和步长的减少,从而对整体积分时间产生负面影响。

可变步长积分器继续产生良好的结果。恒定步长积分器不是解决此类问题的良好补救措施,因为它们首先无法检测到这些问题(没有错误估计)。

您可以做的只是将问题分成多个部分。如果您事先知道将发生更改的时间点,则只需为每个间隔启动一个新的集成,每次使用前一个集成的输出作为下一个集成的初始值。

如果事先知道问题所在,您可以在Matlab的ODE求解器中使用这个非常好的功能,称为事件函数(参见the documentation })。你让Matlab的一个求解器检测到事件(导数中的符号变化,if - 语句中的条件变化,或其他),并在检测到这些事件时终止积分。然后开始一个新的集成,从上一次开始,并与之前的集成的初始条件一样,如前所述,直到达到最终时间。

总体执行时间仍然会有轻微的损失,因为Matlab会尝试准确地检测事件的位置。但是,当涉及到执行时间和结果的准确性时,它仍然比盲目地运行集成要好得多。

答案 1 :(得分:0)

是的,这是真的,因为你的解决方案在某些方面不够顺畅。

假设您想要整合。 y'(t) = f(t,y)。然后,f中发生的事情就是集成到y。因此,如果您在f的定义中有

  • abs(),然后f有一个扭结,y仍然是平滑的,1次可区分
  • if,然后f跳跃,y扭结,不再具有差异性

Matlab的ODE45假设你的解决方案是5倍可微分,并试图确保4阶的准确性。你的功能的非光滑点被误解为刚度导致小步长甚至故障。

你可以做什么:由于缺乏光滑度,你无论如何都不能期望高精度。因此,ODE23可能是更好的选择。在最坏的情况下,你必须坚持一阶方案。