【数学建模笔记 13】数学建模的微分方程建模

13. 微分方程建模

定义

微分方程建模是数学建模的重要方法,大体可以按以下几步:

  1. 根据实际要求确定要研究的量 (自变量、未知函数、必要参数),确定坐标系;
  2. 找出这些量所满足的基本规律;
  3. 运用规律列出方程和定解条件。

微分方程的数值解

考虑一阶常微分方程
{ d y d x = f ( x , y ) , y ( x 0 ) = y 0 . \left\{\begin{aligned} &\frac{dy}{dx}=f(x,y),\\ &y(x_0)=y_0. \end{aligned}\right. dxdy=f(x,y),y(x0)=y0.
在区间 [ a , b ] [a,b] [a,b] 上的解。

所谓数值解法,就是求 y ( x ) y(x) y(x) 在若干点
a = x 0 < x 1 < x 2 < ⋯ < x N = b a=x_0a=x0<x1<x2<<xN=b
处的近似值 y n , n = 1 , 2 , … , N y_n,n=1,2,\dots,N yn,n=1,2,,N,称
h n = x n + 1 − x n h_n=x_{n+1}-x_n hn=xn+1xn
为步长,一般取等步长 h = ( b − a ) / N h=(b-a)/N h=(ba)/N

为求数值解,首先要将微分方程离散化,方法有:

  • 用差商近似导数:

若用向前差商 y ( x n + 1 ) − y ( x n ) h \frac{y(x_{n+1})-y(x_n)}{h} hy(xn+1)y(xn) 代替 y ′ ( x n ) y'(x_n) y(xn),代入微分方程,则
y ( x n + 1 ) − y ( x n ) h ≈ f ( x n , y ( x n ) ) , n = 0 , 1 , … , N − 1. \frac{y(x_{n+1})-y(x_n)}{h}\approx f(x_n,y(x_n)),n=0,1,\dots,N-1. hy(xn+1)y(xn)f(xn,y(xn)),n=0,1,,N1.

y ( x n + 1 ) ≈ y ( x n ) + h f ( x n , y ( x n ) ) . y(x_{n+1})\approx y(x_n)+hf(x_n,y(x_n)). y(xn+1)y(xn)+hf(xn,y(xn)).
y ( x n ) y(x_n) y(xn) 的近似值 y n y_n yn 代入,即
y n + 1 = y n + h f ( x n , y n ) , n = 0 , 1 , … , N − 1. y_{n+1}=y_n+hf(x_n,y_n),n=0,1,\dots,N-1. yn+1=yn+hf(xn,yn),n=0,1,,N1.
于是原方程组化为
{ y n + 1 = y n + h f ( x n , y n ) , n = 0 , 1 , … , N − 1 , y 0 = y ( a ) . \left\{\begin{aligned} &y_{n+1}=y_n+hf(x_n,y_n),n=0,1,\dots,N-1,\\ &y_0=y(a). \end{aligned}\right. {yn+1=yn+hf(xn,yn),n=0,1,,N1,y0=y(a).
通过 y 0 y_0 y0 可逐次算出 y 1 , y 2 , … , y N y_1,y_2,\dots,y_N y1,y2,,yN

  • 数值积分方法:

y ( x n + 1 − y ( x n ) ) = ∫ x n x n + 1 f ( x , y ( x ) ) d x , y(x_{n+1}-y(x_n))=\int_{x_n}^{x_{n+1}}f(x,y(x))dx, y(xn+1y(xn))=xnxn+1f(x,y(x))dx,

右边的积分用矩形或梯形公式计算。

  • 泰勒多项式近似:

y ( x ) y(x) y(x) x n x_n xn 处展开,即
y ( x n + 1 ) ≈ y ( x n ) + h y ′ ( x n ) y(x_{n+1})\approx y(x_n)+hy'(x_n) y(xn+1)y(xn)+hy(xn)

= y ( x n ) + h f ( x n , y ( x n ) ) , =y(x_n)+hf(x_n,y(x_n)), =y(xn)+hf(xn,y(xn)),

代入近似值得
y n + 1 = y n + h f ( x n , y n ) . y_{n+1}=y_n+hf(x_n,y_n). yn+1=yn+hf(xn,yn).
上式又称欧拉法,为了提高精度,可以使用梯形积分代替矩形积分,称改进欧拉法,即
y n + 1 = y n + h 2 [ f ( x n , y n ) + f ( x n + 1 , y n + 1 ) ] . y_{n+1}=y_n+\frac{h}2[f(x_n,y_n)+f(x_{n+1},y_{n+1})]. yn+1=yn+2h[f(xn,yn)+f(xn+1,yn+1)].
然而由于每一步都会产生截断误差,欧拉法会随着递推误差越来越大。

龙格-库塔法

龙格库塔法的主要思想,就是在 x x x 点附近选取一些特定的点,将这些点的函数值进行线性组合,用组合值代替泰勒展开中的导数值。

根据微分中值定理有
y n + 1 − y ( x n ) h = y ′ ( x n + θ h ) , 0 < θ < 1. \frac{y_{n+1}-y(x_n)}{h}=y'(x_n+\theta h),0<\theta<1. hyn+1y(xn)=y(xn+θh),0<θ<1.
y ′ = f ( x , y ) y'=f(x,y) y=f(x,y),于是有
y ( x n + 1 ) = y ( x n ) + h f ( x n + θ h , y ( x n + θ h ) ) . y(x_{n+1})=y(x_n)+hf(x_n+\theta h,y(x_n+\theta h)). y(xn+1)=y(xn)+hf(xn+θh,y(xn+θh)).
K ‾ = f ( x n + θ h , y ( x n + θ h ) ) \overline{K}=f(x_n+\theta h,y(x_n+\theta h)) K=f(xn+θh,y(xn+θh)) 为区间 [ x n , x n + 1 ] [x_n,x_{n+1}] [xn,xn+1] 的平均斜率。

欧拉法简单取 K ‾ = f ( x n , y n ) \overline{K}=f(x_n,y_n) K=f(xn,yn)​​,精度很低,而改进欧拉法则取
K ‾ = 1 2 [ f ( x n , y n ) + f ( x n + 1 , y ‾ n + 1 ) ] , \overline{K}=\frac12[f(x_n,y_n)+f(x_{n+1},\overline{y}_{n+1})], K=21[f(xn,yn)+f(xn+1,yn+1)],

y ‾ n + 1 = y n + h f ( x n , y n ) , \overline{y}_{n+1}=y_n+hf(x_n,y_n), yn+1=yn+hf(xn,yn),

则提高了精度。

于是,在区间 [ x n , x n + 1 ] [x_n,x_{n+1}] [xn,xn+1] 内多取几个点进行加权平均作为 K ‾ \overline{K} K,就有可能构造出精度更高的计算公式。

不妨在区间内仍取 2 个点,有
{ y n + 1 = y n + h ( λ 1 k 1 + λ 2 k 2 ) , k 1 = f ( x n , y n ) , k 2 = f ( x n + α h , y n + β h k 1 ) , 0 < α , β < 1. \left\{\begin{aligned} &y_{n+1}=y_n+h(\lambda_1k_1+\lambda_2k_2),\\ &k_1=f(x_n,y_n),\\ &k_2=f(x_n+\alpha h,y_n+\beta hk_1),0<\alpha,\beta<1. \end{aligned}\right. yn+1=yn+h(λ1k1+λ2k2),k1=f(xn,yn),k2=f(xn+αh,yn+βhk1),0<α,β<1.
y n = y ( x n ) y_n=y(x_n) yn=y(xn),则可以化为
{ y n + 1 = y ( x n ) + h ( λ 1 k 1 + λ 2 k 2 ) , k 1 = f ( x n , y ( x n ) ) = y ′ ( x n ) , k 2 = f ( x n + α h , y ( x n ) + β h k 1 ) . \left\{\begin{aligned} &y_{n+1}=y(x_n)+h(\lambda_1k_1+\lambda_2k_2),\\ &k_1=f(x_n,y(x_n))=y'(x_n),\\ &k_2=f(x_n+\alpha h,y(x_n)+\beta hk_1). \end{aligned}\right. yn+1=y(xn)+h(λ1k1+λ2k2),k1=f(xn,y(xn))=y(xn),k2=f(xn+αh,y(xn)+βhk1).
k 2 k2 k2 ( x n , y ( x n ) ) (x_n,y(x_n)) (xn,y(xn)) 作泰勒展开,则有
k 2 = f ( x n , y ( x n ) ) + α h f x ( x n , y ( x n ) ) k_2=f(x_n,y(x_n))+\alpha hf_x(x_n,y(x_n)) k2=f(xn,y(xn))+αhfx(xn,y(xn))

+ β h k 1 f y ( x n , y ( x n ) ) + O ( h 2 ) . +\beta hk_1f_y(x_n,y(x_n))+O(h^2). +βhk1fy(xn,y(xn))+O(h2).

于是有
y n + 1 = y ( x n ) + ( λ 1 + λ 2 ) h y ′ ( x n ) y_{n+1}=y(x_n)+(\lambda_1+\lambda_2)hy'(x_n) yn+1=y(xn)+(λ1+λ2)hy(xn)

+ λ 2 α h 2 ( f x + β α f f y ) + O ( h 3 ) . +\lambda_2\alpha h^2(f_x+\frac{\beta}{\alpha}ff_y)+O(h^3). +λ2αh2(fx+αβffy)+O(h3).

可见为使误差 y ( x n + 1 ) − y n + 1 = O ( h 3 ) y(x_{n+1})-y_{n+1}=O(h^3) y(xn+1)yn+1=O(h3),只须令
λ 1 + λ 2 = 1 , λ 2 α = 1 2 , β α = 1. \lambda_1+\lambda_2=1,\lambda_2\alpha=\frac12,\frac{\beta}{\alpha}=1. λ1+λ2=1,λ2α=21,αβ=1.
解不唯一,其中若
λ 1 = λ 2 = 1 2 , α = β = 1 , \lambda_1=\lambda_2=\frac12,\alpha=\beta=1, λ1=λ2=21,α=β=1,
即为改进欧拉法。

若取 4 个点,就构成常用的四阶龙格-库塔法 RK4
y n + 1 = y n + h 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) , y_{n+1}=y_n+\frac{h}{6}(k_1+2k_2+2k_3+k_4), yn+1=yn+6h(k1+2k2+2k3+k4),
其中
k 1 = f ( x n , y n ) , k_1=f(x_n,y_n), k1=f(xn,yn),

k 2 = f ( x n + h 2 , y n + h 2 k 1 ) , k_2=f(x_n+\frac{h}{2},y_n+\frac{h}{2}k_1), k2=f(xn+2h,yn+2hk1),

k 3 = g ( x n + h 2 , y n + h 2 k 2 ) , k_3=g(x_n+\frac{h}{2},y_n+\frac{h}{2}k_2), k3=g(xn+2h,yn+2hk2),

k 4 = f ( x n + h , y n + h k 3 ) . k_4=f(x_n+h,y_n+hk_3). k4=f(xn+h,yn+hk3).

k 1 , k 2 , k 3 , k 4 k_1,k_2,k_3,k_4 k1,k2,k3,k4​ 分别为起点、中点、终点的斜率,通过一定的加权平均使得误差尽可能小。

微分方程建模实例

Malthus 模型

x ( t ) x(t) x(t) 表示 t t t 时人口数,人口增长率 r r r 是常数,假设人口数量的变化封闭,即人口数量增加和减少只取决于人口个体的生育和死亡。

t t t 时刻到 t + Δ t t+\Delta t t+Δt 时刻,人口增量为
x ( t + Δ t ) − x ( t ) = r x ( t ) Δ t , x(t+\Delta t)-x(t)=rx(t)\Delta t, x(t+Δt)x(t)=rx(t)Δt,
于是得
{ d x d t = r x , x ( 0 ) = x 0 . \left\{\begin{aligned} &\frac{dx}{dt}=rx,\\ &x(0)=x_0. \end{aligned}\right. dtdx=rx,x(0)=x0.
解为
x ( t ) = x 0 e r t . x(t)=x_0e^{rt}. x(t)=x0ert.
然而模型的预测结果远高于实际人口增长,误差的原因是对增长率 r r r 估计过高。

Logistic 模型

由于资源是有限的,随着人口数量增长,资源对人口增长的限制将越来越显著。人口较少时可以将增长率 r r r 看作常数,到达一定数量后 r r r 应随人口增加而减小。因此,将 r r r 表示为人口 x ( t ) x(t) x(t) 的函数 r ( x ) r(x) r(x),且 r ( x ) r(x) r(x) x x x 的减函数。

r ( x ) r(x) r(x) x x x 的线性函数, r ( x ) = r − s x r(x)=r-sx r(x)=rsx

设容纳最大人口为 x m x_m xm,当 x = x m x=x_m x=xm 时, r ( x m ) = 0 r(x_m)=0 r(xm)=0

于是有
r ( x ) = r ( 1 − x x m ) , r(x)=r(1-\frac{x}{x_m}), r(x)=r(1xmx),

{ d x d t = r ( 1 − x x m ) x , x ( t 0 ) = x 0 . \left\{\begin{aligned} &\frac{dx}{dt}=r(1-\frac{x}{x_m})x,\\ &x(t_0)=x_0. \end{aligned}\right. dtdx=r(1xmx)x,x(t0)=x0.
解为
x ( t ) = x m 1 + ( x m x 0 − 1 ) e − r ( t − t 0 ) . x(t)=\frac{x_m}{1+(\frac{x_m}{x_0}-1)e^{-r(t-t_0)}}. x(t)=1+(x0xm1)er(tt0)xm.
r , x m r,x_m r,xm 为变量,对某一数据集进行拟合,就可以得到结果。

Python 代码

微分方程求解

求微分方程
{ y ′ = − 2 y + x 2 + 2 x , y ( 1 ) = 2. \left\{\begin{aligned} &y'=-2y+x^2+2x,\\ &y(1)=2. \end{aligned}\right. {y=2y+x2+2x,y(1)=2.
的解析解和数值解,代码如下:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @ author: Koorye
# @ date: 2021-7-27
# @ function: 使用 scipy、sympy 求微分方程的数值解、解析解

# %%

import numpy as np
from scipy.integrate import odeint
from sympy import *

# %%

# 使用 scipy 求数值解
# 微分方程
dy = lambda y,x:-2*y + x**2 + 2*x

# 数值范围
x1 = np.linspace(1,10,20)

# 求数值解,y 的初始值为 2
y1 = odeint(dy, 2, x1)
y1

# %%

# 使用 sympy 求解析解

# 定义变量和函数
x = symbols('x', real=True)
y = Function('y')

# 定义方程和约束
eq = y(x).diff(x) + 2*y(x) - x**2 - 2*x
con = {
	y(1): 2,
}

# 求解
f = simplify(dsolve(eq, ics=con))
f

# %%

# 向解中代入不同的值
x2 = np.linspace(1,10,100)
y2 = []
for each in x2:
	y2.append(list(sorted(f.subs(x,each).evalf().atoms()))[1])

# %%

# 画图
import matplotlib.pyplot as plt

plt.scatter(x1,y1, label='x1', color='coral')
plt.plot(x2,y2, label='x2')
plt.legend()

输出如下:
y ( x ) = x 2 2 + x 2 + 5 e 2 − 2 x 4 − 1 4 y(x)=\frac{x^2}{2}+\frac{x}{2}+\frac{5e^{2-2x}}{4}-\frac14 y(x)=2x2+2x+45e22x41
【数学建模笔记 13】数学建模的微分方程建模_第1张图片

得到解析解的公式,以及数值解 x 1 x_1 x1 和解析解的曲线 x 2 x_2 x2,发现数值解和解析解大致吻合。

Logistic 模型

对下列人口数据:

年份 人口
1790 3.9
1800 5.3
1810 7.2
1820 9.6
1830 12.9
1840 17.1
1850 23.2
1860 31.4
1870 38.6

使用 Logistic 模型拟合,求出 r , x m r,x_m r,xm 的值。

代码如下:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @ author: Koorye
# @ date: 2021-7-27
# @ function: 使用 Logistic 模型拟合人口数据

# %%

import numpy as np
import pandas as pd
from scipy.optimize import curve_fit

# %%

# 源数据
df = pd.DataFrame({
    'year': [1790, 1800, 1810, 1820, 1830, 1840, 1850, 1860, 1870],
    'population': [3.9, 5.3, 7.2, 9.6, 12.9, 17.1, 23.2, 31.4, 38.6],
})

x0 = float(df['population'][0])
t0 = float(df['year'][0])

# %%

# Logistic 模型
def x(t, r, xm):
    return xm / (1 + (xm/x0-1)*np.exp(-r*(t-t0)))

# 拟合参数
popt, pcov = curve_fit(x,
                       df['year'].tolist(),
                       df['population'].tolist(),
                       bounds=((0, 1), (.1, np.inf)))
r, xm = popt[0], popt[1]
print('r =', r)
print('xm =', xm)

# 预测 1900 人口
print('population in 1900 =', x(1900, r, xm))

# %%

# 画出预测曲线
import matplotlib.pyplot as plt

year = np.linspace(1790,2000,21)
population = []
for each in year:
	population.append(x(each,r,xm))
plt.scatter(df['year'], df['population'], label='actual')
plt.plot(year, population, label='predict', color='coral')
plt.legend()

输出如下:

r = 0.031999710099329476
xm = 159.3028433863908
population in 1900 = 73.09203839061287

【数学建模笔记 13】数学建模的微分方程建模_第2张图片
得到 r = 0.032 , x m = 159.3 r=0.032,x_m=159.3 r=0.032,xm=159.3,并预测 1900 年人口为 73.09 73.09 73.09,得到预测曲线。

你可能感兴趣的:(数学建模,数学建模,scipy,python)