我正在努力解决:
x' = 60*x - 0.2*x*y;
y' = 0.01*x*y - 100* y;
使用四阶Runge-Kutta算法。
起点: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
尺寸。它现在有效!谢谢!
答案 0 :(得分:2)
看起来像Lotka-Volterra等式的某种形式?
我不确定您的初始条件是[300;8000]
还是[8000;300]
(您在上面指定了两种方式),但无论如何,您都有一个振荡系统,您正试图与之积分大的固定时间步长(大大)大于振荡周期。这就是你的错误爆炸的原因。如果您尝试增加n
(例如1e6
),您会发现最终会得到一个稳定的解决方案(假设您的Runge-Kutta实现方式正确无误)。
您是否有理由不使用Matlab的内置ODE求解器,例如: ode45
或ode15s
?
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
给出的内容和/或使用odeset
调整'AbsTol'
和'RelTol'
选项
答案 1 :(得分:1)
当前的问题是RK4代码没有从标量情况完全演化为两个耦合方程式的情况。请注意,导数功能中没有时间参数。 x
和y
都是因变量,因此可以在每个步骤中获得由导数函数定义的斜率更新。然后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