上一篇在数值积分中我们介绍了插值型求积公式以及如何分析对应的代数精度、稳定性和收敛性。当然啦,有数值积分就有数值微分,在以往的学习中我们可能已经掌握了很多解析解法,但是解析解法只能用来求解一些具有特定类型的方程,大部分方程都是需要数值求解的。 按照教材内容,我们着重点是一阶常微分方程初值问题的数值微分方法。
具体内容详见 《数值分析》 李庆扬、王能超、易大义(华中科大出版社)第五章
# 前向Euler
# Author: Junno
# Date: 2022-04-14
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
# 1-order differential equation
F=lambda x,y: y-2*x/y
# parsing solution of y
Solve_Y=lambda x:np.sqrt(1+2*x)
# initial value
initial_x=0
initial_y=1
# sep width
h=0.1
x_min=0
x_max=5
x=np.arange(x_min,x_max,h)
Euler_polygonal_arc=[]
for i in range(len(x)):
if x[i]==initial_x:
Euler_polygonal_arc.append(initial_y)
else:
Euler_polygonal_arc.append(Euler_polygonal_arc[i-1]+h*F(x[i-1],Euler_polygonal_arc[i-1]))
plt.figure()
plt.scatter(x,Solve_Y(x),s=5, marker='*',c='black')
plt.scatter(x,Euler_polygonal_arc,s=5, marker='*',c='red')
plt.xlabel('x')
plt.ylabel('y')
Parsing_Solution=mpatches.Patch(color='black', label='Parsing_Solution')
Numerical_Solution=mpatches.Patch(color='red', label='Numerical_Solution')
plt.title('Euler_polygonal_arc method in range {}-{} with h={:.1f}'.format(x_min,x_max,h))
plt.legend(handles=[Parsing_Solution,Numerical_Solution],loc='best')
plt.show()

在0-5的范围内步长0.1查看结果:

可以看到欧拉前向差分仅在 [ 0 , 2 ] [0,2] [0,2]范围内还比较拟合,之后显著偏离原来的曲线,即前向差分欧拉方法的误差还是很大的。
T n + 1 = y ( x n + 1 ) − y n + 1 = [ y ( x n ) + h y ′ ( x n ) + h 2 2 y ′ ′ ( x n ) + O ( h 3 ) ] − [ y n + h f ( x n , y n ) ] = h 2 2 y ′ ′ ( x n ) + O ( h 3 ) ≈ O ( h 2 ) T_{n+1}=y(x_{n+1})-y_{n+1}=[y(x_n)+h y^{'}(x_n)+\frac{h^2}{2} y^{''}(x_n)+O(h^3)]-[y_n+h f(x_n,y_n)]=\frac{h^2}{2} y^{''}(x_n)+O(h^3) \approx O(h^2) Tn+1=y(xn+1)−yn+1=[y(xn)+hy′(xn)+2h2y′′(xn)+O(h3)]−[yn+hf(xn,yn)]=2h2y′′(xn)+O(h3)≈O(h2)
即前向欧拉方法具有1阶精度。
# 前向Euler
# Author: Junno
# Date: 2022-04-24
def iter_back_Euler(x,y_,y,F,h,eps=1e-4,N=100):
v0=y-eps*10
v1=y
while N or abs(v1-v0)>eps:
v1=y_+h*F(x,v0)
v0=v1
N-=1
return y
Euler_polygonal_arc_back=[]
for i in range(len(x)):
if x[i]==initial_x:
Euler_polygonal_arc_back.append(initial_y)
else:
Euler_polygonal_arc_back.append(iter_back_Euler(x[i],Euler_polygonal_arc_back[i-1],Euler_polygonal_arc_back[i-1]+h*F(x[i-1],Euler_polygonal_arc_back[i-1]),\
F,h))
相应的求解结果:
