现代科学运算-matlab语言与应用
东北大学 http://www.icourses.cn/home/ (薛定宇)
《高等应用数学问题的MATLAB求解(第四版)》
代码可在matlab r2016b 运行。
07 微分方程问题的计算机求解
07.01 微分方程解析解(上)
线性常系数微分方程解析解的数学描述
常系数线性微分方程的一般描述方法
其中,
均为常数
u(t) 已知输入信号,求y(t)的解析解
简单形式,默认自变量为t
y = dsolve(
)
指明自变量 x (一定要注意!)
y = dsolve(
, ‘x’)
可以同时求解多个方程,已知条件
注意自变量设置,否则可能得出无用结果
例7-1 微分方程解析解
假设输入信号为
试求出下面微分方程的通解
syms t y;
u = exp(-5*t)*cos(2*t+1)+5;
uu = 5 *diff(u, t, 2) + 4*diff(u, t) + 2*u;
% y即为解析解
y = dsolve(['D4y + 10*D3y + 35*D2y + 50*Dy + 24*y = ', char(uu)])
% 解析解检验
diff(y, 4) + 10*diff(y, 3) + 35*diff(y, 2) + ...
50*diff(y) + 24*y - uu
simplify(ans)
解得数学形式
用符号表达式描述微分方程
微分方程重新求解
syms t y(t);
u = exp(-5*t)*cos(2*t+1)+5;
uu = 5*diff(u, t, 2) + 4*diff(u, t) + 2*u;
y1 = diff(y);
y2 = diff(y, 2);
y3 = diff(y, 3);
y4 = diff(y, 4);
z1 = dsolve(y4 + 10*y3 + 35*y2 + 50*y1 + 24 * y == uu);
z1 = simplify(z1)
已知初值条件
y = dsolve(['D4y + 10*D3y + 35*D2y + ' ...
'50*Dy + 24*y = ', char(uu)], 'y(0) = 3', ...
'Dy(0) = 2', 'D2y(0) = 0', 'D3y(0) = 0')
ezplot(y, [0, 5])
复杂边界条件
假设
则可以获得方程的解析解
y = dsolve(['D4y + 10*D3y + 35*D2y + 50*Dy + 24*y = ', ...
char(uu)], 'y(0) = 1/2', 'Dy(pi) = 1', ...
'D2y(2*pi) = 0', 'Dy(2*pi) = 1/5')
% 由不易读的解析解求出近似解
vpa(y),
ezplot(y, [0, 5])
例7-4 变系数微分方程
变系数微分方程
微分方程直接求解
% 错误做法
y = dsolve('(2*x+3)^3*D3y + 3*(2*x+3)*Dy - 6*y = 0')
% 正确做法,指定自变量x
y = dsolve('(2*x+3)^3*D3y + 3*(2*x+3)*Dy - 6*y = 0', 'x');
y = simplify(y)
% 验证
syms x;
simplify((2*x+3)^3*diff(y, x, 3) + 3*(2*x+3)*diff(y, x, 1) - 6*y)
% 用解析表达式
syms x y(x);
y = dsolve((2*x+3)^3*diff(y, 3) + 3*(2*x+3)*diff(y) - 6*y==0)
例7-5 多维微分方程组
微分方程组
初值
求解
[x, y, z] = dsolve('D2x - x + y + z = 0', 'x + D2y - y +z = 0', ...
'x+y+D2z - z = 0', 'x(0) = 1, y(0) =0, z(0) = 0', ...
'Dx(0) = 0, Dy(0) = 0, Dz(0) = 0')
07.02 微分方程解析解(下)
线性状态空间方程的解析解
假设线性状态空间模型的一般表示
其中,A, B, C, D 是常数矩阵,且已知状态向量初值 x(t_0), 该方程的解析解是
例7.7 线性状态方程
给定输入信号为
, 求出下面矩阵描述的状态空间方程的解析解
数学公式:
syms t tau;
u = 2 + 2*exp(-3*t)*sin(2*t);
A = [-19, -16, -16, -19; 21, 16, 17, 19;
20, 17, 16, 20; -20, -16, -16, -19];
B = [1; 0; 1; 2];
C = [2, 1, 0, 0];
x0 = [0; 1; 1; 2];
y = C*(expm(A*t)*x0 + ...
int(expm(A*(t - tau))*B*subs(u, t, tau), tau, 0, t));
simplify(y)
特殊非线性微分方程的解析解
只有极少数非线性微分方程可以通过dsolve()函数得出解析解
例7-8 非线性微分方程
syms t x;
x = dsolve('Dx = x*(1-x^2)') % 有解析解
改变原微分方程形式
syms t x;
x = dsolve('Dx = x*(1-x^2)+1') % 无解析解
例7-9 VanderPol方程
试求出著名的VanderPol方程的解析解
syms t y(t) mu;
y = dsolve(diff(y, 2) + mu*(y^2-1)*diff(y) + y == 0) % 无解析解
07.03 微分方程数值解算法概述
一阶显式微分方程组
标准形式
其中,状态向量
非线性函数:
微分方程求解的误差与步长问题
Euler算法:
设初始时刻系统状态向量的值为 x(t_0)
微分方程左测的导数近似为:
在
时刻系统状态向量的值为:
简记为
故可以假设在
时刻系统的状态向量为
在
时刻 Euler 算法的数值解为:
h 被称为步长
步长的选择与措施
不能无限制地减小h的值的两条原因:
减慢计算速度
增加累积误差
在对微分方程求解过程中应该采取的三个措施
选择适当的步长
改进近似算法
采用变步长方法
四阶定步长Runge-Kutta算法及Matlab实现
四阶定步长Runge-Kutta算法的数学描述
其中 h 为计算步长
matlab调用: [t, x] = rk_4(fun, [
, h])
function [tout,yout] = rk_4(fun, tspan, y0)
ts = tspan;
t0 = ts(1);
tf = ts(2);
yout = [];
tout = [];
y0 = y0(:);
if length(ts) == 3
h=ts(3);
else
h = (ts(2)-ts(1))/100;
tf = ts(2);
end
for t = [t0:h:tf]
k1 = h*fun(t,y0);
k2 = h*fun(t+h/2,y0+k1/2);
k3 = h*fun(t+h/2,y0+k2/2);
k4 = h*fun(t+h,y0+k3);
y0 = y0+(k1+2*k2+2*k3+k4)/6;
yout=[yout; y0.'];
tout=[tout; t];
end
07.04 一阶微分方程组数值解
四阶五级Runge-Kutta-Felhberg算法
Runge-Kutta-Felhberg算法
假设当前的步长为
,定义6个
变量:
新状态向量
误差判定
微分方程的求解步骤
写出微分方程的数学步骤
编写方程的matlab代码
M-函数
匿名函数
求解方程,并绘制结果
验证结果的正确性
求解微分方程的matlab函数调用格式
[t, x] = ode45(fun,
)
[t, x] = ode45(fun,
, options)
[t, x] = ode45(fun,
)
其它求解函数 ode15s、ode23 等
不同的算法适合于不同类型的微分方程
描述需要求解的微分方程组
function
function
修改控制变量:
options = odeset(‘RelTol’, 1e-7)
options = odeset; options.RelTol = 1e-7;
例7-10 Lorenz方程
求解下列Lorenz(洛伦兹)模型
式中参数为:
初始条件为:
M-文件描述:
function y = lorenzeq(t, x)
y = [-8/3*x(1) + x(2)*x(3); -10*x(2) + 10*x(3);
-x(1)*x(2) + 28*x(2) - x(3)];
匿名函数描述:
f = @(t, x) [-8/3*x(1) + x(2)*x(3); -10*x(2) + 10*x(3);
-x(1)*x(2) + 28*x(2) - x(3)];
求解
t_final = 100;
x0 = [0; 0; 1e-10];
[t, x] = ode45(@lorenzeq, [0, t_final], x0);
plot(t, x);
figure;
plot3(x(:, 1), x(:, 2), x(:, 3));
用comet3()绘制相空间轨迹
figure;
comet3(x(:, 1), x(:, 2), x(:, 3));
matlab带有附加参数的微分方程求解
引入附加参数的目的
如果参数
改变,不需要修改原函数
可以利用附带的参数
新的函数编辑格式
function
新的函数调用命令(对应关系)
[t, x] = ode45(fun,
例7-11 附加参数的方程
Lorenz方程
附加参数:
重新求解:
f = @(t, x, beta, rho, sigma) [-beta *x(1) + x(2)*x(3);
-rho*x(2) + rho*x(3);
-x(1)*x(2) + sigma*x(2) - x(3)];
t_final = 100;
x0 = [0; 0; 1e-10];
%b1 = 8/3;r1 = 10; s1 = 28;
b1 = 2;r1 = 5; s1 = 20;
[t2, x2] = ode45(f, [0, t_final], x0, [], b1, r1, s1);
plot(t2, x2);
figure;
plot3(x2(:, 1), x2(:, 2), x2(:, 3));
07.05 微分方程标准型转换
微分方程转换成标准型
现有的微分方程数值解函数只能处理一阶显示微分方程组的初值问题
单个高阶常微分方程处理方法
一个高阶常微分方程的一般形式:
输出变量的各阶导数初始值为:
选择一组状态变量
原高阶常微分方程模型变换为一阶常微分方程组
初值为:
例7-12 VanderPol方程
VanderPol方程
初值为
选择状态变量:
新微分方程组
f = @(t, x, mu)[x(2); -mu*(x(1)^2-1)*x(2)-x(1)];
x0 = [-0.2; -0.7];
t_final = 20;
mu = 1;
[t1, y1] = ode45(f, [0, t_final], x0, [], mu);
mu = 2;
[t2, y2] = ode45(f, [0, t_final], x0, [], mu);
plot(t1, y1, t2, y2, '--')
figure;
plot(y1(:,1), y1(:, 2), y2(:, 1), y2(:, 2), '--')
非线性微分方程的极限环
一个反例:特别大的
, 如
= 3000
给定如下参数:
% 不要运行下述语句,耗时太长
% 应该使用刚性微分方程的算法
x0 = [2; 0];
t_final = 3000; mu = 1000;
[t, y] = ode45(f, [0, t_final] x0, [], mu);
高阶常微分方程组的变换方法
多元高阶常微分方程组的处理
状态变量的选择不唯一
建议:选择如下状态变量
新的状态方程:
可以描述该方程,然后用ode45等求解
例7-13 Apollo卫星轨迹
Apollo卫星的运动轨迹(x, y) 满足
其中,
并且
初始状态
选择状态变量:
得出一阶常微分方程组
其中:
并且
function dx = apolloeq(t, x)
mu = 1/82.45;
mu1 = 1 - mu;
r1 = sqrt((x(1)+mu)^2 + x(3)^2);
r2 = sqrt((x(1) - mu1)^2 + x(3)^2);
dx = [x(2);
2*x(4) + x(1) - mu1*(x(1) + mu)/r1^3-mu*(x(1) - mu1)/r2^3;
x(4);
-2*x(2) + x(3) - mu1*x(3)/r1^3 - mu*x(3)/r2^3];
求解
x0 = [1.2; 0; 0; -1.04935751];
tic,
[t, y] = ode45(@apolloeq, [0, 20], x0);
toc
length(t),
plot(y(:, 1), y(:, 3))
结果验证:
改变精度
options = odeset;
options.RelTol = 1e-6;
tic,
[t1, y1] = ode45(@apolloeq, [0, 20], x0, options);
toc
length(t1),
plot(y1(:, 1), y1(:, 3));
绘制计算步长曲线:
全程所采用的最小步长:
min(diff(t1));
plot(t1(1:end-1), diff(t1));
不应太依赖默认值,最好设置一下控制精度
步长值必须达到0.0001;对结果应该进行验证
例7-14 定步长求解
用定步长的四阶Runge-Kutta算法求下式
其中,
并且
初始状态
选择不同步长比较结果:
% 步长 0.01:
x0 = [1.2; 0; 0; -1.04935751];
tic,
[t1, y1] = rk_4(@apolloeq, [0, 20, 0.01], x0);
toc,
plot(y1(:, 1), y1(:, 3))
% 步长0.001:
tic, [t2, y2] = rk_4(@apolloeq, [0, 20, 0.001], x0);
toc,
figure;
plot(y2(:, 1), y2(:, 3))
options = odeset;
options.RelTol = 1e-6;
tic,
[t1, y1] = ode45(@apolloeq, [0, 20], x0, options);
toc,
length(t1),
figure;
plot(y1(:, 1), y1(:, 3))
例7-15 另一个方程组
微分方程
选择状态变量
设位置量为:
syms x1 x2 x3 x4;
[p1, p2] = solve('p1 + 2*p2*x1 = 2*p2', ...
'p1*x4 + 3*x2*p2 + x1*x4 - x3 = 5', 'p1, p2')
求解结果:
和前面完全一致的结果
07.06 刚性微分方程
刚性微分方程的求解
VanderPol方程中
刚性微分方程没有定义也没有判定方法
某些状态的解变换缓慢,另外一些变化快
变化快、慢相差悬殊
这类方程被称为刚性方程
而应该使用函数ode15s()求解该类方程,函数的调用格式和ode45()完全一致
h_opt=odeset;
h_opt.RelTol = 1e-6;
x0 = [2;0];
t_final = 3000;
f = @(t, x, mu)[x(2); -mu*(x(1)^2-1)*x(2)-x(1)];
tic,
mu = 1000;
[t, y] = ode15s(f, [0, t_final], x0, h_opt, mu);
toc
plot(t, y(:, 1));
figure;
plot(t, y(:, 2))
例7-19 传统刚性方程
求解微分方程
解析解:
syms t;
A = [-21, 19, -20; 19, -21, 20; 40, -40, -40];
y0 = [1; 0; -1];
y = expm(A*t)*y0
定步长求解
为了得到更好的结果,需要减小步长值,但是,计算速度会随之降低
定步长算法精度难以保证
例7-20 刚性微分方程
对下式用数值解法求解
初值条件:
f = @(t, y)[0.04*(1 - y(1)) - (1-y(2))*y(1) ...
+ 0.0001*(1 - y(2))^2;
-10^4*y(1) + 3000*(1-y(2))^2];
tic,
[t2, y2] = ode45(f, [0, 100], [0;1]);
toc,
length(t2),
plot(t2, y2)
% 步长显示
[min(diff(t2)), max(diff(t2))],
plot(t2(1:end-1), diff(t2))
% 用函数ode15s()替代函数ode45()
figure();
opt = odeset;
opt.RelTol = 1e-6;
tic,
[t1, y1] = ode15s(f, [0, 100], [0;1], opt);
toc,
length(t1),
plot(t1, y1, t2, y2)
07.07 隐式微分方程
例7.21 隐式微分方程
给定
, 求下式的数值解
令
, 可以将原微分方程改写成矩阵形式:
其中
如果
非奇异, 则
f = @(t, x) inv([sin(x(1)) cos(x(2));
-cos(x(2)) sin(x(1))])*[1-x(1); -x(2)];
opt = odeset;
opt.RelTol = 1e-6;
[t, x] = ode45(f, [0, 10], [0; 0], opt);
plot(t, x)
例7.22 隐式微分方程
给定
,微分方程
定义状态变量:
令
改写隐式方程
function dy = c7impode(t, x)
dx = @(p,x)[p(1)*sin(x(4)) + p(2)^2+2*x(1)*x(3)* ...
exp(-x(2)) - x(1)*p(1)*x(4);
x(1)*p(1)*p(2) + cos(p(2)) - ...
3*x(3)*x(2)*exp(-x(1))];
ff = optimset
ff.Display = 'off';
dx1 = fsolve(dx, x([1,3]), ff, x);
dy = [x(2); dx1(1); x(4); dx1(2)];
[t, x] = ode15s(@c7impode, [0, 2], [1, 0, 0, 1]);
plot(t, x)
使用函数ode15i()求解
隐式微分方程的数学描述:
相容的初始条件计算
隐式微分方程的求解
res = ode15i(fun, tspan,
)
例7-23 隐式微分方程
给定初始状态
用隐式微分方程求解的方法解出
选择状态变量
可以写出标准型
隐式方程的标准型
通过变换,可以得出
f = @(t, x, xd)[xd(1) - x(2);
xd(2)*sin(x(4)) + xd(4)*xd(4) + 2*x(1)*x(3)*exp(-x(2)) - x(1)*xd(2)*x(4);
xd(3) - x(4);
x(1)*xd(2)*xd(4) + cos(xd(4)) - 3*x(3)*x(2)*exp(-x(1))];
x0 = [1; 0; 0; 1];
x0F = [1; 1; 1; 1];
xd0 = [0; 1; 1; -1];
[x0, xd0] = decic(f, 0, x0, x0F, xd0, [])
r = ode15i(f, [0, 20], x0, xd0);
plot(r.x, r.y)
07.08 微分代数方程
微分代数方程求解
微分代数方程(DAE),是指在微分方程中,某些变量间满足某些代数方程的约束
微分方程的一般形式:
微分代数方程中,
矩阵为奇异矩阵
微分代数方程的求解中不能使用
例7-24 微分代数方程
给定初值条件,
微分方程
矩阵形式表示该微分代数方程
描述微分代数方程
f = @(t, x)[-0.2*x(1)+x(2)*x(3)+0.3*x(1)*x(2);
2*x(1)*x(2) - 5*x(2)*x(3) - 2*x(2)*x(2);
x(1)+x(2)+x(3)-1];
% 解此微分代数方程
M = [1, 0, 0; 0, 1, 0; 0, 0, 0];
options = odeset;
options.Mass = M;
x0 = [0.8; 0.1; 0.1];
[t, x] = ode15s(f, [0, 20], x0, options);
plot(t, x)
* 转换成一般ODE求解*
由约束式求出
代入其它两个微分方程
% 绝大部分微分代数方程不能使用这种方法,属于特例
f = @(t, x)[-0.2*x(1) + x(2)*(1-x(1)-x(2))+0.3*x(1)*x(2);
2*x(1)*x(2) - 5*x(2)*(1-x(1)-x(2))-2*x(2)*x(2)];
x0 = [0.8; 0.1];
[t1, x1] = ode45(f, [0, 20], x0);
plot(t1, x1, t1, 1-sum(x1'))
隐式方程求解方法
隐式微分方程描述
f = @(t, x, xd)[xd(1) + .2*x(1) - x(2)*x(3) - .3*x(1)*x(2);
xd(2) - 2*x(1)*x(2) + 5*x(2)*x(3) + 2*x(2)^2;
x(1) + x(2) + x(3) - 1];
x0 = [0.8; 0.1; 2];
x0F = [1; 1; 0];
xd0 = [1; 1; 1];
[x0, xd0] = decic(f, 0, x0, x0F, xd0, [])
res = ode15i(f, [0, 20], x0, xd0);
plot(res.x, res.y)
例7-25 重新求解隐式方程
用微分代数方程求解隐式微分方程
初始条件:
f = @(t, x)[1-x(1); -x(2)];
M = @(t, x)[sin(x(1)), cos(x(2)); -cos(x(2)), sin(x(1))];
ff = odeset;
ff.Mass = M;
ff.RelTol = 1e-6;
[t, x] = ode45(f, [0, 10], [0;0], ff);
plot(t, x)
07.09 延迟微分方程
所谓延迟微分方程,指微分方程中信号不是同时发生的,除了当前时刻的值,还含有信号以前时刻的值。
典型延迟微分方程的数值求解
延迟微分方程组的一般形式:
其中,
为状态变量 x(t) 的延迟常数
隐式 Runge-Kutta 算法 dde23()
sol = dde23(
)
描述微分方程和延迟模型
例7-28 延迟微分方程
用数值法求解下述延迟微分方程组
初始状态:
选择状态变量:
新的标准形式:
M-函数描述
function dx = c7exdde(t, x, z)
xlag1 = z(:, 1);
xlag2 = z(:, 2);
dx = [1-3x(1) - xlag1(2) - 0.2*xlag2(1)^3 - xlag2(1);
x(3);
4*x(1) - 2*x(2) - 3*x(3)];
% 延迟微分方程求解语句
lags = [1 0.5];
tx = dde23(@c7exdde, lags, zeros(3, 1), [0, 10]);
plot(tx.x, tx.y(2, :))
% 也可以用匿名函数描述延迟微分方程
f = @(t, x, Z)[1-3*x(1) - Z(2, 1) - 0.2*Z(1, 2)^3 - Z(1, 2);
x(3);
4*x(1) - 2*x(2) - 3*x(3)];
lags = [1 0.5];
tx = dde23(f, lags, zeros(3, 1), [0, 10]);
plot(tx.x, tx.y(2, :))
例7-29 非零初值问题
如果前面的微分方程初始值非零
f = @(t, x, Z)[1 - 3*x(1) - Z(2, 1) - 0.2*Z(1, 2)^3 - Z(1, 2);
x(3);
4*x(1) - 2*x(2) - 3*x(3)];
f2 = @(t, x)[exp(2.1*t); sin(t); cos(t)];
lags = [1 0.5];
tx = dde23(f, lags, f2, [0, 10]);
plot(tx.x, tx.y(2, :))
变时间延迟微分方程的求解
如果时间延迟不是常数
matlab求解函数: sol = ddesd(f,
, options)
三个函数(或句柄)
微分方程函数
变时间延迟函数
初始值函数
例7-30 变延迟微分方程
tau = @(t, x)[t - 0.2*abs(sin(t)); t - 0.8];
f = @(t, x, Z)[-2*x(2) - 3*Z(1, 1);
-0.05*x(1)*x(3) - 2*Z(2, 2) + 2;
0.3*x(1)*x(2)*x(3) + cos(x(1)*x(2)) + 2*sin(0.1*t^2)];
sol = ddesd(f, tau, zeros(3, 1), [0, 10]);
plot(sol.x, sol.y)
例7-32 复杂延迟方程
延迟微分方程:
tau = @(t, x)[t - 0.2*abs(sin(t)); 0.77*t];
f = @(t, x, Z)[-2*x(2) - 3*Z(1, 1);
-0.05*x(1)*x(3) - 2*Z(2, 2) + 2;
0.3*x(1)*x(2)*x(3) + cos(x(1)*x(2)) + 2*sin(0.1*t^2)];
sol = ddesd(f, tau, zeros(3, 1), [0, 10]);
plot(sol.x, sol.y);
中立型延迟微分方程求解
中立型延迟微分方程
含有导数以前的值
matlab函数: sol = ddensd(f,
, options)
例7-33 中立延迟方程
其中:
A1 = [-13, 3, -3; 106, -116, 62; 207, -207, 113];
A2 = [0.02, 0, 0; 0, 0.03, 0; 0, 0, 0.04];
B = [0; 1; 2];
u = 1;
f = @(t, x, z1, z2)A1*z1 + A2*z2 + B*u;
x0 = zeros(3, 1);
sol = ddensd(f, 0.15, 0.5, x0, [0, 15]);
plot(sol.x, sol.y)
07.10 微分方程边值问题
已知终止时刻的值,称为边值问题
边值问题的标准型
二阶微分方程的边值问题的数学描述
假设想在区间[a, b]上研究该方程的解,且已知在这两个边界点上满足
上面的方程称为边界a和b的边界条件
bvp5c()函数求出一般边值微分方程
参数初始化:M取值
v = linspace(a, b, M)
sinit = bvpinit(v,
)
微分方程和边值问题的matlab函数表述和边值问题的求解
sol = bvp5c(fun1, func2, sinit, options,
)
例7-37 边值问题的变换
使用bvp5c()函数重新求解下述边值问题
选择状态变量:
状态方程变为:
边界条件
f1 = @(t, x)[x(2); 2*x(1)*x(2)];
f2 = @(xa, xb)[xa(1)+1; xb(1)-1];
sinit = bvpinit(linspace(0, pi/2, 5), rand(2, 1));
sol = bvp5c(f1, f2, sinit);
plot(sol.x, sol.y);
若边界条件变成
f2 = @(xa, xb)[xb(2) - 1; xb(1) - xa(1) - 1];
sol = bvp5c(f1, f2, sinit);
plot(sol.x, sol.y);
例7-39 含参数微分方程
已知某常微分方程模型为
且已知
令
f = @(t, x, v)[4*x(1) + v(1)*x(1)*x(2);
- 2*x(2) + v(2)*x(1)*x(2)];
g = @(ya, yb, v)[ya(1)-2; ya(2)-1; yb(1)-4; yb(2)-2];
x1 = [1;1];
x2 = [-1;1];
sinit = bvpinit(linspace(0, 3, 5), x1, x2);
sol = bvp5c(f, g, sinit);
sol.parameters;
plot(sol.x, sol.y);
figure;
plot(sol.y(1, :), sol.y(2, :));
初值向量 选择若不当,可能使得求解过程中的Jacobian矩阵奇异,若出现此现象,选择其它的初值