梯形方法求解常微分方程

对于一阶常微分方程初值问题:

\left\{\begin{matrix} \frac{dy}{dx}=f(x,y),a<x<b \\ y(a)=\alpha \end{matrix}\right.

利用数值积分可以推导出如下的梯形方法:

y_{i+1}=y_{i}+h/2[f(x_{i},y_{i})+f(x_{i+1},y_{i+1})]

从公式可以看出,梯形方法是隐式方法,因此需要迭代法进行求解,这里迭代初值采用欧拉方法,当然也可以采用其他方法,只要是显式方法即可,采用欧拉方法提供初值的改进梯形公式如下:

\left\{\begin{matrix} y_{i+1}^{(0)}=y_{i}+hf(x_{i},y_{i})\\ y_{i+1}^{(k+1)}=y_{i}+h/2[f(x_{i},y_{i})+f(x_{i+1},y_{k}^{(k)})] \end{matrix}\right.

使用迭代法需要设置误差限以控制迭代步数,数值算例如下:

\left\{\begin{matrix} \frac{dy}{dx}=y-\frac{2x}{y},0< x\leq 1\\ y(0)=1 \end{matrix}\right.

步长取0.1,迭代误差限取\varepsilon =10^{-4},MATLAB主函数代码如下:

% 梯形方法,为隐式方法,需要借助欧拉方法进行迭代
% L区间右端点,左端点默认为0,h为步长
function [err]=tixing(L,h)
x=(0:h:L);
% 设置误差限
eps=10^(-4);
%初始化分配内存
ye=zeros(1,length(x));y=ye;
%初值
y(1)=1;
% 精确解
for i=1:length(x)
    ye(i)=sqrt(1+2*x(i));
end
% 数值解
% 先用欧拉方法提供初值,再利用梯形方法
for i=1:length(x)-1
y1=y(i)+h*(y(i)-2*(x(i)/y(i)));
y2=y(i)+h/2*(y(i)-2*(x(i)/y(i))+y1-2*(x(i+1)/y1));
    while 1
        if abs(y1-y2)<eps
            y(i+1)=y2;
            break
        else
            y1=y2;
            y2=y(i)+h/2*(y(i)-2*(x(i)/y(i))+y1-2*(x(i+1)/y1));
            continue
        end

    end
end
% 计算误差
err=abs(ye-y);

计算收敛阶代码如下:

% 梯形方法收敛阶计算
dh=[1/100,1/200,1/400,1/800];
n=length(dh);
for i=1:n
    e(i)=max(tixing(1,dh(i)));
end
for i=1:n-1
    rate_tixing(i)=log2(e(i)/e(i+1));
end
% 由结果可以知道梯形方法是二阶收敛的

并且结合主函数代码可以得出梯形方法确实二阶收敛的,与理论分析是一致的 ,另外考虑到也有些学者们使用python编程,因此这里也给出python代码,如下:

import numpy as np
def euler_tixing(f,x,y0,args=(),eps=1e-4,max_iter=100):
    """
    :param f: 右端函数
    :param x: 离散的节点
    :param y0: 初值
    :param args:
    :param eps: 精度
    :param max_iter: 最大迭代次数
    :return: 返回数值解
    """
    y=np.zeros_like(x)
    y[0]=y0
    for i in range(len(x)-1):
        h=0.1
        y[i+1]=y[i]+h*f(x[i],y[i],*args)
        for j in range(max_iter):
            last_y=y[i+1]
            y[i+1]=y[i]+0.5*h*(f(x[i],y[i],*args)+f(x[i+1],y[i+1],*args))
            if np.abs(y[i+1]-last_y)<eps:
                break
            else:
                pass
    return y
x=np.linspace(0,1,num=11)
y0=1
y=euler_tixing(lambda x,y:y-2*x/y,x,y0)
print('   步长,   数值解,    精确解,     误差')
for i in range(len(x)):
    ans=np.sqrt(1+2*x[i])
    err=np.abs(y[i]-ans)
    print(f'{x[i]:4.0f},{y[i]:10.6f},{ans:10.6f},{err:10.2e}')

至于python计算收敛阶,这里就留作一个小习题,感兴趣的小伙伴可以尝试尝试

PS:最后,初来乍到,觉得满意的小伙伴们能否点个赞和关注呢,你们的支持将是我创作的最大动力

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mi@MI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值