MATLAB:使用'assignin'在ode45中保存参数

时间:2013-05-22 01:13:08

标签: matlab ode

我在MATLAB中使用ode45运行一组ODE,我需要保存其中一个变量(不是衍生物)供以后使用。我正在使用函数'assignin'在基础工作区中分配临时变量并在每一步更新它。这似乎有效,但是,数组的大小与从ode45获取的解决方案向量的大小不匹配。例如,我有以下嵌套函数:

function [Z,Y] = droplet_momentum(theta,K,G,P,zspan,Y0)

options = odeset('RelTol',1e-7,'AbsTol',1e-7);
[Z,Y] = ode45(@momentum,zspan,Y0,options);

function DY = momentum(z,y)

    DY = zeros(4,1);

    %Entrained Total Velocity
    Ve = sin(theta)*(y(4));

    %Total Relative Velocity
    Urs = sqrt((y(1) - y(4))^2 + (y(2) - Ve*cos(theta))^2 + (y(3))^2);

    %Coefficients
    PSI = K*Urs/y(1);
    PHI = P*Urs/y(1);

    %Liquid Axial Velocity
    DY(1) = PSI*sign(y(1) - y(4))*(1 + (1/6)*(abs(y(1) - y(4))*G)^(2/3));

    %Liquid Radial Velocity
    DY(2) = PSI*sign(y(2) - Ve*cos(theta))*(1 + (1/6)*(abs(y(2) - ...
        Ve*cos(theta))*G)^(2/3));

    %Liquid Tangential Velocity
    DY(3) = PSI*sign(y(3))*(1 + (1/6)*(abs(y(3))*G)^(2/3));

    %Gaseous Axial Velocity
    DY(4) = (1/z/y(4))*((PHI/z)*sign(y(1) - y(4))*(1 + ...
        (1/6)*(abs(y(1) - y(4))*G)^(2/3)) + Ve*Ve - y(4)*y(4));

    assignin('base','Ve_step',Ve);
    evalin('base','Ve_out(end+1) = Ve_step');
end

end

在上面的代码中,theta(弧度),K(负值),P和& G是常数,并且为了这个例子可以作为任何值。 Zspan只是ODE求解器的积分时间步长,Y0是初始条件向量(4x1)。同样,为了这个例子,这些可以采取任何合理的价值。现在在主文件中,使用以下函数调用该函数:

Ve_out = 0;
[Z,Y] = droplet_momentum(theta,K,G,P,zspan,Y0);
Ve_out = Ve_out(2:end);

这种方法没有MATLAB的抱怨,但问题是Ve_out的大小与Z或Y的大小不同。原因是因为MATLAB为其算法多次调用ODE函数,所以解决方案将略小于Ve_out。正如am304建议的那样,我可以简单地通过给ode函数一个Z和Y向量来计算DY,例如DY =动量(Z,Y),但是,我需要使用'assignin'(或类似的方法)来处理它,因为另一个这个问题的版本在DY和Ve之间存在隐含的依赖关系,并且在每次迭代时计算DY的计算成本太高(我将在许多次迭代中运行此问题)。

2 个答案:

答案 0 :(得分:3)

好的,让我们先来看一个SSCCE的快速示例:

function [Z,Y] = khan

options = odeset('RelTol',1e-7,'AbsTol',1e-7);
[Z,Y] = ode45(@momentum,[0 12],[0 0],options);
end

function Dy = momentum(z,y)
Dy = [0 0]';

Dy(1) = 3*y(1) + 2* y(2) - 2;
Dy(2) = y(1) - y(2);

Ve = Dy(1)+ y(2);

    assignin('base','Ve_step',Ve);
    evalin('base','Ve_out(end+1) = Ve_step;');

    assignin('base','T_step',z);
    evalin('base','T_out(end+1) = T_step;');
end

通过运行[Z,Y] = khan作为命令行,我得到了一个完整的功能代码,可以演示您的问题,而不会产生任何麻烦。我对此的耐心已经筋疲力尽:生活和学习。

  

这似乎有效,但是,数组的大小不匹配   从ode45获得的溶液向量的大小

请注意,我在代码中添加了两行,用于提取时间变量。在命令提示符下,只需运行以下命令即可了解正在发生的事情:

Ve_out = [];
T_out = [];
[Z,Y] = khan;
size (Z)
size (T_out)
size (Ve_out)
plot (diff(T_out))

ans =
   109     1

ans =   
     1   163

ans =
     1   163

enter image description here

基本上ode45是一种迭代算法,这意味着它会定期校正(这就是你经常看到diff(T)= 0的原因)。你不能强迫算法做你想做的事情,你必须忍受它。

所以你的选择是   1. Use a fixed step algorithm
  2.在ode45算法完成其脏工作后,进行函数调用以再现所需的函数。 (am304的解决方案)
  3.使用时间函数收集数据,然后使用算法解析所有内容以删除额外数据。

答案 1 :(得分:1)

你不能做那样的事吗?显然,检查矩阵/向量的大小是否正确,并相应地修改代码。

[Z,Y] = droplet_momentum2(theta,K,G,P,zspan,Y0);
DY = momentum(Z,Y);
Ve = sin(theta)*(0.5*z*DY(4) + y(4));

即。一旦ODE得到解决,就计算导数DY作为ZY(刚刚由ODE解决)和最后Ve的函数。