如何将Maple代码重写为Matlab,fsolve()和resolve()函数?

时间:2018-12-24 06:59:46

标签: matlab solver ode maple

我有一个常微分方程(ODE)-Van Der Pol振荡器问题:

y''-2a(1-y ^ 2)y'+ y = 0,

y(0)= 0,y'(0)= 0.5,[0,10]中的x​​,a = 0.025。

ODE已通过 fsolve()函数在Maple Software上解决。

enter image description here

我需要在Matlab(R2013a版本)上重写代码。

我的尝试在下面。

n = 0
h = 0.1
syms z0; % z in point 0
syms y0; % z in point 0
f0 = 2 * 0.025 * z0 - 2 * 0.025 * ((y0)^2) * z0 - y0 
syms z1; % z in point 1
syms y1; % z in point 1
f1 = 2 * 0.025 * z1 - 2 * 0.025 * ((y1)^2) * z1 - y1
syms z2; % z in point 2
syms y2; % z in point 2
f2 = 2 * 0.025 * z2 - 2 * 0.025 * ((y2)^2) * z2 - y2
syms z32; % z in point 3/2
syms y32; % z in point 3/2
f32 = 2 * 0.025 * z32 - 2 * 0.025 * ((y32)^2) * z32 - y32
syms z3; % z in point 3
syms y3; % z in point 3
syms p;
f3 = 2 * p * (1-(y3)^2) * z3 - y3
syms z4; % z in point 4
syms y4; % z in point 4
f4 = 2 * p * (1-(y4)^2) * z4 - y4
syms z72; % z in point 7/2
syms y72; % z in point 7/2
f72 = 2 * p * (1-(y3)^2) * z72 - y72

[c1,c2,c3,c4]=solve(y0, z0, y2 - (-y0 + 2 * y1 + (1/12) * h^2 * f0 + 5/6 * h^2 * f1 + (1/12) * h^2 * f2), y32 - (-1/2 * y0 + 3/2 * y1 + 1/24 *h^2 *f0 + 13/32 * h^2 *f1 - 5/48 * h^2 * f32 + 1/32 * h^2 * f2), -360 * h * z0 - (89 * h^2 * f0 + 186 * h^2 * f1 + 33 * h^2 * f2 - 128 * h^2 * f32 + 360 * y0 -360 * y1))

我有警告:

Warning: 4 equations in 1 variables. 
> In C:\Program Files\MATLAB\R2013a\toolbox\symbolic\symbolic\symengine.p>symengine at 56
  In mupadengine.mupadengine>mupadengine.evalin at 97
  In mupadengine.mupadengine>mupadengine.feval at 150
  In solve at 170 
Warning: Explicit solution could not be found. 
> In solve at 179 

问题。能否在Matlab R2013a中解决问题?谁能给我一个思路,重写代码吗?

1 个答案:

答案 0 :(得分:1)

在matlab中找到数值解的方法是定义

VDP_ODE = @(t,u) [ u(2), 2*a*u(2)*(1-u(1)^2) ]; % u = [ y, z ]

(或使用完整的function声明进行定义),然后使用数值解算器调用它

a=0.025; h=0.1;
t = 0:h:10;
y0 = 0; z0 = 0.5;
u0 = [y0, z0 ];
u = ode45(@VDP_ODE, t, u0)
figure(1); plot(t,u(:,1));
figure(2); plot(u(:,1),u(:,2));

如果要构建自己的求解器,则应首先了解该方法。看来这是一种四阶方法,与线性多步方法相似,但并不完全等同于线性多步方法,就像用来计算分子动力学的Beeman-Schofield方法一样。

每个步骤的输入均为值y(n), y(n+1),输出减小为y(n+2),其他值均不接管下一步。在方法步骤内,在所有采样时间y(n+3/2)上为z和导数t(n), t(n+1), t(n+3/2), t(n+2)计算附加值。目的是获得浮点结果,因此没有必要用符号定义方程式,从而使系统适应fsolve的界面。

通过观察有6个方程,因此有6个未知参数,可以简化用Maple码求解的系统。该方法基于具有作为未知数的6个系数的5次多项式,它对值,解的一阶和二阶导数进行插值。对于给定的值y0,y1,这给出了2个方程,对于在插值点处的微分方程的精确满足,给出了4个方程。

Y = [ y0, step0(y0,z0) ]
for n=1:N-2
    Y(n+2,:)=stepN(Y(n,:), Y(n+1,:), h)
end

在该方法的步骤中执行类似的操作

  %%%% ======== General step ========
  %% fit a degree 5 polynomial to values, 1st and 2nd derivatives
  %% at t0, t1, t1h=t1+0.5*h, t2
  %% p(s) = sum c_k s^k/k!,  c0=y1,  y(t1+s) ~ p(s)
  %% eqn y0 = p(-h)
  %% def z0 = p'(-h)
  %% eqn f(y0,z0) = p''(-h)
  %% def z1 = p'(0)
  %% eqn f(y1,z1) = p''(0)
  %% eqn y2 = p(h), etc
  %%
  %% state vector for non-lin solver is u = [y2, c1, c2, ...c5 ]


  function y2 = stepN(y0,y1,h)
    zz = (y1-y0)/h;
    predict = [ y1+h*zz, zz, f(y1,zz), 0, 0, 0];
    options = optimset("TolX", 1e-1*h^6, "TolFun", 1e-2*h^6);
    u = fsolve(@(u) systemN(u,[y0,y1], h), predict, options);
    y2 = u(1);
  end

设置一些预测值(仅O(h)精确),设置求解器的公差,以使求解器误差希望小于离散化误差O(h^6),调用求解器端提取所需值解决方案数组中的值。

为使系统求解函数,首先将常量和变量提取为命名变量以提高可读性,计算给定点处的函数值,然后返回离散方程式中的缺陷数组。

  function eqn = systemN(u,init,h)
    [ y0, y1 ] = num2cell(init){:};
    [ y2, c1, c2, c3, c4, c5 ] = num2cell(u){:};
    p = @(h) y1 + h*(c1+h/2*(c2+h/3*(c3+h/4*(c4+h/5*c5))));
    dp = @(h) c1+h*(c2+h/2*(c3+h/3*(c4+h/4*c5)));
    d2p = @(h) c2+h*(c3+h/2*(c4+h/3*c5));
    z0 = dp(-h); z1 = c1;
    y1h = p(0.5*h); z1h = dp(0.5*h);
    z2 = dp(h);

    eqn = [ y2-p(h), 
            y0-p(-h), 
            f(y0,z0)-d2p(-h), 
            f(y1,z1)-c2, 
            f(y1h,z1h)-d2p(0.5*h),
            f(y2,z2)-d2p(h) ];
  end