常用的仿真算法总结

对于每种数值积分法,在应用中最关心的一是计算精度,二是其稳定性。

设一阶微分方程组为:
Y ˙ = F ( t , Y ) \mathbf{\dot{Y}=F}(t,\mathbf{Y}) Y˙=F(t,Y)
式中, Y = ( y 1 , y 2 , . . y n ) T \mathbf{Y}=(y_1,y_2,..y_n)^T Y=(y1,y2,..yn)T, F = ( f 1 ( t , Y ) , f 2 ( t , Y ) , . . . f n ( t , Y ) ) T \mathbf{F}=(f_1(t,\mathbf{Y}),f_2(t,\mathbf{Y}),...f_n(t,\mathbf{Y}))^T F=(f1(t,Y),f2(t,Y),...fn(t,Y))T,初值为 Y ( t 0 ) = Y 0 \mathbf{Y}(t_0)=Y_0 Y(t0)=Y0

1.四阶龙格-库塔法

基本原理

h h h为固定步长,此时的4阶龙格库塔法的向量形式为:
Y n + 1 = Y n + h 6 ( K 1 + 2 K 2 + 2 K 3 + K 4 ) K 1 = F ( t n , Y n ) K 2 = F ( t n + h 2 , Y n + h 2 K 1 ) K 3 = F ( t n + h 2 , Y n + h 2 K 2 ) K 4 = F ( t n + h , Y n + h K 3 ) \mathbf{Y_{n+1}} = \mathbf{Y_n}+\frac{h}{6}(\mathbf{K_1+2K_2+2K_3+K_4})\\ \mathbf{K_1}=\mathbf{F}(t_n,\mathbf{Y_n})\\\mathbf{K_2}=\mathbf{F}(t_n+\frac{h}{2},\mathbf{Y_n}+\frac{h}{2}\mathbf{K_1})\\\mathbf{K_3}=\mathbf{F}(t_n+\frac{h}{2},\mathbf{Y_n}+\frac{h}{2}\mathbf{K_2})\\\mathbf{K_4}=\mathbf{F}(t_n+h,\mathbf{Y_n}+h\mathbf{K_3}) Yn+1=Yn+6h(K1+2K2+2K3+K4)K1=F(tn,Yn)K2=F(tn+2h,Yn+2hK1)K3=F(tn+2h,Yn+2hK2)K4=F(tn+h,Yn+hK3)

%下面是4阶龙格库塔法模块
function [t_,y] = RK_4(f,tspan,x0,h)
    t_ = [tspan(1):h:tspan(2)]';
    t = tspan(1);x = x0;
    y = [];
    while(t<=tspan(2))
        y = [y;x'];
        K1 = h*f(t,x);
        K2 = h*f(t + h/2,x + 1/2*K1);
        K3 = h*f(t + h/2,x + 1/2*K2);
        K4 = h*f(t + h,x + K3);
        x = x + (K1 + 2*K2 + 2*K3 + K4)/6;
        t = t + h;
    end
    if size(y,1) < size(t_,1)
       t_ = t_(1:size(y,1)); 
    end
end

稳定区域

​ 将 y n + 1 y_{n+1} yn+1 t n t_n tn点进行泰勒级数展开:
y n + 1 = y n + ∑ i = 1 r h i i ! y n ( i ) + O ( h r + 1 ) y_{n+1}=y_{n}+\sum_{i=1}^r\frac{h^i}{i!}y_n^{(i)}+O(h^{r+1}) yn+1=yn+i=1ri!hiyn(i)+O(hr+1)
对于 y ˙ = λ y \dot{y}=\lambda y y˙=λy y ( i ) = λ i y y^{(i)}=\lambda^iy y(i)=λiy,代入到上面的式子有:
y n + 1 = y n ∑ i = 0 r ( λ h ) i i ! + O ( h r + 1 ) y_{n+1}=y_{n}\sum_{i=0}^r\frac{(\lambda h)^i}{i!}+O(h^{r+1}) yn+1=yni=0ri!(λh)i+O(hr+1)
该式的稳定条件为迭代系数的绝对值小于1:
∣ ∑ i = 0 r ( λ h ) i i ! ∣ < 1 |\sum_{i=0}^r\frac{(\lambda h)^i}{i!}|<1 i=0ri!(λh)i<1
得到以下表格

r r r h λ h\lambda hλ所在的实稳定区域
1 ( − 2 , 0 ) (-2,0) 2,0
2 ( − 2 , 0 ) (-2,0) 2,0
3 ( − 2.51 , 0 ) (-2.51,0) 2.51,0
4 ( − 2.78 , 0 ) (-2.78,0) 2.78,0

代码实现

​ 在步长取0.1和0.2时,用RK-4计算如下两个微分方程组的数值解,并与解析解比较:
S 1 : y ˙ = − 20 y , y ( 0 ) = 1 , y ∗ = e − 20 t S 2 : y ˙ = − 10 y , y ( 0 ) = 1 , y ∗ = e − 10 t S_1:\dot{y}=-20y,y(0)=1,y^*=e^{-20t}\\ S_2:\dot{y}=-10y,y(0)=1,y^*=e^{-10t} S1:y˙=20y,y(0)=1,y=e20tS2:y˙=10y,y(0)=1,y=e10t
分析:对于 S 1 S_1 S1,当 h = 0.2 h=0.2 h=0.2时,很明显, λ h = − 4 ∉ ( − 2.78 , 0 ) \lambda h=-4\notin(-2.78,0) λh=4/(2.78,0),故在 h = 0.2 h=0.2 h=0.2时应该是不稳定的。

代码:

clc,clear;
%下面是计算
f1 = @(t,x)(-20*x);
f2 = @(t,x)(-10*x);
[t1,y1] = RK_4(f1,[0 2],1,0.1);
[t2,y2] = RK_4(f1,[0 2],1,0.2);
[t3,y3] = RK_4(f2,[0 2],1,0.1);
[t4,y4] = RK_4(f2,[0 2],1,0.2);
%下面是画图
subplot(221)
hold on;grid on;box on;xlabel('t/s');ylabel('y(t)');title('dot y=-20y,h=0.1');
plot(t1,exp(-20*t1),'r-',t1,y1,'b.-');legend('真实值','计算值');
subplot(222)
hold on;grid on;box on;xlabel('t/s');ylabel('y(t)');title('dot y=-20y,h=0.2');
plot(t2,exp(-20*t2),'r-',t2,y2,'b.-');legend('真实值','计算值');
subplot(223)
hold on;grid on;box on;xlabel('t/s');ylabel('y(t)');title('dot y=-10y,h=0.1');
plot(t3,exp(-10*t3),'r-',t3,y3,'b.-');legend('真实值','计算值');
subplot(224)
hold on;grid on;box on;xlabel('t/s');ylabel('y(t)');title('dot y=-10y,h=0.2');
plot(t4,exp(-10*t4),'r-',t4,y4,'b.-');legend('真实值','计算值');

结果:

常用的仿真算法总结_第1张图片

2.实时龙格-库塔公式

​ 实时仿真要求模型运行速度与实际系统运行速度保持一致。一般的数值积分方法很难满足实时仿真的要求。常用的原因有:

  • 常用的仿真方法递推公式执行速度较慢

  • 算法机理不符合实时仿真的要求

    对一般的龙格-库塔法进行改进得到实时仿真用的数值积分公式。

实时2阶龙格库塔法

Y n + 1 = Y n + h K 2 K 1 = F ( t n , Y n ) K 2 = F ( t n + h 2 , Y n + h 2 K 1 ) \mathbf{Y_{n+1}} = \mathbf{Y_n}+h\mathbf{K_2}\\ \mathbf{K_1}=\mathbf{F}(t_n,\mathbf{Y_n})\\\mathbf{K_2}=\mathbf{F}(t_n+\frac{h}{2},\mathbf{Y_n}+\frac{h}{2}\mathbf{K_1}) Yn+1=Yn+hK2K1=F(tn,Yn)K2=F(tn+2h,Yn+2hK1)

function [t_,y] = rt_RK_2(f,tspan,x0,h)
    t_ = [tspan(1):h:tspan(2)]';
    t = tspan(1);x = x0;
    y = [];
    while(t<=tspan(2))
       y = [y;x'];
       K1 = f(t,x);
       K2 = f(t + h/2,x + h/2*K1);
       x = x + h*K2;
       t = t + h;
    end
    if size(y,1) < size(t_,1)
       t_ = t_(1:size(y,1)); 
    end
end

实时4阶龙格库塔法

Y n + 1 = Y n + h 24 ( − K 1 + 15 K 2 − 5 K 3 + 5 K 4 + 10 K 5 ) K 1 = F ( t n , Y n ) K 2 = F ( t n + h 5 , Y n + h 5 K 1 ) K 3 = F ( t n + 2 h 5 , Y n + 2 h 5 K 1 ) K 4 = F ( t n + 3 h 5 , Y n − 2 h 5 K 1 + h K 2 ) K 5 = F ( t n + 4 h 5 , Y n + 3 h 10 K 1 + h 2 K 4 \mathbf{Y_{n+1}} = \mathbf{Y_n}+\frac{h}{24}(\mathbf{-K_1+15K_2-5K_3+5K_4+10K_5})\\ \mathbf{K_1}=\mathbf{F}(t_n,\mathbf{Y_n})\\\mathbf{K_2}=\mathbf{F}(t_n+\frac{h}{5},\mathbf{Y_n}+\frac{h}{5}\mathbf{K_1})\\\mathbf{K_3}=\mathbf{F}(t_n+\frac{2h}{5},\mathbf{Y_n}+\frac{2h}{5}\mathbf{K_1})\\\mathbf{K_4}=\mathbf{F}(t_n+\frac{3h}{5},\mathbf{Y_n}-\frac{2h}{5}\mathbf{K_1}+h\mathbf{K_2})\\\mathbf{K_5}=\mathbf{F}(t_n+\frac{4h}{5},\mathbf{Y_n}+\frac{3h}{10}\mathbf{K_1}+\frac{h}{2}\mathbf{K_4} Yn+1=Yn+24h(K1+15K25K3+5K4+10K5)K1=F(tn,Yn)K2=F(tn+5h,Yn+5hK1)K3=F(tn+52h,Yn+52hK1)K4=F(tn+53h,Yn52hK1+hK2)K5=F(tn+54h,Yn+103hK1+2hK4

%下面是4阶实时龙格库塔法
function [t_,y] = rt_RK_4(f,tspan,x0,h)
    t_ = [tspan(1):h:tspan(2)]';
    t = tspan(1);x = x0;
    y = [];
    while(t<=tspan(2))
       y = [y;x'];
       K1 = f(t,x);
       K2 = f(t + h/5,x + h/5*K1);
       K3 = f(t + 2*h/5,x + 2/5*h*K1);
       K4 = f(t + 3*h/5,x - 2/5*h*K1 +h*K2);
       K5 = f(t + 4*h/5,x + 3/10*h*K1 +h/2*K4);
       x = x +(-K1 + 15*K2 - 5*K3 +5*K4 + 10*K5)*h/24;
       t = t + h;
    end
    if size(y,1) < size(t_,1)
       t_ = t_(1:size(y,1)); 
    end
end

代码实现:

clc,clear;close all;
f1 = @(t,x)(-20*x);
[t1,y1] = rt_RK_2(f1,[0 2],1,0.05);
[t2,y2] = rt_RK_4(f1,[0 2],1,0.05);
subplot(121)
hold on;grid on;box on;
xlabel('t/s');ylabel('y(t)');
plot(t1,y1,'b.-',t1,exp(-20*t1),'r-');
title('dot y=-20y,h=0.05,二阶实时龙格库塔法');
legend('计算值','真实值');
subplot(122)
hold on;grid on;box on;
xlabel('t/s');ylabel('y(t)');
plot(t2,y2,'b.-',t2,exp(-20*t2),'r-');
title('dot y=-20y,h=0.05,四阶实时龙格库塔法');
legend('计算值','真实值');

常用的仿真算法总结_第2张图片

3.变步长龙格库塔法

​ 当求解步长太大时不能达到精度要求,当求解步长太小时,会增加不必要的计算量,比较好的方法是对步长进行自动调整。其前提是要有一个局部误差估计公式,为了得到每一步的局部误差估计值。通过巧妙选取龙格库塔法公式的系数,可以使得两个公式中的 k i k_i ki相同,从而使得一些中间结果对龙格库塔法都适用,减少计算量,使得误差估计值可以利用 k i k_i ki进行计算。

龙格-库塔-默森法

常用的仿真算法总结_第3张图片

%下面是4阶变步长龙格库塔默森法
function [t_,y] = RKM3_4(f,tspan,x0,hspan,espan)
    t = tspan(1);x = x0;
    h_min = hspan(1);h_max = hspan(2);
    e_min = espan(1);e_max = espan(2);
    y = [];h = h_min;t_ = [];
    while(t<=tspan(2))
        y = [y;x'];
        t_ = [t_;t];
        K1 = f(t,x);
        K2 = f(t+h/3,x + h/3*K1);
        K3 = f(t+h/3,x + h/6*(K1 + K2));
        K4 = f(t+h/2,x + h/8*(K1 + 3*K2));
        K5 = f(t + h,x + h/2*(K1 - 3*K3 + 4*K4));
        xn = x;
        x = xn + h/6*(K1 + 4*K4 + K5);
        x_ = xn + h/6*(3*K1 -9*K3 + 12*K4);
        E = (x-x_)./x;
        e = norm(E);
        if (e>e_max)&&(h > h_min)
            h = h/2;
        elseif(e<e_min)&&(h < h_max)
            h = 2*h;
        else
            h = h;
        end
        t = t + h;
    end
end

当执行以下代码时:

clc,clear;close all;
f1 = @(t,x)(-20*x);
%设置相对误差在0-0.15,步长在0.01-1之间
[t3,y3] = RKM3_4(f1,[0 2],1,[0.01 0.1],[0 0.15]);
hold on;grid on;box on;
xlabel('t/s');ylabel('y(t)');
title('dot y=-20y,变步长4阶龙格库塔法');
plot(t3,y3,'b.-',t3,exp(-20*t3),'r-');
legend('计算值','真实值');

得到:
常用的仿真算法总结_第4张图片

龙格-库塔-菲尔别格法和步长折半法略

4.亚当姆斯法

下面是显示法


%下面是4阶亚当姆斯显式法
function [t_,y] = Adams_4(f,tspan,x0,h)
    t_min = tspan(1);x = x0;t = t_min;
    y = [];t_ = [];t_max = tspan(2);
    t_f = [t_min,t_min+h,t_min+2*h,t_min+3*h];
    %下面是用RK-4初始化
    while(t<t_f(end))
        y = [y;x'];
        t_ = [t_;t];
        K1 = h*f(t,x);
        K2 = h*f(t + h/2,x + 1/2*K1);
        K3 = h*f(t + h/2,x + 1/2*K2);
        K4 = h*f(t + h,x + K3);
        x = x + (K1 + 2*K2 + 2*K3 + K4)/6;
        t = t + h;
    end
    fn = zeros(1,4);t = t_f(end);
    coffient = [-9/24 37/24 -59/24 55/24];
    for i = 1:4
        fn(i) = f(t_f(i),x);
    end
    while(t < t_max)
        y = [y;x'];
        t_ = [t_;t];
        x = x + h*coffient*fn';
        t = t + h;
        t_f = [t_f(2:end) t];
        for i = 1:4
           fn(i) = f(t_f(i),x); 
        end
    end
end

下面是预估校正法

%下面是4阶亚当姆斯预估-校正法
function [t_,y] = Adams_4v(f,tspan,x0,h)
    t_min = tspan(1);t_max = tspan(2);
    t_f1 = [t_min,t_min+h,t_min+2*h,t_min+3*h];
    t_f2 = [t_min+h,t_min+2*h,t_min+3*h,t_min+4*h];
    fn1 = zeros(1,4);fn2 = zeros(1,4);
    y = [];t_ = [];x = x0;t = t_min;
    %下面是用RK-4初始化提供初值
    while(t<t_f1(end))
        y = [y;x'];
        t_ = [t_;t];
        K1 = h*f(t,x);
        K2 = h*f(t + h/2,x + 1/2*K1);
        K3 = h*f(t + h/2,x + 1/2*K2);
        K4 = h*f(t + h,x + K3);
        x = x + (K1 + 2*K2 + 2*K3 + K4)/6;
        t = t + h;
    end
    for t = (t_min+3*h):h:t_max
        y = [y;x'];t_ = [t_;t];
        x_ = x + h/24*(55*f(t,x)-59*f(t-h,x)+37*f(t-2*h,x)-9*f(t-3*h,x));
        f_ = f(t+h,x_);
        x = x + h/24*(9*f_ + 19*f(t,x) - 5*f(t-h,x) + f(t-2*h,x));
    end
end

常用的仿真算法总结_第5张图片

你可能感兴趣的:(系统仿真技术,算法,机器学习,线性代数)