对我来说,估计的hstep似乎需要相当长的时间和长的迭代才能收敛。我用第一个ODE试了一下。基本上,你用h/2执行步长为h的RK 4之间的差。请注意,为了达到相同的时间步长值,你必须在两个h/2的时间步长后使用y值,这样它也达到h。
frhs=@(x,y) x.^2*y;
我的代码是否正确?
clear all;close all;clc
c=[]; i=1; U_saved=[]; y_array=[]; y_array_alt=[];
y_arr=1; y_arr_2=1;
frhs=@(x,y) 20*cos(x);
tol=0.001;
y_ini= 1;
y_ini_2= 1;
c=abs(y_ini-y_ini_2)
hc=1
all_y_values=[];
for m=1:500
if (c>tol || m==1)
fprintf('More')
y_arr
[Unew]=vpa(Runge_Kutta(0,y_arr,frhs,hc))
if (m>1)
y_array(m)=vpa(Unew);
y_array=y_array(logical(y_array));
end
[Unew_alt]=Runge_Kutta(0,y_arr_2,frhs,hc/2);
[Unew_alt]=vpa(Runge_Kutta(hc/2,Unew_alt,frhs,hc/2))
if (m>1)
y_array_alt(m)=vpa(Unew_alt);
y_array_alt=y_array_alt(logical(y_array_alt));
end
fprintf('More')
%y_array_alt(m)=vpa(Unew_alt);
c=vpa(abs(Unew_alt-Unew) )
hc=abs(tol/c)^0.25*hc
if (c<tol)
fprintf('Less')
y_arr=vpa(y_array(end) )
y_arr_2=vpa(y_array_alt(end) )
[Unew]=Runge_Kutta(0,y_arr,frhs,hc)
all_y_values(m)=Unew;
[Unew_alt]=Runge_Kutta(0,y_arr_2,frhs,hc/2);
[Unew_alt]=Runge_Kutta(hc/2,Unew_alt,frhs,hc/2)
c=vpa( abs(Unew_alt-Unew) )
hc=abs(tol/c)^0.2*hc
end
end
end
all_y_values
1条答案
按热度按时间2w3kk1z51#
更好的时间循环结构只有一个计算时间步长的位置。
对于代码中给定的数据
这给出了与精确解相对的结果
计算出的点正好位于精确解上,对于它们之间的线段,需要使用“密集输出”插值。或者作为第一个改进,仅包括来自半步计算的中间值。
修订版1
返回的误差是实际的步长误差。但是,步长控制所需的误差是单位步长误差或误差密度,即步长误差除以
h
将示例改为在稳定平衡的两个分支之间振荡的简单双稳态模型
给出了解、误差(针对
ode45
积分)和步长的曲线图红色叉号表示被拒绝步骤的步长。
修订版2
函数值中的误差可用作5阶外推值的误差指导,使该方法成为外推模式下的5阶方法。由于它使用4阶误差预测5阶最佳步长,因此建议使用一个警告因子,代码在适当位置进行更改以
在图中,步长适当增大,但误差显示更尖锐和更大的尖峰,该版本的方法显然不太稳定。