1

我正在尝试解决:

x' = 60*x - 0.2*x*y;
y' = 0.01*x*y - 100* y;

使用四阶龙格-库塔算法。

起点:x(0) = 8000, y(0) = 300范围:[0,15]

这是完整的功能:

function [xx yy time r] = rk4_m(x,y,step)
A = 0;
B = 15;

h = step;
iteration=0;
t = tic;

xh2 = x;
yh2 = y;


rr = zeros(floor(15/step)-1,1);
xx = zeros(floor(15/step)-1,1);
yy = zeros(floor(15/step)-1,1);
AA = zeros(1, floor(15/step)-1);

while( A < B)


    A = A+h;
    iteration = iteration + 1;

    xx(iteration) = x;
    yy(iteration) = y;
    AA(iteration) = A;
    [x y] = rkstep(x,y,h);


    for h2=0:1
        [xh2 yh2] = rkstep(xh2,yh2,h/2);
    end
    r(iteration)=abs(y-yh2);



end
time = toc(t);

xlabel('Range');
ylabel('Value');     
hold on
plot(AA,xx,'b');
plot(AA,yy,'g');
plot(AA,r,'r');
fprintf('Solution:\n');
fprintf('x: %f\n', x);
fprintf('y: %f\n', y);
fprintf('A: %f\n', A);
fprintf('Time: %f\n', time);

end

function [xnext, ynext] = rkstep(xcur, ycur, h)
    kx1 = f_prim_x(xcur,ycur);
    ky1 = f_prim_y(xcur,ycur);

    kx2 = f_prim_x(xcur+0.5*h,ycur+0.5*h*kx1);
    kx3 = f_prim_x(xcur+0.5*h,ycur+0.5*h*kx2);
    kx4 = f_prim_x(xcur+h,ycur+h*kx3);

    ky2 = f_prim_y(xcur+0.5*h*ky1,ycur+0.5*h);
    ky3 = f_prim_y(xcur+0.5*h*ky2,ycur+0.5*h);
    ky4 = f_prim_y(xcur+h*ky2,ycur+h);

    xnext = xcur + (1/6)*h*(kx1 + 2*kx2 + 2*kx3 + kx4);
    ynext = ycur + (1/6)*h*(ky1 + 2*ky2 + 2*ky3 + ky4);
end

function [fx] = f_prim_x(x,y)
fx = 60*x - 0.2*x*y;
end

function [fy] = f_prim_y(x,y)
fy = 0.01*x*y - 100*y;
end

我通过执行来运行它:[xx yy time] = rk4_m(8000,300,10)

问题是在 2-3 次迭代后一切都崩溃了,返回了无用的结果。我究竟做错了什么?或者只是这种方法不适合这种方程?

分号被有意省略。


看起来我没有注意实际h大小。现在可以了!谢谢!

4

2 回答 2

2

看起来像是某种形式的 Lotka-Volterra 方程?

我不确定您的初始条件是否是[300;8000][8000;300](您在上面两种方式都指定),但无论如何,您有一个振荡系统,您正试图与一个大的固定时间步长集成,该时间步长(远)大于振荡周期。这就是你的错误爆炸的原因。如果你尝试增加n(比如1e6),你会发现最终你会得到一个稳定的解决方案(假设你的 Runge-Kutta 实现在其他方面是正确的)。

您是否有理由不使用 Matlab 的内置 ODE 求解器,例如ode45ode15s

function ode45demo

[t,y]=odeode45(@f,[0 15],[300;8000]);

figure;
plot(t,y);

function ydot=f(t,y)
ydot(1,1) = 60*y(1) - 0.2*y(1)*y(2);
ydot(2,1) = 0.01*y(1)*y(2) - 100*y(2);

您会发现自适应步长求解器对这些类型的振荡问题更有效。因为您的系统具有如此高的频率并且看起来相当僵硬,所以我建议您也查看ode15s提供的内容和/或调整'AbsTol''RelTol'选项odeset

于 2013-05-27T20:26:14.517 回答
1

直接的问题是 RK4 代码没有完全从标量情况演变为两个耦合方程的情况。请注意,导数函数中没有时间参数。xy都是因变量,因此在每一步中得到由导数函数定义的斜率更新。然后xcur获取kx更新并ycur获取ky更新。

function [xnext, ynext] = rkstep(xcur, ycur, h)
    kx1 = f_prim_x(xcur,ycur);
    ky1 = f_prim_y(xcur,ycur);

    kx2 = f_prim_x(xcur+0.5*h*kx1,ycur+0.5*h*ky1);
    ky2 = f_prim_y(xcur+0.5*h*kx1,ycur+0.5*h*ky1);

    kx3 = f_prim_x(xcur+0.5*h*kx2,ycur+0.5*h*ky2);
    ky3 = f_prim_y(xcur+0.5*h*kx2,ycur+0.5*h*ky2);

    kx4 = f_prim_x(xcur+h*kx3,ycur+h*ky3);
    ky4 = f_prim_y(xcur+h*kx3,ycur+h*ky3);

    xnext = xcur + (1/6)*h*(kx1 + 2*kx2 + 2*kx3 + kx4);
    ynext = ycur + (1/6)*h*(ky1 + 2*ky2 + 2*ky3 + ky4);
end
于 2020-06-28T16:13:11.757 回答