一、数值微分与数值积分
1、数值微分
?当函数过于复杂或者以列表的方式给出时,就要用到数值方法。
?(1)数值差分与差商
向前差分:
向后差分:
中心差分:
向前差商:
向后差商:
中心差商:
函数在点的微分,接近于其在该点的差分
函数在点的导数,接近于其在该点的差商
?(2)数值微分的实现
MATLAB提供了求向前差分的函数diff,其调用格式如下:
dx = diff(x):计算向量x的一阶向前差分,dx(i)=x(i+1)-x(i),i =1,2,...,n-1。
dx = diff(x,n):计算向量x的n阶向前差分。例如,diff(x,2) = diff(diff(x))。
dx = diff(A,n,dim):计算矩阵A的n阶差分,dim = 1时(默认状态),按列计算差分;dim = 2,按列计算差分。
?注意:diff函数计算的是向量元素间的差分。故差分向量元素的个数比原向量少一个。对矩阵来讲就是少了一行或者一列。
?f(x)在某点处的差商作为,f(x)在某点处的导数值。
%数值微分
%验证向前差商求出的导数与实际导数之间的差距。
clear
clc
%f(x) = sinx,在[0,2*pi]范围内随机采样
x = [0,sort(2*pi*rand(1,5000)),2*pi]; % 有5002个元素 %按升序随机在[0,2*pi]上生成5000个数
y = sin(x); % 有5002个元素
f1 = diff(y)./diff(x); % 有5001个元素,y的差分除以x的差分,得到差商向量f1,此时长度减1
f2 = cos(x(1:end - 1)); % 有5001个元素,求各点导数的理论值向量f2,要保证长度相同,所以是x(1:end-1),
plot(x(1:end - 1),f1,'b',x(1:end - 1),f2,'r');
d = norm(f1-f2) %求近似值和理论值之间的范数,其值较小,说明近似值和理论值比较接近
2、数值积分
?(1)数值积分基本原理
求定积分,一般采用牛顿—莱布尼兹公式,但是有些情况牛莱公式不好用,采用数值积分则更为放方便。如:被积函数的原函数无法用初等函数表示,或被积函数是用表格形式给出的。
数值解法可以求定积分的近似值。
(2)数值积分的实现
①基于自适应辛普森方法
[l,n] = quad(filename,a,b,tol,trace)
②基于自适应Gauss-Lobatto方法
[l,n] = quadl(filename,a,b,tol,trace)
其中,filename是被积函数名;a和b分别是定积分的下限和上限,积分限[a,b]必须是有限的,不能为无穷大(inf);tol用来控制积分精度,默认时取tol = 10的-6次方;trace控制是否展现积分过程,若取非0则展现积分过程,取0则不展现,默认时取trace = 0;返回参数i即定积分的值,n为被积函数的调用次数。
%分别调用quad函数和quadl函数,比较被积函数的调用次数
format long;
f =@(x)4./(1+x.*x);
q = integral(f,0,1);
[I1,n1] = quad(f,0,1,1e-8,0);
[I2,n2] = quadl(f,0,1,1e-8,0);
disp('q=');
disp(q);
disp('I1、n1 = ');
disp([I1,n1]);
disp('I2、n2 = ');
disp([I2,n2]);
③基于全局自适应积分方法
I = integral(filename,a,b)
其中,I是计算得到的积分;filename是被积函数;a和b分别是定积分的下限和上限,积分限可以是无穷大。
clear
clc
%求定积分
format long
f =@(x)1./(x.*sqrt(1-log(x).*log(x))); %注意分子的整体性,加括号
q = integral(f,1,exp(1));
disp('q = ');
disp(q);
④基于自适应高斯-克朗罗德方法
[I,err] = quadgk(filename,a,b)
其中,err返回近似误差范围,其他参数同上。积分上下限可以是无穷大(-inf、inf),也可以是复数。如果积分上下限是复数,则quadgk函数在复平面上求积分。
⑤基于梯形积分法
在科学实验和实际应用中,有时函数关系表达式往往是不知道的,只有实验测定的一组样本点和样本值?,此时无法使用quad等函数来计算定积分,这种情况可以利用梯形积分函数trapz(),调用格式如下:
I = trapz(x,y),其中,向量x、y定义函数关系y = f(x)。
%求定积分,quadgk()函数
format short
f =@(x)(1./x.^2).*(sin(1./x));
q = integral(f,2/pi,inf); %用integral求函数积分
q1 = quadgk(f,2/pi,+inf); %用quadgk求函数积分
disp('q = ');
disp(q);
disp('q1 = ');
disp(q1);
clear
clc
%计算定积分
x = 1:6;
y = [6,8,11,7,5,2];
plot(x,y,'-ko');
grid on;
I = trapz(x,y);
I0 = sum(diff(x).*(y(1:end-1)+y(2:end))/2);
disp('定积分为:');
disp(I);
disp('I0 = ');
disp(I0);
(3)多重定积分的数值求解
clear
clc
format long
%分别求二重积分和三重积分
f1 =@(x,y)exp((-x.^2)/2).*(sin(x.^2 + y));
f2 =@(x,y,z)4.*x.*z.*exp(-z.^2.*y-x.^2);
I1 = integral2(f1,-2,2,-1,1);
I2 = integral3(f2,0,pi,0,pi,0,1);
disp('二重积分为:');
disp(I1);
disp('三重积分为:');
disp(I2);
当函数比较复杂或是用离散的表格形式给出时,导数或定积分的解析求解就比较困难,这是使用数值微分和数值积分就十分好用。
二、线性方程组求解
1、直接法
(1)利用左除运算符的直接解法,使用列主元消去法
Ax = b? ——>? x=A\b;? ? ? ? 其中,x即为线性方程组Ax = b的解。
注意:如果矩阵A是奇异的或接近奇异的,则MATLAB会给出警告信息。
format short
%用左除运算符求解线性方程组
A = [2,1,-5,1;...
1,-5,0,7;...
0,2,1,-1;...
1,6,-1,-4];
b = [13;-9;6;0]; %b = [13,-9,6,0]',和前面表达式意思相同
x = A\b;
disp('x = ');
disp(x);
(2)利用矩阵分解求解线性方程组
矩阵的分解:指将一个一般的矩阵,分解为若干个特殊的矩阵乘积,从而将一个一般的矩阵计算问题转化为几个易求的特殊矩阵的计算问题。优点为:运算速度快、节约存储空间。
重点:LU分解法,就是将非奇异的矩阵分解为,一个上三角矩阵与下三角矩阵的乘积。
LU分解的基本思想:
lu()函数,调用格式如下:
?[L,U] = lu(A):产生一个上三角阵U和一个变换形式的下三角阵L,使之满足A = LU。注意,这里的矩阵A必须是方阵。
? [L,U,P] = lu(A):产生一个上三角阵U和一个下三角阵L以及一个置换矩阵P,使之满足PA=LU。同样,矩阵A必须是方阵。
用LU分解求解线性方程组方法:
%用LU分解分解求解方程组
format short
A = [2,1,-5,1;...
1,-5,0,7;...
0,2,1,-1;...
1,6,-1,-4];
b = [13;-9;6;0]; %b = [13,-9,6,0]',和前面表达式意思相同
[L1,U1] = lu(A);
x1 = U1\(L1\b);
disp('x1 = ');
disp(x1);
[L2,U2,P] = lu(A);
x2 = U2\(L2\P*b);
disp('x2 = ');
disp(x2);
2、迭代法?
?不断用变量的原值推出它新值的过程,是用计算机解决问题的基本方法。
?(1)雅可比迭代法
jacobi.m函数文件
%jacobi函数,有四个输入变量,
%分别是系数矩阵A、右边列向量b、迭代初值和精度
%有两个输出参数,分别是方程的解和迭代次数。
function [y,n] = jacobi(A,b,x0,ep)
D = diag(diag(A)); %求A的对角矩阵
L = -tril(A,-1); %求A的下三角阵
U = -tril(A,1); %求A的上三角阵
B = D\(L+U); %求B矩阵
f = D\b; %求f向量
y = B*x0+f; %根据第一次x0求第一次迭代结果
n = 1; %将迭代次数置为1
while norm(y-x0)>=ep %用前后两个解之差的二范数,来判断两个解向量是否很接近
x0 = y;
y = B*x0+f; %用原来的解计算新的解,直到两次解的结果在精确度以内,结束
n = n+1;
end
?(2)高斯-赛德尔迭代法
?用新分量替代旧分量,精度比雅可比高一点。
%例子,用雅可比迭代法,高斯迭代法求线性方程组
A=[4,-2,-1;-2,4,3;-1,-3,3];
b = [1;5;0];
[x1,n1] = jacobi(A,b,[0,0,0]',1.0e-16);
disp('x1 = ');
disp(x1);
disp('n1 = ' );
disp(n1);
[x2,n2] = gauseidel(A,b,[0,0,0]',1.0e-6);
disp('x2 = ');
disp(x2);
disp('n2 = ');
disp(n2);
%例子,用雅可比迭代法,高斯赛德尔迭代法,求方程组
clear
clc
A = [1,2,-2;1,1,1;2,2,1];
b = [9;7;6];
[x1,n1] = jacobi(A,b,[0,0,0]',1.0e-6);
disp('x1 = ');
disp(x1);
disp('n1 = ' );
disp(n1);
[x2,n2] = gauseidel(A,b,[0,0,0]',1.0e-6);
disp('x2 = ');
disp(x2);
disp('n2 = ');
disp(n2);
总结:
1、一般情况下,高斯赛德尔迭代法收敛性好于雅可比迭代法。(一般高斯好于雅可比)
2、但是,有时候用雅可比迭算法收敛,但是高斯赛德尔迭代不收敛?(但是,有时候,雅可比还能用,高斯已经不能用了)
3、直接法:以矩阵初等变换为基础,可以求得方程组的精确解;占用的内存空间大、程序实现较为负责;一般适合求解低阶稠密线性方程组。
4、迭代法:从给定初值逐步逼近精确解的过程,求解过程占用存储空间小、程序设计简单;适合求解大型稀疏矩阵线性方程组;要考虑算法的收敛性。
三、线性方程组应用举例
%例子
alpha=sqrt(2)/2;
A=[0,1,0,0,0,-1,0,0,0,0,0,0,0;
0,0,1,0,0,0,0,0,0,0,0,0,0;
alpha,0,0,-1,-alpha,0,0,0,0,0,0,0,0;
alpha,0,1,0,alpha,0,0,0,0,0,0,0,0;
0,0,0,1,0,0,0,-1,0,0,0,0,0;
0,0,0,0,0,0,1,0,0,0,0,0,0;
0,0,0,0,alpha,1,0,0,-alpha,-1,0,0,0;
0,0,0,0,alpha,0,1,0,alpha,0,0,0,0;
0,0,0,0,0,0,0,0,0,1,0,0,-1;
0,0,0,0,0,0,0,0,0,0,1,0,0;
0,0,0,0,0,0,0,1,alpha,0,0,-alpha,0;
0,0,0,0,0,0,0,0,alpha,0,1,alpha,0;
0,0,0,0,0,0,0,0,0,0,0,alpha,1];
b=[0;10;0;0;0;0;0;15;0;20;0;0;0];
x = A\b;
disp('x = ');
disp(x);
四、非线性方程求解与函数极值计算
用数值计算求解非线性方程组的解,非常必要。
函数的极值问题实际上是一个最优化问题。在MATLAB中,非线性方程求解和最优化问题,可以使用最优化工具箱来解决。
1、非线性方程数值求解
(1)单变量非线性方程求解
? ? ? ? x = fzero(filename,x0),其中,filename是待求根方程左端的函数表达式,x0是初始值。
%x^2-1-0的根
f = @(x)x.^2-1;
x = [];
x0=-0.25:0.001:0.25;
for x00=x0
x=[x,fzero(f,x00)]; %用for循环结构,将函数值存在向量x中。
end
%画处初值和方程根的关系
plot(x0,x,'-o');
xlabel('初值');
ylabel('方程的根');
axis([-0.25,0.25,-1,1]);
%通过所画的图表明在x=0附近,相同的根所对应的初值范围并不连续。
%求得的根也并非是离初值比较近的根
(2) 非线性方程组的求解
函数的调用格式如下:
? ? ? ? x = fsolve(filename,x0,option)
x为返回的近似解,filename是待求根方程左端的函数表达式,x0是初值,option用于设置优化工具箱的优化参数,可以调用optimset函数来完成。
%求非线性方程组的解
f =@(x,y,z)[sin(x)+y+z.^2.*exp(x);x+y+z;x.*y.*z];
f(1,1,1);
x = fsolve(f,1,1,1,optimset('Display','off'));
%相比于用x、y、z三个单独的参数,用一个向量的三个元素更为方便,初值要求时一个变量,这个变量可以是向量。
f=@(x) [sin(x(1))+x(2)+x(3)^2*exp(x(1)),x(1)+x(2)+x(3),x(1)*x(2)*x(3)];
f([1,1,1]); %展示f函数的调用格式
x = fsolve(f,[1,1,1],optimset('Display','off'))
2、函数极值的计算
极大值(最大值);极小值(最小值),Matlab只考虑最小值的计算,如果要求最大值可以通过求-f(x)的最小值来解决。
求非线性函数最小值问题,属于最优化问题。
(1)无约束最优化问题
?[xmin,fmin] = fminbnd(filename,x1,x2,option)
[xmin,fmin] = fminsearch(filename,x0,option)
[xmin,fmin] =fminunc(filename,x0,option)
其中,filename是定义的目标函数。第一个函数的输入变量x1、x2分别表示被研究区间的左、右边界。后两个函数的输入变量x0是一个向量,表示极值点的初值。option为优化参数,可以通过optimset函数来设置。
%函数极值的计算,无约束最优化问题
%单变量函数求极小值的问题
f =@(x)x-1/x+5;
[xmin1,fmin1] = fminbnd(f,-10,-1,optimset('Display','off'));%求f在(-10,1)的最小值
disp('xmin1 = ');
disp(xmin1);
disp('fmin1 = ');
disp(fmin1);
[xmin2,fmin2] = fminbnd(f,1,10,optimset('Display','off'));%求f在(1,10)的最小值
disp('xmin2 = ');
disp(xmin2);
disp('fmin2 = ');
disp(fmin2);
(2)有约束最优化问题
?约束条件可细化为:线性不等式约束,线性等式约束、非线性不等式约束、非线性等式约束、X的上界和下界。
求有约束条件下最小值的函数为:
[xmin,fmin] = fmincon(filename,x0,A,b,Aeq,beq,Lbnd,Ubnd,NonF,option)
xmin、fmin、filename、x0、optionton参数含义同上。其余参数为约束条件。如果某个约束条件不存在,则用空矩阵来表示。
%求解有约束最优化问题
% f =@(x)0.4*x(2)+x(1)*x(1)+x(2)*x(2)-x(1)*x(2)+(1/30)*x1^3;
%
% x0 = [0.5;0.5];
% %线性不等式约束
% A =[-1,-0.5;-0.5,-1];
% b=[-0.4;-0.5];
% %解的下界
% Ib = [0;0];
% option=optimset('Display','off');
% [xmin,fmin] = fmincon(f,x0,A,b,[],[],Ib,[],[],option)
f=@(x) 0.4*x(2)+x(1)^2+x(2)^2-x(1)*x(2)+1/30*x(1)^3;
x0=[0.5;0.5];
A=[-1,-0.5;-0.5,-1];
b=[-0.4;-0.5];
lb=[0;0];
option=optimset('Display','off');
[xmin,fmin]=fmincon(f,x0,A,b,[],[],lb,[],[],option)
例5,某公司有A、B、C、D、E5个工厂,分别位于xy平面上的坐标点(10,10),(30,50),(16.667,29),(0.555,29.888)和(22.2221,49.988)处。设两点之间的距离表示在工厂之间开车的距离,以公里为单位。公司计划在平面上某点处建造一座仓库,预期平均每周到A、B、C、D、E工厂分别有10、18、20、14和25次送货。理想情况下,要使每周送货车的里程最小,仓库应建在xy平面的什么位置??
解题思路:
%无约束条件的最优化问题
clear
clc
u = [10,30,16.667,0.555,22.2221];
v = [10,50,29,29.888,49.988];
z = [10,18,20,14,25];
d =@(x)sum(z.*sqrt((x(1)-u).^2+(x(2)-v).^2));
[xmin,fmin] = fminsearch(d,[0,0]);
disp('xmin =');%最佳坐标
disp(xmin);
disp('fmin =');%最短距离
disp(fmin);
例6、在例5中,如果由于地域的限制,仓库必须建在曲线y=x2上,则它应该 建在何处?
%funny.m 代码
function [c,h] = funny(x)
c=[]; %非线性不等式约束条件
h = x(2)-x(1)^2; %非线性等式约束条件
%仓库选址,加约束条件,
clear
clc
u = [10,30,16.667,0.555,22.2221];
v = [10,50,29,29.888,49.988];
z = [10,18,20,14,25];
d =@(x)sum(z.*sqrt((x(1)-u).^2+(x(2)-v).^2));
[xmin,fmin] = fmincon(d,[0,0],[],[],[],[],[],[],'funny');
disp('xmin =');%最佳坐标
disp(xmin);
disp('fmin =');%最短距离
disp(fmin);
五、常微分方程数值求解
1、常微分方程数值求解的一般概念
?常微分方程初值问题就是寻找函数y(t)使之满足如下方程:
y' = f(t,y),? ? ? ? t0<=t<=b
y(t0) = y0? ? ? ? 初始条件
所谓数值解法,就是求y(t)在离散节点tn处的函数近似值yn的方法,yn ≈y(xn)。
2、常微分方程数值求解函数
?函数调用格式为:
? ? ? ? [r,y] = solver(filename,tspan,y0,option)
其中,t为时间向量,y为相应的数值解,solver为求常微分方程数值解的函数,filename是定义f(t,y)的函数名,该函数必须返回一个列向量;tspan形式为[t0,tf],表示求解区间,y0是初始状态向量;Option是可选参数,用于设置求解属性。
常微分方程数值求解函数的统一命名格式:
? ? ? ? ? ? ? ? odennxx
?其中,ode是常微分方程的简写,nn是数字,代表所用方法的阶数;xx是字母,用于标注方法的专门特征。
例如:ode23采用2阶龙格库塔算法,用三阶公式做误差估计来调节步长。具有低等精度
ode45采用4阶龙格库塔算法,用5阶公式做误差估计来调节步长。
%例一
%求解微分方程初值问题,并与精确解相比较
f =@(t,y)(y^2-t-2)/4/(t+1);
[t,y]=ode23(f,[0,10],2);
y1 = sqrt(t+1)+1;
plot(t,y,'b:',t,y,'r-');
?需要将二阶的常微分方程转化为一阶的常微分方程。
令x2 = x,x1 = x',则得到系统的状态方程:
%求解二阶线性系统的微分方程
f =@(t,x)[-2,0;0,1]*[x(2);x(1)];
[t,x]=ode45(f,[0,20],[1,0]);
subplot(2,2,1);plot(t,x(:,2));
subplot(2,2,2);plot(x(:,2),x(:,1));
3、刚性问题
??? 函数需要加S。专门处理刚性问题
六、常微分方程应用举例
???Lotka-Volterra模型
|