MATLAB数值分析应用教程 周品
MATLAB数值分析应用教程 周品


目录
内容简介
前言
第1章 MATLAB软件使用基本介绍
1.1 MATLAB软件概述
1.1.1 MATLAB基本功能
1.1.2 MATLAB例子演示
1.2 MATLAB帮助系统
1.2.1 联机帮助系统
1.2.2 命令帮助系统
1.2.3 联机演示系统
1.2.4 远程帮助系统
1.3 常量与变量
1.3.1 常量
1.3.2 变量
1.4 MATLAB数据类型
1.4.1 数值型
1.4.2 逻辑类型
1.4.3 字符与字符串
第2章 矩阵与数组
2.1 矩阵的创建
2.1.1 直接方式创建矩阵
2.1.2 创建特殊矩阵
2.2 矩阵拼接
2.2.1 基本拼接
2.2.2 拼接函数
2.3 矩阵的扩展
2.3.1 扩展矩阵
2.3.2 缩小矩阵
2.4 改变矩阵的形状
2.4.1 重塑矩阵形状
2.4.2 预分配内存
2.5 向量、标量与空矩阵
2.5.1 向量
2.5.2 标量
2.5.3 空矩阵
2.6 寻访矩阵元素
2.6.1 寻访双下标
2.6.2 寻访单下标
2.6.3 寻访多个元素
2.7 获取矩阵信息
2.7.1 获取矩阵的维数
2.7.2 获取矩阵数据结构
2.7.3 获取矩阵数据类型
2.8 稀疏矩阵
2.8.1 创建稀疏矩阵
2.8.2 稀疏矩阵的操作
2.9 高级数组
2.9.1 建立高维数组
2.9.2 访问高维数组信息
2.9.3 高维数组操作函数
2.9.4 用多维数组组织数据
第3章 元胞与结构数组
3.1 元胞数组
3.1.1 元胞数组的创建
3.1.2 显示元胞数组
3.1.3 字符串元胞数组
3.1.4 取元胞数组数据
3.1.5 元胞数组的扩展、删减和重塑
3.1.6 访问元胞数组
3.1.7 嵌套元胞数组
3.1.8 高维元胞数组
3.1.9 元胞数组与数字数组间的转换
3.2 结构数组
3.2.1 创建结构数组
3.2.2 取结构数组数据
3.2.3 扩展与删除结构字段
3.2.4 结构数组的其他操作函数
3.2.5 用结构数组组织数据
3.2.6 嵌套结构数组
3.2.7 高维结构数组
第4章 程序控制与矩阵分析
4.1 程序控制流
4.1.1 顺序控制结构
4.1.2 分支结构
4.1.3 循环结构
4.1.4 程序终止结构
4.1.5 错误控制结构
4.2 M函数
4.2.1 脚本文件与函数文件
4.2.2 脚本文件与函数文件间区别
4.2.3 M文件结构
4.3 函数类型
4.3.1 主函数
4.3.2 子函数
4.3.3 匿名函数
4.3.4 嵌套函数
4.3.5 私有函数
4.4 矩阵运算
4.4.1 矩阵的加、减
4.4.2 矩阵的乘法运算
4.4.3 矩阵除法运算
4.4.4 矩阵幂运算
4.4.5 矩阵的按位运算
4.5 矩阵特征量
4.5.1 矩阵的行列式
4.5.2 矩阵的逆
4.5.3 矩阵的范数
4.5.4 矩阵条件数
4.5.5 矩阵的特征值及特征向量
4.5.6 标准正交基
4.6 矩阵的分解
4.6.1 特征分解
4.6.2 Cholesky分解
4.6.3 LU分解
4.6.4 QR分解
4.6.5 SVD分解
4.7 矩阵函数
第5章 数据分析
5.1 数据排序
5.1.1 最大(小)值
5.1.2 中位数
5.1.3 分位数
5.1.4 排序
5.2 求和与求积
5.2.1 求和
5.2.2 求积
5.2.3 求累加和与累乘积
5.3 均值方差与相关系数
5.3.1 均值
5.3.2 方差
5.3.3 相关与协方差
5.3.4 相关系数
5.4 数据预处理
5.4.1 缺失数据处理
5.4.2 异常值
5.5 数据插值
5.5.1 一维插值
5.5.2 二维插值
5.5.3 高维插值
5.5.4 样条插值
5.5.5 拉格朗日插值
5.5.6 牛顿插值
5.6 曲线拟合
5.6.1 多项式曲线拟合
5.6.2 正交最小二乘拟合
5.6.3 加权最小方差拟合
5.6.4 曲线拟合界面
第6章 线性与非线性方程组的求解
6.1 线性方程组的概述及表示法
6.2 线性方程组的种类
6.2.1 非奇异线性方程组
6.2.2 奇异线性方程组
6.2.3 欠定线性方程组
6.2.4 超定线性方程组
6.3 利用MATLAB内置函数求解线性方程组
6.3.1 高斯消元法求解
6.3.2 LU分解法求解
6.3.3 Cholesky分解法求解
6.3.4 奇异值分解法求解
6.3.5 双共轭梯度法求解
6.3.6 共轭梯度的LSQR法求解
6.3.7 最小残差法求解
6.3.8 标准最小残差法求解
6.3.9 广义最小残差法求解
6.4 利用自定义编写函数求解线性方程组
6.4.1 雅可比迭代法
6.4.2 高斯-赛德尔迭代法
6.4.3 松弛迭代法
6.5 函数法
6.5.1 一般方程求解
6.5.2 非线性方程求解
6.5.3 多元非线性求解
6.5.4 多项式的根求解
6.6 编写自定义函数求解非线性方程
6.6.1 二分法
6.6.2 迭代法
6.6.3 抛物线法
6.6.4 牛顿法
6.6.5 正割法
6.7 编写自定义函数求解非线性方程组
6.7.1 不动点
6.7.2 牛顿法
6.7.3 拟牛顿法
6.7.4 共轭梯度法
第7章 数值微积分
7.1 数值微分积分概述
7.2 微分
7.2.1 符号微分
7.2.2 向量微分
7.2.3 数值微分
7.3 积分
7.3.1 符号积分
7.3.2 证明积分等式
7.3.3 数值积分
7.4 复合求积公式
7.4.1 复合梯形求积法
7.4.2 复合抛物线形求积法
7.4.3 龙贝格求积法
7.4.4 复合辛普森求积法
7.4.5 逐步区间二分法
7.5 多元函数的梯度
7.6 级数
7.6.1 级数求和
7.6.2 泰勒展开
7.6.3 傅里叶展开
7.7 积分变换
7.7.1 傅里叶积分变换
7.7.2 拉普拉斯积分变换
7.7.3 Z积分变换
第8章 微分方程
8.1 符号法求解常微分方程
8.1.1 符号法求解线性常微分方程
8.1.2 符号法求解特殊非线性微分方程
8.2 数值法求解微分方程
8.2.1 欧拉方法
8.2.2 改进的欧拉方法
8.2.3 Runge-Kutta法
8.3 MATLAB中微分方程的求解
8.3.1 显性常微分方程
8.3.2 隐式微分方程
8.3.3 微分代数方程的求解
8.3.4 加权常微分方程
8.3.5 延迟微分方程
8.4 常微分方程的仿真
8.5 常微分方程的边界问题
第9章 偏微分方程
9.1 偏微分方程组求解
9.2 偏微分方程的边界求解
9.2.1 边界条件概述
9.2.2 边界条件设置
9.2.3 区域设置及网格化
9.3 二阶偏微分方程
9.3.1 椭圆型偏微分方程
9.3.2 抛物型偏微分方程
9.3.3 双曲型偏微分方程
9.3.4 非线性椭圆型方程
9.3.5 特征值型偏微分方程
9.4 偏微分方程的PDE图形界面
9.4.1 PDE图形界面概述
9.4.2 绘制偏微分方程求解区域
9.4.3 偏微分方程边界条件设置
9.4.4 用图形界面求解偏微分方程
9.4.5 用图形界面求解函数参数的偏微分方程
9.5 偏微分方程的其他函数
9.5.1 图形界面函数
9.5.2 几何处理函数
9.5.3 通用函数
第10章 最优化设置
10.1 优化参数设置
10.1.1 设置优化参数
10.1.2 获取优化参数
10.2 线性规划
10.2.1 MATLAB线性规划函数
10.2.2 线性规则的MATLAB实现
10.3 非线性规划
10.3.1 无约束非线性规划
10.3.2 有约束非线性规划
10.3.3 二次规划问题
10.3.4 最小最大值规划
10.3.5 “半无限”多元函数规划
10.3.6 多目标规划
10.3.7 最小二乘拟合规划
参考文献
图书在版编目(CIP)数据
MATLAB数值分析应用教程 / 周品编著.— 北京:电子工业出版社,2014.11
ISBN 978-7-121-24439-1
Ⅰ.①M… Ⅱ.①周… Ⅲ.①Matlab软件 Ⅳ.①TP317
中国版本图书馆CIP数据核字(2014)第225267号
策划编辑:陈韦凯 特约编辑:蒲玥
责任编辑:陈韦凯
印 刷:
装 订:
出版发行:电子工业出版社
北京市海淀区万寿路173信箱 邮编:100036
开 本:787×1 092 1/16 印张:25.25 字数:647千字
版 次:2014年11月第1版
印 次:2014年11月第1次印刷
印 数:3 000册 定价:59.00元
凡所购买电子工业出版社图书有缺损问题,请向购买书店调换。若书店售缺,请与本社发行部联系,联系及邮购电话:(010)88254888。
质量投诉请发邮件至[email protected] om.cn,盗版侵权举报请发邮件至[email protected]。
服务热线:(010)88258888。
1. 内容简介
本书介绍了MATLAB在数值分析中的应用,内容涉及MATLAB介绍、数值分析的数学基础、数值分析在工程及科研中的应用等问题。全书共分10章,首先介绍了MATLAB软件使用、矩阵与数组、元胞与结构数组等基础内容。接着逐步向读者展示MATLAB在数值分析中的应用,介绍了程序控制与矩阵分析、数据分析、线性与非线性方程组求解、数值微积分、微分方程求解、偏微分方程求解及最优化设置等。
本书可以作为高等学校教材、教辅,也可供广大科研人员、学者、工程技术人员自学或参考。
未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。
版权所有,侵权必究。
2. 前言
MATLAB是矩阵实验室(Matrix Laboratory)的简称,是由美国MathWorks公司发布的主要面对科学计算、可视化及交互式程序设计的高科技计算环境。它以强大的科学计算与可视化功能,简单易用、开放式可扩展环境,特别是所附带的多种面向不同领域的工具箱,使得它在许多科学领域中成为计算机辅助设计和分析、算法研究和应用开发的基本工具及优选平台。因此MATLAB语言被通俗地称为演算纸的科学算法语言。同时MATLAB将数值分析、矩阵计算、科学数据可视化以及非线性动态系统的建模和仿真等诸多强大功能集成在一个易于使用的视窗环境中,为科学研究、工程设计以及必须进行有效数值计算的众多科学领域提供了一种全面的解决方案,并在很大程度上摆脱了传统非交互式程序设计语言(如C、Fortran)的编辑模式,代表了当今国际科学计算软件的先进水平。
数值分析(numerical analysis)是研究分析用计算机求解数学计算问题的数值计算方法及其理论的学科,是数学的一个分支,它以数字计算机求解数学问题的理论和方法为研究对象,是计算数学的主体部分。
随着科学技术的迅猛发展和生产实践的不断丰富,越来越多的数值分析问题亟待人们去解决。而计算机技术的日益丰富和提高,以及人们对计算机软件的深入研究和发展,使得这些问题的解决变得相对容易。因此,一般高等学校的绝大多数理科专业都相继开设了数值分析这门课。数值分析属于计算数学的范畴,是一门与计算机紧密结合的学科,数值分析在数学理论基础上研究各种数学问题的数值解法,主要通过算法设计程序,同时结合分析结果来解决实际问题。
本书以MATLAB软件为基础实现数值分析,具有如下特点:
(1)主要介绍科学及工程中常用的算法,内容新颖、简单,参考性强,方便查阅。
(2)条理清晰,语言通俗易懂,针对性强,内容涵盖范围广。如先介绍MATLAB的计算基础知识,然后由MATLAB带领读者解决数值分析中的问题。
(3)理论与实践相结合。书中对所涉及的概念都进行了介绍,并通过MATLAB自带的函数、自定义编写的函数以例子形式验证相关概念,一步步带领读者领略MATLAB的强大,在挖掘MATLAB丰富宝库的同时打开并进入数值分析的大门。
本书共分10章,下面阐述每章的主要内容。
第1章:MATLAB软件使用基本介绍。主要介绍MATLAB基本功能及特点、MATLAB帮助系统、MATLAB数据类型等。
第2章:矩阵与数组。主要介绍矩阵的创建、矩阵拼接、矩阵的扩展、矩阵元素的寻访等。
第3章:元胞与结构数组。主要介绍元胞数组、结构数组等。
第4章:程序控制与矩阵分析。主要介绍程序控制流、函数类型、矩阵运算、矩阵特征量、矩阵的分解等。
第5章:数据分析。主要介绍数据排序、数据预处理、数据插值、曲线拟合等。
第6章:线性与非线性方程组的求解。主要介绍线性方程组的种类、利用MATLAB内置函数求解线性方程组、利用自定义编写函数求解线性方程组等。
第7章:数值微积分。主要介绍微分、积分、用MATLAB函数实现复合求积公式、积分变换等。
第8章:微分方程。主要介绍符号法求解常微分方程、数值法求解微分方程、MATLAB中微分方程的求解等。
第9章:偏微分方程。主要介绍偏微分方程组求解、偏微分方程的边界求解、二阶偏微分方程、偏微分方程的PDE图形界面等。
第10章:最优化设置。主要介绍优化参数设置、线性规划、非线性规划等。
本书涉及很多数学公式,按照国家标准规定,公式中的变量要用斜体字母表示,其中矩阵、矢量又要用“黑斜体”字母(斜体字母再加粗)表示;而在MATLAB函数及其代码中,变量又只能以正体字母表示。所以本书中的公式变量只能正、斜体并用。
为便于读者演示学习,本书提供主要实例的源代码,读者可登录华信教育资源网(www.hxedu.com.cn)搜索本书所在页面下载。
本书主要由周品编写,此外参加编写的还有张德丰、李晓东、丁伟雄、雷晓平、李娅、杨文茵、何正风、赵新芬、赵书梅、栾颖、刘志为、周灵、赵书兰、余智豪。
本书结构清晰、内容丰富,论述详细得当,适合MATLAB软件刚入门做进一步学习的读者阅读,也可作为广大工程技术人员、科研工作人员、理工科学生的工具用书。
编著者
3. 第1章 MATLAB软件使用基本介绍
MATLAB是矩阵实验室(Matrix Laboratory)的简称,是美国MathWorks公司出品的商业数学软件,用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境,主要包括MATLAB和Simulink两大部分。
3.1 1.1 MATLAB软件概述
MATLAB是由美国MathWorks公司发布的主要面对科学计算、可视化以及交互式程序设计的高科技计算环境。它将数值分析、矩阵计算、科学数据可视化以及非线性动态系统的建模和仿真等诸多强大功能集成在一个易于使用的视窗环境中,为科学研究、工程设计以及必须进行有效数值计算的众多科学领域提供了一种全面的解决方案,并在很大程度上摆脱了传统非交互式程序设计语言(如C、Fortran)的编辑模式,代表了当今国际科学计算软件的先进水平。
MATLAB和Mathematica、Maple并称为三大数学软件。它在数学类科技应用软件中在数值计算方面首屈一指。MATLAB可以进行矩阵运算、绘制函数和数据、实现算法、创建用户界面、连接其他编程语言的程序等,主要应用于工程计算、控制设计、信号处理与通信、图像处理、信号检测、金融建模设计与分析等领域。
3.1.1 1.1.1 MATLAB基本功能
MATLAB具有以下基本功能。
- 友好的工作平台和编程环境
MATLAB由一系列工具箱组成。这些工具箱非常方便用户使用MATLAB函数和文件,其中许多工具箱采用的是图形用户界面。包括MATLAB桌面和命令窗口、历史命令窗口、编辑器和调试器、路径搜索和用于用户浏览帮助、工作空间、文件的浏览器。随着MATLAB的商业化以及软件本身的不断升级,MATLAB的用户界面也越来越精致,更加接近Windows的标准界面,人机交互性更强,操作更简单。且新版本的MATLAB提供了完整的联机查询、帮助系统,极大地方便了用户的使用。简单的编程环境提供了比较完备的调试系统,程序不必经过编译就可以直接运行,而且能够及时地报告出现的错误及进行出错原因分析。
- 简单易用的程序语言
MATLAB为一个高级的矩阵/阵列语言,其包含控制语句、函数、数据结构、输入和输出和面向对象编程特点。用户可以在命令窗口中将输入语句与执行命令同步,也可以先编写好一个较大的复杂的应用程序(M文件)后再一起运行。新版本的MATLAB语言是基于最为流行的C++语言基础上的,因此语法特征与C++语言极为相似,而且更加简单,更加符合科技人员对数学表达式的书写格式。使之更利于非计算机专业的科技人员使用。而且这种语言可移植性好、可拓展性极强,这也是MATLAB能够深入到科学研究及工程计算各个领域的重要原因。
- 强大的科学计算机数据处理能力
MATLAB是一个包含大量计算算法的集合。其拥有600多个工程中要用到的数学运算函数,可以方便地实现用户所需的各种计算功能。函数中所使用的算法都是科研和工程计算中的最新研究成果,而且经过了各种优化和容错处理。在通常情况下,可以用它来代替底层编程语言,如C和C++。在计算要求相同的情况下,使用MATLAB的编程工作量会大大减少。MATLAB的这些函数集包括从最简单最基本的函数到诸如矩阵,特征向量、快速傅里叶变换的复杂函数。函数所能解决的问题大致包括矩阵运算和线性方程组的求解、微分方程及偏微分方程的组的求解、符号运算、傅里叶变换和数据的统计分析、工程中的优化问题、稀疏矩阵运算、复数的各种运算、三角函数和其他初等数学运算、多维数组操作以及建模动态仿真等。
- 出色的图形处理功能
(1)有一系列绘图函数,可方便地输出复杂的二维、三维图形。
(2)高级图形处理。如:色彩控制、句柄图形、动画等。
(3)图形用户界面GUI制作工具,可以制作用户菜单和控件。使用者可以根据自己的需求编写出满意的图形界面。
- 应用广泛的模块集合工具箱
MATLAB对许多专门的领域都开发了功能强大的模块集和工具箱。一般来说,它们都是由特定领域的专家开发的,用户可以直接使用工具箱学习、应用和评估不同的方法而不需要自己编写代码。目前,MATLAB已经把工具箱延伸到了科学研究和工程应用的诸多领域,诸如数据采集、数据库接口、概率统计、样条拟合、优化算法、偏微分方程求解、神经网络、小波分析、信号处理、图像处理、系统辨识、控制系统设计、LMI控制、鲁棒控制、模型预测、模糊逻辑、金融分析、地图工具、非线性控制设计、实时快速原型及半物理仿真、嵌入式系统开发、定点仿真、DSP与通信、电力系统仿真等,都在工具箱(Toolbox)家族中有了自己的一席之地。
- 实用的程序接口和发布平台
新版本的MATLAB可以利用MATLAB编译器和C/C++数学库和图形库,将自己的MATLAB程序自动转换为独立于MATLAB运行的C和C++代码。允许用户编写可以和MATLAB进行交互的C或C++语言程序。另外,MATLAB网页服务程序还容许在Web应用中使用自己的MATLAB数学和图形程序。MATLAB的一个重要特色就是具有一套程序扩展系统和一组称之为工具箱的特殊应用子程序。工具箱是MATLAB函数的子程序库,每一个工具箱都是为某一类学科专业和应用而定制的,主要包括信号处理、控制系统、神经网络、模糊逻辑、小波分析和系统仿真等方面的应用。
- 应用软件开发(包括用户界面)
在开发环境中,使用户更方便地控制多个文件和图形窗口;在编程方面支持了函数嵌套,有条件中断等;在图形化方面,有了更强大的图形标注和处理功能,包括对图形添加标注和对语句进行注释等;在输入输出方面,可以直接向Excel和HDF5进行连接。
- 源程序的开放性
MATLAB语言有丰富的库函数和开放性,在进行复杂的数学运算时可以直接调用,而且用户文件和MATLAB的库函数在形式上是一样的,所以用户文件可以作为MATLAB的库函数来调用。因此,用户可以根据自己的需要,方便地建立新的库函数或扩充原有的库函数,以提高使用MATLAB的效率。
开放性是MATLAB十分受人们喜爱的主要原因之一,除了内部函数以外,所有的MATLAB的核心文件和工具箱文件都是可读可改的源文件,用户可以对源文件进行修改,也可加入用户自己的文件。开放性使得MATLAB成为众多领域的“专家工具”。
为了充分利用FORTRAN、C等语言的资源,包括用户已经编好的FORTRAN、C语言程序,通过建立MEX文件的形式,混合编辑,方便地调用有关FORTRAN、C语言的子程序。在MATLAB中,又增加了C/C++数学库的内容,并且加强了与Excel等应用软件的接口的功能。
- 可以直接处理声言和图形文件
● 声言文件。如:WAV文件(例:wavread,sound等)。
● 图形文件。如:bmp、gif、pcx、tif、jpeg等文件。
- 具有完善的联机帮助功能
(1)提供十分详细的帮助文件(PDF、HTML、demo文件)。
(2)联机查询指令:help指令(例:help elfun,help exp,help simulink),lookfor关键词(例:lookfor fourier)。
3.1.2 1.1.2 MATLAB例子演示
MATLAB的应用范围非常广,包括信号和图像处理、通信、控制系统设计、测试和测量、财务建模和分析以及计算生物学等众多应用领域。附加的工具箱(单独提供的专用MATLAB 函数集)扩展了MATLAB环境,以解决这些应用领域内特定类型的问题。
下面通过介绍MATLAB几个示例让读者对MATLAB有一个概要的认识。
【例1-1】 在命令窗口中输入两个矩阵,进行各个矩阵运算。
1 | >> clear all; |
【例1-2】 利用MATLAB绘制三维切片图。
1 | >>clear all; |
运行程序,效果如图1-1所示。

图1-1 切片图
【例1-3】 对给定的数据进行拟合。
1 | >> clear all; |
运行程序,效果如图1-2所示。

图1-2 数据的拟合效果
【例1-4】 绘制4个首尾相接的圆环。
1 | >> clear all; |
运行程序,效果如图1-3所示。

4个首尾相接的圆环
3.2 1.2 MATLAB帮助系统
作为一种高级语言和一个成熟的工程软件,MATLAB为用户提供了详细完善的帮助系统。养成经常查阅帮助系统的习惯,对于熟练掌握MATLAB的各项强大功能是十分必要的。随着MATLAB版本的不断更新,MATLAB的帮助文档也在不断地改进和完善。在早期的版本中,由于MATLAB的图形用户接口(GUI)还没有出现,所以用户只能在命令窗口中使用help命令和lookfor命令来查看帮助文本,而MATLAB7.0以后版本都提供了以下4种帮助方式:
- 联机帮助系统;
- 命令窗口查询帮助系统;
- 联机演示系统;
- 远程帮助系统。
下面将分别对这4大类的前两类进行详细介绍。
3.2.1 1.2.1 联机帮助系统
MATLAB的联机帮助非常系统、全面,简直就是一本MATLAB的百科全书。进入联机帮助系统的方法有以下4类:
- 单击桌面工具栏中的问号按钮“
”; - 按“F1”键;
- 在主窗口中单击“Help”菜单下的【Demos】、【About MATLAB】、【Using the Desktop】、【Using the Command Window】中的任一选项;
- 在命令窗口中输入“helpwin”、“helpdesk”、“doc”,都可以打开帮助窗口,帮助窗口如图1-4所示。

图1-4 帮助窗口
MATLAB R2011a的帮助窗口与以往MATLAB的帮助窗口都有所不同,以往的MATLAB帮助窗口中有4个标签,分别为【Contents】(帮助主题)、【Search Index】(索引帮助)、【Results】(查寻帮助)、【Demos】(演示帮助)。而在图1-4的MATLAB R2011a的帮助窗口中只有两个标签,分别为【Contents】(帮助主题)、【Search Results】(搜索结果)。
当知道要查寻内容的所属主题或想要学习某个主题的内容时,可以用【Contents】。知道了某个问题的关键词时,多数用【Search Results】,这时一般在文本编辑框“Search”中输入关键词就可以查寻。
用【Contents】获取帮助时,帮助窗口分为左右两个小窗口,单击左边小窗口中的某个主题,就会在右边的小窗口中显示出相应的帮助内容。图1-5所示的就是左边的小窗口中选择【MATLAB】选项下的【Functions】子选项下的【Mathematics】子选项下的【Elementary Math】主题,在右边的小窗口中显示出这一主题下的帮助内容。

图1-5 帮助主题
用【Search Results】获取帮助时,左边是两个小窗口(分别为搜索小窗口和查询结果目录窗口),右边是一个大窗口(显示查询结果窗口)。如在“Search”窗口中输入“sin”函数,回车,即图1-6为用联机帮助查询sin函数效果。

图1-6 sin函数查询结果
1.2 1.2.2 命令帮助系统
熟练的用户可以使用更为快捷的命令窗口查询帮助。这些帮助主要可以分为help系列、lookfor系列与其他常用帮助命令。
- help系列
help系列的帮助命令有help、help+函数(类)名、helpwin及helpdesk。其中后两者是用来调用联机帮助窗口的。下面对help、help+函数(类)名这两个命令作介绍。
1)help
help命令是最常用的命令。在命令窗口中直接输入help命令将会显示当前的帮助系统中所包含的所有项目,以及搜索路径中所有的目录名称,如下所示:
1 | >> help |
2)help+函数(类)名
在实际应用中,这是最有用也最常用的一个帮助命令,可以辅助用户进行深入学习与应用。
【例1-5】 利用help命令查询elmat(类)名的帮助。
1 | >> help elmat |
【例1-6】 利用help命令查询power函数的帮助。
1 | >> help power |
2. lookfor命令
当用户知道某函数名而不知其用法时,help命令可以帮助用户正确地了解此函数的用法。然而,如果想查找一个不知道其确切名称的函数名时,help命令就显得无能为力了。这时就需要lookfor命令出马了。可以用lookfor命令来查询根据用户提供的关键字搜索相关的函数。其调用格式为:
lookfor abc:系统按照已设置的MATLAB路径在所有文件中查找字符串abc。对每个文件首部注释行的第一行所描述的帮助信息进行扫描。若在该行中找到字符串abc,则将其所在的文件名以及所在行显示在屏幕上。
lookfor abc -all:与lookfor abc类似,但查找范围扩大为每个文件首部的第一个注释块。
【例1-7】 利用lookfor命令查询power函数的帮助信息。
1 | >> lookfor power |
3. which命令
which命令用于查找指定函数和文件的目录。其调用格式如下:
which fun:显示指定fun的全部路径和文件名。其中fun可以是工作空间的变量、内置函数、已经加载的Simulink模型或者Java类的方法。
which fun -all:显示所有名为fun的函数路径。
which file.ext:显示指定文件的全路径名称。
which fun1 in fun2:显示在m文件fun2中出现的函数fun1的路径名称。
which fun(a, b, c, …):显示指定的带有输入参数a, b, c,…的函数fun的路径。
s=which(…):把查询结果返回给字符串s,而不是输出到屏幕上。当fun为内置函数时,s的内容为’built-in’。
w=which(…, ‘-all’):返回多项式搜索方法的结果。w是个细胞数组,它包含通常在屏幕上输出的路径字符串。
【例1-8】 利用which命令查询zeros帮助信息。
1 | >> which power |
1.3 1.2.3 联机演示系统
MATLABR2011a的联机演示系统可通过以下3种方式打开:
- 在主窗口的“help”菜单下选择“Demos”选项;
- 在帮助目录窗口选择“Demos”表单;
- 在命令窗口输入“demo”命令。
打开后的联机演示窗口如图1-7所示。

图1-7 联机演示窗口
在联机演示窗口的左边是帮助向导页面Demos表单窗口,在左边选择所需表单时,右边显示表单相应的例子。单击图1-7中右上角的“Product page at mathworks.com”跳转按钮,即链接到MATLAB在线网站,对MATLAB进行相关介绍。
单击图1-7中的“Getting Started with MATLAB(5min, 18 sec)”按钮,跳转到如图1-8所示的界面。

图1-8 Getting Started with MATLAB(5min, 18 sec)界面
单击图1-8中右上角的“Run this demo”按钮,可弹出在线视频讲解及演示该例子。
1.4 1.2.4 远程帮助系统
MATLAB R2011a的远程帮助系统由网络资源(Wb Resources)和更新检查(Check for Updates)两部分组成,可通过主窗口中的“Help”菜单选择打开这两个选项。“Wb Resources”中只要用户选择某一项链接就可以直接链接到相应的网站或网页。更新检查选项用来进行MATLAB各组件的更新检查和更新。当用户的计算机联网并选择了该项后,稍后(与计算机配置和网络速度有关)帮助系统会弹出如图1-9所示的对话框,即系统经过远程查询以后告诉用户目前各组件的安装版本是不是最新版本,如果是,则显示“Up to date”;如果不是,则显示当前的最新版本号。如果没有找到该组件,则显示“Not found‘。

图1-9 更新检查对话框
2. 1.3 常量与变量
2.1 1.3.1 常量
常量,在MATLAB中习惯称之为特殊变量,即系统自定义的变量,它们在MATLAB启动以后驻留在内存里面。在MATLAB R2011a中常用的特殊变量如表1-1所示。
表1-1 MATLAB常用特殊变量表

在MATLAB的命令窗口中输入一个表达式或一组数据,系统将会自动把计算结果赋值给ans变量。
【例1-9】 在命令窗口中计算tan(2*pi)。
1 | >> pi |
2.2 1.3.2 变量
变量,即为一个值(数值,字符串,数值)指定的名称。当一个值存在于内存时,不可能直接从内存中访问该值,只能通过其名称来访问其的值。
变量,是要变化的,在程序运行中它的值可能会改变。
MATLAB不需要事先声明变量,也不需要任何维数语句声明数组。当MATLAB遇到一个新变量名时,自动建立变量并分配适当的存储空间。
MATLAB变量名必须以字符开头,是字母和数字的任意组合,允许使用下划线。除此之外,命名变量还应遵循以下规则:
- 理论上,变量名可任意长度,但只使用前面的63个字符;
- 不能使用函数名和系统保留字;
- 不能用i与j,这两个字符是MATLAB复数专用的;
- 大小写字符是不同的。
为了避免使用不同合法的变量名,在MATLAB中提供了isvarname函数用于验证函数名。其调用格式为:
1 | tf = isvarname('str') |
【例1-10】 利用isvarname函数验证各函数名是否正确。
1 | >> isvarname foo |
3. 1.4 MATLAB数据类型
MATLAB的数值计算是以数组为基本单元的,而MATLAB数据类型的最大特点是每一种类型都以数组为基础。事实上,MATLAB也是把每种类型的数据作为数组来处理。
数据类型是掌握任何一门编程语言都必须首先了解的内容。MATLABR2011a的数据类型主要有:逻辑、数值、字符串、矩阵、元胞、Java、函数句柄、稀疏以及结构等类型。
3.1 1.4.1 数值型
数值型又分为单精度型、双精度型以及整数型。而整数类型里又分为无符号型(uint8、uint16、uint32、uint64)和符号类型(int8、int16、int32、int64)两种。
- 整数类型
有符号整数和无符号整数的不同在于前者必须有一位来表示符号位,而后者则不需要。因此,有符号整数不仅可以表示正整数和零,还可以表示负整数,而无符号整数却只能表示正整数和零。表1-2列出了各种整数类型的名称及其表示的数据范围以及相应的转换函数。对于一个整数,MATLAB支持多种整数存储方式,这与各种整数类型的存储范围有关。以整数100为例,其可以用整数类型中的任何一种类型存储,但用户可以根据需要,选择最适合的存储类型int8,即单字节无符号整数类型存储。这样选择的好处是可以尽量节省内存空间,以便提高程序调用和运算速度。
表1-2 MATLAB中的整数类型

不同的整数类型所占用的位数不同,因此所能表示的数值范围不同,在实际应用中,应该根据需要的数据范围选择合适的整数类型。有符号的整数类型拿出一位用来表示正负,因此表示的数值范围和相应的无符号整数类型不同。
由于MATLAB中数值的默认存储类型是双精度浮点类型,因此,必须通过表1-2中列出的转换函数将双精度浮点数值转换成指定的整数类型。在转换过程中,MATLAB默认将待转换数值转换为最接近的整数,如果小数部分正好为0.5,那么MATLAB转换后的结果是绝对值较大的那个整数。另外,应用这些转换函数也可以将其他类型转换成指定的整数类型。
【例1-11】 通过转换函数创建整数类型。
1 | >> clear all; %清除MATLAB原空间变量 |
MATLAB中还有多种取整函数,可以用不同的策略把浮点小数转换成整数,如表1-3所列。
表1-3 MATLAB中的取整函数

整数类型参与的数学运算与MATLAB中默认的双精度浮点运算不同。当两种相同的整数类型进行运算时,结果仍然是这种整数类型;当一个整数类型数值与一个双精度浮点类型数值进行数学运算时,计算结果是这种整数类型,取整采用默认的四舍五入(round)方式。需要注意的是,两种不同的整数类型之间不能进行数学运算,除非提前进行强制转换。
【例1-12】 数据的取整。
1 | >> clear all; |
- 浮点数类型
MATLAB中提供了单精度浮点数类型和双精度浮点数类型,它们在存储位宽、各数据位的用处、表示的数值范围、数值精度等方面都不相同,如表1-4所列。
表1-4 MATLAB的单精度浮点数和双精度浮点数的比较

从表1-4可看出,存储单精度浮点类型所用的位数较少,因此内存占用上开支小,但从各数据位的用处来看,单精度浮点数能够表示的数值范围和数值精度都比双精度小。
MATLAB中默认的数据类型为双精度浮点类型。
【例1-13】 浮点数据转换函数演示。
1 | >> clear all; |
为双精度浮点数参与运算时,返回值的类型依赖于参与运算中的其他数据类型。
双精度浮点数与逻辑型、字符型进行运算时,返回结果为双精度浮点类型;而与整数型进行运算时返回的结果为相应的整数类型,与单精度浮点型运算返回单精度浮点型。
单精度浮点型与逻辑型、字符型和任何浮点型进行运算时,返回结果都是单精度浮点型。需要注意的是,单精度浮点型不能和整数型进行算术运算。
【例1-14】 浮点型参与的运算。
1 | >> clear all; |
- 复数
MATLAB中,复数由独立的两部分:实部和虚部组成,其基本形式为a+bi,其中i为虚数符号,是-1的算术平方根,由于表示习惯的不同也可以用j来表示虚数符号。
【例1-15】 创建复数。
1 | >> a=pi+5i |
由以上结果可知:
(1)虚数符号i和j在MATLAB中代表相同的意义。
(2)复数虚部的表示既可以是5i,也可以是5*i。
(3)单个复数间的比较是对应项之间进行比较,即实部与实部比较,虚部与虚部比较。如果是复数构成的矩阵间的比较,则是对应元素的对应项的比较。
(4)用“==”比较两个复数时,其返回值为0或1,当返回值为1时,表示真,即两个复数相等;当返回值为0时,则两个复数不等。
在MATLAB中,还有多种对复数操作的函数,如表1-5所列。
表1-5 MATLAB中复数相关操作函数

【例1-16】 复数的操作函数。
1 | >> x=rand(3) |
- 无穷量与非数
MATLAB中用Inf和-Inf分别代表正无穷和负无穷,用NaN表示非数值的值。正负无穷的产生一般是由于0做了分母或者运算溢出,产生了超出双精度浮点数数值范围的结果;非数值量则是因为0/0或者Inf/Inf型的非正常运算。需要注意的是,两个NaN彼此是不相等的。
除了运算造成这些异常结果外,MATLAB也提供了专门函数可以创建这两种特别的量,读者可以用Inf函数和NaN函数创建指定数值类型的无穷量和非数值量,默认是双精度浮点类型。
【例1-17】 无穷量和非数值量。
1 | >> x=1/0 |
3.2 1.4.2 逻辑类型
MATLAB中逻辑数据类型用“0”和“1”分别代表逻辑“假”和“真”状态。在MATLAB中存在一些函数和符号,如表1-6所列,通过返回逻辑“真”或逻辑“假”作为某种条件可否执行的判断依据,例如:
1 | >> clear all; |
运行程序,输出如下:
1 | ans = |
表1-6 MATLAB的常用逻辑类型

逻辑类型数据常以标量形式出现,但有时也可以是逻辑数组(Logical Array)。采用true和false可以直接创建逻辑向量,只需将向量的每一个元素置为true或false即可,true和false分别代表逻辑真和逻辑假。
【例1-18】 创建逻辑类型。
1 | >> clear |
3.3 1.4.3 字符与字符串
使用MATLAB进行工作和学习时,用户不可避免会遇到诸如文本处理、字符显示等。字符串是以向量的形式来存储的,其每个元素中存放的是字符的内部代码(ASCII码),当在屏幕上显示字符变量的值时,将显示文本,而不是ASCII数字,故用户可以对显示的字符进行直接操作。
在MATLAB中,字符和字符串分别用char和string表示,MATLAB中的char类型都是以2个字节的Unicode统一字符编码来存储的,一般用单引号括注一个字符变量,如下代码所示:
1 | >> a='v' |
在MATLAB中,对于每个字符,系统都有其对应的ASCII数值。一般情况下,用户可以不用关心此数值,而直接针对显示的字符进行操作。如果用户需要获得此数值,可以调用abs函数,例如,对于字符’b’,调用abs指令,得到其对应底层ASCII数值为96;而字符’B’对应的数值则为66,如下代码所示。如需查询ASCII数值对应的字符类型数据,则可以调用char函数。
1 | >> abs('b') |
字符串是1×n的字符类型数组,是单引号括注的一系列字符的组合,每个字符都是该字符串的一个元素,如果字符串本身包含单引号,需要双写此单引号,否则会产生错误,如下代码所示:
1 | >> a='this is a string containing''A''' %字符串本身为this is a string |
- 创建字符数组
在MATLAB中,用户可以运用两种不同的方式表示字符串,即字符数组和字符串元胞,有关字符串元胞的概念将在下面章节介绍。在此主要介绍用字符数组的方式创建字符串的方法。例如,以字符数组的形式创建一个字符串:
1 | >> a='the MATLAB is...' |
说明:
(1)字符串可以包含标点符号。
(2)建立二维字符数组时,字符数组要求每行字符含有相同的列。当多个字符串具有相同长度时,为了避免出现错误,用户需要在短字符串的尾部添加空格来强制保证字符串等长。
【例1-19】 将短字符串合并成长字符串。
1 | >> %在'abc'和'abcd'的末尾分别补2个和1个空格 |
- 字符串比较
MATLAB中,如果需要进行字符串或字符串的比较,可以有以下几种方法:
- 直接比较两字符串的全部或者部分是否相等;
- 比较字符串中的单个字符是否相等;
- 对字符串中的每个元素进行识别,判断其是字符或是空白符号。
【例1-20】 判断两个字符数组中的每个元素是否相同。
1 | >> str1='Matlab' |
除了使用关系运算符比较这种方式外,还有一种功能更加强大,使用更为广泛的就是使用函数来比较,常用的比较函数如表1-7所列。
表1-7 常用字符数组比较函数

【例1-21】 使用函数比较字符数组。
1 | >> strcmp('human','HUMAN') |
- 字符串查找与替换
MATLAB中提供了若干字符串查找与替换的函数,其名称与功能描述如表1-8所列。
表1-8 字符串查找与替换函数

【例1-22】 字符串查找与替换演示。
1 | >> s = 'Find the starting indices of the shorter string.'; |
- 字符串与数值类型的相互转换
在前面例子中,提到了字符类型与数值类型相互转换的函数char和abs,事实上,MATLAB还提供了很多两种数据类型之间的转换函数,具体如表1-9与表1-10所列。
表1-9 数值类型转换到字符串

表1-10 字符串转换到数值类型

【例1-23】 将数值类型转换为字符串类型演示例子。
1 | >> int2str(eye(3)) |
【例1-24】 字符串转换为数值类型示例演示。
1 | >> s = 'Find the starting indices of the shorter string.'; |
下面将通过求曲线长度的例子来体会在MATLAB中如何使得复杂的求解数学积分问题过程变得简单、明了、快捷,也直观地感受一下MATLAB数值计算功能的强大。
【例1-25】 求曲线长度。
曲线参数方程为
根据曲线长度求法,可列出求该曲线长度的表达式为

其实现的MATLAB代码为:
1 | >> clear all; |
编写li1_25a.m文件来实现求曲线长度:
1 | function f=li1_25(t) |
由以上结果可知,所示曲线的长度为17.2220,曲线图形如图1-10所示。

图1-10 所求曲线的图形
第2章 矩阵与数组
矩阵是MATLAB中数据存储的最佳形式,尽管MATLAB还可以采用其他的存储方式,但采用矩阵的方式有利于各类数据的运算和操作。作为MATLAB的基本数据结构,从形式上看,矩阵是一个二维的数组,构成矩阵的元素可以是数值,也可以是非数值的元素。通过矩阵可以方便地存储和访问MATLAB中的其他数据类型。
2.1 矩阵的创建
在MATLAB中,创建矩阵最常用的方法有两种:一种是直接录入矩阵元素,另一种是调用函数生成。
2.1.1 直接方式创建矩阵
对于简单的矩阵,特别是元素数目不多的矩阵,逐个输入矩阵元素是最常用、最便捷的矩阵创建方法,其遵循以下3条原则:
- 运用矩阵构造符[]包含所创建矩阵的所有元素;
- 使用逗号“,”或者空格“”分隔矩阵的列;
- 使用分号“;”或者回车键分隔矩阵的行。
【例2-1】 创建一个5×4的矩阵A。
1 | >> A=[1 7 8 9 0;3 7 11 15 169; |
除了以上逐个元素输入矩阵外,还可用冒号生成矩阵,其调用格式为:
x=a:i:b
其中,a表示该行的第一个元素,i表示相邻元素之间的间隔,假设x(n)和x(n-1)分别表示生成该行的第n个和第n-1个元素,则i=x(n)-x(n-1)。如果(b-a)是i的整数倍,则生成该行的最后一个元素等于b,否则小于b。i可以省略,默认状态下为1。例如:
1 | >> B=1:1:10 |
注意: 矩阵中的元素必须是数字或者值已经确定的变量或表达式,如果输入的矩阵元素包含系统未知量,系统将报错,如:
1 | >> A=[2,b+a*i,3-b+2i;sqrt(a),sin(pi/4),a+4*b] |
如果在没有定义a、b的情况下,直接输入上面的代码,将产生错误提示。
2.1.2 创建特殊矩阵
在MATLAB中还提供了一些特殊矩阵的生成函数,如全1矩阵、全0矩阵、单位矩阵等,常用的特殊矩阵如表2-1所列。
表2-1 特殊矩阵生成函数

下面对diag及magic函数用法作介绍,其他函数的用法和功能,读者可参考MATLAB帮助文档。
- diag函数
diag函数用于创建对角矩阵与矩阵的对角线。其调用格式如下。
X = diag(v,k):v为n个元素的向量,k表示对角线的位置。
diag函数利用n个元素的向量v生成一个对角矩阵X。矩阵的阶数等于n+abs(k),v的元素排列在k表示的对角线上。k=0,表示主对角线;k>0,表示对角线在主对角线的右上方;k<0,表示对角线在主对角线的左下方,如图2-1所示。

图2-1 v的元素排列
X = diag(v):diag函数将v的元素摆在主对角线,使用k的默认值(k=0)。
v = diag(X,k):diag函数用X矩阵的第k条对角线的元素生成一个列向量v。
v = diag(X):diag函数用X矩阵的主对角线的元素生成一个列向量v。
- magic函数
该函数用于创建魔方矩阵。其调用格式为:
M = magic(n)
magic函数从整数1到n^2构造一个n×n的矩阵,矩阵中行与列的元素之和都相等,序数n必须是一个大于等于3的标量。
序数3的魔方矩阵为:
1 | >> magic(3) |
魔方矩阵不仅行与列的元素和相等,而且对角线的元素和与行列的元素和也相等。
对于序数n的魔方,求其特殊的行与列元素和的公式为:
sum(1:n^2)/n
● 当n=3时,和为15。
● 当n=4时,和为34。
……
如果给出的n小于3,那么,magic函数或者返回非魔方,或者返回1,或者返回[]。
下面通过示例来演示部分函数的使用。
【例2-2】 创建特殊矩阵。
1 | >> zeros(4,5) %生成4×5阶全0矩阵 |
【例2-3】 利用magic函数创建魔方矩阵,绘制其相应图形。
1 | >> clear all; |
当n=18时,以上代码绘制魔方效果如图2-2(a)所示,当n=19时,绘制魔方效果如图2-2(b)所示,当n=20时,绘制魔方效果如图2-2(c)所示。

图2-2 magic函数绘制魔方图
2.2 矩阵拼接
矩阵的拼接是指两个或两个以上的单个矩阵,按一定的方向进行连接,生成新的矩阵。从本质上说,矩阵的拼接就是一种创建矩阵的特殊方法,区别在于基础元素是原始矩阵,目标是新的合并矩阵。
2.2.1 基本拼接
一般来说,矩阵的拼接包括水平方向拼接和垂直方向拼接。以两个矩阵为例,假设有矩阵A与B,其连接表达分别为:
- 水平方向连接:C=[A B]或C=[A,B]。
- 垂直方向连接:C=[A;B]。
【例2-4】 方阵的连接。
1 | >> A=magic(3) %创建3阶魔方矩阵 |
【例2-5】 一般矩阵的连接。
1 | >> A=[1 2;10 5;9 17] %采用一般输入法创建3×2阶矩阵 |
注意: 由以上运行结果可见,矩阵连接不成功,原因是矩阵水平方向连接时,两矩阵的行数不匹配,即行数不同;而在垂直方向连接时,列数不匹配。矩阵连接要求在连接方向上有相同的行(列)数。
2.2.2 拼接函数
除了使用矩阵拼接符[],还可以使用MATLAB提供的矩阵拼接函数执行,具体的函数与功能如表2-2所列。
表2-2 矩阵拼接函数

- cat函数
该函数用于指定维拼接矩阵。其调用格式如下。
C = cat(dim, A, B):dim指定连接方向。dim的可选值有:
- 当dim=1时,即垂直方向拼接矩阵;
- 当dim=2时,即水平方向拼接矩阵;
- 当dim=3时,即生成三维数组。
cat函数依dim指定的方向拼接矩阵A与B,构造出矩阵C。
C = cat(dim, A1, A2, A3, A4, …):依dim指定的方向拼接的多个矩阵A1, A2, A3, A4, …,形成新矩阵C。
【例2-6】 利用cat函数拼接矩阵。
1 | >> A = magic(3), B = pascal(3), %创建魔方矩阵A,与Pascal矩阵B |
- horzcat函数
该函数用于水平拼接矩阵。其调用格式如下。
C = horzcat(A1, A2, …):水平拼接多个矩阵A1、A2等,参数列表中的所有矩阵都必须有相同的行数。
horzcat函数拼接n维数组是沿二维(即行)的方向,因此,被连接数组的第一维和其他维的大小必须匹配。
【例2-7】 利用horzcat函数拼接矩阵。
1 | >> A = magic(5); % 创建5阶魔方矩阵 |
- vertcat函数
该函数用于垂直方向拼接矩阵。其调用格式如下。
C = vertcat(A1, A2, …):垂直拼接多个矩阵A1、A2等,参数列表中的所有矩阵都必须有相同的列数。
vertcat函数拼接n维数组是沿第一维(即列)的方向,因此,被拼接数组的其他维的大小必须匹配。
在MATLAB中使用C=[A1;A2;…]垂直连接矩阵时,实际上就是调用C = vertcat(A1, A2, …)拼接矩阵。
【例2-8】 利用vertcat函数对创建的矩阵A与B进行水平拼接。
1 | >> A = magic(5); %创建5阶魔方矩阵 |
- repmat函数
该函数用于对现有的矩阵复制和粘贴拼接一个新矩阵。其调用格式如下。
B = repmat(A,m,n)或B = repmat(A,[m n]):建立一个大矩阵B,B是由矩阵A的复制拼接而成,纵向摆m个复制,横向摆n个复制,B中总共包含m×n个A。
B = repmat(A,[m n p…]):生成一个多维(m×n×p×…)数组B,B由矩阵A的m×n×p×…个复制在多个方向拼接而成。
在repmat(A,m,n)格式中,当A为标量时,生成一个m×n矩阵,矩阵由指定数据类型的A值组成。对于某些值,使用其他函数也可以获得同样的结果。下面是某些值用不同函数得到同样的结果代码:
- repmat(NaN,m,n) 与NaN(m,n);
- repmat(single(inf),m,n) 与inf(m,n,’single’);
- repmat(int8(0),m,n) 与zeros(m,n,’int8’);
- repmat(uint32(1),m,n)与ones(m,n,’uint32’);
- repmat(eps,m,n) 与eps(ones(m,n))。
【例2-9】 利用repmat函数对现有矩阵拼接一个新矩阵。
1 | >> uint=[1,0;0,1] %现有矩阵 |
- blkdiag函数
该函数用于以对角阵的方式重组矩阵。其调用格式如下。
out = blkdiag(a,b,c,d,…):用输入的矩阵a,b,c,d,…构造一个块对角矩阵out,形如

输入矩阵不一定为方阵,而且a、b、c、d等也不必有相同的大小。
【例2-10】 利用blkdiag函数以对角阵的方式重组矩阵。

2.3 矩阵的扩展
矩阵的尺寸又称矩阵的大小。在MATLAB中,用户可以方便地对矩阵的尺寸进行扩大和缩小,扩大矩阵的主要方式是拼接和添加元素,缩小矩阵的方式是删除矩阵中的某行或某列元素。
2.3.1 扩展矩阵
在MATLAB中,用户可以通过两种方式扩展矩阵的尺寸,一是进行矩阵拼接,二是在矩阵的尺寸之外添加元素。
【例2-11】 在矩阵尺寸之外增加一个或多个元素,改变原矩阵的大小。
1 | >> A=rand(3) %创建3阶随机矩阵 |
注意: 在例子中是通过对现有矩阵的赋值操作而创建新的矩阵,如果对超出现有矩阵行列的某个位置或某行(列)进行赋值,那么创建的新矩阵的阶数将扩展到相应的行列。
2.3.2 缩小矩阵
要减小矩阵的尺寸,只需删除矩阵的某行或某列就可以了。用户只需将要删除的行或列赋值为[]。
【例2-12】 缩小矩阵的尺寸例子演示。
1 | >> A=[1 5 7 9 11;3 88 1 0 12;88 10 13 7 14] %创建3×5阶矩阵 |
注意: 使用双坐标下标时,不可以使用此方法删除单个元素,否则系统会出错;在线性下标下,可以用此方法删除单个或多个元素,得到矩阵的剩余元素排列成为行向量。如。
1 | >> A(2,3)=[] |
2.4 改变矩阵的形状
改变已有矩阵的大小和形状是非常容易的,还可以绕不同的轴旋转它。
2.4.1 重塑矩阵形状
在MATLAB中,除了用来改变矩阵大小的函数外,还提供了一些改变矩阵形状的函数,这些函数只是改变矩阵内元素的排列状态,而并不增减矩阵元素的个数。在表2-3列出了常用改变矩阵形状的函数。
表2-3 改变矩阵形状的函数

下面分别介绍这些函数的用法。
- reshape函数
该函数用于按指定的行列数重新排列矩阵。其调用格式如下。
B = reshape(A,m,n):reshape函数从老矩阵A中以列方式取数据,重新构成一个m×n的矩阵B。如果A的元素不足m×n个,将产生错误。
B = reshape(A,m,n,p,…)或B = reshape(A,[m n p …]):reshape函数以数组A的元素为基础,重新生成一个m×n×p×…的数组B,A和B的元素数应该相等,也就是m×n×p×…的积必须等于prod(size(A))。
B = reshape(A,…,[],…):计算占位符[]所表示的那一维的长度,这样,生成的数组B各维的乘积等于prod(size(A))(新老数组的元素相等)。prod(size(A))的值必须能被已经指定的维数的乘积m×n×p×…整除。输入参数中只能有一个[]。
B = reshape(A,siz):利用数组A的元素重新生成一个n维数组B,n由向量siz指定。prod(siz)必须等于prod(size(A))。
【例2-13】 将6阶魔方矩阵重塑为二维和三维数组。
1 | >> A=magic(6) %创建一个6阶魔方阵 |
- rot90函数
该函数用于逆时针旋转矩阵90°。其调用格式如下。
B = rot90(A):逆时针旋转矩阵90°,形成矩阵B。
B = rot90(A,k):逆时针旋转矩阵k×90°,形成矩阵B。
【例2-14】 对创建的矩阵实现逆时针旋转。
1 | >> A=[3 9 7 8;0 11 78 1;6 45 2 18] |
- fliplr函数
该函数用于对矩阵进行左右翻转。其调用格式如下。
B = fliplr(A):如果A为行向量,翻转A将得到一个与A同样长度但元素顺序相反的行向量;如果A为列向量,可想而知,再翻转也是它自己。
fliplr函数的应用是有限制的,被操作的数组不能大于二维。因为数组是沿着一个轴翻转的,多维数组不能定义这个轴。
- flipud函数
该函数用于对矩阵进行上下翻转。其调用格式如下。
B = flipud(A):如果A为一个列向量,翻转的结果为与A一样长但元素的顺序相反的列向量;如果A为行向量,翻转的结果仍为它自己。
使用这个函数的限制也是数组不能大于二维。
- flipdim函数
该函数用于按指定的维对矩阵进行翻转。其调用格式如下。
B = flipdim(A,dim):按指定的dim维对矩阵A进行翻转,生成矩阵B。dim的取值为:
- 当dim=1时,数组上下翻转,相当于函数flipud(A);
- 当dim=2时,数组左右翻转,相当于函数fliplr(A)。
【例2-15】 对已创建的矩阵实行翻转处理。
1 | >> A=[8 9 11;7 3 5] |
2.4.2 预分配内存
有时候,使用者会反复地增加数组的元素,这种扩展数组的方法对程序的性能有不利的影响。因为每次增大数组,MATLAB都要耗费分配内存的时间。而且,多次分配的内存可能是不连续的,这样就会延续对数组执行的必要操作。那么,怎样避免这种弊病,既要使用足够大的数组,又不降低程序的性能呢?
最好的方法是,估算被操作数组可能的最大空间,在建立它的时候,为它预先分配估算的量。如此,不仅内存足够大,而且整个内存是连续的块。
预分配内存通常采用的方法是,使用zeros函数,这样既可以得到足够大的数组,又把每个元素初始化为0。例如:
1 | A=zeros(25000,10000); |
一旦为一个估算好大小的数组预分配了内存,就可以写数据到数组了。
【例2-16】 为一个大数组预分配内存,然后从文件读数据到这个数组,直到文件结束。
1 | blocksize=5000; |
尽管为数组预分配了大内存,但有可能还不够。这时,可以为另一个数组预分配足够的内存,将它连接到原来的数组中。
2.5 向量、标量与空矩阵
MATLAB中的矩阵多维数是以矩形(m×n)的形式显示,但有时常出现特殊形式的矩阵,即由于m和n的取值特殊,矩阵常常表现出非矩形的特征。
2.5.1 向量
向量是行数或列数为1的特殊矩阵,其一般显示为1×n或n×1的数列。生成一维向量的一般调用格式为:
x=(a:n:b)
其中,a表示向量的起始值,b表示向量将要终止的值,n为该向量数列的公差,即向量中某一数与其前一个数的差值。
【例2-17】 向量的生成示例演示。
1 | %生成递增的等差向量。 |
注意:
(1)公差n可以省略,在默认情况下,公差为1。
(2)在生成向量时,从起始值a开始,以公差n依次进行递增,直到生成向量的最后一个值等于终止值或与终止值最为接近为止。
(3)如果n大于零,一般来说要求a小于b。否则,将生成一个空矩阵。
1 | %生成递减等差向量 |
生成向量除了以上介绍的这种常用调用格式外,MATLAB还提供了一些函数,下面分别给予介绍。
- linspace函数
该函数用于作线性行向量生成函数,产生指定长度的等差数列。其调用格式如下。
y = linspace(a,b):生成一个首尾分别为a和b的100个数(包含a、b)的行向量。
y = linspace(a,b,n):生成一个首尾分别为a和b的n个数(包含a、b)的行向量。
【例2-18】 利用linspace函数,生成一个首尾分别为1和36,包含12个数的等差数列。
1 | >> A = linspace(1,36,12) |
- logspace函数
该函数用于以对数等差数列生成函数,产生指定长度的对数等距数列。其调用格式如下。
y = logspace(a,b):在[10a,10b]区间生成50个差值相等的数,并返回50个数以10为底的幂组成的行向量。
y = logspace(a,b,n):在[10a,10b]区间生成n个差值相等的数,并返回n个数以10为底的幂组成的行向量。
y = logspace(a,pi):在[10^a,pi]区间生成50个差值相等的数,并返回50个数以10为底的幂组成的行向量,常用于数字信号处理。
【例2-19】 调用logspace函数,产生指定长度的对数等距数列。
1 | %在区间[10^2,10^3]生成50个差值相等的数,并返回50个数以10为底的幂组成的行向量 |
2.5.2 标量
标量是行列数都为1的特殊矩阵,任意以1×1的矩阵形式表示的单个实数或复数,称之为标量。如下的实数A即为一个标量。
1 | >> A=6 |
从以上代码可以看出,实数6的维数为2,即行和列;且各维数值都为1。在MATLAB中,单个的数字也可以理解为矩阵的一种。
1 | >> A=6; |
2.5.3 空矩阵
MATLAB中为了表示和操作的方便,引入了“空矩阵”的概念,其含义是至少一维的数值为0的矩阵。空矩阵可以是0×0、0×n和n×0(0为正整数)。空矩阵不是全0矩阵。如:
1 | >> A=[] |
从上代码可看出,空矩阵是确实存在的,而并非虚幻不存在,中括号中没有任何数值或只有空格符,并不表示矩阵是没有意义的。如果需要建立一个0×6的随机空矩阵B,其代码为:
1 | >> B=rand(0,6) |
如果用户给矩阵(包括向量和标量)添加一个空矩阵,不会给原矩阵的值产生影响,如下代码所示:
1 | >> A=magic(3) %一般矩阵 |
需要注意的是,空矩阵和0矩阵不是同一个概念,前者是没有元素,而后者是其元素为0的矩阵。如:
1 | >> A=[] %空矩阵 |
注意: 以上代码不适合使用关系运算符“==”来进行两者的比较,因为涉及空矩阵的所有关系运算都返回空矩阵的结果。
对于空矩阵的操作,基本遵循一般矩阵的规则。例如,对于两个矩阵的拼接,如果对两个m×n和p×n的矩阵进行垂直方向的拼接,结果应该生成(m+p)×n的矩阵,假设,m、n和p有任意一个值为0,即两个矩阵有一个为空矩阵(m或p为0),或皆为空矩阵(n为0),结果依然正确,新矩阵也为空矩阵,如:
1 | >> A=ones(3,0) |
注意: 两个空矩阵拼接结果仍为空矩阵;而一个非空矩阵与一个空矩阵拼接,结果为非空矩阵本身。
2.6 寻访矩阵元素
矩阵作为存储各数据的基本单位,是若干相关元素的有序集合,为方便用户访问矩阵中的一个或多个元素,MATLAB引入了元素下标的概念。利用这些下标用户可以方便地访问矩阵中任何元素,对其进行提取或者赋值等操作。
2.6.1 寻访双下标
在数学习惯中,常用“双下标”的形式来表示矩阵中的某个元素,如在矩阵m中第3行、第2列的元素表示为m32 。MATLAB中,同样采用双下标(Row-Column Index)的方式来寻访矩阵中的元素,矩阵中的元素由其行列数唯一确定,如,同样是矩阵m中第3行、第2列元素,在MATLAB中有与数学习惯相似的表示方式,即m(3,2)。MATLAB中矩阵元素的这种双下标表示方式,可以方便地访问一个矩阵中的单个元素。需要注意的是,有两个参数必不可少,即其所在行数和列数。
【例2-20】 采用双下标访问矩阵单个元素。
1 | >> A=randn(4,3) %利用函数生成4×3的矩阵 |
2.6.2 寻访单下标
矩阵中元素除了双下标表示外,MATLAB中还提供了一种线性下标(Linear Index)表示方法,又称“单下标”表示法,即将矩阵中元素按照一定的线性规则有序排列,给矩阵中的每个元素一个固定的序号,用户只需知道所要寻访的序号就可以方便地访问矩阵中的元素。使用线性下标时,系统默认矩阵的所有元素按照列从上到下,行从左到右排列。
以一个m×n的二维矩阵A为例,双下标表示的x位置为A(p,q),即“第p行,第q列”,那么元素x对应的线性坐标表示的单下标为u,且u=(q-1)×m+p。
【例2-21】 对创建的矩阵实现单下标寻访。
1 | >> A=rand(3,4) |
当矩阵很大时,利用以上单双下标计算显得比较烦琐,事实上,在MATLAB中还提供了双下标和单下标的转换函数sub2ind和ind2sub函数,下面分别对这两个函数给予介绍。
- sub2ind函数
该函数用双下标计算出单下标。其调用格式如下。
linearInd = sub2ind(matrixSize, rowSub, colSub):参量linearInd为矩阵元素的线性下标;matrixSize表示矩阵的大小,用两个元素的向量表示。
- rowSub,矩阵元素二维索引的行下标。
- colSub,矩阵元素二维索引的列下标。
linearInd = sub2ind(arraySize, dim1Sub, dim2Sub, dim3Sub, …):将大小为arraySize的数组元素的n维下标dim1Sub, dim2Sub, dim3Sub, …转换成元素的线性下标linearInd。
【例2-22】 对建立的数组A,取某个元素的值,再将此元素的三维下标转换为线性下标。
1 | >> rand('state', 0); %设置矩阵的初始状态为0 |
- ind2sub函数
该函数用于单下标计算出双下标。其调用格式如下。
[I,J] = ind2sub(siz,IND):把大小为siz的矩阵元素的线性索引IND,转换成元素的二维下标I和J。siz为两个元素的向量。
[I1,I2,I3,…,In] = ind2sub(siz,IND):把大小为siz的数组元素的线性索引IND,转换成元素的n维下标I1,I2,I3,…,In。siz为n个元素的向量,指定数组每维的大小。
【例2-23】 2×2×2的数组A,由线性索引求出4个元素的三维索引。图2-3是数组的线性索引映射到三维索引的示意图。

图2-3 数组的线性索引映射到三维索引的示意图
1 | >> IND = [3 4;5 6]; |
2.6.3 寻访多个元素
在MATLAB中仅仅对单个元素操作是不够的,往往需要对矩阵中整行、整列元素进行操作,或者需要针对矩阵的部分元素操作,这时就需要实现对多个元素的寻访操作。在MATLAB表2-4中列出了寻访矩阵中多个元素的常用调用格式。
表2-4 寻访多个元素调用格式

【例2-24】 矩阵多元素访问。
1 | >> A=hilb(4) |
2.7 获取矩阵信息
对已经建立的矩阵,使用者不一定知道它们的模样。怎样获取它们的有关信息?主要使用MATLAB函数。
2.7.1 获取矩阵的维数
在MATLAB中提供了若干函数用于获取已建立矩阵的维数。下面分别给予介绍。
- length函数
该函数用于返回矩阵最长的那一维的长度。其调用格式如下。
numberOfElements = length(array):返回矩阵array的最长维的大小给numberOfElements。如果array为一个向量,则大小等于向量的长度。
- ndims函数
该函数用于返回矩阵的维数。其调用格式如下。
n = ndims(A):返回数组A的维数给n。数组的维数总大于等于2。
【例2-25】 获取给定矩阵的长度及维数。
1 | >> X = [5, 3.4, 72, 28/4, 3.61, 17 94 89]; |
- numel函数
该函数用于返回矩阵的元素数。其调用格式如下。
n = numel(A):返回数组A的元素数给n。
n = numel(A, index1, index2, … indexn):返回数组A的元素数为n,并指定A的维数为index1, index2, … indexn。
【例2-26】 获取数组A的元素数。
1 | >> a = magic(4); |
- size函数
该函数用于返回矩阵每一维的长度。其调用格式如下。
d = size(X):把数组X每一维的大小返回到向量d,d的元素数等于X的维数。如果X为一个标量,则MATLAB视其为1×1数组,返回向量[1,1]。
[m,n] = size(X):返回矩阵行与列的大小,分别放在变量m和n中。
m = size(X,dim):返回由标量dim指定的数组X某一维的大小在m中。
[d1,d2,d3,…,dn] = size(X):当n>1而且输出参数个数n等于X的维数时,size函数返回数组X各维的大小在变量d1,d2,d3,…,dn中。
如果n不等于数组X的维数,分两种情况讨论:
● 当n<ndims(X),di等于X的第i维的大小,1≤i≤n,而dn等于X的剩余各维大小的乘积。
● 当n>ndims(X),在额外的变量(即对应于ndims(X)+1到n的变量)中返回1。
【例2-27】 求已建立矩阵每一维的长度。
1 | >> m = size(rand(2,3,4),2) |
2.7.2 获取矩阵数据结构
在MATLAB中提供了若干函数用于判断矩阵本身数据结构,如表2-5所示。
表2-5 矩阵数据结构判断函数

【例2-28】 获取矩阵结构信息。
1 | >> A = rand(2,2,2); |
2.7.3 获取矩阵数据类型
MATLAB不但提供了判断矩阵本身数据结构的函数,还提供了判断矩阵内元素数据类型的若干函数,如表2-6所示。
表2-6 矩阵元素数据结构判断函数

注意:
(1)这些函数命令都是is开头的。
(2)这些函数的返回值为0和1,0表示假,1表示真。
(3)函数isa的调用格式为:isa(obj,’class_name’),obj代表目标矩阵,class_name代表指定数据类型。class_name可以是:double、logical、char、single、float、int8、uint8、int16、uint16、int32、uint32、int64、uint64、integer、numeric、cell、struct、function_handle。
【例2-29】 判断矩阵数据结构。
1 | >> A=[1 4 7;2 5 8]; %一般矩阵 |
注意: 事实上,矩阵A中的元素是双精度浮点类型的数据,并非表面上看到的整数类型,这一点可通过调用class来确定,如:
1 | >> class(A) %返回矩阵数据类型 |
2.8 稀疏矩阵
有些矩阵包含大量的0值元素,而实际上处理这些矩阵时,0是没有用处的。通常,MATLAB存储0与存储别的数字值使用同样的方法,0也堂皇而之地占据内存。让这大量的0占据内存空间是无必要的,更何况它们还要耗费额外的处理时间。
完全与稀疏是一种对比。完全矩阵即矩阵的元素一个不少,哪怕是0;稀疏矩阵缺失的是那些0,把0当作水分挤压出来,仅保留有效数字。
稀疏矩阵提供了一种更为有效的方法,用它来存储0元素占据有大百分比的数据。稀疏矩阵只存储非0元素和它们的行索引。使用稀疏矩阵能够有效地减少内存需求。
而完全矩阵则存储每一个元素。
【例2-30】 稀疏矩阵的存储效率。
1 | >> A=sprand(1000,2000,0.1); %创建稀疏矩阵 |
稀疏矩阵所需的存储空间仅为2291748个字节,而全矩阵所需要存储空间这16000000,全矩阵所需要存储空间是稀疏矩阵所需存储空间的6.9816倍,由此可看出,稀疏矩阵可以提高存储效率。
采用稀疏矩阵的另外一个好处就是执行效率的提高。对M×N矩阵A,非零元所占比例为a,计算2×A需要执行M×N次浮点数乘法;将矩阵A转换为稀疏矩阵,利用稀疏矩阵计算2×A,仅对非零元素进行运算,因此仅需要执行M×N×a次浮点数乘法,运行效率提高了(1/a-1)倍。
【例2-31】 演示稀疏矩阵的执行效率。
1 | >> tic %执行稀疏矩阵计算开始 |
运行结果说明稀疏矩阵对算法执行效率有明显提高,当然,这种效率的提升也视具体问题而定。
2.8.1 创建稀疏矩阵
在MATLAB中提供了若干函数用于实现稀疏矩阵的创建,下面分别给予介绍。
- sparse函数
该函数用于创建一般的稀疏矩阵。其调用格式如下。
S = sparse(A):将全矩阵A转换为稀疏矩阵,如果A已经为稀疏矩阵,则返回A。
S = sparse(i,j,s,m,n,nzmax):生成m×n稀疏矩阵,i、j、s是具有相同长度的向量,s、(i,j)分别是非0元素及其对应的索引,S(i(k),j(k))==s(k):nzmax必须不小于向量的长度;s中的0元素元及其对应的(i(k),j(k))被忽略。
S = sparse(i,j,s,m,n):生成m×n稀疏矩阵,该函数调用sparse(i,j,s,m,n,nzmax),并将nzmax设置为length(s)。
S = sparse(i,j,s):生成m×n稀疏矩阵,m=max(i),n=max(j),计算m、n时不会忽略s中的0元素。
S = sparse(m,n):等价于sparse([],[],[],m,n,0),用于生成m×n全0稀疏矩阵。
【例2-32】 用不同的i、j和s向量,创建相应的稀疏矩阵。
1 | %建立i、j和s三个向量,nzmax=7,生成5×5阶稀疏矩阵 |
- speye函数
该函数用于生成单位稀疏矩阵。其调用格式如下。
S = speye(m,n)或S = speye([m n]):生成m×n稀疏矩阵,该稀疏矩阵除对角线元素为1外,其余元素为0。
S = speye(n):等价于speye(n,n),用于生成n阶单位稀疏方阵。
【例2-33】 利用speye函数创建单位稀疏矩阵。
1 | >> Seye=speye(4,3) %创建4×3阶稀疏矩阵 |
- sprand函数
该函数用于创建均匀分布随机稀疏矩阵。其调用格式如下。
R = sprand(S):生成与A具有相同稀疏结构的随机稀疏矩阵,但非0元素服从均匀分布。
R = sprand(m,n,density):生成m×n稀疏矩阵,非0元素服从均匀分布,非0元素个数接近m×n×density(0≤density≤1)。
R = sprand(m,n,density,rc):生成条件数接近1/rc的m×n稀疏矩阵,非0元服从均匀分布,非0元素个数接近m×n×density(0≤density≤1)。如果rc为长度(lr)不大于min(m,n)的向量,则稀疏矩阵的前lr个奇异值为rc,其他奇异值为0。
- sprandn函数
该函数用于创建正态分布随机稀疏矩阵。其调用格式如下。
R = sprandn(S)
R = sprandn(m,n,density)
R = sprandn(m,n,density,rc)
该函数参数含义与sprand函数参数含义相同。
【例2-34】 创建均匀与正态分布随机稀疏矩阵。
1 | >> A= sprand(3) |
- sprandsym函数
该函数用于创建随机对称稀疏矩阵。其调用格式如下。
R = sprandsym(S):生成对称随机稀疏矩阵,其下三角和对角线与稀疏矩阵S具有相同的稀疏结构,非0元素服从正态分布。
R = sprandsym(n,density):生成n×n对称随机稀疏矩阵,非0元素服从正态分布,个数约为n×n×density。
R = sprandsym(n,density,rc):生成条数为1/rc的n×n对称随机稀疏矩阵,非0元素个数约为n×n×density,但这里的非0元素不服从正态分布,而是[-1,1]上的均匀分布。如果rc是长度为n的向量,则S的n个特征值为rc。
R = sprandsym(n,density,rc,kind):生成正定稀疏矩阵。如果kind=1,则矩阵是由正态对称矩阵经随机Jacboi矩阵旋转得到的,其条件数为1/rc;如果kind=2,则矩阵为外积的换位和,条件数近似为1/rc。
R = sprandsym(S,[],rc,3):生成一个与S具有相同结构的稀疏矩阵,近似条件数为1/rc,density被忽略。
【例2-35】 创建对称随机矩阵。
1 | >>i=eye(3); |
- spdiags函数
该函数用于创建带状和对角稀疏矩阵。其调用格式如下。
B = spdiags(A)或[B,d] = spdiags(A):返回A的各个对角线作为B的列。
B = spdiags(A,d):返回A的第d个对角线。
A = spdiags(B,d,A):将A的第d个对角线用B的列替换,这里的d也可以是向量。
A = spdiags(B,d,m,n):创建m×n稀疏矩阵,A的第d个对角线为B的列,d可以为向量。
【例2-36】 创建带状和对角稀疏矩阵。
1 | >> A=[0 5 0 10 0 0;0 0 6 0 11 0;3 0 0 7 0 12;1 4 0 0 8 0;0 2 5 0 0 9] |
2.8.2 稀疏矩阵的操作
一般地,能用于全矩阵的操作函数对稀疏矩阵同样有效,并且具有相似的操作规则。下面先通过示例来演示全矩阵操作函数在稀疏矩阵中的应用。
【例2-37】 全矩阵操作函数在稀疏矩阵中的应用。
1 | >> A=speye(4) %创建4阶单位矩阵 |
除了全矩阵操作函数外,MATLAB还提供了专门用于稀疏矩阵的操作函数,下面分别给予介绍。
- nnz函数
该函数用于返回矩阵的非0元素数。其调用格式如下。
n = nnz(X):返回矩阵X中的非0元素数。
稀疏矩阵的密度为nnz(X)/prod(size(X))。
- nonzeros函数
该函数用于返回矩阵的非0元素构成的列向量。其调用格式如下。
s = nonzeros(A):返回矩阵A中的非0元素构成的列向量s。s的元素按A的列排序,即先是第一列的非0元素从上到下排,接着是第二列、…、最后的列。
通常,s和A之间有这样的关系:
length(s) = nnz(A) ≤ nzmax(A) ≤prod(size(A))
如果使用find函数,不但得到非0元素的列向量s,还可以得到A中行和列的索引。
[i,j,s]=find(A)
【例2-38】 从矩阵A中取出非0元素,并构成一个列向量。
1 | >> clear |
- nzmax函数
该函数用于返回为非0元素分配的存储量。其调用格式如下。
n = nzmax(S):返回矩阵S的非0元素分配的存储总量。
● 如果S为一个稀疏矩阵,nzmax(S)是为S中的非0元素分配的存储单元数。
● 如果S为一个完全矩阵,nzmax(S)=prod(size(S))。
nnz(S)经常与nzmax(S)是一样的。但是,如果S由一个能够产生替代矩阵元素的操作建立的,分配给矩阵的存储要比实际需要的多,这就是nzmax(S)所体现的。这样的操作如稀疏矩阵增值,或缺失的LU因子分解。另外,sparse(i,j,s,m,n,nzmax)函数或它的最简单形式spalloc(m,n,nzmax),能够预置非0元素最大存储为nzmax,这些单元以后被非0元素替代。
- spalloc函数
该函数用于为稀疏矩阵分配存储空间。其调用格式如下。
S = spalloc(m,n,nzmax):建立一个全0的稀疏矩阵S,大小为m×n,其中为非0元素保留的空间是nzmax。然后逐列生成这个矩阵,用非0值代替0,而不必重复地分配存储。
【例2-39】 生成稀疏矩阵,平均每列至多有3个非0元素。
1 | >> clear all; |
- full函数
该函数用于将稀疏矩阵转换为完全矩阵。其调用格式如下。
A = full(S):把稀疏矩阵S转换成完全矩阵A。如果S为完全矩阵,那么得到A值为其本身。
完全矩阵与稀疏矩阵需要的存储空间表示如下:如果X为一个m×n的矩阵,所含的非0元素为nz=nnz(X)。那么,完全矩阵需要的存储空间为m×n个实数,而稀疏矩阵需要的存储空间为nz个实数加(nz+n)个整数。
【例2-40】 稀疏矩阵S,密度大约为2/3,转换成完全矩阵后,二者需要的存储差不多。
1 | >> S = sparse(+(rand(200,200) < 2/3)); |
- spy函数
该函数用于查看稀疏矩阵中非0元素分布情况。其调用格式如下。
spy(S):用图形化的方式显示稀疏矩阵S元素分布情况。
spy(S,markersize):设置稀疏矩阵元素分布图曲线的标记。
spy(S,’LineSpec’):设置稀疏矩阵元素分布图曲线的线型。
spy(S,’LineSpec’,markersize):同时设置稀疏矩阵元素分布图曲线的标记及线型。
【例2-41】 绘制所创建的稀疏矩阵元素分布图。
1 | >> clear all; |
运行程序,效果如图2-4所示。

图2-4 稀疏矩阵元素分布图
2.9 高级数组
在MATLAB中,把大于二维的数组叫做高维数组。能在矩阵上执行的大部分操作都可以用于高维数组。那么,如何建立和操作高维数组?与矩阵的建立和操作有什么异同?
MATLAB的高维数组,实际上是矩阵(二维数组)的扩展。矩阵有二维:行和列(如图2-5所示)。

图2-5 矩阵的行与列示意图
存取矩阵的一个元素用两个下标:第一个表示行索引,第二个表示列索引。
存取高维数组的元素需要更多的下标。以三维数组为例,使用3个下标:第一个表示行索引;第二个表示列索引;第三个表示第3维索引,第3维称做“页”。图2-6是三维数组示意图。

图2-6 三维数组示意图
要存取第2页第2行第3列的元素,用下标表示为(2,3,2),如图2-7所示。

图2-7 存取第2页第2行第3列元素示意图
在三维数组上再加一维,变成四维数组。存取四维数组要用4个下标,分别表示行、列、页、和第4维。大于三维的数组,在一般人的脑子里就很难想象它的空间模样了。
2.9.1 建立高维数组
建立矩阵的方法(或技术),用来建立多维数组是不成问题的,除此之外,MATLAB还提供了建立多维数组的特别连接函数。
- 使用索引扩展数组
先建立一个二维数组,然后扩展它。如:
1 | >> A=[0 7 9;2 5 11;3 6 4]; %建立二维数组 |
形成具有2页的三维数组。如法炮制,可以再加行、列或页。
1 | >> A(4,:,1)=[14 24 34]; |
利用MATLAB的标量扩展功能,再单个值完善整个数组。
1 | >> A(:,:,3) = 5 |
- 使用索引建立数组
利用索引直接建立数组。建立一个四维数组。
1 | >> B(:,:,1,2) = [1 2 3; 4 5 6; 7 8 9]; |
- 使用函数建立数组
在前面已经讨论过建立一些特殊矩阵的MATLAB函数,比如randn、rand、ones、zeros和repmat等。这些函数具有多种调用格式,建立多维数组的格式中多了三维、四维、…大小的参数。
如,建立一个4×3×2的随机正态分布的数组:
1 | >> B = randn(4,3,2) |
又如,把单个常数6复制到整个数组,形成一个3×4×2的数组:
1 | >> B = repmat(6, [3 4 2]) |
函数cat也提供了一个简单方法,按照指定的维连接多个数组成为一个高维数组。
如按照第3维连接数组,建立一个新三维数组:
1 | >> B = cat(3, [2 8; 0 5], [1 3; 7 9]) |
又如,嵌套cat函数,创建四维数组:
1 | >> A = cat(3, [9 2; 6 5], [7 1; 8 4]); |
再如,在cat生成的四维数组中,第3维是单一维(即只有一页),第4维是双维,即有第4维一、第4维二。
1 | >> C = cat(4, [1 2; 4 5], [7 8; 3 2]) |
如果在存取值8,则使用索引:
1 | >> C(1,2,1,2) |
2.9.2 访问高维数组信息
高维数组的信息访问与二维矩阵的信息访问相同,读者可参考前面内容。下面举例说明高维数组的信息访问。
【例2-42】 高维数组信息查询。
1 | >> A=[1 3;5 9] |
2.9.3 高维数组操作函数
在MATLAB中提供了若干函数专门用于对高维数组进行操作。这些函数分别用来实现高维数组的降维、翻转等,如函数squeeze、flipdim、shftdim和permute等,下面分别对这几个函数作介绍。
- squeeze函数
该函数用于删除高维数组中大小为1的维。其调用格式如下。
B = squeeze(A):删除高维数组A中大小为1的维,得到新高维数组B。
【例2-43】 利用squeeze函数对高维数组进行降维处理。
1 | >> clear |
- flipdim函数
该函数用于对高维数组进行翻转操作。其调用格式如下。
B = flipdim(A,dim):表示将数组A以第dim维为基准进行翻转。
【例2-44】 利用flipdim函数对高维数组进行翻转。
1 | >> A=cat(3,[2 88;4 3],[3 7;11 0]) %调用cat函数创建三维数组 |
- shiftdim函数
该函数用于移动高维数组维度。其调用格式如下。
B = shiftdim(X,n):n为正整数,表示将数组A的前n维移动到数组维度的右侧。
[B,nshifts] = shiftdim(X):返回移动维度的索引号nshifts。
【例2-45】 利用shiftdim函数移动高维数组维度。
1 | >> a = rand(1,1,3,1,2) |
- permute函数
该函数用来重新排列数组的维度。其调用格式如下。
B = permute(A,order):将数组A的维度按照向量order的顺序重新排列。
【例2-46】 利用permute函数重新排列高维数组的维度。
1 | >> X = rand(12,13,14); %创建高维数组 |
【例2-47】 分别利用函数permute和shiftdim函数实现同一功能。
1 | >> A=reshape(1:36,4,3,3) %调用reshape函数生成三维数组A |
2.9.4 用多维数组组织数据
计算机最广泛的用途之一,是处理各种各样的数据。因此,如何组织数据,将数据放在什么样的结构中,就成了要考虑的问题。选择不同结构存储数据的目的,是为了处理更容易、更快、更节省空间。
在MATLAB中,用多维数组存储数据有两种方法:
- 一是平面形式,即用二维数组存储数据,然后把数据作为矩阵处理;
- 二是立体形式,即用三维或更高维的数组存储数据,然后或者处理其中的页,或者处理数据子集。
如:用三维数组存储RGB图像数据,使得存储和存取都极其容易,如图2-8所示。

图2-8 用三维数组存储RGB图像数据
要存取图像的一个完整平面,使用:
1 | redPlane = RGB(:,:,1); |
要存取一个子图像,使用:
1 | subimage = RGB(20:40,50:85,:); |
第3章 元胞与结构数组
元胞(Cell)和结构(Structrue)数组是MATLAB所有15种数据类型中较为特殊的两种。一般来说,一个数据只能是一种数据类型,而元胞和结构这两种类型的数据却可以包含多种类型的数据。元胞和结构的表现形式分别是元胞数组(Cell Array)和结构数组(Structure Array)。
3.1 元胞数组
元胞数组具有处理复杂字符串的能力。许多大银行都有一个十分完善的保险箱库。保险箱库的最小单位是箱柜,它可以存放任何东西(如珠宝、债券、现金、文件等)。每个箱柜被编号,一个个编号的箱柜组合成排,一排排编号的箱柜组合成室,一个个编号的室便组合成银行的保险箱库。
元胞数组如同银行里的保险箱库一样。该数组的基本组成(Element)是元胞。每个元胞本身在数组中是平等的,它们只能以下标区分。元胞可以存放任何类型、任何大小的数组(如任意维数值数组、字符串数组、符号对象等)。而且,同一个元胞数组中各元胞中的内容可以不同。
与数字数组一样,元胞数组维数不受限制,可以一维、二维或更高维,不过一维元胞数组用得最多。元胞数组对元胞的编址方法也有单下标编址和全下标编址两种。
以三维元胞数组为例,全下标编址由3个序号组成。编址中的第1序号是“行”号,第2个是“列”号,第3个是“页”号。而单下标编址中,第1行第1列第1页的元胞是序号为1,然后沿第1列往下记号2、3、4等;直到第一列的元胞全部编完,接下去编第2列的第1行元胞,然后再沿第2列往下编,依次类推。直到这第1页的元胞全部编完,紧接着往下的是第2页上的第1行第1列元胞,再沿列而下,如此进行直到全部编完。
图3-1为包含6个单元的元胞数组。
在图3-1的单元数组中包含的6个单元:cell 1,1存储无符号整数数组;cell 1,2存储字符串;cell 1,3为复数;cell 2,1为浮点数向量;cell 2,2为有符号整数数组;cell 2,3为一个嵌套单元数组。

图3-1 单元数组示意图
3.1.1 元胞数组的创建
创建一个元胞数组的方式有两种:
- 直接赋值创建,这是一种最为直接和简单的创建方式。
- 函数创建元胞数组。
【例3-1】 使用赋值法创建元胞数组。
1 | %利用单元索引创建一个2×2的元胞数组 |
如果被赋值的单元在当前数组的维数之外,MATLAB将自动扩展这个数组,以包含指定的下标,并且用空矩阵填充插入的单元。如,下面这条赋值语句将把2×2的元胞数组A扩展到3×3的元胞数组,如图3-2所示。

图3-2 3×3的元胞数组
1 | A(3,3) = {5}; |
赋值语句中用到的花括号{},是单元数组的构造符,就像方括号[]是数字数组的构造符一样。花括号用逗号或空格作为单元之间的分隔符,用分号作为行分隔符。如:
1 | >> C={[1 2],[3 4],[5 6],[7 8]}; |
效果如图3-3所示。

图3-3 C元胞数组
除了上面介绍的赋值法创建元胞数组外,在MATLAB中还提供了专门的cell函数用于创建元胞数组。
用cell函数能够预先分配指定大小的空单元数组。其调用格式为:
C = cell(n):建立一个n×n的空矩阵元胞数组C。如果n不是标量,即产生错误。
C = cell(m, n)或C = cell([m, n]):建立一个m×n的空矩阵元胞数组C,m与n必须为标量。
C = cell(m, n, p,…)或C = cell([m n p…]):创建一个m×n×p×…的空矩阵元胞数组C,m,n,p, …必须都为标量。
C = cell(size(A)):建立一个元胞数组C,其大小与数组A一样,也就是说,C中的空矩阵单元数等于A的元素数。
C = cell(javaobj):将Java数组或Java对象javaobj转换为MATLAB单元数组。结果元胞数组的元素将是最接近于Java数组元素或Java对象的MATLAB类型。
【例3-2】 采用cell函数创建元胞数组。
1 | >> A = ones(2,2) |
3.1.2 显示元胞数组
在MATLAB中可以使用简略形式显示元胞数组,前面示例中已有应用。除此之外,MATLAB还提供了专门的函数用于显示元胞数组。下面分别给予介绍。
- celldisp函数
该函数用于显示元胞数组的全部内容。其调用格式为:
celldisp(C):以列顺序显示元胞数组C的内容。
celldisp(C, name):以列顺序显示元胞数组C的内容,但用字符串name作为数组的显示名。
【例3-3】 调用celldisp函数显示所创建的元胞数组。
1 | >> C = {[1 2] 'Tony' 3+4i; [1 2;3 4] -5 'abc'}; |
- cellplot函数
该函数用于显示元胞数组的结构图。其调用格式为:
cellplot(c):显示一个图形窗口,里面为单元数组内容c的图形表示。涂满颜色的方格表示向量或数组的元素,而标量和短文本串被显示为文本。
cellplot(c, ‘legend’):显示一个图形窗口,里面为单元数组内容c的图形表示。涂满颜色的方格表示向量或数组的元素,而标量和短文本串被显示为文本,并且在图形旁边设置一个图例。
handles = cellplot(c):返回元胞数组的句柄值。
【例3-4】 调用cellplot函数显示所创建元胞数组的结构示意图。
1 | >> clear all; |

图3-4 元胞数组结构示意图
3.1.3 字符串元胞数组
在MATLAB中创建字符串数组时,要求数组中所有字符串有相同的长度,这意味着用户必须用空格将较短的字符串补齐,使得所有的字符串长度相等。然而这种计算空格个数将字符串补齐的方式并不方便,所以,MATLAB引入了字符串元胞数组的形式来生成字符串,字符串元胞数组可以包括不同尺寸和类型的数据,而无须用空格将不同长度的字符串补齐。
【例3-5】 字符串元胞数组示例演示。
1 | >> S = ['abc '; 'defg'; 'hi '] %自动用空格补齐 |
3.1.4 取元胞数组数据
对元胞赋值有两种索引方式:内容索引和单元索引。从元胞数组取数据也使用这两种方式。
为避免在后面的叙述中混淆,先要弄清楚两个概念:元胞数组的子集和元胞的子集。前者指整个元胞数组的部分元胞,而后者是指一个元胞中的部分元素。
- 内容索引获取元胞内容
其实,存取元胞的内容仍然是一种赋值,是把元胞的内容赋给一个变量。赋值语句的右边使用内容索引,左边的变量接近元胞的内容。不要忘了,元胞索引表达式要放在花括号中。不妨先建立一个2×2的元胞数组,然后取一个元胞的数据,都用到内容索引,可作为对比。
1 | >> clear |
- 单元索引获取元胞数组的子集
利用单元索引的赋值语句,可以建立一个新的元胞数组。存取元胞数组的子集,要用冒号运算符“:”。比如,从3×3的单元数组A,抽取4个单元,建立一个新的单元数组B:
1 | >> A={3 5 9;5 6 0;4 7 2}; |
用元胞数组图示表示如图3-5所示。

图3-5 由元胞数组A建立的元胞数组B
注意: 单元索引存取元胞数组中的元胞(即元胞数组的子集),可以建立一个新的元胞数组;内容索引存取单个元胞中的数据(即元胞的子集),可以建立一个标准数组。
3.1.5 元胞数组的扩展、删减和重塑
针对元胞数组的操作主要包括元胞数组的扩展、删除和重塑。对于元胞数组的这些操作和对于数值数组的操作基本类似,都针对数组元胞本身进行,而不涉及元胞的内容,所以,以下的操作只用到元胞索引方式。
- 扩展元胞数组
元胞数组的扩展规则基本类似,唯一不同一的是,系统自动添加的不是元素0,而是空数组[]。
【例3-6】 对所创建的元胞数组进行扩展。
1 | >> A(1,1) = {[1 4 3; 0 5 8; 7 2 9]}; |
由以上结果可知,原元胞数组为一个2×2的元胞数组,给其添加A(1,3)后,系统将在A(2,3)处自动生成空数组[],形成一个2×3的新元胞数组。
- 删除元胞
删除元胞数组的元胞,使用向量下标(即线性索引),并指定被删除的元胞为空数组。
【例3-7】 删除所创建的元胞数组元胞。
1 | >> header = {'Name', 'Age', 'Pulse/Temp/BP'}; |
注意: 删除元胞时,花括号不能出现在赋值语句中。
- 重塑元胞数组
像重塑普通数组一样,使用reshape函数可以重新塑造元胞数组的形状。重塑以后的元胞数必须与原来的相同,不能用reshape函数增加或减少元胞。
【例3-8】 重塑元胞数组。
1 | >> A=cell(3,4); %原元胞数组 |
3.1.6 访问元胞数组
元胞数组内容的访问与一般数组访问类似,都是采用索引的方式,下面通过示例来演示对元胞数组的访问。
【例3-9】 对元胞数组内容进行访问。
1 | >> A(1,1) = {[1 4 3; 0 5 8; 7 2 9]}; |
3.1.7 嵌套元胞数组
嵌套元胞数组,不过是在元胞中包含另一个元胞数组,甚至包含元胞数组的数组。在元胞数组中,包含非元胞数据的元胞被称做叶元胞,是一片叶子。说起来简单,做起来还会难么?可以用cell函数、嵌套的花括号和直接赋值语句建立嵌套元胞数组,然后存取和处理独立的元胞、元胞的子数组或元胞的元素。
- 用嵌套的花括号建立嵌套元胞数组
花括号是元胞数组的构造符,只要在建立元胞数组的语句中嵌套一对花括号,就会建立一个嵌套 元胞数组。
【例3-10】 利用花括号建立嵌套元胞数组。
1 | >> clear |
这是在赋值语句的右边包括了两组花括号,第1层表示元胞数组A的元胞(1,2),第2层包装了2×2的元胞数组,第3层在2×2的元胞数组中又建立一个元胞。
1 | >> celldisp(A) %显示所创建的元胞数组A |
- 用cell函数建立嵌套元胞数组
使用cell函数,建立与上面元胞数组A一样的数组。
【例3-11】 利用cell函数建立元胞数组。
1 | >> A=cell(1,2); %建立一个1×2的空元胞数组 |
注意: 赋值语句左边花括号的层次,表示嵌套的层次。
3.1.8 高维元胞数组
在MATLAB中,高维元胞数组是二维元胞数组的扩展。建立高维元胞数组是非常容易的,就像建立高维数字数组一样,使用cat函数建立高维元胞数组。
【例3-12】 建立一个简单的三维元胞数组C。
1 | >> clear |
三维元胞数组C如图3-6所示,可以更清楚地看到各单元的下标。

图3-6 三维元胞数组C的图示
3.1.9 元胞数组与数字数组间的转换
在MATLAB中元胞数组与数字数组间的转换有两种方法:
(1)用程序代码实现转换。
(2)用函数实现转换。
元胞数组与数字数组之间的转换,由for循环组成的代码实现。
【例3-13】 元胞数组与数字数组间的转换。
1 | >> A{1,1}=[3 5;9 1]; |
注意: B为一个三维数组。A的一个元胞变成B数组的一页。
同样,使用for循环,把数字数组的每个值赋给元胞数组的每个单元:
1 | >> C=cell(1,16); |
这里,对数组B与C都是使用线性索引,B为一维元胞数组。
利用num2cell函数把数字数组转换成元胞数组:
1 | >> D=num2cell(B,3) |
3.2 结构数组
与元胞数组一样,结构数组(Structure Array)也能在一个数组里存放各类数据。从一定意义上讲,结构数组组织数据的能力比元胞数组更强、更富于变化。
结构数组的基本成分(Element)是结构(Structure)。数组中的每个结构是平等的,它们以下标区分。结构必须在划分“域”后才能使用。数据不能直接存放在结构中,而只能存放在域中。结构的域可以存放任何类型、任何大小的数组(如任意维数数值数组、字符串数组、符号对象等)。而且,不同结构的同名域中存放的内容可以不同。
与数值数组一样,结构数组维数不受限制,可以是一维、二维或更高维,不过一维结构数组用得最多。结构数组对结构的编址方法也有单下标编址和全下标编址两种。
在MATLAB中,一个结构体对象就是一个1×1的结构体数组,因此,可以创建具有多个结构体对象的二维或多维结构体数组。
3.2.1 创建结构数组
创建结构体对象有两种方法:直接采用赋值语句给结构体的字段赋值;通过结构体创建函数struct来创建。
- 采用赋值语句创建结构数组
在对结构体的字段进行赋值时,赋值表达式的左边代表了结构体的字段变量名,用“结构体名称.字符名称”的形式书写,可以对一个结构体多个字段赋值。
【例3-14】 通过字段赋值创建结构体。
1 | >> patient.name = 'John Doe'; |
在例3-14中,通过对3个字段(name、billing、test)赋值,创建了一个具有3个字段的结构体对象patient。用whos显示发现patient为一个1×1的结构体数组。
通过圆括号索引指派,用字段赋值的方法还可以创建任何尺寸的结构体数组。
注意: 同一个结构体数组中的所有结构体对象具有相同的字段,没有明确赋值的字段,MATLAB默认赋值为空数组。
【例3-15】 通过圆括号索引指派,用字段赋值的方法创建结构体数组。
1 | >> patient(1).name='John Doe'; |
- 通过struct函数创建结构数组
除了通过字段赋值,在MATLAB中还提供了struct函数创建结构体。其调用格式为:
s = struct(‘field1’, values1, ‘field2’, values2, …):filedi表示字段名。valuei表示对应于filedi的字段值,必须是同样大小的元胞数组或标量。
s = struct(‘field1’, {}, ‘field2’, {}, …):用指定字段filed1,field2等建立一个空结构(无任何数据)。
s = struct([]):建立一个没有字段的空结构。
s = struct(obj):将对象obj转换为它的等价结构。
【例3-16】 利用struct函数创建结构数组。
1 | >> W(2)=struct('total','sunny','temp',18,'rainfall',0.0) |
说明: 结构体在内存中的存储并不需要连续的内存块,只是结构体的每一个字段存储在一块连续内存中。
3.2.2 取结构数组数据
对于结构数组,也可以通过括号、下标索引来访问其内部的数据,需要注意的是结构体名和字段之间用点(.)连接。
对于图3-7所示的结构体,例3-17给出了访问其内部数据的多种方法。

图3-7 结构数组图示
【例3-17】 结构体内部数据的获取。
1 | >> patient.name = 'John Doe'; |
3.2.3 扩展与删除结构字段
结构数组中的常见操作,包括获取其尺寸信息和增删字段。
和一般的数组一样,size函数可以获取结构体数组的尺寸,也就是数组中包含多少行、多少列的结构体对象。当然,如果size函数的输入参数是结构体字段,则返回的是该字段的尺寸信息。
向结构体中增加新的字段,只需要添加新的字段赋值语句即可。没有被明确赋值的结构体中,添加的新字段被初始化为空数组。
从结构体中删除字段,需要用到rmfield函数,其调用格式为:
s = rmfield(s, ‘fieldname’):从结构数组s中删除指定的字段fieldname。
s = rmfield(s, fields):从结构数组s中删除一个以上字段。fields是多个字段名的字符数组或字串元胞数组。
【例3-18】 获取与删除结构数组。
1 | >> whos |
3.2.4 结构数组的其他操作函数
在MATLAB中提供了若干函数对结构数组进行操作,常用操作函数如表3-1所列。
表3-1 有关结构的操作函数

【例3-19】 结构数组的其他操作函数演示示例。
1 | %调用deal函数操作结构数组 |
3.2.5 用结构数组组织数据
结构数组首先是一个数组,而数组可以包含一个或许多结构,每个结构有相同数目的字段。如何存取数据的子集,是决定数组结构的关键。考虑一个128×128的RGB图像,目前图像的数据按Red、Green、Blue分别存储于3个独立的数组中,如图3-8所示。

图3-8 3个独立的数组
可以按两种方式将RGB图像组织为结构数组,如图3-9所示。

图3-9 按两种方式将RGB图像组织为结构数组
- 平面组织
把上面的3个数组变为结构数组A的3个字段:
1 | A.r = RED; |
每个字段是完整的一个图像平面。当想一次对整个图像进行处理,如显示、过滤等时,这种方式可以很容易地抽取完整的图像平面。如,要存取整个红色平面,代码为:
1 | redPlane = A.r; |
平面组织的另一个优点是,它的扩展性好。如果有很多个图像,可以建立A(2),A(3)等,每个结构都是一个完整的图像。
平面组织的不足之处是,存取子图像非常麻烦,需要分别存取每个字段:
1 | redSub = A.r(2:12,13:30); |
- 单元素组织
单元素组织,就是把RGB图像3个独立的单个元素,作为结构中每个字段的值。这种组织的优势,显然在于存取图像的子集。
从RGB图像3个独立的数组,建立一个128×128个结构的数组,需要用循环语句完成:
1 | for m = 1:size(RED,1) |
单元素组织的结构数组,要存取图像的子集,只需一行语句(存取若干字段):
1 | Bsub = B(1:10,1:10); |
而要存取整个单色平面(如红色),麻烦一点,需组织一个循环:
1 | redPlane = zeros(128, 128); |
当然,把RGB图像的每个最基本单元组织成一个结构(每个结构包含r、g、b三个字段),对于图像处理,并不一定是最好的结构选择。
【例3-20】 将客户信息组织成两种结构——平面组织和单元素组织(结构图如图3-10所示),比较它们的优缺点。

图3-10 平面组织与单元素组织两种结构
两种结构都有长处和短处,如何扬长避短,取决于怎样存取数据:
平面组织更适于一次操作所有的字段。比如,计算amount字段所有值的平均值,注意语句的区别。
使用平面组织:
1 | avg = mean(A.amount); |
使用单元素组织:
1 | avg = mean([B.amount]); |
单元素组织更容易存取单个客户的所有信息。假定一个M文件client.m显示指定客户的姓名和地址。
对于平面组织,这个函数为:
1 | function client(name,address) |
调用函数要传送两个单独字段,如显示第2个客户的姓名与地址,代码为:
1 | >> client(A.name(2,:), A.address(2,:)); |
而对于单元素组织,函数为:
1 | function client(B) |
调用函数要传送整个结构,如也显示第2个客户的姓名与地址,代码为:
1 | client(B(2)) |
3.2.6 嵌套结构数组
结构体可以有多个字段,可以存储多种类型的数据,结构体的字段中也能存储结构体类型的数据,这就是结构体嵌套。
下面通过一个示例来演示嵌套结构体数组的创建及操作。
【例3-21】 结构体嵌套。
1 | >> clear all; |
3.2.7 高维结构数组
高维结构数组是方形结构数组的扩展。普通高维数组可以使用直接赋值语句或cat函数建立,高维结构数组也能够如法炮制。
- 建立高维结构数组
【例3-22】 创建一个高维结构数组。
1 | >> clear |
这一组语句建立如图3-11所示的高维结构数组。

图3-11 高维结构数组
- 将函数应用于高维结构数组
和将函数应用于二维结构数组一样,操作高维结构数组的字段和字段元素,使用索引。例如,计算patient(1,1,2)中test数组各列的和:
1 | >> sum((patient(1,1,2).test)) |
计算patient数组中所有billing字段的总和:
1 | >> total = sum([patient.billing]) |
查询patient数组的大小:
1 | >> size(patient) |
查询patient数组的长度:
1 | >> length(patient) |
第4章 程序控制与矩阵分析
MATLAB为工程技术人员、科研工作者提供了方便、强大的数值计算功能,这也是MATLAB得以流行的重要因素。用户在利用MATLAB解决实际问题时,首先将该问题转化为数学问题,然后将相应的数学求解过程翻译为MATLAB程序代码。与其他计算机语言(如C、C++、Java等)不同的是,MATLAB语言是一种边解释边执行的程序语言,其风格更像是一种数学语言。因此用户利用MATLAB解决问题并不需要了解很多编程方面的知识,而只需懂得基本的MATLAB语法即可。
4.1 程序控制流
MATLAB程序设计既有传统高级语言的特征,又有自己独特的优点。在MATLAB程序设计时,充分利用MATLAB数据结构的特点,可以使程序结构简单,编程效率高。
与其他高级语言一样,MATLAB也提供了对程序控制的支持,从而使得MATLAB语言的编程显得十分灵活。MATLAB共有5种控制结构,与C语言的控制语句很相似。
- 顺序控制结构:input、disp。
- 条件控制结构:if、switch。
- 循环控制结构:for、while、continue、break。
- 程序终止结构:return。
- 错误控制结构:try-catch。
4.1.1 顺序控制结构
顺序控制结构是指按照程序中语句的排序顺序依次执行,直到程序的最后一个语句。这是最简单的一种程序结构。一般涉及数据的输入、数据的计算或处理、数据输出等内容。
- 数据的输入
从键盘输入数据,则可以使用input函数来进行,该函数的调用格式为:
A=input(提示信息,选项):其中提示信息为一个字符串,用于提示用户输入什么样的数据。例如,从键盘输入A矩阵,可以采用下面的命令来完成。
A=input (‘输入A矩阵:’):执行该语句时,首先在屏幕上显示提示信息“输入A矩阵:”,然后等待用户从键盘按MATLAB规定的格式输入A矩阵的值。
如果在input函数调用时采用‘s’选项,则允许用户输入一个字符串,例如:
1 | >> reply = input('Do you want more? Y/N [Y]: ', 's'); |
- 数据的输出
MATLAB提供的命令窗口输出函数主要有disp函数,其调用格式为:
disp(输出项):其中输出项既可以为字符串,也可以为矩阵。例如:
1 | >> A='THE MATLAB'; |
输出为:
1 | THE MATLAB |
又如:
1 | >> B=[1 4 7;2 5 8;3 6 9]; |
注意: 和前面介绍的矩阵显示方式不同,用disp函数显示矩阵时将不显示矩阵的名字,而且其输出格式更紧凑,且不留任何没有意义的空行。
4.1.2 分支结构
分支结构语句可以使程序中的一段代码只在满足一定条件下才执行,因此也称为分支选择或条件控制。MATLAB中分支语句有两类:if语句与switch语句。
● if与else或elseif连用,偏向于是非选择,当某个逻辑条件满足时,执行if后的语句,否则执行else语句。
● switch与case、otherwise连用,偏向于情况的列举,当表达式结果为某个或某些值时,执行特定case指定的语句段,否则执行otherwise语句。
- if分支
if语句用来检查逻辑运算、逻辑函数、逻辑变量值等逻辑表达式的真假,若为真则执行if和else之间的执行语句,否则,转去执行另一分支。其语法格式如下:
1 | if expression |
其中,elseif和else语句都是可选语句。if、elseif和else构成的各项分支里面,哪个分支的条件满足(逻辑表达式statements的结果为真),就执行哪个分支后面紧跟的程序语句。因此,各条分支条件满足的情况应该是互斥的和完备的,就是被选的条件能在一个分支中成立,而且只能在一个分支中成立。
【例4-1】 利用if-else语句判断给定值是否超过给定范围,并显示出来。
1 | >> A = rand(1,10); |
运行程序,输出如下:
1 | Indices of values > 0.75: |
【例4-2】 利用if语句生成一个7阶矩阵。
1 | >> for m = 1:7 |
运行程序,输出如下:

【例4-3】 判断随机输入的一个年份是否为闰年。
分析:先要明确闰年的概念。所谓闰年,从纯数学角度上,可以用一句话概括。即“闰年是能被4整除,但不能被100整除;如能被100整除,同时能被400整除的年份”。
1 | % 判断一个年份是否为闰年 |
以上程序包含两个独立的if语句,其中第1个为多分支if语句,主要功能是判断输入的年份是否为闰年;第2个为双分支if语句,主要输出判断的结果。
- switch分支
switch语句也是MATLAB中的一个分支语句。如果在一个程序中,必须针对某个变量值来进行多种不同的执行,switch语句更为方便,此外,合理地使用switch语句也可以使程序更具有可读性。
其调用格式为:
1 | switch switch_expression |
执行中,先计算表达式switch_expressionr的值,当结果等于某个case的case_expression时,就执行该case紧随的语句。如果所有case的case_expression都和switch_expressionr计算结果不相等,则执行otherwise后面紧随的语句。
otherwise语句是可选的,当没有otherwise语句时,如果所有case的value都和switch_expressionr计算结果不相等,则直接执行后续代码。
switch语句与if语句具有相等价的意义,对于数值类型来说,相当于判断if reslut==case_expression,对于字符串类型来说,相当于判断strcmp(reslut, case_expression)。
由此可见,switch-case语句实际上可以被if-elseif-else语句等效替换,不过两种结构各有千秋。
【例4-4】 利用switch-case语句判断一个数据的输入。
1 | mynumber = input('Enter a number:'); |
运行程序,输出如下:
1 | Enter a number:6 |
学过C语言的读者需要注意,MATLAB中的switch-case结构,只执行表达式结果匹配的第一个case分支,然后就跳出switch-case结构,因此,在每一个case语句中不需要用break语句跳出。
【例4-5】 利用switch-case函数绘制一个三维饼图。
1 | >> x = [12, 64, 24]; |
运行程序,效果如图4-1所示。

图4-1 三维饼图
【例4-6】 学生的成绩管理作为演示switch结构的应用,划分区域:满分(100)、优秀(9099)、良好(8089)、及格(60~79)和不及格(<60)。程序如下:
1 | >> for i=1:10 |
运行程序,输出如下:
1 | 学生姓名 得分 等级 |
在一条case语句后可以列举多个值,只需要以元胞数组的形式列举多个值,就是用花括号把用逗号或空格分隔的多个值括起来即可。
【例4-7】 一条case语句列举多个值的switch-case语句。
1 | >> result = 52; |
运行程序,输出如下:
1 | result is 52 |
4.1.3 循环结构
循环结构可以用来重复计算某一任务,在MATLAB中提供了for和while两种实现循环函数的结构,它们分别实现固定和不定次数的计算。
- for循环
for循环用于知道循环次数的情况,其调用格式为:
1 | for index = start:increment:values |
index为循环变量,increment为增量,value用于判断循环是否应该终止。
增量increment默认为1,可以自由设置,当增量为正数时,循环开始先将index赋值为start,然后判断index是否小于等于value,如果是,则执行循环语句,执行完后,对index累加一个增量increment,再判断index是否小于等于value,如果是,则继续执行循环语句,对index累加,循环往复,直到index大于value时退出循环。
增量increment也可以设置为负整数,表示每次循环执行后对循环变量index进行递减,当index数目小于value时,退出循环。
【例4-8】 利用循环语句创建一个6阶循环数组。
1 | >> k = 6; %创建数组阶数 |
运行程序,输出如下:
1 | hilbert = |
【例4-9】 设
分析:求函数f(x) 在[a,b]上的定积分,其几何意义就是求曲线y=f(x) 与直线x=a 、x=b 及y =0所围成的曲边梯形的面积。为了求得曲边梯形面积,先将积分区间[a,b ]分成n 等分,每个区间的宽度为h =(b-a )/n ,对应地将曲边梯形分成n 等分,每个小部分即是一个小曲边梯形。近似求出每个小曲边梯形面积,然后将n 个小曲边梯形的面积加起来,就得到总面积,即定积分的近似值。近似地求每个小曲边梯形的面积,常用的方法有:矩形法、梯形法以及辛普森法则等。以梯形法为例,程序代码如下:
1 | >> clear all; |
运行程序输出如下:
1 | s = |
上述程序来源于传统的编程思想。也可以利用向量运算,从而使得程序更加简洁,更有MATLAB的特点。其源程序如下:
1 | >> clear all; |
程序中x、f、s均为向量,f的元素为各个x点的函数值,s的元素分别为n个梯形的面积,s各元素之和即定积分近似值。
在上述例子中,for语句的循环变量都是标量,这与其他高级语言的相关循环语句(如Fortran语言中的DO语句,C语言中的for语句等)等价。按照MATLAB的定义,for语句的循环变量可以是一个列向量。for语句更一般的格式为:
1 | for 循环变量=矩阵表达式 |
执行过程是依次将矩阵的各列元素赋给循环变量,然后执行循环体语句,直至各列元素处理完毕。实际上,“表达式1:表达式2:表达式3”是一个行向量,它可以被看作仅为一行的矩阵,每列是单个数据。所以在此一开始给出的for语句格式是一种特例。
【例4-10】 数组赋值循环变量的for循环。
1 | >> clear all; |
- while循环
while循环则用在已知循环退出条件的情况。其调用格式为:
1 | while expression |
当表达式expression的结果为真时,就执行循环语句,直到表达式expression的结果为假,才退出循环。
如果表达式expression为一个数组A,则相当于判断all(A)。特别地,空数组则被当作逻辑假,循环不执行。
【例4-11】 利用while循环,计算1到100位数的阶乘。
1 | >> n = 1; |
运行程序,输出如下:
1 | nFactorial = |
【例4-12】 利用while嵌套if语句求方程的解。
1 | >> a = 0; fa = -Inf; |
运行程序,输出如下:
1 | 方程的解为: |
- continue语句
continue命令通常用在for或while循环结构中,并与if一起使用,其作用是结束本次循环,即跳过其后的循环语句而直接进行下一次是否执行循环的判断。
【例4-13】 计算文件magic.m的行数,空白行与注释行除外。continue命令相当于在遇到空白行或注释行时,继续读入magic.m中的下一行而不增加行数值。
1 | >> fid = fopen('magic.m','r'); |
运行程序,输出如下:
1 | 25 lines |
- break语句
break命令一般用来终止for或while循环,通常与if条件语句一起使用,如果条件满足则利用break命令将循环终止。在多层循环嵌套中,break只终止最内层的循环。
【例4-14】 实现查找某二维逻辑数组A(元素为0或1)中每一行上第一个零元素的位置。
1 | >> clear all; |
运行程序,输出如下:
1 | A = |
以上代码中的rand(m,n)<0.7语句通过关系运算返回一个二维逻辑数组,两层for循环遍历这一数组的每一行每一列,在某一行中找到非零元素时,将其下标保存在结果中,并退出这一行在列方向的循环(注:break仅仅是退出它所在的那一层循环)。
4.1.4 程序终止结构
return命令用于终止当前命令的执行,并且立即返回上一级调用函数或等待键盘输入命令,可以用来提前结束程序的运行。
【例4-15】 return命令应用示例,编写一个求两矩阵相加之和的程序。
1 | function c=li4_15(a,b) |
将以上文件保存在MATLAB搜索目录中,并命名为li4_15.m,选取两个矩阵a、b,运行结果如下:
1 | >> a=[]; |
4.1.5 错误控制结构
在程序设计中,有时候会遇到不能确定某段代码是否会出现运行错误的情况。这时候就可以用错误控制结构了。MATLAB提供了try-catch结构用来捕获和处理错误。其调用格式为:
1 | try |
程序运行时,首先尝试执行try语句后面的代码段,如果try和catch之间的代码执行没有错误发生,则程序通过,不执行catch和end之间的部分,而是继续执行end后面的代码。一旦try和catch之间的代码执行发生错误,则立刻转而执行catch和end之间的部分,然后才继续执行end后的代码,MATLAB提供了lasterr函数,可以获得出错的原因。
【例4-16】 错误控制结构演示代码。
1 | function d_in = read_image(filename) |
4.2 M函数
简单地说,M文件就是一系列相关代码组成的一个扩展名为.m的文件,用户可以在MATLAB自带的M文件编辑窗口或者普通文本编辑器中编写代码,然后以filename的文件名+.m扩展名保存在MATLAB的工作空间,以后在MATLAB命令窗口直接调用文件名filename,就可以执行文件中一系列代码所综合表示的操作。
M文件具有简单、交互性较好和易于调试的特点,虽然语法与高级语言一样,但是M文件却是ASCII型的文本文件。MATLAB包含类型齐全、功能完善的各种“工具箱”,它们都是以M文件存在和封装的,广大工程师和学者不断在工具箱内添加新的M文件,使MATLAB的功能愈加增加。
M文件可以分为脚本文件(MATLAB scripts)和函数文件(MATLAB function)两类。两种M文件都是以.m为文件扩展名。
4.2.1 脚本文件与函数文件
脚本文件是较为简单的M文件,因为其没有输入和输出变量。函数文件相对复杂,从“外观”上看,函数文件只多了一行代码,但是其代码组织结构和调用方法却与对应的脚本文件截然不同。
脚本文件只是将一系列相关代码结合封装,没有输入参数和输出参数,即不自带参数,也不一定要返回结果。而对于函数文件,尽管有一些函数文件不带参数,文件中一般使用一些全局变量来实现与外界和其他函数之间的数据交换。多数函数文件一般都有输入变量和输出变量,即自带参数,并见有返回结果,这样可以更好地把整个程序连为整体。
函数文件的第一行都是从function…开始,说明此文件为一个函数文件,其实质就是用户向MATLAB函数库里添加子函数G函数式。M文件中的变量都是局部变量,而非全局变量(除非使用特别形式声明),但是在函数运行期间失效,函数运行完毕后,其定义的变量将从工作区间中清除。对于这一点,读者要注意和脚本文件的区别。
【例4-17】 编写脚本文件,根据不同的theta用三角函数计算rho多次,然后根据theta和rho的值画图。
1 | % An M-file script to produce %Comment lines |
将以上文件保存在MATLAB搜索目录中,并命名为li4_7.m,然后在命令窗口中直接输入:
1 | >> li4_7 |
效果如图4-2所示。

图4-2 脚本文件运行结果
【例4-18】 编写一个函数文件,用于求解一元二次方程
,并分析根取值的不同情况。
分析:学习过初等数学的读者都知道,当a =0时,方程“退化”为一元一次方程,只有一个根x =-c /b ;当a ≠0时,则方程根的取值和方程求解主要取决于判别式
的值,当
= 0时,方程只有一个根
;当
>0时,方程有两个实根
,分别等于
;而当
<0时,方程有两个虚根,分别为
。
1 | function [x1,x2]=root(a,b,c,disc,realpart,imagpart) |
将文件保存在MATLAB的搜索目录中,默认文件名为root.m。在MATLAB命令窗口中输入:
1 | >> root |
4.2.2 脚本文件与函数文件间区别
下面总结脚本文件和函数文件间在各方面的联系与区别:
● 函数文件和脚本文件在编写格式、命名规则、调用方法等方面基本类似,不同的是函数文件被调用时,MATLAB会专门分配一个临时工作空间,称为函数工作空间(Function workspace),用于存储函数执行过程中的中间变量。当函数文件完成被调用的操作时,这个空间将被MATLAB“收回”,空间中的中间变量也随之被擦除。函数空间是独立的和临时的,MATLAB允许分配任意多个这样的空间给任意多个函数文件使用,这与脚本文件存在本质的区别。
● 如果在函数文件中调用脚本文件,那么脚本文件产生的所有变量都存储于此函数工作空间中,而非MATLAB基本工作空间。
● 不论是函数文件还是脚本文件,其中的变量都必须遵守有关变量的规定,函数文件中的变量除特别声明外,都是局部变量。
● 函数文件的函数名与文件名必须相同,否则MATLAB默认以保存的文件名为准来调用函数。
● 函数文件包含输入参数和输出参数,但在调用函数文件时,MATLAB只允许比文件中标定的个数少的输入/输出参数。
4.2.3 M文件结构
从M文件结构上看,函数文件只比脚本文件多了一行函数声明代码,M文件的基本结构是什么样的呢?首先,举一个简单的M文件的例子,该函数用于求向量或数组的平均数,代码为:
1 | function y=average(x) |
这个例子包含了典型的M函数的各个部分;函数定义行、H1行、帮助文档、函数主体以及注释。
- 函数定义行
函数定义行定义了函数的名称。函数首行以关键字function开头,并在首行中列出全部输入、输出参量以及函数名。函数名应置于等号右侧,虽没作特殊要求,但一般函数名与对应的M文件名相同。输出参量紧跟在function之后,常用方括号括起来(若仅有一个输出参量则无需方括号);输入参量紧跟在函数名之后,用圆括号括起来。如果函数有多个输入或输出参数,输入变量之间用“,”分隔,返回变量用“,”或空格分隔。与输入或输出参数相关的两个特殊变量是varargin和varargout,它们都是单元数组,分别获取输入和输出的各元素内容。两个参数对可变输入或输出参数特别有用。
- H1行
H1行是函数帮助文本的第一行,以%开头,用来概要说明该函数的功能。在MATLAB中用命令lookfor查找某个函数时,查找到的就是函数H1行及其相关信息。
- 函数帮助文本
在H1行之后而在函数体之前的说明文本就是函数的帮助文本。它可以有多行,每行均以%开头,用于比较详细地对该函数进行注释,说明函数的功能与用法、函数开发与修改的日期等。在MATLAB中用命令“help+函数名”查询帮助时,就会显示函数H1行与帮助文本的内容。
- 函数体和注释
函数体是函数的主要部分,是实现该函数功能、进行运算所有程序代码的执行语句。函数体中除了进行运算外,还包括函数调用与程序调用的必要注释。注释语句段每行用%引导,%后的内容不执行,只起注释作用。
此外,函数结构中一般都应有变量检测部分。如果输入或返回变量格式不正确,则应该给出相应的提示。输入和返回变量的实际个数分别用nargin和nargout两个MATLAB保留变量给出,只要进入函数,MATLAB就将自动生成这两个变量。nargin和nargout可以实现变量检测。
注意: 函数声明行和函数体是不可缺少的部分,是直接关系运算的“实用”行;而以%符号开头的所有声明、帮助和注释行都属于可以缺省的“辅助”行,即缺少了也不影响函数的运行,只是让函数的可读性和交互性大大降低。
4.3 函数类型
函数是MATLAB中的一个重要概念,函数的作用是使问题解决模块化,用户不需要知道内部步骤。函数只需要接受用户指定的输入、输出参数,返回结果。
MATLAB中的函数可以分为:主函数、子函数、匿名函数、私有函数、嵌套函数等。
4.3.1 主函数
主函数在结构上与其他函数没有一点区别,之所以叫它主函数,就是因为它在M文件上坐了第一把交椅,其他函数都排在它后面。按惯例它与M文件同名,在命令窗口或者其他函数中调用这个函数,都是引用M文件名。也有例外,当主函数与M文件不同名时,只能用文件名引用这个函数。M文件上的其他函数扮演着它的子函数角色。
4.3.2 子函数
一个M文件上排在主函数后面的都叫子函数,子函数的排列无规定顺序。子函数只能被同一个文件上的主函数或其他子函数调用。子函数与主函数没有形式上的区别,每个子函数都有自己的函数定义行。
【例4-19】 编写主函数,在主函数中调用子函数。
1 | % 任意输入两数,求两数分别为底和指数的幂和 |
注意: 一个M文件可以有任意多个子函数,但是只能有一个主函数。
4.3.3 匿名函数
匿名函数通常是很简单的函数。不像一般的M文件主函数要通过M文件编写,匿名函数是面向命令行代码的函数形式,它通常只由一句很简单的声明语句组成。
与一般M文件函数一样的是,匿名函数也可以接受多个输入和输出参数。使用匿名函数的优点是不需要维护一个M文件,而只需要一句非常简单的语句,就可以在命令窗口或M文件中调用函数,这对于那些函数内容非常简单的情况是很方便的。
创建匿名函数的标准格式为:
1 | fhandle=@(arglist) expression |
其中,expression通常为一个简单的MATLAB变量表达式,实现函数的功能,比如x+x.^2,sin(x).*cos(x)等。
arglist为此匿名函数的输入参数列表,它指定函数的输入参数列表,对于多个输入参数的情况,通常要用逗号分隔各个参数。
符号@是MATLAB中创建函数句柄的操作符,表示创建由输入参数列表arglist和表达式expression确定的函数句柄,并把这个函数句柄返回给变量fhandle,这样,以后就可以通过fhandle来调用定义好的这个函数。
下面的表达式创建了一个匿名函数,此函数计算某数的平方值:
1 | sqr=@(x)x.^2; |
例如,可以这样计算5的平方值:
1 | sqr(5) |
因为sqr是一个函数句柄,所以,可以将之作为参数传递给别的函数。下面的例子就将sqr作为参数传递给了积分函数quad进行计算:
1 | >> quad(sqr,0,1) |
匿名函数还可以有多个输入参数,比如,可以在命令行中输入:
1 | sumAxBy=@(x,y)(A*x+B*y) |
A,B是某已知矩阵,分别给x、y赋值5和7,调用此函数:
1 | sumAxBy(5, 7) |
匿名函数也可以不包含任何输入参数,但@后面的参数列表仍必须用空的括号表示,以表示后面表达式是函数,如:
1 | >> t=@()datestr(now); |
调用此匿名函数同样也要使用括号,如:
1 | >> t() |
否则,MATLAB仅仅识别此句柄,而不会调用此函数,如输入:
1 | t |
则显示:
1 | t = |
可以建立匿名函数数组,用元胞数组(Cell Array)来存储,如:
1 | >> A={@(x)x.^2,@(y)y+10,@(x,y)x.^2+y+10} |
得到的元胞数组的前两个函数句柄,可以使用常规的调用数组元素的方法,即A{1}和A{2},得到句柄后,就可以调用函数,如:
1 | >> A{1}(3)+A{2}(7) |
在函数定义中使用空格可增加函数的可读性,但是在元胞数组中定义的匿名函数体中使用空格却容易产生歧义。
为了使用元胞数组中的匿名函数有唯一的解释,可以:
(1)删除每个函数体的所有空格(参数中的不必要删除):
1 | A={@(x)x.^2,@(y)y+10,@(x,y)x.^2+y+10}; |
(2)对有空格的匿名函数用圆括号括起来:
1 | A={(@(x)x.^2),(@(y)y+10),(@(x,y)x.^2+y+10)}; |
(3)每个匿名函数赋值给一个变量,然后使用这些变量创建细胞数组:
1 | A1=@(x)x.^2;A2=@(y)y+10; |
像MATLAB的其他函数一样,匿名函数返回的输出的个数主要决定于调用此函数时等号左边的参数个数。比如,一个匿名函数getPersInfo返回一个人的信息,按顺序是:地址、家庭电话、工作电话和生日。仅仅获取地址,可以这样调用:
1 | address=getPersInfo(name); |
获取更多的信息,可以用更多的参数:
1 | [address, homePhone, busPhone]= getPersInfo(name); |
4.3.4 嵌套函数
MATLAB可以在任意一个函数体内定义一个或多个函数,它们称之为外部函数的嵌套函数。甚至可以在嵌套函数内定义嵌套函数。
嵌套函数也跟其他M文件函数一样,包含M文件的基本元素。当嵌套函数结束时必须用end表示结束。因为成对出现的关键字function和end使MATLAB容易辨别一个完整的函数,不会因为嵌套函数的出现而使函数范围发生混淆。
简单的嵌套函数的格式如下:
1 | function x = A(p1, p2) |
上述代码中的主函数是A,A内嵌套了函数B,函数B的声明行为function y=B(p3)。除了简单的单层嵌套方式,用户还可以在函数内部定义两种复杂的嵌套结构,分别为:多平行层嵌套。
(1)多平行层嵌套函数的格式为:
1 | function x = A(p1, p2) |
函数A仍然为主函数,但是其中嵌套了两个函数B与C,并且B与C是并列的平行关系。
(2)多层嵌套函数的格式为:
1 | function x = A(p1, p2) |
嵌套函数有以下调用规则:
① 一个函数可以调用自己的直接嵌套函数。本例中,函数A可以调用函数B和函数D,但是不能调用函数C或函数E,因为函数C和函数E不是函数A的直接嵌套函数。
② 嵌套在同一个函数体内的同一级别的嵌套函数可以相互调用。本例中,函数B可以调用函数D,同样,函数D可以调用函数B,但函数C和函数E不能互相调用,因为函数C和函数E不是同一个函数的嵌套函数(直接嵌套)。
③ 嵌套函数可以被任意低层的嵌套函数调用。如本例函数C可以调用函数B和函数D,但是不能调用函数E。
1 | function A(x,y) %主函数 |
每个函数的局部变量往往局限于本函数。例如,子函数不与主函数或其他子函数共享变量,因为每个函数都有独自的工作空间来存储各自的局部变量。嵌套函数虽然也有独自的工作空间,但是它可以访问嵌套它的外部函数的工作空间。例如,外部函数定义的一个变量可以被它的任意层次的嵌套函数读/写。同样,一个嵌套函数的变量可以被任何嵌套它的外部函数所读/写。
【例4-20】 实例说明嵌套函数变量作用域,嵌套函数访问外部函数变量。
1 | function varScope1 |
其中,变量x是外部函数varSpcope的局部变量,但是可由其嵌套函数nestfun2所读/写。
【例4-21】 实例说明嵌套函数变量作用域,外部函数访问嵌套函数变量。
1 | function varScope2 |
其中,x是嵌套函数nestfun2的局部变量,但也可由外部函数varScope2所读/写。
【例4-22】 实例说明嵌套函数变量作用域,外部函数不能访问不确定的嵌套函数变量。
1 | function varScope3 |
其中,外部函数varScope3不能访问变量x,因为嵌套函数nestfun1和nestfun2是同一级的嵌套函数,其工作空间是独立的,即nestfun1的x和nestfun2的x是不同的,当varScope3访问x时,MATLAB无法确定要访问哪一个,就会出错。
4.3.5 私有函数
私有函数实际上是另一种子函数,它是私有的,只有父M文件函数和脚本能存取它。它放在一个特别名字的子目录——private下。
(1)调用私有函数的函数放在一个M文件上,而这个M文件所在的目录下直接有一个名为private的子目录,被调用的私有函数就在此子目录下。这就形成了父对子的调用。
(2)调用私有函数的脚本,它本身要被一个M文件函数调用,而M文件函数也可以访问这个私有函数。当然,私有函数所在的private子目录,应该直接在M文件所在的目录下。
(3)假如私有函数名为myprivfun,为了得到私有函数的帮助信息,需要输入命令:
1 | help private/myprivfun |
4.4 矩阵运算
二维数组和矩阵在外观形状和数据结构上没有根本的区别,但是矩阵作为一种数学变换,其运算有着严格的数学规则。
4.4.1 矩阵的加、减
矩阵的加、减运算定义为相应元素的加减。对M ×N 矩阵A 、B ,其和(差)C =A ±B ,C 也为M ×N 矩阵,且
。
矩阵的加、减运算要求参与运算的矩阵具有相同的大小,或者其中之一为标量,例如M ×N 矩阵A 与标量x 的和(差)C =(A ±x ),C 为M ×N 矩阵,且
。
【例4-23】 对所给定的矩阵进行加与减运算。
1 | >> clear all; |
注意:
(1)矩阵加法减运算要求参与运算的矩阵具有相同的大小,即行数、列数相同,否则MATLAB会拒绝运算,并给出运行错误信息。
(2)3个及3个以上矩阵的加、减运算适用结合律,如A+B+C=(A+B)+C,所有参与运算的矩阵,除标量外,都应具有相同的大小,否则MATLAB给出错误信息。
4.4.2 矩阵的乘法运算
M ×K 阶矩阵A 与K ×M 阶矩阵B 的乘积C 为一个M ×N 阶矩阵,且C 中的任一元素cmn 的值为A 的第m 行和B 的第n 列对应的元素乘积的和,即

N 是A 的列数,也是B 的行数,也称为两相乘矩阵的内阶数,两矩阵相乘的必要条件是它们的内阶数相等。一般来说矩阵乘法不具有交换性,即A ×B ≠B ×A 。对于标量x ,矩阵的数相乘是可交换的,即A ×x =x ×A 。
【例4-24】 对已创建矩阵进行乘法运算。
1 | >> A=[1 2 1;-1 4 5]; |
注意:
(1)矩阵乘法要求被乘矩阵的列数与乘矩阵的行数相等。
(2)3个及3个以上矩阵的乘法运算适用结合律,如A*B*C=(A*B)*C。
4.4.3 矩阵除法运算
在MATLAB中,矩阵除法有两种运算符“\和“/”,分别表示矩阵运算左除和右除。如果A或B为非奇异矩阵,则
。其中,
是矩阵A的逆。MATLAB提供了用于求矩阵的逆矩阵的函数inv,因此可以用inv(A)求矩阵A的逆矩阵。一般情况下,
是方程
的解,而
是方程
的解,两种运算的结果不相等。
【例4-25】 对同维数矩阵实现除法运算。
1 | >> A=[1 0 1;0 1 1;1 1 0]; |
【例4-26】 不同维数矩阵相除。
1 | >> A=[1 0 1;0 1 1;1 1 0]; |
4.4.4 矩阵幂运算
矩阵的幂与矩阵乘法有着紧密联系。MATLAB中,M阶方阵A的n次幂写为C=A^n(n为标量),即

请注意,参与幂运算的矩阵必须是方阵。MATLAB还允许将矩阵作为指数,标量作为底数进行求幂运算,表达式为C=x.^A,其中x为一标量,A、C均为M×N阶矩阵,表示数学中的
。
注意: 幂运算的底数和指数不能同时为矩阵,否则将显示出错信息。
【例4-27】 对给定矩阵进行幂运算。
1 | >> A=[1 8;5 9]; |
4.4.5 矩阵的按位运算
矩阵的按位运算定义为矩阵各元素的运算。矩阵的按位运算符前一般有“.”作为前导符,表4-1列出了矩阵的几种按位运算符。
表4-1 矩阵的按位运算符

按位乘(.*)、按位右除(./)、按位左除(.\的两个操作数是大小相同的数值数组,或者其中之一为标量。当两个操作数之一为标量时,等价于将该标量操作数扩展为与另一个操作数大小相同的数组。对按位右除(./)和按位左除(.\的区别,首先考虑标量的左除和右除的区别。对标量a、b,
,根据按位运算的意义,不难想象按位右除(./)和按位左除(.\的区别。
【例4-28】 矩阵的按位运算示例演示。
1 | >> A=[1 2;0 1];B=[2 1;3 4];a=2; |
【例4-29】 按位运算对代码的优化效果。
1 | >> tic,A.*B, toc %矩阵按位乘,以及测试时间 |
从以上代码可看出,按位运算可以简化代码,减轻用户的编程负担。除此之外,按位运算还有另外两个好处:
(1)MATLAB在实现按位运算时,对多重循环进行了优化处理,因此能够大大提高代码的执行效率;
(2)MATLAB对按位运算的出错处理有比较周全的考虑。
事实上,MATLAB对按位运算的支持是非常广泛的,除前面介绍的加、减、乘、除、幂运算,还有比较运算等。另外,MATLAB提供的很多数值计算函数也都支持按位运算。如sin、log等。特别是MATLAB对逻辑运算、关系运算有特别的按位运算支持,这对向量化是一个非常有利的条件。
4.5 矩阵特征量
线性代数中有一些矩阵特征量用于刻画矩阵某方面的性质,如行列式、范数、条件数、秩等。
4.5.1 矩阵的行列式
n阶矩阵A的行列式不等于0时,称矩阵A为非奇异,否则A为奇异。当线性方程系数矩阵非奇异,则线性方程有唯一解。对n阶方阵A,MATLAB中由函数det(A)得到行列式|A|。
【例4-30】 求已创建矩阵的行列式。
1 | >> A=magic(4) |
注意: 由以上结果可看出,只能求方阵的行列式,否则系统将会报错。
4.5.2 矩阵的逆
对非奇异矩阵A,其逆矩阵
是满足以下条件矩阵:AA-1 = A-1 A=I(I为单位矩阵)。如果线性方程组的系数矩阵A非奇异,则|A|≠0,则线性方程组有唯一解,该唯一解可由
得到,其中
为A的逆矩阵。
MATLAB中提供了inv(A)求A的逆矩阵
。
【例4-31】 已知矩阵A=[1 2 3;1 4 9;1 8 27],b=[12 16 8]‘,求
,并验证AA-1 = A-1 A=I,求Ax=b的解。
1 | >> A=[1 2 3;1 4 9;1 8 27]; %系数矩阵 |
注意: 当A为奇异时,inv(A)依然能够被执行,MATLAB只会给出警告信息,例如,求矩阵B=[1 2 3;1 2 3;1 2 3]的逆:
1 | >> B=[1 2 3;1 2 3;1 2 3]; |
4.5.3 矩阵的范数
设A 为n 阶方阵,
中已定义了向量范数
,则
称为矩阵A 的范数或模,记为
。

矩阵A 的任一特征值的绝对值不超过A 的范数
。
矩阵A 的诸特征值的最大绝对值称为A 的谱半径,记为:

MATLAB提供了以下求几种矩阵范数的函数。
norm(A)或norm(A,2):计算矩阵A的2-范数。
norm(A,1):计算矩阵A的1-范数。
norm(A,inf):计算矩阵A的∞(无穷)-范数
norm(A,’fro’):计算矩阵A的F-范数。
【例4-32】 对已创建的矩阵求其1-范数、2-范数、无穷范数。
1 | >> A=[2 4 6;1 3 5;0 2 9]; |
4.5.4 矩阵条件数
在线性代数中,描述线性方程A x =b 的解对b 中的误差或不确定性的敏感度的度量就是矩阵A 的条件数,其对应的数学定义为:

根据基础的数学知识,矩阵的条件数总是大于等于1。其中,正交矩阵的条件数为1,奇异矩阵的条件数为∞,而病态矩阵的条件数则比较大。
依据条件数,方程解的相对误差可以由以下不等式来估计:

在MATLAB中提供了cond(X)用于求取矩阵X的条件数。
【例4-33】 对所创建矩阵求其条件数。
1 | >> A=magic(5); %创建5阶魔方矩阵 |
4.5.5 矩阵的特征值及特征向量
关于矩阵特征值和特征向量,对应的定义如下:对阶方阵A ,λ 为标量,v 为非零的n 维向量,且满足Av =λv ,则λ 称为方阵A 的特征值,v 为方阵A 相对于特征值λ 的特征向量。方阵A 特征值的全体称为A 的谱,记为σ (A )。
在MATLAB中提供了eig函数用于求矩阵特征值和特征向量,其调用格式为:
d = eig(A):其中D为n个特征值(可能重复)组成的向量。
[V,D] = eig(A):其中D为n阶对角矩阵,对角线上的元素为A的特征值,v为n×n矩阵,其第i列为特征值D(i,i)对应的特征向量。D、V、A满足
。
eig函数除了上述这两种调用格式外还有一些不常用的使用方式,例如可用于求广义特征值和特征向量的调用方式。关于这些内容,如读者想要了解可参考MATLAB的联机帮助文档。
【例4-34】 求3阶范德蒙矩阵A的特征值及特征向量。
1 | >> A=vander(1:3) %3阶范德蒙矩阵 |
此外,MATLAB还提供了另一个函数eigs求矩阵的特征值,eigs可以只求计算矩阵的n个最大或最小的特征值及对应的特征向量。这对某些应用是很方便的,例如对一个规模非常大的矩阵求n个最大的特征值。
对该问题,一种可行的方案是用eig求出所有特征值,再挑选出n个最大的,但是明显这种方案的效率是非常低的,直接利用eigs则是一种高效的方法。
【例4-35】 计算5阶魔方矩阵的最大3个特征值。
1 | >> A=magic(5) |
说明: 从上面的结果中可看出,eigs函数得到的结果与eig计算得到的3个最大的特征值相等。
4.5.6 标准正交基
一个矩阵通过其每一列向量的线性运算,可以派生出一个向量空间,这称之为矩阵的线性空间。每一个矩阵的线性空间下所有的向量,实际上只需通过一组基向量的线性运算就可以产生。这样的最少个数的一组基向量称为该空间的基,如果这些向量正好长度为1,彼此正交,则称为标准正交基。
在MATLAB中提供了orth函数可以产生矩阵A的线性空间的一组标准正交基,即如果B=orth(A),则B的列向量组成了矩阵A的线性空间的一组标准正交基,于是B’*B=eye(rank(A))。
【例4-36】 求创建矩阵的标准正交基。
1 | >> A=rand(3,4) %创建3×4阶随机分布矩阵 |
4.6 矩阵的分解
矩阵分解是矩阵理论的重要内容,在信号处理、自动控制等众多领域中有非常广泛的应用。矩阵分解通过将复杂矩阵分解成形式简单或具有良好数学性质的矩阵(统称为简单矩阵)的组合,便于理论分析或数值计算。
通常矩阵分解将复杂的矩阵分解为几个简单矩阵的乘积。在很多算法研究中,围绕算法的稳定性和快速性等,各种矩阵分解方法相继被提出,如特征分解(EVD)、Schur分解、Cholesky分解、LU分解、QR分解、SVD分解等。
4.6.1 特征分解
对n 阶方阵A ,其特征值为
,对应的特征向量为
,令

则有AV =VA 。其中
为A 的特征值-特征向量对。如果
线性无关,则V 可逆,因此有式
。此式称为矩阵A 的特征分解(EVD),对角矩阵V 称为A 的标准型。
在MATLAB中提供了eig用于矩阵的特征分解。
【例4-37】 对创建的4阶魔方矩阵进行特征分解。
1 | >> A=magic(4) |
4.6.2 Cholesky分解
Cholesky分解是专门针对对称正定矩阵的分解。设
是对称正定矩阵,
称为矩阵A 的Cholesky分解,其中
是一个具有正的对角元素的上三角矩阵,即

这种分解是唯一存在的。
在MATLAB中,提供了chol函数实现这种分解,其调用格式如下:
R = chol(A):返回Cholesky分解因子R。
[R,p] = chol(A):该命令不产生任何错误信息,若A为正定矩阵,则p=0,R与上相同;若A非正定,则p为正整数,R是有序的上三角矩阵。
【例4-38】 对已创建的矩阵实现Cholesky分解。
1 | >> n = 5; |
说明: 从上面的结果可看出,修改后的矩阵A为非正定矩阵。
4.6.3 LU分解
LU分解也称为三角分解。它的目的是将一个矩阵分解成一个下三角矩阵L 和一个上三角矩阵U 的乘积,即A =LU 。LU分解是用Gaussian主元消去进行的。其中L 和U 矩阵可以分别写为:

在MATLAB中,提供了lu函数实现LU分解。其调用格式如下:
[L,U] = lu(A):把矩阵A分解为下三角矩阵的置换矩阵L和上三角矩阵U,满足A=L×U。
[L,U,P] = lu(A):分解结果中,L为一个下三角矩阵,U为一个上三角矩阵,P为一个置换矩阵,满足L×U=P×A。
【例4-39】 对创建的矩阵实现LU分解。
1 | >> A=rand(3,4) |
4.6.4 QR分解
QR分解在解决最小二乘问题、特征值计算等方面有十分重要的应用。设A 为M ×N 矩阵,如果存在M ×N 酉矩阵Q (即
)和M ×N 阶梯形矩阵R ,使A =QR ,则称为A 的QR分解。
在MATLAB中提供了qr函数用于实现矩阵的QR分解。其调用格式为:
[Q,R] = qr(A):返回正交矩阵Q和上三角矩阵R,Q和R满足A=QR。若A为m×n矩阵,则Q为m×m矩阵,R为m×n矩阵。
[Q,R] = qr(A,0):产生矩阵A的“经济型”分解,即若A为m×n矩阵,且m>n,则返回Q的前n列,R为n×n矩阵;否则该命令等价于[Q,R]=qr(A)。
[Q,R,E] = qr(A):求得正交矩阵Q和上三角矩阵R,E为置换矩阵,使得R的对角线元素按绝对值大小降序排列,满足AE=QR。
[Q,R,E] = qr(A,0):产生矩阵A的“经济型”分解,E为置换矩阵,使得R的对角线元素按绝对值大小降序排列,且A(:,E)=Q*R。
R = qr(A):对稀疏矩阵A进行分解中产生一个上三角矩阵R,R为A’A的Cholesky分解因子,即满足R’R=A’A。
【例4-40】 对所创建的矩阵实现QR分解。
1 | >> A=[2 4 6 8;1 3 5 7;0 2 9 11]; |
4.6.5 SVD分解
设A 为M ×N 矩阵,
特征值为
,则称
为矩阵A 的奇异值,r 为A 的秩。存在M 阶酉矩阵U 和N 阶酉矩阵V ,使得
,其中
,上式称为A 的SVD分解(奇异值分解)。
在MATLAB中提供了svd函数用于矩阵SVD分解。其调用格式为:
s = svd(X):返回矩阵A的奇异值向量s。
[U,S,V] = svd(X):返回矩阵A奇异值分解因子U、S、V。
[U,S,V] = svd(X,0)或[U,S,V]=svd(X,’econ’):返回m×n矩阵A的“经济型”奇异值分解。若n>m,则只计算出矩阵U的前n 列,矩阵S为n×n矩阵,否则同[U,S,V]=svd(A)。
矩阵的奇异值大小通常决定矩阵的形态,如果矩阵的奇异值变化特别大,则矩阵中某个元素有一个很小的变化就会严重影响到原矩阵的参数,此类矩阵又称为病态矩阵。
【例4-41】 对创建的矩阵做奇异值分解。
1 | >> A=[1 5 9;2 6 10;3 7 11;4 8 12]; |
很多情形下,线性方程组
没有解,因此计算其最小二乘解,即使
最小的x 。设A 的SVD分解为
(0 表示0 矩阵),由于2-范数具有酉不便性,因此
。由此
的最小二乘解即为
的最小二乘解。
令
的最小二乘解为
,所以原方程组的最小二乘解为
。
【例4-42】 利用SVD求线性方程组
的最小二乘解。
1 | >> A=[1 2;2 1;2 4]; |
4.7 矩阵函数
矩阵函数是以矩阵为参变量的函数。虽然MATLAB中有很多函数都支持矩阵作为输入参数,但是这其中大部分是对矩阵进行按位运算,如sqrt、exp、log等都是作用在矩阵的各元素上。在此介绍的矩阵函数与以上函数不同,如,矩阵指数函数eA 定义为
,而不是
。
- sqrtm函数
在MATLAB提供了sqrtm函数用于计算矩阵A的平方根
。其调用格式如下:
X = sqrtm(A):返回矩阵A的平方根X。
[X, resnorm] = sqrtm(A):如果A矩阵开平方出现剩余值,则不显示任何警告信息,并返回其剩余值resnorm。
[X, alpha, condest] = sqrtm(A):返回一个稳定因子alpha和平方根矩阵X的条件数condest。
- logm函数
在MATLAB中提供了logm函数用于计算矩阵A的自然对数矩阵。该函数输入参数的条件与输出结果间的关系和函数sqrtm完全一致。
- expm函数
在MATLAB中提供了expm函数用于求矩阵指数eA 。如,对上面计算所得到的A的自然对数矩阵L,求其矩阵指数。
【例4-43】 对创建的矩阵,计算各种函数的数值,并比较各种函数的数值。
1 | >> A=magic(4) |
用户除了可以使用MATLAB内建的函数之外,还可以用MATLAB提供的funm函数,创建自定义的矩阵函数。
fun函数以矩阵和自定义函数句柄作为输入参数,其调用格式为:
1 | F = funm(A,fun) |
其中,fun为函数句柄;option用于计算过程的控制、结果显示等,这里不做具体介绍;exitflag保存了函数结束信息,如果exitflag=0,则函数计算成功;如果exitflag=1,则表明计算过程不收敛,但结果也有可能是正确的。
函数fun必须遵循一定的约定:
- fun(除log之外)必须具有泰勒展开式,且收敛域为|x|<正无穷;
- f=fun(x,k)接受向量x和整数k为输入参数,返回值f是与x大小相同的向量,f(i)为x(i)处的k阶导数。
对于一些特殊函数,用户可以直接将该函数句柄作为输入参数,表4-2列出了这些特殊函数及其调用格式。
表4-2 funm特殊函数

【例4-44】 利用funm计算自定义矩阵函数。
1 | >> A=pascal(5) |
可以看到以上两种计算方式获得的结果是相同的。
第5章 数据分析
根据大量数据提取某些目标信息(称为数据分析、数据挖掘等)是一类非常重要的实际问题。
5.1 数据排序
数据序列的排序分析是实际中最常用的一类数据分析、数据处理方法。
5.1.1 最大(小)值
在MATLAB中提供了max、min函数分别用于求数值序列的最大值、最小值。max函数的调用格式为:
C = max(A):如果A为向量,则返回A的最大值;如果A为N维数组,则沿A的第一个长度不为1的维求最大值,返回N-1维数组C;特别是,当N=2时,则返回一个行向量,行向量的元素对应A每列的最大值。
C = max(A,B):返回与A、B大小相同的数组,数组元素取A、B对应元素的较大者。
C = max(A,[],dim):沿A第dim维求最大值,如max(A,[],1)沿A列向取最大值。
[C,I] = max(…):不仅返回最大值,而且返回最大值对应的索引;如果最大值有重复,则返回第一个最大值的索引。
min函数的调用格式与max函数调用格式类似,只是其用于返回最小值。
【例5-1】 求数值序列的最大(小)值。
1 | >> X = [2 8 4; 7 3 9]; |
对于复数矩阵,max、min在比较数值大小时,仅考虑模值,而不会分开比较实部与虚部的值。
【例5-2】 已知复数的矩阵与向量,计算各种最大值与最小值。
1 | >> A=((1:5)+(0:2:8)*i)' |
5.1.2 中位数
中位数即依照排序关系居于中间位置的数,需要注意的是,当数据序列含偶数个元素时,中位数是中间两个数的平均数。在MATLAB中提供了median函数用于求数据序列中位数,其调用格式为:
median(X):返回向量X的算术中位数。
median (A):返回一个行向量,其第i个元素是矩阵A的第i列的算术中位数。
median (A, dim):当dim为1时,该函数等同于median (A);当dim为2时,返回一个列向量,其第i个元素是A的第i行的算术中位数。
【例5-3】 求向量与矩阵的中位数。
1 | >> X=[1 8 9 -3 7 12 0 -10 25]; %创建向量 |
注意: median不能返回中位数的索引值。
5.1.3 分位数
对数值序列X,其中
分位数是满足
的q,其中count(X)为数值序列的长度,count(X≤q)是X中不大于q的元素个数。通常上式的等号不能成立,可以定义p分位数是使
最小的q。
在MATLAB中提供了quantile函数用于求数值序列的分位数。其调用格式为:
1 | Y = quantile(X,p) |
其中X为数值序列,p可以为向量,用法与max类似。
【例5-4】 已知数据序列X=[-500,-499,…,500],求X的0、1/4、1/2、3/4、1分位数。
1 | >> clear |
注意: quantile将NaN视为缺失数据,在计算分位数时会忽略这些缺失数据。
5.1.4 排序
数据的排序是理论和实际中经常遇到的问题。MATLAB提供sort和sortrow两个函数用于数据的排序操作。这两个函数不仅可以用于数值数据的排序,而且对字符串数据也可以进行排序。
- sort函数
sort对数组元素按升序或降序进行排列,数组元素的类型可以是整型、浮点型、逻辑类型等数值类型,也可以是字符、字符串。函数sort对字符或字符串数组的排列依据ASCII表进行;对复数数值类型,sort函数首先比较各元素的模值,在模值相同的情况下,考虑(-pi,pi)上的相位值;对于NaN数据,sort函数将其排在最后,不管是按升序还是降序排列。
sort函数的调用格式为:
B = sort(A):其中A为M×N×…×P数组,函数沿第一个长度非1的维进行升序排列。例如当A为M×1(M>1)向量时,函数沿第一维进行升序排列;当A为1×N(N>1),第一维长度为1,因此函数沿第二维进行升序排列;当A为M×N(M,N>1),函数沿第一维即列向排序。
B = sort(A,dim):其中A的M×N×…×P数组,函数沿第dim维进行升序排列。
B = sort(…,mode):mode为排序模式,可以选择升序‘ascend’或降序‘descend’,默认情况下为升序排列。
[B,IX] = sort(A,…):函数不仅返回排序后的数组,而且返回B在原来数组中相应的索引值。
【例5-5】 对数值矩阵进行排序。
1 | >> A = [ 3 7 5; 6 8 3; 0 4 2 ]; |
【例5-6】 对复数矩阵进行排序。
1 | >> A=magic(3)+magic(3)*i |
- sortrows函数
sortrows用于将每一行作为一个整体,沿列向进行排序。sortrows函数的调用格式为:
B = sortrows(A):将A的每一行作为整体沿列向进行升序排列,如果依据第一列,A具有相同的两行,那么再依据第二列对这两行进行比较,依次类推。
值得注意的是,这里的A只能是列向量或矩阵。
B = sortrows(A,column):依据第column列对A进行升序排列,column可以为向量,如果依据是column列,A的某两行相同,那么sortrows不改变原有的次序。
[B,index] = sortrows(A,…):返回排序的索引值index,index为列向量。当A为列向量时,B=A(index);当A为矩阵时,B=A(index,:)。
【例5-7】 利用sortrows函数对所创建矩阵进行排序。
1 | >> A=floor(gallery('uniformdata',[6 7],0)*100); |
5.2 求和与求积
本节主要介绍数据序列的求和、求积、求累和与求累积运算。
5.2.1 求和
在MATLAB中提供了sum函数用于对数组进行求和。其调用格式为:
B = sum(A):沿数组A第一个长度大于1的维进行求和运算。如果A为向量,则返回该向量的和;如果A为矩阵,则沿列方向求和,返回一个行向量,行向量各元素对应A每一列的和。
B = sum(A,dim):指定沿数组A第dim维求和。
实际上MATLAB很多函数的调用格式都与此类似,如前面提到的min、max、median等,称此类函数为数组支持函数。
另外,sum函数还提供了一个选项,用于限定运算结果的类型,如sum(…,’double’)限定结果为double型,即使输入数据为整型,返回结果也是double型。
【例5-8】 求向量及矩阵的和。
1 | >> X=[1 3 8 9 11 0 5]; |
5.2.2 求积
在MATLAB中提供了prod函数用对数据序列求积,是一种数组支持函数。其调用格式为:
1 | B = prod(A) |
【例5-9】 对矩阵进行求积运算。
1 | >> A=magic(3) |
5.2.3 求累加和与累乘积
设
为一个向量,V 、W 是与U 等长的另外两个向量,并且

称V 为U 的累加和向量,W 为U 的累乘积向量。在MATLAB中,使用cumsum和cumprod函数能方便地求得向量和矩阵元素的累加和与累乘积向量。它们的调用格式为:
cumsum(X):返回向量X累加和向量。
cumsum(A):返回一个矩阵,其第i列是矩阵A的第i列的累加和向量。
cumsum(A, dim):当dim为1时,该函数等同于comsum(A);当dim为2时,返回一个矩阵,其第i行是矩阵A的第i行的累加和向量。
cumprod(X):返回向量X累乘积向量。
cumprod (A):返回一个矩阵,其第i列是矩阵A的第i列的累乘积向量。
cumprod (A, dim):当dim为1时,该函数等同于comprod (A);当dim为2时,返回一个矩阵,其第i行是矩阵A的第i行的累乘积向量。
【例5-10】 对矩阵进行累加和与累乘积运算。
1 | >> A = [1 2 3; 4 5 6]; |
注意: cumsum、cumprod不能识别NaN数据,读者使用cumsum、cumprod时需要首先去掉数据序列中的NaN数据。
5.3 均值方差与相关系数
5.3.1 均值
对于数据序列
,其均值为

在MATLAB中提供了mean函数用于求数据序列的均值。其调用格式为:
mean(X):返回向量X的算术平均值。
mean(A):返回一个行向量,其第i个元素是矩阵A的第i列的算术平均值。
mean(A, dim):当dim为1时,该函数等同于mean(A);当dim为2时,返回一个列向量,其第i个元素是A的第i行的算术平均值。
【例5-11】 求矩阵的均值。
1 | >> A = [1 2 3; 3 3 6; 4 6 8; 4 7 7]; |
5.3.2 方差
对于具有N 个元素的数据序列
,标准方差的计算公式为:

在MATLAB中提供了std函数用于求数据序列的方差。其调用格式为:
s = std(X):求数据序列X的方差。
s = std(X,flag):flag取值为0或1,当flag=0时,按数据序列S1所列公式计算方差;当flag=1时,按数据序列S2所列公式计算方差。默认flag=0。
s = std(X,flag,dim):其中,dim可以取1或2。当dim=1时,求各列元素的标准方差;当dim=2时,则求各行元素的标准方差,默认dim=1。
【例5-12】 求矩阵的方差。
1 | >> A=[1 5 9;3 7 5;2 8 11]; |
注意: mean、std不能识别NaN数据,读者使用mean、std时应该首先去掉数据序列中的NaN数据。
5.3.3 相关与协方差
对于数据序列X 和Y ,自相关函数定义为
;互相关函数定义为
;协方差定义为
;互协方差定义为
。
在MATLAB中提供了corr函数用于相关分析,提供了cov函数用于协方差分析。它们的调用格式为:
cov(X):X为n×p矩阵,返回值R为p×p矩阵。
cov(X,Y):X、Y分别为n×p1、n×p2矩阵,返回值R为p1×p2矩阵。
RHO = corr(X):如果X为向量,则返回X的方差;如果为矩阵,则Cov(x)=
。
RHO = corr(X,Y):X、Y为长度相等的向量,cov(X,Y)=cov([X(:),Y(:)])。
【例5-13】 数据相关分析、协方差分析。
1 | >> A = [-1 1 2 ; -2 3 1 ; 4 0 3]; |
注意: corr、cov不能识别NaN数据,读者使用corr、cov时应该首先去掉数据序列中的NaN数据。
5.3.4 相关系数
对于两组数据序列
,可以由下式计算出两组数据的相关系数:

在MATLAB中提供了corrcoef函数用于求数据的相关系数矩阵。其调用格式为:
R = corrcoef(X):返回从矩阵X形成的一个相关系数矩阵。此相关系数矩阵的大小与矩阵X一样。它把矩阵X的每列作为一个变量,然后求它们的相关系数。
R = corrcoef(x,y):在这里,x,y为向量,它们的作用与corrcoef([x,y])中一样。
【例5-14】 求矩阵的相关系数。
1 | >> x = randn(30,4); |
5.4 数据预处理
数据在传输、处理过程中可能引入一些随机错误,从而使数据出现部分缺失或异常等现象,这对后续的数据分析可能存在不利的影响,因此需要对待分析的数据序列作相应的数据预处理。针对不同的实际问题,数据预处理方法都有所不同。
5.4.1 缺失数据处理
缺失数据的处理是一个非常困难的问题,随具体问题的不同,处理方法也各异。为了便于数据分析和处理,MATLAB将缺失数据用NaN表示。NaN是MATLAB的一个特殊数据,即Not a Number,MATLAB规定,NaN参与的数学运算结果均为NaN。例如,向量x=[1 2 NaN 4],对其求和、积,结果均为NaN。
缺失数据处理的一般方法是去除缺失数据,表5-1列出去除缺失数据的MATLAB代码。
表5-1 缺失数据处理

有一个问题值得注意,即不能利用“ ”运算符判断是否为NaN数据,而只能用函数isnan。例如,NaN NaN的运算结果为逻辑0,在MATLAB命令窗口中输入:
1 | >> NaN==NaN |
5.4.2 异常值
数据传输、处理的错误可能使数据发生异常。
对异常数据可以采用与缺失数据相似的处理方法,即去除异常数据。至于异常数据的标准,将视具体问题而定,实际中经常使用一种标准是:与平均值的偏差大于3倍标准差。
【例5-15】 异常数据处理。
1 | %对一个1×100的零均值高斯分布随机向量施加干扰产生异常数据 |
![]() |
![]() |
| 图5-1 异常数据处理、异常数据 | 图5-2 正常数据 |
5.5 数据插值
数据分析在各个领域中有着广泛的应用,尤其是在数学、物理等科学领域和工程领域的实际应用中,会经常遇到进行数据分析的情况。例如,在工程领域根据有限的已知数据对未知数据进行推测时经常需要用到数据插值和拟合的方法。
插值(Interpolation)是指在所给定基准数据的情况下,研究如何平滑地估算出基准数据之间其他点的函数数值。每当其他点上函数数值获取的代价比较高时,插值就会发挥作用。
在MATLAB中提供了多种插值函数,这些函数在获得数据的平滑度、时间复杂度和空间复杂度方面有着完全不同的性能。
在本节中,将主要介绍一维插值命令、二维插值命令、高维插值等MATLAB内置函数。同时,还将根据不同的插值方法自行编写M文件,完成不同的插值运算,如Lagrange插值、Newton插值。
5.5.1 一维插值
被插值函数为一元函数f(x)时,插值过程称为一维插值,图5-3为一维插值的简单示意图。

图5-3 一维插值示意图
在MATLAB中提供了interp1函数用于实现一维插值,该函数利用多项式插值函数,将被插值函数近似为多项式函数(包括分段多项式函数),其调用格式为:
yi = interp1(x,Y,xi,method):对数据向量x和Y依选用的方法构造插值函数,并计算xi处的函数值,返回给yi。method指定插值方法,其选项如下:
‘nearest’——最邻近插值。
‘linear’——线性插值,为默认设置。
‘cubic’——三次插值。
‘spline’——三次样条插值。
‘v5cubic’——三次多项式插值。
这几种方法在速度、平滑性、内存使用方面有所区别,在使用时可以根据实际需要进行选择,包括:
- 最邻近法插值是最快的方法,但是,利用它得到的结果平滑性最差。
- 线性插值要比最邻近插值占用更多的内存,运行时间略长。与最邻近法不同,它生成的结果是连续的,但在顶点处会有坡度变化。
- 三次插值需要更多内存,而且运行时间比最邻近法和线性插值要长。但是,使用此方法时,插值数据及其导数都是连续的。
- 三次样条插值的运行时间相对来说最长,内存消耗比三次插值略少。它生成的结果平滑性最好。但是,如果输入数据不很均匀,可能会得到意想不到的结果。
所有的插值方法要求X的元素是单调的,可不等距。当x的元素是单调、等距时,使用“linear”、“nearest”、“cubic”或“spline”选项可快速得到插值结果。如果Y是矩阵,那么Y的各列将以x为公共的横坐标,计算多个(等于Y的列数,size(Y,2))插值函数,输出值YI将是xi维数×size(Y,2)矩阵。超出范围[Xmin, Xmax]的xi值,YI将返回NaN。
yi=interp1(Y,xi):这里,x和method均为默认设置,即x=1:N,其中N=size(Y);method=linear。
另外,已知数据点不等间距分布时,interp1q函数比interp1函数执行速度快,因为前者不检查已知数据点是否等间距,不过interp1q函数要求x必须单调递增。
【例5-16】 使用不同方法对sin函数进行插值。
1 | >> x = 0:10; |
运行程序,效果如图5-4所示。

图5-4 不同的一维插值效果
【例5-17】 比较对同一数据插值interp1与interp1q函数速度。
1 | >> x = (0:10)'; |
运行程序,输出如下:
1 | Elapsed time is 0.058357 seconds. |
插值运算可以分为内插值和外插值两种:
(1)只对已知数据点集内部的点进行插值运算称为内插,内插可以根据已知数据点的分布,构建能够代表分布特性的函数关系,比较准确地估计插值点上的函数值。
(2)当插值点落在已知数据集外部时的插值被称为外插,要估计外插函数值是很难的。
MATLAB中没有指定外插值算法,对已知数据集外部点上的函数值都返回NaN。
interp1函数中可以通过添加’extrap’参数,指明插值算法也用于外插运算。另外还可以直接对数据集外的函数点赋值为extraval,一般赋值为NaN(MATLAB默认)或者0。
【例5-18】 外插运算方法与误差。
1 | >> x = 0:10; |
运行程序,输出如下,效果如图5-5所示。


图5-5 sin函数外插效果图
由图5-5可以看出,不管用哪种插值方法,当插值点位于已知数据集合外时,插值运算对该处函数值的估计都很可能与实际函数值有很大的偏差。
【例5-19】 利用插值法预测人口数量。
某城市在1900年到1990年中,每隔10年统计该城市的人口数量,得到结果为:
1 | 75.995 91.972 105.711 123.203 131.669 150.697 179.323 203.212 226.505 249.633 |
上面的数据单位为百万,以上面的数据为基础,对没有进行人口统计的年限的人口数量进行预测,分别使用不同的插值法。
1 | >> t = 1900:10:1990; |

图5-6 不同插值方法得到的结果

图5-7 使用“Nearest”方法得到的结果
5.5.2 二维插值
被插值函数为二元函数时,插值过程为二维插值,依次类推,有三维插值、高维插值。图5-8为二维插值的简单示意图。

图5-8 二维插值示意图
在MATLAB中提供了interp2函数用于实现二维插值。其调用格式为:
1 | ZI = interp2(X,Y,Z,XI,YI) |
式中,X,Y,Z为样本数据矩阵,XI,YI,ZI为插值数据矩阵,ntimes为在元素间插入扩充数据的回归次数,method为选取插值的方法。插值的方法有以下4种:
(1)邻近插值,method=nearest:将插值点周围的4个数据点中离该插值点最近的数据点函数值作为该插值点的函数值估计。
(2)双线性插值,method=linear:将插值点周围4个数据点函数值的线性组合作为插值点的函数值估计,双线性插值是interp2的默认选项。
(3)样条插值,method=spline:该方法是实际过程中经常使用的插值方法,得到的曲面光滑,并且具有很高的效率。
(4)立方插值,method=cublic:该方法利用插值点周围的16个数据点,相对于前两种方法,双立方插值得到的曲面更为光滑,但是也消耗更多的内存和时间。
注意: [X,Y]、[XI,YI]应该是单调的网格,可以是等距的或是不等距的,如果网格是等距的,那么可以在method字符串前加“*”以提高运算效率,如“*spline”。
【例5-20】 设人们对平板上的温度分布估计感兴趣,给定的温度值取自平板表面均匀分布的格栅。
采集了下列的数据:
1 | >> width=1:5; %定义平板宽度(例如x方向) |
矩阵temps表示整个平板的温度分布。temps的列与下标depth或y维相联系,行与下标width或x维相联系。为了估计在中间点的温度,必须对它们进行辨识。其实现的MATLAB程序代码如下:
1 | >> wi=1:0.2:5; |
运行程序,效果如图5-9所示。

图5-9 在深度d=2处的平板温度
另一种方法,可以在两个方向插值。先在三维坐标绘制出原始数据,看一下该数据的粗糙程度。其实现的MATLAB程序代码如下:
1 | >> mesh(width,depth,temps); |
运行程序,效果如图5-10所示。

图5-10 平板温度
然后以平滑数据在两个方向上插值。其实现的MATLAB程序代码如下:
1 | >> di=1:0.2:3; |
运行程序,效果如图5-11所示。

图5-11 二维插值后的平板温度
可选的参数method可以是linear、cubic或nearest。在这种情况下,cubic不意味着三次样条,而是使用三次多项式的另一种算法。linear方法是线性插值,仅用作连接图上数据点。nearest方法只选择最接近各估计点的粗略数据点。在所有的情况下,假定独立变量x和y是线性间隔和单调的。
5.5.3 高维插值
MATLAB支持三维及三维以上的高维插值,分别由函数interp3和interpn实现。高维插值与三维插值类似,这里仅介绍三维插值,至于高维插值,读者可参考MATLAB的联机帮助文档。
三维插值函数interp3函数的调用格式为:
1 | VI = interp3(X,Y,Z,V,XI,YI,ZI): |
其中,X、Y、Z、V为具有相同大小的三维数组,[X,Y,Z]为三维数据网格,V为数据网格上的函数值;XI、YI、ZI、VI是具有相同大小的三维数组,返回值VI是三维插值网格[XI,YI,ZI]上的函数值估计;method为字符串,表示不同的插值方法,主要有4种,与二维插值中的method相同。
【例5-21】 三维插值。
1 | >> [x,y,z,v] = flow(10); |
运行程序,效果如图5-12所示。

图5-12 利用三维插值数据绘制切片图
三维数据网格由函数ndgrid生成,其调用格式为:
[X1,X2,X3,…] = ndgrid(x1,x2,x3, …):用于产生n维空间上的栅格,高维插值中已知点栅格和插值点栅格都要用ndgrid函数产生。
【例5-22】 根据
的采样数据,在图上绘制栅格。
1 | >> [X1,X2] = ndgrid(-2:.2:2, -2:.2:2); |
运行程序,效果如图5-13所示。

图5-13 栅格图
5.5.4 样条插值
除了前面介绍中提到一维、二维及高维插值方法外,MATLAB还提供了样条插值的方法。样条函数的主要思想是:假设有一组已知的数据点,目标是找到一组拟合多项式,存在多项式拟合的过程中,对于每组相邻的样本数点,用三次多项式去拟合样本数据点之间的曲线。为了保证拟合的唯一性,对这个三次多项式在样点处的一阶、二阶导数加以约束。因此,除了研究区间的端之外,所有样本点之间的数据也能保证是连续的一阶和二阶导数。
在MATLAB中提供了spline、ppval函数用于样条插值,pchip函数用于三次多项式插值。它们调用格式为:
1 | yy = spline(x,Y,xx):相当于yi=interp1(x,y,xi,'spline')。 |
【例5-23】 对给定数据进行样条插值。
1 | >> x = -3:3; |
运行程序,输出如下,效果如图5-14所示。
1 | ppol = |

图5-14 样条插值效果
【例5-24】 使用样条插值进行圆形数据插值。
1 | >> x = pi*[0:.5:2]; |
运行程序,效果如图5-15所示。

图5-15 圆形数据插值
5.5.5 拉格朗日插值
插值一直是工程和科学中的重要内容,根据工程中不同的实践要求,已知发展出了多种插值运算方法。因此,除了MATLAB内置的插值函数外,还可以根据实践需要编写插值运算的M文件,然后将其应用在其他适合的领域中。
通过平面上不同的两点可以确定一条直线经过这两点,这就是拉格朗日(Lagrange)线性插值问题,对于不在同一条直线的三个点得到的插值多项式称为抛物线。拉格朗日插值方法是比较基础的方法,方法本身比较容易实现,而且效果还不错。也容易理解。
拉格朗日插值多项式可表示为:

在MATLAB中没有提供专门的函数实现拉格朗日插值,可自定义编写lang.m函数实现拉格朗日插值。
1 | function f = lang(x,y,x0) |
【例5-25】 利用拉格朗日插值法,计算x=1.5时的y值。
1 | >> x=0:0.5:3; |
运行程序,输出如下:
1 | f = |
5.5.6 牛顿插值
首先,有必要了解Newton(牛顿)插值基本原理。对于N +1个已知数据系列
,可以被下面的N -1阶的多项式循环引用,满足下面的N 个数据系列
的等式:

同时,需要满足的约束条件为
。
根据上面的等式方程组,得到的牛顿插值的数值系数满足下面的等式:

根据数学归纳法,得到牛顿插值方法的系数通式为:

在MATLAB中没有提供专门的函数实现牛顿插值,可自定义编写Newton.m函数实现牛顿插值。
1 | function [n,DD]=Newton(x,y) |
【例5-26】 以函数
为基准函数,分别采用不同阶数的牛顿插值多项式,然后比较不同阶数的插值误差。
1 | >> %计算4阶牛顿方法 |

图5-16 不同阶数的牛顿插值图

图5-17 不同阶数的牛顿插值误差
5.6 曲线拟合
插值法是一种简单函数近似代替较复杂函数的方法,它的近似标准是在插值点处的误差为零。
但是在实际应用中,有时不要求具体某些点的误差为零,而是要求考虑整体的误差限制。为达到这个目的,即需要引入拟合概念。
对数表形式的函数即离散型函数考虑数据较多的情况。若将每个点都当作插值节点,则插值函数是一个次数很高的多项式,插值运算显得非常复杂。
另一面,实验中给出的数据总是有观测误差的,而所求的插值函数要通过所有的节点,这样就会保留全部观测误差的影响,如果不是要求近似函数通过所有的数据点,而是要求它反映原函数整体的变化趋势,那么就可以用数据拟合的方法得到更简单活用的近似函数。
在实际中,常常给定一组测定的离散数据
,要求自变量x 和因变量y 的近似表达式
。这种影响因变量y 只有一个自变量x 的数据拟合方法称之为直线拟合。
直线拟合最常用的近似标准是最小二乘原理,它也是最流行的数据处理方法之一。
5.6.1 多项式曲线拟合
在科学实验与工程实践中,经常进行测量数据
的曲线拟合,其中
。要求一个函数
与所给数据
拟合,若记误差
,
,设
是C [a ,b ]上的线性无关函数簇,在
中找一函数
,使误差平方和为:

其中:

在MATLAB中提供了polyfit函数用于实现曲线拟合。其调用格式如下:
p = polyfit(x,y,n):对x与y进行n维多项式的曲线拟合,输出结果p为含有n+1个元素的行向量,该向量以维数递减的形式给出拟合多项式的系数。
[p,S] = polyfit(x,y,n):结果中的S包括R、df与normr,分别表示对x进行OR分解的三角元素、自由度、残差。
[p,S,mu] = polyfit(x,y,n):在拟合过程中,首先对x进行数据标准化处理,以在拟合中消除量纲等的影响,mu包含两个元素,分别是标注化处理过程中使用的x的均值与标准差。
【例5-27】 多项式的曲线拟合。
1 | >> clear all; |
运行程序,输出如下,效果如图5-18所示。
1 | p1 = |

图5-18 多项式曲线拟合效果
5.6.2 正交最小二乘拟合
正交多项式最小二乘拟合是选择一组在给定点上正交的多项式函数系
作为基函数进行最小二乘拟合。拟合的多项式记为:

其中:

对给定的试验数据点
,构造m 次正交多项式最小二乘拟合的多项式步骤为:
(1)令B 0 (x)=0,根据递推公式为:

则
。


在MATLAB中没有提供专门的函数用于实现正交最小二乘拟合,通过编写MINSERT.M函数实现,其源代码为:
1 | function a=MINSERT(x,y,m) |
【例5-28】 对给定数据进行4阶最小二乘拟合。
1 | >> x=1:5; |
运行程序,输出如下:
1 | a = |
即拟合后的多项式为:
y =18.2-32.8333x +20.8167x 2 -5.1167x 3 +0.4333x 4
5.6.3 加权最小方差拟合
所谓加权最小方差(Weighted Least Squares),就是根据基础数据各自的准确度(或者被称为可靠性)的不同,在拟合的时候给每个数据以不同的加权数值。
对于N 阶多项式的拟合公式,所要求解的拟合系数需要求解线性方程组,其中线性方程组的系数矩阵和需要求解的拟合系数(也就是变量)矩阵分别为:

其对应的加权最小方差为表达式
最小。
在MATLAB中没有提供专门的函数实现WLS拟合,编写wlsfit.m函数实现,其源代码为:
1 | function [th,err,yi]=wlsfit(x,y,N,xi,r) |
【例5-29】 使用WLS方法进行数据拟合。
1 | >> clear all; |
运行程序,效果如图5-19所示。

图5-19 使用WLS方法求解的拟合效果
利用polyfit函数对上面的基础数据进行拟合。
1 | >> clear all; |
运行程序,效果如图5-20所示。

图5-20 使用polyfit函数进行拟合得到效果图
5.6.4 曲线拟合界面
在MATLAB中提供了一个交互式曲线拟合工具,即Basic Fitting interface。通过该工具,用户无须编写代码就可以完成一些常用的曲线拟合。
下面以MATLAB自带的census data数据拟合为例介绍Basic Fitting interface的使用方法。
(1)载入census data数据。
1 | >> load census |
此时MATLAB基本工作空间生成两个double型列向量cdate和pop,cdate表示1970~1990内10年为间隔的年份,pop为对应年份美国的人口。
1 | >> whos |
(2)作census data点图。
1 | >> plot(cdate,pop,'rp'); %效果如图5-21所示 |

图5-21 census data曲线
(3)在MATLAB的figure中选择【Tool】菜单下的【Basic Fitting】(如图5-22所示)即得到Basic Fitting interface界面,如图5-22所示。

图5-22 Basic Fitting interface界面1
用户通过Plot fits界面选择不同的曲线拟合方式,为了便于比较,用户可以选择多种拟合方式,从而选择效果最好的一种拟合。如果某次拟合的效果较差,MATLAB会给出警告,这时用户可以试着Center and Scale X data改善拟合效果。
如果Show equations复选框被选中,那么图形窗口会显示拟合方程,如图5-23所示。如果Plot residuals复选框被选中,那么拟合结果将显示误差余量,如图5-24所示。此外还可以选择不同的显示类型,如Bar Plot(直方图)、Scatter Plot(散点图)、Line Plot(线图);可以将误差余量图作为拟合结果的子图或者单独的图形窗口。
![]() |
![]() |
| 图5-23 选择Show equations复选框拟合效果 | 图5-24 同时选择Plot residuals复选框拟合效果 |
如果Show norm of residuals复选框被选中,那么误差余量图将显示误差余量的范数,如图5-24所示。
单击图5-22中的
按钮,得到如图5-25所示界面,通过该界面用户能看到拟合的数值结果,并将结果保存在MATLAB基本工空间中。
在图5-25所示的界面中再次单击
按钮,得到如图5-26所示的界面。通过该界面右侧的面板,用户可以得到任意点处拟合函数的值,如在编辑框中输入2000:15:2080,并单击Evaluate按钮,计算结果显示在列表框中。如果Plot evaluated result复选框被选中,那么计算结果将显示在拟合曲线中,如图5-27所示。

图5-25 Basic Fitting interface 界面2

图5-26 Basic Fitting interface界面3

图5-27 census data数据拟合效果
第6章 线性与非线性方程组的求解
对于科学与工程而言,数值代数是一门基础工具。随着计算技术的发展,产生了各种数值代数计算方法。而数值代数的主要问题之一就是线性方程组与非线性方程组的计算。
6.1 线性方程组的概述及表示法
解线性方程组的方法,主要分为直接方法和迭代方法两种。直接法是在没有舍入误差的假设下,能在预定的运算次数内求得精确解。而实际上,原始数据的误差和运算的舍入误差是不可能避免的,实际上获得的也是近似解。
迭代法是构造一定的递推格式,产生逼近精确解的序列。对于高阶方程组,如一些偏微分方程数值求解中出现的方程组,采用直接法计算代价比较高,迭代法则简单又实用,所以比较受工程人员青睐。
一般线性方程组通常表示为如下的形式:

这里
是n 个未知数,m 行代表了未知数满足的m 个方程。
这一线性方程组实际上可以用矩阵乘法表示为AX =b 这样的形式,其中X 为n 个未知数构成的行向量
,b 为方程组右边的数值构成的列向量
。A 为方程组左边各个未知数的系数构成的矩阵,即

A 被称为线性方程组的系数矩阵,[A , b ]称为线性方程组的扩展矩阵。在MATLAB中就是通过矩阵A 、列向量b 来描述一个线性方程组的。
根据系数矩阵A 的形状和秩,线性方程组可以分为:恰定方程组、欠定方程组和超定方程组:
(1)当方程个数等于未知数个数,即系数矩阵A 为一个方阵而且满秩时,即rank(A )=m = n ,此线性方程组具有唯一解,称为恰定方程组。
(2)当方程个数小于未知数个数,即m <n 时,线性方程组有无穷多个可能的解,称为欠定方程组。
(3)当有效方程个数(线性无关的方程个数)大于未知个数时(一般m >n 都对应这种情况),线性方程组肯定没有精确解,称为超定方程组。
6.2 线性方程组的种类
线性方程组大概分为:
- 非奇异线性方程组。
- 奇异线性方程组。
- 欠定线性方程组。
- 超定线性方程组。
6.2.1 非奇异线性方程组
在恰定方程组中矩阵A 是方阵,矩阵b 可能是向量也可能是方阵。对于恰定方程组,MATLAB提供了一个十分方便的命令,左除“\。根据系数矩阵A 的奇异属性,该命令可以得到不同的结果:
- 如果恰定方程是非奇异的,则左除命令给出了恰定方程组的精确解。
- 如果恰定方程组是奇异的,MATLAB会显示提示警告信息,同时给出解NaN。
【例6-1】 求非奇异矩阵的线性方程组的解。
1 | >> clear all; |
从以上结果可以看出,方程组的系数矩阵A的行列式为1,则系数矩阵A是非奇异的,因此MATLAB可以给出准确的数值解。同时,该数值解和系数矩阵相乘,得到的结果和原来的数值完全相同。
6.2.2 奇异线性方程组
下面通过示例来演示奇异线性方程组的解。
【例6-2】 求奇异矩阵线性方程组的解。
1 | >> clear |
从以上结果可以看出,MATLAB会显示提示信息,表示该矩阵是奇异矩阵,因此无法得到精确的数值解。
1 | >> det(A) %求系数矩阵A的行列式 |
从上面的结果可以看出,矩阵A的行列式为0,同时矩阵的秩为2,表示该矩阵A是严格奇异的,MTALAB无法给出精确的数值解。
对于恰定方程组,如果数值解有解,则可以使用矩阵A的伪逆矩阵pinv(A)来得到方程的一个解,其对应的数值解为pinv(A)*b。
【例6-3】 使用伪逆矩阵的方法求奇异矩阵的线性方程组的解。
1 | >> clear |
从以上结果可以看出,通过使用伪逆矩阵的方法,可以求解得到数值解,同时该数值解可以精确地满足结果。
1 | %通过以下代码,修改需要求解的数值 |
从以上结果可以看出,通过该方法求解得到的结果并不完全满足原来的数值条件,并不如上面精确。
6.2.3 欠定线性方程组
欠定线性方程组的解不是唯一的,MATLAB将首先寻求一个基本解,然后再寻求非零解。从解法的角度来看,MATLAB采用的是QR分解的方法来求解欠定线性方程组。
【例6-4】 求欠定线性方程组的解。
1 | >> A=[1 2 3;4 5 6;7 8 9;10 11 12]; |
从以上结果可以看出,直接通过左除求解得到的数值解和使用QR分解得到的数值解是完全相同的,因此读者可以了解到MATLAB求解欠定方程组的原理。
6.2.4 超定线性方程组
超定线性方程组是指方程组的个数比未知个数多的情况,对于这种情况,MATLAB提供了伪逆矩阵的方法来求解,关于该方程在前面已经介绍过,下面通过示例来演示。
【例6-5】 求超定线性方程组的解。
1 | >> A=magic(8) |
6.3 利用MATLAB内置函数求解线性方程组
在MATLAB中求解线性方程组可以利用MATLAB内置函数,也可以通过自定义编写函数求解。
6.3.1 高斯消元法求解
利用消元法求解首先需用初等变换转化线性方程组为阶梯形方程组,把最后一些恒等式“0=0”(如果出现的话)去掉。如果剩下的方程当中最后的一个等式为零等于一个非零数,那么方程组无解,否则有解。
求解线性方程组可以通过高斯消元法,即将扩展矩阵[A,b]通过行方向的线性运算变形为[D,nb]形式,其中D和A尺寸相同且其最左上部分是一个单位矩阵。
(1)对于恰定方程组,D是和A同尺寸的单位矩阵,此时方程组的解的每一个分量可以通过X(i)=nb(i)/D(i,i)计算得到。
(2)对于欠定方程组,D的左上部分是一个比A小的k*k的单位矩阵,这时把i>k的X(i)置为0,i≤k的X(i)就可以通过X(i)=nb(i)/D(i,i)计算得到。
(3)对于超定方程组,高斯消元后只能看出该方程组没有解。
在MATLAB中提供了rref函数用于对线性方程组进行求解。其调用格式为:
1 | R = rref(A) |
其中,R为返回的最简阶梯形矩阵形式。jb中元素表示基向量所在的列。A为输入的矩阵,它可以是系数矩阵A或增广矩阵
。tol为指定的精度,其默认值为(max(size(A))*eps* norm(A,inf)),相应地有函数rrefmovie来给出每一步化简的过程。
【例6-6】 利用高斯消元法求恰定方程组的解。
1 | >> A=[0.2722 0.7468 0.4660;0.1988 0.4451 0.4186;0.0153 0.9318 0.8462]; |
例6-6中待求解的线性方程组为A*x=b,通过D=rref([A,b])计算,得到了此线性方程组扩展矩阵经高斯消元后的矩阵D。从矩阵D可以直接得到此方程组为恰定方程组,其解为x=[-0.5708 1.3080 -0.6358]‘。
【例6-7】 利用高斯消元法求欠定方程组的解。
1 | >> A=[0.7095 0.3046 0.1934 0.3028;0.4289 0.1897 0.6822 0.5417]; |
例6-7中的线性方程组A*x=b有4个未知数,2个方程,因此必须是一个欠定方程组,通过rref([A,b])得到的高斯消元结果,可以看到此方程组至少有一个特解X=[-46.5801 108.9937]‘。
对于有无穷多个解的欠定方程组,要获得其一般解的形式,可以先求线性方程组A*x=0的解x0,再求A*x=b的一个特解s,那么A*x=b的一般解就可以表示为s+r*x0。MATLAB中求解A*x=0,可以用null命令,null(A)返回A*x=0的解空间的一组标准正交基。
【例6-8】 欠定方程组的一般解。
1 | >> A=[0.8180 0.3420 0.3412 0.7271;0.6602 0.2897 0.5341 0.3093]; |
例6-8中,通过null函数得到了A*x=0的解空间的一组标准正交基,通过rref([A,b])可以得到A*x=b的一个特解[4.3467 -7.9448]‘。因此,欠定方程组A*x=b的一般解可以表示为:

对于超定方程组,高斯消元结果只能看出该方程组没有一般意义的解。
6.3.2 LU分解法求解
如果方阵A 可以分解为一个下三角矩阵L 和一个上三角矩阵U 的乘积,就把这样的分解叫做A 的三角分解或者LU分解。特别地,如果L 为下三角矩阵时候,称其为Doolittle分解,U 为上三角矩阵时候,称其为Crout分解。
对于矩阵A ,如果所有的顺序主子式都不为零,则A 可以唯一的分解为A =LU 。其中,L 为下三角矩阵,U 为上三角矩阵。这时方程Ax =b 可写成:
LUx =b
令Ux =Y ,则有LY =b 。
那么由此,把原方程的求解变为,求解系数矩阵为三角阵的方程,很容易实现。
【例6-9】 利用LU分解法求如下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | L = |
6.3.3 Cholesky分解法求解
在许多工程与实践中,方程组的系数矩阵往往是实对称的。对此直接三角分解还可以做一些改进。
如果
是对称正定矩阵,则必存在一个非奇异下三角矩阵
,使得
,称为矩阵A 的Cholesky分解,而且当G 的主对角元素均为正时,这种分解是唯一的。
于是方程组Ax =b 可以写为:

在方程两边做矩阵变换,可以得到方程组的解。
【例6-10】 利用Cholesky分解法求以下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
注意: 对一个矩阵进行分解的前提是,矩阵必须为Hermitan矩阵。如果不是正定对称,引用该函数时,MATLAB会给出错误信息。
6.3.4 奇异值分解法求解
可以这么说,奇异值分解是现代数值分析中最基本和最重要的工具之一,在统计分析、信号处理、控制理论等领域都被广泛地应用。
设
,则存在矩阵
,使得
,称为矩阵A 的奇异值分解。
有了奇异值分解,直接在原方程两边做矩阵变换就可以得到方程组的解。
【例6-11】 利用奇异值分解法对以下线性方程进行求解。

其实现的MATLAB代码为:
1 | >> clear all; |
6.3.5 双共轭梯度法求解
共轭梯度算法是一种迭代方法。它从一组初值向量出发,定义代价函数,进而转化为最优化问题。从数学的角度讲,是寻找一个向量,这个向量使得计算代价函数为极值,这里是极小值。国外有学者甚至把这样的方法归结到人工神经网络计算原理之下。双共轭梯度法在MATLAB中基本函数是bicg。其调用格式为:
1 | x = bicg(A,b) |
bicg函数用来处理线性方程组,要求系数矩阵为方阵,在计算比较大的稀疏矩阵时比较有效。如前面所说,一般系统给出的这样一些函数都是比较有效的。在计算失败时会给出失败信息,同时会给出相对误差,误差是通过范数给出的,相对误差范数为:

在输入参数(A,b,tol,maxit,M1,M2,x0)中,A、b为方程矩阵。tol为误差容限,默认情况下为1e-6;maxit为最大迭代次数,默认情况下如果方程在20阶以下,就以方程的阶数为迭代次数,大于20的,以20次为迭代次数;x0为迭代初值,默认为从零向量开始迭代。其他一些参数可以参考帮助文档。
在输出参数[x,flag,relres,iter,resvec]中,x表示要计算的方程组的解;flag给出计算成功与否的标志;relres为相对误差,用刚才的范数给出;iter为迭代次数;resvec为每次迭代的残差,以范数||b-Ax||给出。
【例6-12】 利用共轭梯度求解以下线性方程组。

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
6.3.6 共轭梯度的LSQR法求解
在MATLAB中提供了lsqr函数用于实现LSQR方法求解,它可以处理一般的线性方程组,同时可以处理超定方程,标准是范数||b-Ax||最小。其中系数矩阵不需要为方阵。lsqr函数的调用格式为:
1 | x = lsqr(A,b) |
参数的意义与双共轭梯度算法类似,这里介绍比较常用的参数设置。在输入参数中,A、b分别对应方程Ax=b中的A、b。tol为期望的计算误差容限,默认为1e-6。maxit为指定的最大的迭代次数,默认为系数矩阵的行、列与自然数20三者之间的最小数。
在输出向量中,x返回运算结果;flag=0表示在指定的误差容限与迭代次数内计算成功;relres为返回误差范数估计;iter为给出迭代的次数;resvec为给出每一步迭代的误差范数。
需要注意的是,上面的输入输出参数中,很多是可选的,所以相互组合会有多种表达形式。但是在调用过程中必须按照参数的对应顺序用参数替代。
【例6-13】 利用共轭梯度的LSQR法求如下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
6.3.7 最小残差法求解
在MATLAB中提供了minres函数用以解线性方程组Ax=b。minres函数的调用格式为:
1 | x = minres(A,b) |
参数的基本意义与共轭梯度法求解意义相似。其中,tol对应指定的误差容限,默认为1e-6;maxit为指定的最大迭代次数,默认情况下,取矩阵A的维数与n之间的小者。
x用于输出运算结果,flag=0表示指定的误差在运算最大迭代次数内满足要求。relres为相对误差范数;iter为实际迭代次数;resvec为每次迭代的误差范数。
【例6-14】 利用最小残差法求以下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
6.3.8 标准最小残差法求解
在MATLAB中提供了qmr函数用于用标准最小残差法求解线性方程组Ax=b。qmr函数的调用格式为:
1 | x = qmr(A,b) |
其中,A可以为大的稀疏矩阵,但必须为方阵。如果计算收敛,给出消息提示,如果计算失败,MATLAB给出警告信息,并且给出迭代的相对误差范数为||b-Ax||/||b||。tol为指定的误差容限,默认为1e-6。maxit为指定的最大迭代次数,默认为n和自然数20之间的小者。
x用于输出运算结果;flag=0表示指定的误差在运算最大迭代次数内满足要求;felres为相对误差范数;iter为实际迭代次数;resvec为每次迭代的误差范数。
【例6-15】 用标准最小残差法计算以下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
6.3.9 广义最小残差法求解
在MATLAB中提供了gmres函数用于利用广义最小残差法求解线性方程组Ax=b。其调用格式为:
1 | x = gmres(A,b) |
各参数意义与前面介绍的算法基本相同。
需要注意的是,gmres(A,b,restart)在每次迭代后会重新启动,最大的外部迭代次数为矩阵A的维数n、restart和10之间的最小数。如果restart缺省,则不会重新启动,而且最大的迭代次数为10和n之间的小者。
【例6-16】 用广义最小残差法求以下线性方程组的解。

其实现的MATLAB代码为:
1 | >> clear all; |
6.4 利用自定义编写函数求解线性方程组
迭代法是对任意给定的初始近似解向量,按照某种方法逐步生成近似解序列,使解序列的极限为方程组的解。因此迭代法是用某种极限过程去逐步逼近真解的方法,也可以用有限步运算来算出具有指定精确度的近似解。
设有线性方程组:
Ax =b
其中,A 为非奇异矩阵,向量b ≠0,因而它有唯一解x * 。即上式可变形等价的同解线性方程组x =Tx +C 的形式。然后任取一个初始向量
作为式x =Tx +C 的近似解,由公式

构造向量序列
,如果向量序列
满足

则称此迭代法收敛,此时x * 就是方程组的解;否则,称此迭代法发散。称式
为迭代格式,T 为迭代矩阵,
为第k 次迭代近似解,称
为第k 次迭代误差。
此时对于给定的允许误差ε ,只要k 适合大,
可作为解x * 的近似值,满足精度如下:

称为迭代终止条件。
下面将对一些主要迭代法进行介绍。
6.4.1 雅可比迭代法
设有方程组:

写成向量形式,即有:

则方程组的矩阵形式可表达为:
Ax =b
(6-2)
假设系数矩阵A 为非奇异阵,即方程组Ax =b 有唯一解
。设A 的主对角元素
,由方程组(6-1)的第一个方程解出x 1 为:

同样,由第二个方程解出x 2 ,由第i 个方程解出x i 。则方程组(6-1)等价于:

对任意i =1,2,…,n 成立。

给定一个初始向量
,将x(0) 代入式(6-4)的右端,确定一个新向量
。至此即完成了Jacobi(雅可比)迭代的第一步。接着,把x(1) 再代入式(6-4)的右端,得到
,至此完成迭代的第二步。一般地,迭代格式可表示为:

通过式(6-6)可以从初值
得到向量序列
,如果序列
收敛到x * ,则
成立。由式(6-5)知A=D(I-B) ,即:

所以有Ax * =b ,这说明x * 是方程组(6-1)的解。以上求解方程组(6-1)的方法就是雅可比迭代法,B 为雅可比迭代法的迭代矩阵。
MATLAB中没有提供现成的函数实现雅可比迭代,可通过自定义编写Jacobifun.m函数实现利用雅可比迭代求解线性方程组的解。
1 | function [x,n]=Jacobifun(A,b,x0,eps,varargin) |
【例6-17】 利用Jacobi迭代法求解线性方程组
。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
6.4.2 高斯-赛德尔迭代法
注意到在雅可比迭代法中,在计算向量x (k -1) 的分量时,当计算到
时,分量
都已经算出,但仍用旧分量
进行计算。实际上,如果用新算出的分量
代替旧分量来计算
,则既可以节省存储单元,又方便编写程序,这样得到的迭代法称为Gauss-Seidel(高斯-赛德尔)迭代法。
在雅可比迭代法中,知方程组(6-1)等价于

给定初值
后,将x (0) 的相应分量代入式(6-1)第一个方程的右端,这就可以确定一个x 1 ,记为
。接着将
的各个分量代入式(6-1)的第二个方程的右端,这又确定一个x 2 值,记为
。一般地,如果已经求出
,那么将
代入式(6-1)的第i 个方程,确定一个值x i ,记为
。即:

又因为
,故(I-L )-1 存在,所以迭代格式(6-10)可化为:

其中,
称为高斯-赛德尔迭代法的迭代矩阵。
从上面的计算过程可看出,与雅尔比迭代法的同时替换不同,高斯-赛德尔迭代法以逐个替换为其特征,也就是说在高斯-赛德尔迭代法中,在对x (k +1) 的各个分量
(i -1,2,…,n )进行计算时,一旦确定x (k +1) 的某个分量
,就马上用
取代
来进行计算
。这种尽可能充分应用最新的分量的方法是基于一种朴素的思想,即新的迭代结果可能比旧的迭代结果更趋近于方程组的精确解。
MATLAB中没有提供专门的函数实现高斯-赛德尔迭代,可通过自定义编写GaussSeid.m函数实现利用高斯-赛德尔迭代求线性方程组的解。
1 | function [x,n]=GaussSeid(A,b,x0,eps,M) |
【例6-18】 用高斯-赛德尔迭代法求解线性方程组
。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
6.4.3 松弛迭代法
SOR法可以视为高斯-赛德尔迭代法的加速,它是解决大型稀疏矩阵方程组的有效方法之一,前面给出高斯-赛德尔迭代法的迭代格式为:

其中,L 、U 、g 的定义与高斯-赛德尔迭代法中的定义相同,参数ω 称为迭代格式的松弛因子,当ω >1时叫超松弛因子,ω <1时叫低松弛因子。ω =1时迭代式(6-11)就是高斯-赛德尔迭代格式。
又由于
,故(I-L )-1 存在,所以迭代格式(6-11)可化为:

其中,
称为松弛法的迭代矩阵。
MATLAB中没有专门现成的函数实现松弛迭代,可通过自定义编写sor.m函数实现利用松弛迭代求线性方程组的解。
1 | function [x,n,flag]=sor(A,b,eps,M,max1) |
【例6-19】 用松弛迭代法求解线性方程组
。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
6.5 函数法
MATLAB提供了函数solve、fzero、roots及fminbnd,用来求解不同形式的方程或者方程组。
6.5.1 一般方程求解
MATLAB中设有求出方程f(x)=0解析解或精确解的符号法指令solve,由它得出的符号量结果,可以转换为任意位有效数字的数值解。其调用格式为:
1 | Y = solve(expr1, expr2, ..., exprn) |
其中,Y表示输出的计算结果,它是一个由符号型数据组成的结构体。expr1, expr2, …, exprn为待解方程组f(x)=0或函数f(x)的字符、符号表达式,或者代表它们的变量名。待解方程可以是任意线性、非线性或超越方程。x1, x2, …, xn为符号变量或未知数的字符串,它的数目必须与方程数目相等。y1, y2, …, yn为指定的输出变量名,方程解的结果分别赋给它们。但是赋值并不是输入变量x1, x2, …, xn的排序,而是按未知变量名在字母表中的排序输出。
【例6-20】 利用solve函数求方程
的解。
1 | >> syms x; %定义符号变量x |
运行程序,输出如下:
1 | ans = |
【例6-21】 利用solve函数求方程
的解。
1 | >> syms a b c x; %定义符号变量 |
运行程序,输出如下:
1 | ans = |
这个结果与用如下二次方程求根公式得到的结果是一致的:

【例6-22】 利用solve函数求解以下的非线性方程组的解:

其实现的MATLAB代码为:
1 | >> clear all; |
【例6-23】 求方程
的解。
分析:一般的3次方程
可以转化为
,因此可以利用solve来求出相应的求根公式。
1 | >> clear all; |
运行程序,输出如下:
1 | t = |
这里使用subexpr进行变量替换来缩短表达式,由以上结果可看出t是一个很长的表达式,而简化后的r与s就简单多了。
6.5.2 非线性方程求解
MATLAB提供了fzero函数用来计算非线性方程的根,这个函数将返回给定初值附近的根。当有多个根的时候,fzero函数需要多次指定初值。fzero函数的调用格式为:
x = fzero(fun,x0):x为方程的零点;fun为所求方程的函数;x0为初始点。
x = fzero(fun,x0,options):options为选择项,它包括Display与TolX。
[x,fval] = fzero(…):fval为计算终止时间的函数值。
[x,fval,exitflag] = fzero(…):exitflag为终止计算的条件信息,当exitflag为正数时表示解存在,为负数时表示解不存在(遇到复数、NaN或者无穷大等)。
[x,fval,exitflag,output] = fzero(…):output为输出关于变量的信息,其为一个结构体,output.algorithm是所用的算法,output.funcCount为函数赋值次数,output.iterations为迭代次数。
函数fzero在搜索区间内发现inf、nan或复数值时中止搜索,如果搜索失败,则返回NaN。
注意: 使用fzero函数是不能得到方程的复数解的,而solve函数可以得到复数解。
【例6-24】 求方程
的实数根(
)。
1 | %先确定方程实数根存在的大致范围,为此,先将方程变成标准形式f(x)=x^2-5sin(x)-18 |

图6-1 确定方程实数根存在位置的曲线
从图6-1可以看出,函数的零点大约在
附近。
1 | %直接使用指令fzero求出方程在x1=-4时的根 |
中间数据表明,求根过程中不断缩小探测范围,最后得出-4附近满足精度的近似根。
1 | %求出x2=4附近的根 |
【例6-25】 研究不同初值对求解方程sin x 2 =0的影响,其中初值选择x0=[-0.1 0 0.1]。
1 | >> clear all; |
运行程序,输出如下,效果如图6-2所示。
1 | x01 = 0 |

图6-2 sin(x2 )曲线
由以上结果可见,初值的选择有时会影响函数的结果。另外从图6-1及图6-2的求解过程中,可以发现利用函数fzero求解结合目标函数绘图的方式是解方程较好的方式。
6.5.3 多元非线性求解
在MATLAB中提供了fsolve函数用于求解多元非线性方程,其调用格式为:
x = fsolve(fun,x0):x为方程的零点;fun为所求方程的函数;x0为初始点。
x = fsolve(fun,x0,options):options为选择项,其包括Display、TolX、Jacobian、MaxFunEvals与MaxIter。其中,Display为显示迭代的情况,其有如下参数:off表示不显示(默认情况);iter表示显示迭代情况;final表示只显示最终的结果。TolX表示x的终止精度。Jacobiano使用时,如果为on表示需要在外部函数中定义Jacobi矩阵,如果是off则表示用差商代替导数(默认情况)。MaxFunEvals为调用函数的最大次数。MaxIter为最大迭代次数。
[x,fval] = fsolve(fun,x0):fval为计算终止时的函数值。
[x,fval,exitflag] = fsolve(…):exitflag为终止计算的条件信息。
[x,fval,exitflag,output] = fsolve(…):output为输出关于变量的信息。
[x,fval,exitflag,output,jacobian] = fsolve(…):jacobian为输出的Jacobi矩阵。
【例6-26】 求解MATLAB自带的啁啾函数chirp的零点,其中参数F0=0,T1=5,F1=1。变量x ∈[0,5],要求得出这个区间内所有的零点。
分析:啁啾信号是频率逐渐变大的一类时间信号,在信号处理中经常使用。这个函数多次穿过0刻度线,使用初值1,2.5,3.5,4,4.7。
1 | >> clear all; |
运行程序,输出如下,效果如图6-3所示。
1 | Norm of First-order Trust-region |

图6-3 啁啾函数曲线
从啁啾函数的曲线可以看出,在区间[0,5]内存在5个零点。利用预先设定的初始值,完全求出了其中的零点。下面进一步考察不同初始值收敛的结果:
1 | >> options = optimset('fsolve'); % 设置控制参数 |
运行程序,效果如图6-4所示。

图6-4 不同位置收敛的结果
两幅图形大小相同,但是在0附近两幅图存在着明显的差异。此外,在右图中存在着离散的小线段。这是因为采用向量方式计算每次迭代次数受限制,有的点没有完全达到收敛而停止。因此,在计算中应该区别使用这两种方式。
【例6-27】 使用fsolve函数求下列非线性方程的根,其初始点为x0=[-5 5]。

其标准形式为:

先建立li6_27fun.m方程表达式函数。
1 | function F = li6_27un(x) |
其实现的MATLAB代码如下:
1 | >> clear all; |
6.5.4 多项式的根求解
在MATLAB中提供了roots函数用于求解多项式的根,其调用格式为:
1 | r = roots(c) |
其中,r表示返回多项式函数的根。c为多项式系数组成的向量,其中c的系数与多项式之间的关系是x(1)*x^N+…+c(N)*x+c(N+1),即c的系数对应于按降幂顺序排列的多项式前面的系数。如果多项式里面缺少某幂次项时,那么它前面的系数等于0,如多项式
中,x 3 是缺少的,则c的值为[1,0,2,4,5]。此外c不能是矩阵。
【例6-28】 求下面多项式的根。

根据三组多项式前面的系数,可以确定出系数向量c,然后调用roots实现求多项式的根:
1 | >> clear all; |
运行程序,输出如下:
1 | r3 = |
与函数roots相对的函数是poly,它是根据多项式的根反过来确定多项式的,其调用格式为:
1 | p1 = poly(A) |
其中,A为向量;r为矩阵。p1为构造的多项式系数;p2为矩阵r的特征多项式(
,其中E n 为n阶单位矩阵,r为一个n×n的方阵)的系数,其长度是n+1。
1 | >> cr5=poly(r5) %恢复例6-28中的r5系数矩阵 |
由得到的结果可看出,roots函数与poly函数互为反函数。
6.6 编写自定义函数求解非线性方程
前面介绍了利用MATLAB自带函数来计算超越方程的根,每个函数都存在一定局限性。下面将介绍几种数值方法来求解超越方程,包括二分法、抛物线法、牛顿法、正割法和Steffenson法。
6.6.1 二分法
二分法是求解非线性方程根的最简单的方法。例如,连续函数f (x )在区间[a ,b ]满足f (a )与f (b )的符号相反的条件,则存在零点,区间[a ,b ]称为有根区间。因此,在有根区间内,逐步将区间对分,直到得到一个满足一定精度要求的包含零点的区间,最终的区间的中点作为方程根的近似值。
二分法的步骤的第一步是在区间[a ,b ]选择中点c =(a +b )/2,然后分析可能存在的3种情况:
- 如果f (a )与f (c )符号相反,则在区间[a ,b ]内存在零点。
- 如果f (c )与f (b )符号相反,则在区间[a ,b ]内存在零点。
- 如果f (c )=0,则c 是零点。
于是,有根的区间比起始区间减小了一半,依此过程,直到区间足够小。为了明晰该过程的细节,可采用如下表示方法:
设当前的有根区间为
,取
,若
,则令
,
;否则令
。再取
,进入下一步计算。
设初始有根区间为[a ,b ],x * 是方程的根,x k 为第k 次区间[ak ,bk ]的中点,则

显然,如果二分过程无限地继续,序列{xk }必将收敛到x * 。
此外,式(6-12)也给出了算法的终止条件,当
时,算法停止运算,其中ε 为给定的满足精度要求的误差限。
二分法的算法如下:
(1)取初始有根区间[a,b ](满足
),以及精度要求。
(2)若
,则停止计算。
(3)取
,若
,则置b=x ;否则置a=x ,转(2)继续。
在MATLAB中没有提供现成的函数实现利用二分法求解非线性方程组的解,可通过自定义编写bisect.m函数实现。
1 | function [c,err,yc]=bisect(fun,a,b,delta) |
【例6-29】 用二分法求方程
在区间[1,3]内的根。
1 | %根据方程,绘制方程与x轴交点图,效果如图6-5所示 |

图6-5 f(x)与x轴交点图
编写所求非线性函数的M文件,代码为:
1 | function f=fun(x) |
运行程序,输出如下:
1 | k = 2 |
6.6.2 迭代法
给定实数域上的光滑的实值函数
以及初值x 0 ,定义数列:

其中数列
称为迭代函数
的迭代序列。
如果数列
,则有:

即x * 是方程f (x )=0的解,此时称x * 为
的不动点,求f (x )=0的解就可以化为求
的不动点问题了,在实际计算中,就选取满足精度要求的xn 作为方程的近似解。如果迭代过程不收敛就称为发散,一个发散的迭代过程,无论进行多少次迭代,其结果都是没有价值的。
直接用式(6-14)求迭代序列xn (n =0,1,…)的方法就是迭代法。
迭代过程的几何意义就是把求方程f (x )=0的根的问题转化为求
两曲线的交点问题,交点的横坐标就是方程的根x * 。
设
在区间[a ,b ]上有连续的一阶导数,并满足:
(1)对任意的
。
(2)对任意的
。
则有:
(1)对函数
在区间[a ,b ]上存在唯一的不动点(方程的根)x * 。
(2)对任何
,由迭代公式(6-14)得到的序列{xk }均收敛到方程的根x * 。
迭代法的算法如下:
(1)取初始点x 0 ,最大迭代次数N 和精度要求ε ,置k =0。
(2)计算
。
(3)若
,则停止计算。
(4)若k =N ,则停止计算;否则,置k =k +1,转(2)。
在MATLAB中没有提供专门的函数实现利用迭代法求解非线性方程组的解,可通过自定义编写fixpt.m函数实现。
1 | function [p0,k,err,p]=fixpt(li6_29fun,p0,tol,max1) |
【例6-30】 求方程
的一个近似值,给定初始值x0=0.5,误差为1e-5。
1 | %根据方程,绘制方程与x轴交点图,效果如图6-6所示 |

图6-6 f(x)与x轴交点图
编写所求非线性函数的M文件,代码为:
1 | function g=li6_29fun(x) |
运行程序,输出如下:
1 | >> fixpt('g',0.5,1e-5,20) |
6.6.3 抛物线法
二分法是利用两点来逼近准确的根,这里使用3点来逼近准确的根,即抛物线法。假设方程f (x )=0的根为x ′。设迭代计算相邻的3个点的坐标是
。下面将利用3点推导获得下一点坐标x k+1 。记
,则过这3点的抛物线可以写为:

显然,
。把x =x k -2 代入上式,经简单计算可以得出
,因此可以知道式(6-15)通过曲线上3个点
。
在抛物线法中,使用多项式p 2 (x )来近似函数f (x )。这里p 2 (x )是一个二次多项式,一般情况下它有两个根,选择离xk 较近的根作为下一个近似的根。考虑到使
取最小值,把式(6-15)写为另一种等价的形式:

令p 2 (x )=0,式(6-16)对应的方程可以写为下面的形式:

在一元二次方程(6-17)中,当ak =fk =0时,可得x =xk ,即此时xk 是方程的解,可以终止迭代。
当ak =fk ≠0时,x ≠xk 成立同时解下面的方程:

这里使用符号函数保证分母中两项同号取绝对值最大,从而保证x 和xk 之间的距离最近。式(6-20)又称为抛物线的迭代公式,同时抛物线法又称为Muller法。
在MATLAB中没有提供专门的函数实现抛物线法,可通过编写parabola.m函数实现用抛物线求解非线性方程,其源代码为:
1 | function xr = parabola(fun,x0,x1,x2,D) |
【例6-31】 利用抛物线法求解方程
在区间[1,3]内的解。
首先,根据需要建立方程的M文件,代码为:
1 | function y=fun(x) |
调用parabola函数求解方程,并绘制其曲线图:
1 | >> xx=linspace(1,3,200); %对自变量采样1,30 |
运行程序,输出如下,效果如图6-7所示。
1 | xr = |

图6-7 抛物线法解方程结果
6.6.4 牛顿法
设x 0 是方程f (x )=0的一个近似根,把f (x )在x 0 点附近展开成泰勒级数:

取其线性部分作为非线性方程f (x )=0的近似方程,则有:

设
,则其解为:

再把f (x )在x 1 附近展开成泰勒级数,也取其线性部分作为f (x )=0的近似方程。若
,则有:

得到牛顿法的一个迭代序列:

此公式为牛顿公式。
设函数f (x )满足:
,且f (x )二次连续可微,则存在δ >0,当
时,牛顿迭代法是收敛的,且收敛的阶至少为平方收敛。
牛顿法的算法如下:
(1)取初始点x 0 ,最大迭代次数N和精度要求ε ,置k =0。
(2)如果
,则停止计算;否则计算:

(3)若
,则停止计算。
(4)若k=N ,则停止计算;否则,置k =k +1,转到(2)。
在MATLAB中没有提供专门的函数实现用牛顿法求解非线性方程,下面通过自定义Newton.m函数实现牛顿法,其代码如下:
1 | function xr =Newton(fun,x0,D) |
【例6-32】 用自定义编写的牛顿法计算下面方程在区间[3, 5]内的解:

首先定义计算函数的函数文件,其代码如下:
1 | function [y, dy, d2y] = li6_31funA(x) |
其实现的MATLAB程序代码如下:
1 | >> clear all; |
运行程序,输出如下,效果如图6-8所示。
1 | xr1 = |

图6-8 牛顿求解方程效果图
6.6.5 正割法
牛顿法在每步计算中需要计算函数f (x )及其一阶导数f ‘(x )的数值,这相当于计算两个函数值,用得比较多。现在利用差商来代替牛顿法中的导数,如此一来可以减少一个函数值的计算。相当于牛顿法的迭代公式改为:

正割法的几何意义如图6-9所示,在此图中,根据几何知识,三角形
和三角形
相似,则
成立,可以进一步写为
,即


图6-9 正割法的几何意义
上式正好是式(6-22)当k =1时的表达式。如此递推下去就可以逐渐逼近方程f (x )=0的解。
在MATLAB中没有现成的函数实现对非线性方程用分割法求解,下面通过用户自定义编写的secant.m函数实现,其代码如下:
1 | function xr = secant(fun,x0,x1,D) |
【例6-33】 利用正割法求非线性方程e x -x -5=0的解。
1 | >> clear all; |
运行程序,输出如下,效果如图6-10所示。
1 | xr = 1.9368 |

图6-10 方程与x 轴的交点示意图
6.7 编写自定义函数求解非线性方程组
在6.6节中介绍了利用自定义编写的函数求解非线性方程,下面介绍通过编写自定义函数求解非线性方程组。
6.7.1 不动点
对于非线性方程组:

可以构造如下形式结构:

方程(6-24)的解x * ,也是方程(6-23)的解。x * 称为方程(6-24)函数向量的不动点。
可以构造如下迭代格式:

在MATLAB中没有专门的函数实现对非线性方程组不动点迭代法,下面通过自定义编写的StablePoint.m函数实现,其代码如下:
1 | function [r,n]=StablePoint(F,x0,eps) |
【例6-34】 利用不动点迭代法解以下非线性方程组:

初始迭代值为x0=[1 0.1]。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | r = |
由计算结果可知,初始迭代值取(1,0.1)时,用615步迭代,得到原方程组的一组解(0.0666,0.2004)。
6.7.2 牛顿法
和非线性方程解法情况类似,非线性方程组的牛顿法是相当重要也是相当基础的方法。很多重要算法也是在此基础上进行演变而得到的。
对于非线性方程组:

这就是著名的牛顿法。牛顿法是工程应用最多的一种非线性方程组的计算方法。
在MATLAB中没有专门的函数实现对非线性方程组进行牛顿迭代法运算,下面通过用户自定义编写的Newtond.m函数实现,其代码如下:
1 | function [x,n,data]=Newtond(x0,tol) |
【例6-35】 利用自定义编写的牛顿迭代法计算非线性方程组
,初值取
。
首先,根据需要编写非线性方程组的M文件,代码如下:
1 | function f=F(x0) |
编写牛顿迭代法的Jacobi矩阵函数,代码为:
1 | function f=Jacobian(x0) |
调用牛顿法求解非线性方程组,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | r = |
6.7.3 拟牛顿法
牛顿迭代法每迭代一次,就要计算当前一步的Jacobi矩阵的逆矩阵,计算量比较大。简化牛顿法也不失为一种方法,但有时计算效果不能令人满意。为了每次迭代都计算逆矩阵,我们设法构造一个矩阵H k ,逼近
的逆矩阵,这样的迭代公式就为:

选取不同的H k 就得到各种类型的拟牛顿法。这里主要介绍拟牛顿方法,拟牛顿方法的基本迭代格式为:

其中
。
拟牛顿法是20世纪60年代之后发展起来的算法,相对而言是比较新的一种方法,它克服了牛顿法需要求导数和求逆的缺点,是非常有效的一种方法。
在MATLAB中没有专门的函数实现对非线性方程组进行拟牛顿法运算,下面通过自定义编写的VNewton.m函数实现,其代码如下:
1 | function [r,m]=VNewton(F,x0,A,eps) |
【例6-36】 用拟牛顿法求解以下非线性方程组:

其初始值为x0=[1 0.1]。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | r = |
由计算结果可知,与例6-34相比,用拟牛顿迭代法求解同样的非线性方程组的速度比不动点迭代法快得多。
6.7.4 共轭梯度法
在共轭梯度算法中,有:

那么整个计算流程为:

在MATLAB中没有提供专门的函数实现用共轭梯度法求解非线性方程组,下面通过自定义Groudfun.m函数实现,其代码如下:
1 | function [r,n]= Groudfun (F,x0,h,eps) |
【例6-37】 用共轭梯度法求解以下非线性方程组:

其初始值为x0=[1 0.1]。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | r = |
由以上运行结果可看出,解同样的非线性方程组,共轭梯度法比前面介绍的几种方法的速度都要快。
第7章 数值微积分
微积分思想是高等数学的基石,很多科学问题中都存在着不同类型的积分公式模型。积分的计算在很多学科中都有着重要的应用。
7.1 数值微分积分概述
设F (x )为f (x )的原函数,由牛顿-莱布尼兹公式可知,对于定义在区间[a,b]上的定积分,有

但是并不是区间[a,b]上的所有可积函数的积分值计算都可由牛顿-莱布尼兹公式解决的,有的原函数不能用初等函数表示,或者有的原函数十分复杂,难以求出或计算。如被积函数
等函数的积分都无法解决;又或当被积函数为一组离散的数据时,对于这种积分更是无能为力了。但是理论上,定积分是一个客观存在的确定的数值,要解决的问题就是能否找到其他途径来解决定积分的近似计算。
由微分知识可知定积分的定义为

可知,如果等式的右边取某一近似值,即

其中,Ak (k =0,1,2…,n)与函数f (x )无关,称为求积函数系数,而式(7-1)称为求积公式。要确定一个求积公式,最主要的就是确定求积系数Ak ,或者说不同的求积系数决定不同的求积公式。
7.2 微分
在数值计算中,微分分为符号微分与数值微分等。
7.2.1 符号微分
当创建了符号表达式后,就可以使用MATLAB提供的diff函数创建符号导数(即微分)。diff函数的调用格式为:
diff(expr):没有指定变量和导数阶数,则系统按findsym函数指示的默认变量对符号表达式expr求一阶导数。
diff(expr, v):以v为自变量,对符号表达式s求一阶导数。
diff(expr, n):按findsym函数指示的默认变量对符号表达式expr求n阶导数,n为正整数。
diff(expr, v, n):以v为自变量,对符号表达式expr求n阶导数。
【例7-1】 求
导数。
1 | >> syms t |
即有
。
【例7-2】 求
的一阶导数和二阶导数。
1 | >> syms x y |
运行程序,输出如下:
1 | dx1 = |
在以上程序中,通过使用简单的diff函数,证明了微积分中的一个结论:
。在本例中
,因此根据上面的程序结果,两者满足
。
在MATLAB中提供了simple函数用于对微分表达式进行化简。下面通过示例来演示。
【例7-3】 使用diff函数求解常见的多项式
的一阶导数值,并使用simple函数对其进行化简。
1 | >> syms x a |
根据相关的微积分知识,即有
。
diff函数除了求解多项式的微分外,还可求矩阵微分。下面通过示例来演示。
【例7-4】 求解多项式矩阵
各阶微分数值。
1 | >> syms s t |
7.2.2 向量微分
在数学分析中,微分运算也可以对列向量进行,所得的结果也是一个列向量。在数学分析中,多元向量函数的jacobian矩阵的定义为:
对于多元向量函数
和向量变量
,其函数f 的jacobian矩阵为

jacobian函数的调用格式如下。
jacobian(f, v):f为一个符号列向量,v为指定进行变换的变量组成的行向量。
【例7-5】 对例7-4中的矩阵A,将其转换为两个列向量B1与B2,分别求解两个列向量的jacobian矩阵。
1 | >> syms s t |
7.2.3 数值微分
函数微分问题的定义为:设函数f (x )在点x 0 的某一去心邻域内有定义,如果对于任意给定的正数ε (无论它多么小),总存在正数δ ,使得对于适合不等式
的一切x ,对应的函数值f (x )都满足不等式:

那么常数A 就叫做函数
时的极限(微分),记作:

上述定义中的x 0 可以是某确定的值,也可以为无穷大。
当常数A 满足
时,可以称函数f (x )在点x 0 连续。函数在某一点连续又可分为左连续和右连续。如果

存在且等于f (x 0 ),就有f (x )在点x 0 处左连续,如果

存在且等于f (x 0 ),就有f (x )在点x 0 处右连续。
在MATLAB中提供了limit函数用于求表达式或者函数的极限(微分),其调用格式为:
limit(expr, x, a):求解当x→a时,符号表达式expr的极限。
limit(expr, a):符号表达式expr采用默认自变量,该函数求得expr的自变量趋近于a时的极限值。
limit(expr):符号表达式expr采用默认自变量,并且以a=0为自变量的趋近值,该函数求得expr的自变量趋近于a的极限值。
limit(expr, x, a, ‘left’):该函数求解符号表达式expr的右极限,也就是自变量从左边趋近于a的函数极限值。
limit(expr, x, a, ‘right’):该函数求解符号表达式expr的左极限,也就是自变量从右边趋近于a的函数极限值。
【例7-6】 求解极限问题
。
1 | >> syms a b x |
【例7-7】 求无穷极限
。
1 | >> syms x n |
【例7-8】 求f (x )在x =0处的左右极限和极限数值。其中函数f (x )当x ≠0时,
;当x =0时,f (x )=0。
1 | >> syms x |

图7-1 函数图形
从图7-1可以很清楚地看到,函数在x =0的地方间断,左侧为数值–1,右侧为数值1,因此函数在x =0的地方不存在极限数值。
7.3 积分
在数学分析中,积分和微分是一种互逆的运算。积分包括不定积分、定积分、旁义积分和重积分等,一般来讲,积分比微分更难求解。
7.3.1 符号积分
在MATLAB中提供了int函数用于求解符号积分。int函数可以直接接通MAPLE,进行十分有效的求积。
和数值积分相比,符号积分的指令简单,适应性比较强,但是可能会占用较长的时间。有时符号积分可能会给出比较冗长的符号表达式。如果求解的是不可积的表达式,int函数会返回积分的原式并显示警告信息。
int函数的调用格式为:
int(expr):用默认的变量求符号表达式expr的不定积分。
int(expr, v):用符号变量v作为变量求符号表达式expr的不定积分数值。
int(expr, a, b):符号表达式采用默认变量,该函数求默认变量从a变到b时符号表达式expr的定积分数值。如果expr为符号矩阵,则积分对各个元素分别进行积分。
int(expr, v, a, b):用符号变量v作为变量求符号表达式expr的定积分数值。
【例7-9】 求函数
的不定积分。
1 | >> clear all; |
运行程序,输出如下,效果如图7-2所示。
1 | dy = |

图7-2 函数y 及其定积分曲线
此外,对于一些不可积的表达式,MATLAB可给出拟解析解。
【例7-10】 求函数
的不定积分表达式。
1 | >> clear all; |
运行程序,输出如下:
1 | f = |
虽然函数y 本来不可积,但是MATLAB中应用数学方法定义了一个符号:

这样就得到了一个拟解析不定积分表达式。
在MATLAB中rsums函数用于实现交互式近似积分,其调用格式为:
rsums(f)
rsums(f, a, b)
rsums(f, [a, b])
其中,f为积分函数,可以是字符串或符号形式,a与b为积分区间。它运行后得到一个界面,里面用梯形近似表示积分值,且窗体右上方的数字是近似积分值,梯形数越大,近似积分的精度越高。
【例7-11】 试对
上求定积分。
1 | >> syms x |
运行程序,输出如下,效果如图7-3所示。
1 | ans = |

图7-3 近似积分公式效果图
【例7-12】 试对
上求定积分。
1 | >> clear all; |
运行程序,输出如下:
1 | ans = |
【例7-13】 求积分
。
1 | >> clear all; |
【例7-14】 计算
,其中V 为椭圆面
的内部区域。
1 | %首先,划分积分区域 |

图7-4 三维积分区域
1 | >> %确定积分限 |
由图7-5、图7-6及椭圆面的性质,可以得到:

图7-5 x 轴侧视图

图7-6 y 轴侧视图
1 | >> syms x y z |
int函数除了可以计算表达式的符号积分外,还可以计算符号矩阵的积分。
【例7-15】 求矩阵
的积分。
1 | >> clear all; |
7.3.2 证明积分等式
下面通过示例来证明积分等式。
【例7-16】 使用int积分函数验证正态分布结果。
1 | >> syms a positive |
根据微积分的相关知识,标准正态分布满足
。因此,在本实例中,使用相应的积分变换可以得到
。在以上程序代码中,得出的结果将a 设定为任意实数的符号变量,MATLAB将会根据变量a 的不同情况来得到积分结果。
7.3.3 数值积分
求解函数定积分的数值方法有多种,如简单的梯形法、Simpson法、Romberg法等。其基本思想是将整个积分空间分割成若干个子空间,而每个小的子空间上的函数积分可求,因而整个空间函数积分可求。
- quad函数
MATLAB中给出了采用变步长辛普生法求定积分的quad函数,该函数的调用格式为:
q = quad(fun,a,b)
q = quad(fun,a,b,tol)
q = quad(fun,a,b,tol,trace)
[q,fcnt] = quad(…)
其中,q为计算的积分结果;fcnt为被积函数计算的次数;fun为函数的句柄值;a和b分别为积分的下限和上限,对于a和b的大小关系没有限制,如果用户交换a和b的位置,所得结果是前面加一个负号;tol为精度控制量,其为一个较小的数,默认值为1e-6;参数trace用于在迭代过程中表示向量[fcnt,a,b-a,q],其中输入参数fun、a和b是必需的。
【例7-17】 已知
,计算
。
由于被积函数可以有3种形式,所以用3种方法积分。
1)用M函数文件法
首先根据需要编写humps(x)的M文件,代码为:
1 | function y=humps(x) |
绘制humps函数图形,并调用quad求其积分:
1 | >> x=-1:0.01:2; |
运行程序,输出如下,效果如图7-7所示。
1 | q = 29.8583 |

图7-7 humps函数的图像
2)用内联函数法
1 | >> syms y2 |
运行程序,输出如下:
1 | p = |
3)用字符串方法
1 | >> y3='1./((x-0.3).^2+0.01)+1./((x-0.9).^2+0.04)-6'; |
运行程序,输出如下:
1 | w = |
- quadv函数
quadv函数与quad函数的功能类似,不同的是quadv函数可以求解被积函数中含向量参数的情况。函数quadv的调用格式为:
Q = quadv(fun,a,b)
Q = quadv(fun,a,b,tol)
Q = quadv(fun,a,b,tol,trace)
[Q,fcnt] = quadv(…)
该函数的输入和输出参数与函数quad的参数含义和用法类似,不同之处是对于函数quadv,被积函数fun中还有向量或者是由多个表达式组成的向量函数,因此输出积分结果q的行数与列数和输入参数fun的行数与列数相同。
【例7-18】 求解下列积分式,其中参数v 为一个向量,其值为v =[1,2,3,4,5]。

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | f1 = |
可见利用函数quadv可以同时计算多个积分,这一点在实际应用中是非常便利的,如果要用函数quad,则需要使用循环结构计算。
- quadl函数
该函数采用自适应洛巴托(Lobatto)积分来计算数值积分,其调用格式为:
q = quadl(fun,a,b)
q = quadl(fun,a,b,tol)
quadl(fun,a,b,tol,trace)
[q,fcnt] = quadl(…)
从上面介绍的调用格式可以发现quadl函数和quad函数完全相同,它们的输出参数意义也相同,这里不再介绍。
quad函数一般对于不光滑函数较低精度有效,而quadl函数对于光滑函数较高精度有效。
【例7-19】 用quad及quadl函数计算积分
,结果显示15位。
1 | %绘制函数图形 |
运行程序,输出如下,效果如图7-8所示。
1 | y1 = |

图7-8 函数的图形
需要说明的是,quad与quadl的积分限不能包含无穷大,如:
1 | >> u=inline('1./x.^2'); %定义被积函数 |
众所周知,
,显然上面两个计算积分的函数quad和quadl对于这样的积分是无能为力的。
- quadgk函数
该函数采用自适应高斯-克朗罗德(Gauss-Kronrod)积分法来计算数值积分,该函数可以用来解决含有无穷区间端点的积分、端点中等奇异的积分,以及沿分段线性路径的路径积分。该函数的调用格式为:
q = quadgk(fun,a,b)
[q,errbnd] = quadgk(fun,a,b)
[q,errbnd] = quadgk(fun,a,b,param1,val1,param2,val2,…)
其中,q为输出结果;errbnd为一个绝对误差的近似范围,其取值不大于max(AbsTol,RelTol*|q|);fun为被积函数对应的句柄;a和b是积分的上下限;param1和param2表示属性名;val1和val2是属性相应的取值。其属性名及取值如下:
● AbsTol:为绝对误差范围,其默认值为1e-10。
● RelTol:为相对误差范围,其默认值为1e-6。
● Waypoints:为积分区间内所有中断点按单调递增或者递减顺序组成的一个向量,其中奇异点不能包含在Waypoint向量里面,奇异点只能是区间端点。
● MaxInterValCount:为允许区间的最大数目,其默认值为650,超过这个数值MATLAB将会以警告的方式通知用户。
【例7-20】 计算下列积分的数值。

其中,函数p (x )和参数s 定义如下:

分析:这是3种不同类型的积分,即积分u1的上积分限是无穷大的,积分u2为一个分段不连续函数,积分u3为一个路径积分。
根据需要,编写u2的M函数文件,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | u1 = |
可见函数quadgk可以用来成功地求解一些特殊的积分问题,对于无穷积分限的情况,该函数可以得到正确的结果;对于含有断点的函数,可以通过设置断点的属性来改善结果,比较u21和u22可以看出,设置断点位置(u23)和不设置(u22)得到的结果在较小的小数位上不一样,其中u23更精确些,并且随着绝对精度参数AbsTol基本不变;对于第3个积分的计算语句,用户可以使用“@(z)1./(2*z-1)”形式来直接输入被积函数,这样对于解决表达式简单的积分问题十分方便,使得编程简单。
此外对于断点奇异的积分,函数quadgk可以解决。
【例7-21】 计算
的积分。
被积函数在x =0处是奇异的,这样的积分利用前面的quad和quadl函数是无法计算的,而quadgk函数可以轻松搞定,其代码为:
1 | >> u4=quadgk(@(x)exp(-x.^2).*log(x).^2,0,inf) |
通过上面的介绍,可以发现quadgk函数可以有效地解决一些不易计算的积分,希望用户熟练掌握这个函数的用法,来解决实际应用中的积分难题。
- dblquad函数
在MATLAB中提供dblquad函数是在矩形区域上求二重积分,其调用格式为:
q = dblquad(fun,xmin,xmax,ymin,ymax):在区域[xmin,xmax,ymin,ymax]上计算二元函数z=f(x,y)的二重积分。输入向量x,标量y,则f(x,y)必须返回一用于积分的向量。
q = dblquad(fun,xmin,xmax,ymin,ymax,tol):用指定的精度tol代替默认精度1e-5,再进行计算。
q = dblquad(fun,xmin,xmax,ymin,ymax,tol,method):用指定的算法method代替默认算法quad。method的取值有@quadl或用户指定的、与命令quad和quadl有相同调用次序的函数句柄。
【例7-22】 用dblquad函数计算二重积分
,式中,
,且精度要求为1e-6。
1 | %绘制函数的图形 |
运行程序,输出如下,效果如图7-9所示。
1 | fun = |

图7-9 函数的图形
对于非矩形积分区域,也可以用矩形积分区域来处理,但需要令超出边界部分函数值为0。
【例7-23】 用dblquad函数计算二重积分
,式中
。
1 | %用直接内联法构造函数 |
运行程序,输出如下:
1 | fun = |
运行程序,输出如下:
1 | fun = |
在很多情况下,第二种方法更便于构造复杂的边界函数
- triplequad函数
triplequad函数用于积分限均为常数的三重积分。triplequad是在立体区域上求三重积的函数,其调用格式为:
q = triplequad(fun,xmin,xmax,ymin,ymax,zmin,zmax)
q = triplequad(fun,xmin,xmax,ymin,ymax,zmin,zmax,tol)
q = triplequad(fun,xmin,xmax,ymin,ymax,zmin,zmax,tol,method)
其中,q为输出的积分结果;fun表示被积函数;xmin和xmax分别对应于变量x的下积分限和上积分限,ymin和ymax分别对应于变量y的下积分限和上积分限,zmin和zmax分别对应于变量z的下积分限和上积分限;tol是精度控制量,其默认值为1e-6;method为用指定的算法代替默认算法quad;method的取值可为@quadl、用户指定的或与命令quad和quadl有相同调用次序的函数句柄。
【例7-24】 计算三重积分
,式中
。
其实现的MATLAB代码为:
1 | >> syms x y |
运行程序,输出如下:
1 | fun = |
对于非立体的积分区域,也可以采用类似于二重积分的方法来处理。
【例7-25】 计算三重积分
,式中
。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | f = |
7.4 复合求积公式
在实际应用中,若将积分区间划分成若干个小区间,在各个小区间上采用低次的求积公式(梯形公式或抛物形公式),然后再利用积分的区间可加性,把各区间上的积分加起来,便得到新的求积公式,这就是复合求积公式的基本思想。
7.4.1 复合梯形求积法
考虑在分割的子区间
内,其积分值可以由如下3种方式来计算。
(1)利用中点的函数值代替整个区间的函数值:

(2)利用梯形面积公式来计算积分值:

(3)在式(7-2)的基础上,在子区间再细分一步的结果为:

利用上面3种公式可以得到不同的数值积分算法,结果的精度随着分割步长的减小而提高。梯形积分法的计算公式为

其中,n 表示在区间[a ,b ]上等分子区间的数目,h 为等分区间的步长。上述公式可以从式(7-3)获得,感兴趣的读者可以推导一下。梯形积分法误差的阶是O (h 2 )。根据公式(7-5)可以写出梯形积分的程序,其源代码为:
1 | function y = trapez(fun,a,b,n,varargin) |
【例7-26】 利用梯形积分法计算下面的积分,其中参数c =4。

其实现的MATLAB代码为:
1 | >> c=4; %参数赋值 |
7.4.2 复合抛物线形求积法
因为抛物形公式用到了区间的中点,所以在构造复合抛物形公式时,把积分区间[a,b]等分为偶数份,令n =2m ,其中m 为正整数,节点为
,在每两个小区间
上用抛物形公式,则有

式(7-6)称为复合抛物形求积公式,S2m 的下标2m 表示将积分区间[a,b]进行2m 等分。
根据以上公式,编写复合抛物形求积分公式M函数文件,源代码为:
1 | function s=simpr(fun,a,b,n) |
【例7-27】 用复合抛物形法求
的积分。
首先,根据需要编写方程M文件,代码为:
1 | function y=fun(x) |
调用复合抛物法求解积分,代码为:
1 | >> simpr('fun',0,2,10) |
运行程序,输出如下:
1 | ans = |
7.4.3 龙贝格求积法
该算法计算函数f (x )在区间[a ,b ]上的定积分的步骤为:
(1)初始参数k =1,并计算最粗略的积分。

(2)计算下一个位置的值。

(3)利用下面的递推公式计算。

(4)如果r k +1,k +1 和r k ,k 之间的差值满足预定义的精度,则终止计算;否则令k →k +1,进入到步骤(2)计算。
龙贝格积分法的过程将组成下面的下三角矩阵:

龙贝格积分法的思想可以理解为不断对分分割步长,并累加增加的采样点函数值。下面给出龙贝格积分的实现程序,源代码为:
1 | function y = romberg(fun,a,b,tol,varargin) |
【例7-28】 利用龙贝格积分法计算下面的两个积分,其中系数的数值为b =4,c =5。

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | f1 = |
7.4.4 复合辛普森求积法
复合辛普森公式是一种比较实用的积分方法,可以给出误差估计。下面阐述该方法的基本原理。
用n +1个点将区间[a ,b ]划分为m 个相等的子区间
。设子区间的中点为x 2k +1 ,且

在实际应用中,可以先根据离散误差估计出需要划分的区间数,然后调用辛普森公式进行积分计算,编写相应的M文件,源代码为:
1 | function s=Simpson(a,b,n) |
【例7-29】 用复合辛普森公式计算积分
,要求精度在10-5 之内。
首先,根据需要编写被积函数的M文件,代码为:
1 | function f=li7_29fun(x) |
用复合辛普森公式计算积分:
1 | >> clear all; |
运行程序,输出如下:
1 | s = |
7.4.5 逐步区间二分法
前面介绍的梯形积分和辛普森积分法的计算公式非常简单,但是对于积分区间[a,b]分割的子区间数目,用户在计算之前需要根据误差余项来估算,这一点在实际应用中不是很方便。下面来介绍逐次区间二分法,其基本思想就是不断地二分分割子区间,直到达到预先定义的精度而终止程序计算,其迭代公式为

其中,n 为分割的区间数目;Dn 为二分区间的积分值;h 2n 是二分后的步长,其值为
。计算的误差可以通过检验不等式
是否成立来控制,其中ε 是一个较小的正数,即绝对误差。对于初始分割区间数目,用户可以选择任意正整数。这里使用n =1作为初值,初始积分值为
。
编写相应的逐步区间二分法的函数,其源代码为:
1 | function y = serttow(fun,a,b,tol,varargin) |
【例7-30】 使用逐步区间二分法计算下面两个积分:

参数取值a =1.6,b =2.1,c =π。
其实现的MATLAB代码为:
1 | >> a=1.6; |
运行程序,输出如下:
1 | f1 = |
7.5 多元函数的梯度
在MATLAB中也有专门的函数求解梯度,该函数为gradient,它专门对实数矩阵求梯度。gradient函数的调用格式为:
FX = gradient(F):计算对水平方向的梯度。
[FX,FY] = gradient(F):计算矩阵F的数值梯度,其中FX为水平方向梯度,FY为垂直方向梯度,各个方向的间隔默认为1。
[FX,FY,FZ,…] = gradient(F):计算三维梯度,并可以扩展到更高的维数。
[…] = gradient(F,h):计算矩阵F的数值梯度,与上一格式的区别是将h作为各个方向的间隔。
[…] = gradient(F,h1,h2,…):三维梯度,使用h1、h2…定义间距,并可扩展到更高的维数。
【例7-31】 计算
的数值梯度。
1 | >> clear all; |
运行程序,效果如图7-10所示。

图7-10 数值梯度效果图
【例7-32】 对三阶魔方矩阵和帕斯卡矩阵计算三维数值梯度,间距为0.2、0.1、0.2。
1 | >> [PX,PY,PZ] = gradient(F,0.2,0.1,0.2) |
7.6 级数
级数是数学分析的重要内容,无论在数学理论本身或者在科学技术的应用中都是一个有力工具。MATLAB具有强大的级数求和命令。
级数是一系列与自然数n 有关的函数集合,其可表示为
an =f (n )
这里f (n )为一个与n 有关的函数。n 是不连续的,其步长为1,而级数求和可以认为是一种比较粗糙的积分模式,即积分步长dn 不是趋于0,而是等于1。
7.6.1 级数求和
在MATLAB中提供了symsum函数用于实现求有限项或者无穷项的和,其调用格式为:
r = symsum(expr):计算expr关于系统默认变量的有限项和。
r = symsum(expr, v):v为求和变量,求和将由v等于1求至v–1。
r = symsum(expr, a, b):求级数expr关于系统默认的变量从a到b的有限项和。
r = symsum(expr, v, a, b):求级数expr关于变量v从a到b的有限项和。
【例7-33】 求级数s =an +bn 的前(n -1)项和(n 从0开始)。
1 | >> syms a b n |
【例7-34】 求级数s =sinnx 的前(n –1)项和(n 从0开始)。
1 | >> syms n x |
【例7-35】 求级数s =2sin nx 的前(n –1)项和(n 从0开始),并求它的前15项的和。
1 | >> syms n |
如果需要求无穷项的和,只需将symsum参数中的求和区间端点改为无穷即可。
【例7-36】 求级数
。
1 | >> syms n |
从求解结果可知:
(1)从数学分析的级数理论知道第一个级数是发散的,因此用MATLAB求出的值为NaN。
(2)zeta(3)表示zeta函数在3处的值,其中zeta函数的定义为

zeta(3)的值为1.2021。
在工程中,有时还需要判断某个级数是否绝对收敛,那应该怎么办呢?这时可以借助abs命令来实现。
需要注意的是,并不是对所有的级数MATLAB都能够计算出结果,当它求不出级数和时会给出求和形式,如求
,当运行symsum命令时,会显示:
1 | >> syms n |
7.6.2 泰勒展开
用简单函数逼近(近似表示)复杂函数是数学中的一种基本思想,也是工程中经常用到的技术手段。
如果函数f (x )在x 0 处n 阶可微,则

其中,Rn (x )称为f (x )的余项。常用的余项公式有:
- Peano型余项:
; - Lagrange型余项:
。
特别地,当x 0 =0时带Lagrange型余项的泰勒公式为

称为Maclaurin公式。
在MATLAB中提供了泰勒函数用于实现泰勒级数展开,其调用格式为:
t=taylor(f)
t=taylor(f, n)
t=taylor(f, a)
t=taylor(f, n, v)
t=taylor(f, n, v, a)
其中,t为返回的泰勒级数;f为函数的符号表达式;n为整数时,MATLAB将进行麦克劳林级数展开而得到n-1阶多项式,n的默认整数值是6;当n为一个小数时,返回在n处展开的一个次多项式;v用来指定对符号变量v进行泰勒级数展开。
【例7-37】 对函数f (x )=a sin x +b cos x ,进行如下求解:
(1)求函数的12阶Maclaurin型近似展开;
(2)求函数在
处的12阶Taylor展开。
1 | >> clear all; |
【例7-38】 求
关于在0处的5阶Taylor展开,关于x 在1.6处的5阶Taylor展开。
1 | >> syms x y |
注意: 当a为正整数,求函数f(x)在a处的6阶Maclaurin型近似展开时,不要用taylor(f,a),否则MATLAB得出的结果将是f(x)在0处的6阶Maclurin型近似展开。
7.6.3 傅里叶展开
在实际问题中,为深入研究周期函数,可以通过将周期函数展开成为由简单的周期函数(例如三角函数)组成的级数。具体地说,将周期为
的周期函数用一系列以T 为周期的正弦函数
组成的级数来表示,记为

其中,
都为常数。为讨论方便,将正弦函数
按三角公式变形,得

最终可得到

其中,
,
,并且它们都存在的话,上式就叫做f (x )的Fourier级数。通常周期函数的周期并不一定都是2π ,更一般情况,周期为2l 的函数的Fourier级数为

在MATLAB中没有提供专门的函数实现Fourier级数展开,通过以上公式编写Forier级数展开函数,其源代码为:
1 | function [A,B,F]=Fourier(f,x,n,low,top) |
【例7-39】 求函数
的Fourier级数展开。
1 | >> syms x |
运行程序,输出如下:
1 | A = |
【例7-40】 考虑信号
,试对该信号进行Fourier级数拟合,并观察结果。
根据需要,定义信号M文件,代码为:
1 | function M=li7_39fun(x,L,p) |
根据需要,调用Fourier级数展开函数,代码为:
1 | >> clear all; |
运行程序,效果如图7-11所示。

图7-11 信号的拟合结果
7.7 积分变换
积分变换是一个非常重要的工程计算手段。它通过参变量积分将一个已知函数变为另一个函数,使函数的求解更为简单。最重要的积分变换有傅里叶变换、拉普拉斯变换、Z变换等。
7.7.1 傅里叶积分变换
在时域中的f (t )与它在频域中的傅里叶变换F (w )之间存在着如下关系:

根据以上积分定义,可以使用前面介绍的int命令直接求解,但是,MATLAB提供了专门的傅里叶变换函数fourier与反傅里叶变换函数ifourier,它们的调用格式为:
F = fourier(f):f返回对默认自变量x的Fourier变换,默认的返回形式为f(w),即f=f(x)→F=F(w);如果f=f(w),则返回F=F(t),即求
。
F = fourier(f,v):返回的Fourier变换以v为默认变量,即求
。
F = fourier(f,u,v):以v代替x并对u积分,即求
。
【例7-41】 求
的Fourier变换。
1 | >> syms x u; |
运行程序,输出如下:
1 | ans = |
【例7-42】 求
的Fourier变换,x 为实数。
1 | >> syms v u; |
运行程序,输出如下:
1 | ans = |
ifourier函数的调用格式为:
f = ifourier(F):f返回对默认自变量w的Fourier逆变换,默认的返回形式为f(x),即F=F(w)→f=f(x);如果F=F(x),则返回f=f(t),即求
。
f = ifourier(F,u):返回的Fourier逆变换以u为默认变量,即求
。
f = ifourier(F,v,u):以v代替w的Fourier逆变换,即求
。
【例7-43】 求
的逆Fourier变换。
1 | >> syms a w real; |
运行程序,输出如下:
1 | F = |
【例7-44】 求
的Fourier逆变换。
1 | >> syms w t real; |
运行程序,输出如下:
1 | ans = |
7.7.2 拉普拉斯积分变换
在数学分析中,拉普拉斯(Laplace)变换和反变换的定义为:

由于该变换也是用积分来定义的,因此,可以用int命令直接求解拉普拉斯变换。同时,MATLAB中提供了专门的函数实现拉普拉斯变换,分别为laplace与ilapace函数。
laplace函数用于实现拉普拉斯变换,其调用格式为:
laplace(F):计算默认自变量t的Laplace变换,默认的返回形式为F(s),即F=F(t)→L=L(s);如果F=F(s),则返回L=L(t),即求
。
laplace(F, t):计算结果以t为默认变量,即求
。
laplace(F, w, z):以z代替并对w积分,即求
。
【例7-45】 求
的Laplace变换。
1 | >> syms t; |
运行程序,输出如下:
1 | ans = |
【例7-46】 求
的Laplace变换。
1 | >> syms s; |
运行程序,输出如下:
1 | ans = |
ilaplace函数的调用格式为:
F = ilaplace(L):计算对默认自变量s的Laplace逆变换,默认的返回形式为F(t),即L=L(s)→F=F(t);如果L=L(t),则返回f=f(x),即求
。
F = ilaplace(L,y):计算结果以y为默认变量,即求
。
F = ilaplace(L,y,x):以x代替t的Laplace逆变换,即求
。
【例7-47】 求
的Laplace逆变换。
1 | >> syms s; |
运行程序,输出如下:
1 | ans =t |
【例7-48】 求
的Laplace逆变换。
1 | >> syms x u; |
运行程序,输出如下:
1 | ans = |
7.7.3 Z积分变换
和前面两个变换不同,Z变换适用于离散的因果系列,Z变换和其反变换定义为:

由于该变换也是用积分来定义的,因此,可以用int命令直接求解Z变换。同时,MATLAB中提供了专门的函数实现Z变换,分别为ztrans与iztrans函数。
ztrans函数用于实现Z变换,其调用格式为:
F = ztrans(f):计算默认自变量n的Z变换,默认的返回形式为F(n),即f=f(n)→F=F(z);如果f=f(z),则返回F=F(w),即求
。
F = ztrans(f, w):计算以w为默认变量,即求
。
F = ztrans(f, k, w):以w代替n并对k积分,即求
。
【例7-49】 求f (n )=x 4 的Z变换。
1 | >> syms n; |
运行程序,输出如下:
1 | ans = |
【例7-50】 求f (n )=sin(an )的Z变换。
1 | >> syms a n w; |
运行程序,输出如下:
1 | ans = |
iztrans函数的调用格式为:
f = iztrans(F):计算对默认自变量n的Z逆变换,默认的返回形式为f(n),如果F=F(n),则返回f=f(k),即求
。
f = iztrans(F,k):计算结果以k为默认变量的逆Z变换。
f = iztrans(F,w,k):以w代替n的Z变换为变量的逆Z变换。
【例7-51】 求
的Z逆变换。
1 | >> syms z |
运行程序,输出如下:
1 | ans = |
【例7-52】 求
的逆Z变换。
1 | >> syms n |
运行程序,输出如下:
1 | ans = |
【例7-53】 求
的逆Z变换。
1 | >> syms z a k |
运行程序,输出如下:
1 | ans = |
第8章 微分方程
许多实际问题的数学模型是微分方程或微分方程组的定解问题,如物体运动、电路振荡、化学反应及生物群体的变化等。能用解析方法求出精确解的微分方程为数不多,而且有的方程即使有解析解,也可能由于解析表达式非常复杂而不易计算。因此有必要研究微分方程的数值解法。
一阶常微分方程的初值,其一般形式为:

在下面的讨论中,总假定函数f (x ,y )连续,且关于y 满足Lipschitz条件,即存在常数L,使得:

这样由常微分方程理论知,式(8-1)的解必定存在惟一。
8.1 符号法求解常微分方程
8.1.1 符号法求解线性常微分方程
MATLAB符号法要求微分方程作如下形式上的变换。
(1)用“Dmy ”表示函数y =f (x )的m 阶导数
。例如,Dy 表示y 对自变量的一阶导数
;Dmy 表示y 对自变量的m 阶导数
,式中的D必须得大写。常微分方程可写成:

(2)初始条件可写为:

(3)不特别界定时,通常默认小写字母“t ”为函数的自变量。
在MATLAB中提供了dsovle函数用符号法求解常微分方程,其调用格式为:
1 | [y1,y2,...,y12]=dsolve(a1,a2,...,a12) |
式中,每个输入参数a1,a2,…,a12都包含3部分内容:符号化的微分方程、初始条件和界定的自变量。每个部分都用单引号界定,两部分之间用逗号分隔,第一部分不得缺省。当“初始条件”全部缺省或部分缺省时,输出含有待定常数的微分方程通解,待定常数的数目等于默认的初始条件数。待定常数用C1,C2,…表示。当“界定的自变量”缺省时,默认的自变量是小写“t”。由于每个输入参量ai(i=1,2,…,12)中第一部分内容不限于一个微分方程,参量ai可以多达12个,所以该命令可以用于求解常微分方程组。输出参量只有在求解一个常微分方程时可以缺省,求解常微分方程组时不得缺省,因为这时要输出多个函数,缺省将无法区分。
【例8-1】 求解一阶常微分方程
。
其实现的MATLAB代码为:
1 | >> clear all; |
以上表达式中含有一个任意常数,其表达式可写为:

1 | >> y=dsolve('Dy=-2*y+2*x^2+2*x','y(0)=1','x') %求解一阶微分方程的一个特解 |
其表达式为:

1 | %利用ezplot函数绘制曲线图 |

图8-1 一阶常微分方程的一条特解曲线图
【例8-2】 求解二阶常微分方程
。
其实现的MATLAB代码为:
1 | >> clear all; |

图8-2 二阶常微分方程的一条特解曲线
【例8-3】 求常微分方程组
的通解及满足初始条件f (0)=0.1、g (0)=2.5的特解。
其实现的MATLAB代码为:
1 | >> clear |

图8-3 常微分方程组的特解曲线
8.1.2 符号法求解特殊非线性微分方程
有一些特殊类型的非线性微分方程,也是可用dsolve函数求解的。这些微分方程往往可以直接求解出解析解。
【例8-4】 求一阶非线性微分方程
的解析解。
其实现的MATLAB代码为:
1 | >> clear all; |
即该微分方程的解析解为:

如果把该方程稍作改动,
,即有:
1 | >> y=dsolve('Dy=5*y*(2-y^4)+3') |
即此时微分方程没有解析解。
8.2 数值法求解微分方程
所谓数值解法,就是求式(8-1)的解在若干点
处的近似值
的方法,
称为式(8-1)的数值解,
称为由
的步长。一般情况下,我们总取步长为常数h 。
建立数值解法,首先要将微分方程离散化。将式(8-1)的解表示成积分形式,用数值积分方法离散化。例如,对微分方程两端积分得:

8.2.1 欧拉方法
Euler方法是最简单的一种显式单步法。对于方程:

这样即得到Euler方法。具体计算时由x 0 出发,根据初值,逐步递推而得到系列离散数值。
在MATLAB中没有提供专门的函数实现Euler法求解微分方程,通过编写eulerfun.m函数实现Euler法,其源代码为:
1 | function E=eulerfun(fun,x0,y0,xn,n) |
【例8-5】 求常微分方程
。
根据需要,建立常微分方程的M文件,源代码为:
1 | function z=fun(x,y) |
调用Euler方法求解微分方程,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | T = |
8.2.2 改进的欧拉方法
Euler方法计算量小,但是精度不高。为此可以构造梯形公式:

其中,
。这是一个二阶方法,比Euler方法精度高。但是上述公式右边有y n +1 ,因而是隐式差分方程,可以用迭代法计算y n +1 。初值可以由Euler公式提供,一般而言迭代一两次即可。在计算中迭代公式为:

即可看出这实际上是一种预估-校正方法,这种改进的Euler方法又称为Henu方法。
在MATLAB中没有提供专门的函数实现改进的Euler法求解微分方程,通过编写Gjeulerfun.m函数实现改进的Euler法,其源代码为:
1 | function E=Gjeulerfun(fun,x0,y0,xn,n) |
【例8-6】 用改进的Euler方法计算常微分方程:

首先,根据需要,编写常微分方程的M文件,源代码为:
1 | function z=fun(x,y) |
调用改进的Euler方法对常微分方程进行求解,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | T = |
8.2.3 Runge-Kutta法
Runge-Kutta(龙格-库塔)法通常简称RK方法,是19世纪末德国科学家C.Runge和M.W,Kutta提出来的一种常微分方程数值方法。Runge-Kutta法避免在算法中直接用到微商,实际上是间接使用泰勒公式的一种技术。它的基本思想是利用在某些点处的值的线性组合构造公式,使其按泰勒展开后与初值问题的解的泰勒展开式比较,有尽可能多的项完全相同以确定其中的参数,从而保证算式有较高的精度。
在Runge-Kutta法中尤其是以4阶方法使用最为广泛,又称为经典的RK方法,其公式表示为

除了经典的4阶公式,还有其他的RK4阶公式,如Gill方法。Gill方法具有减小舍入误差的优点,公式表示为:

在具体使用中,可以根据需要选择。
在MATLAB中没有提供专门的函数实现Runge-Kutta法求解微分方程,可通过编写RK4.m函数实现Runge-Kutta法,其源代码为:
1 | function R=RK4(fun,a,b,ya,n) |
【例8-7】 用Runge-Kutta法求解常微分方程:

首先,根据需要编写常微分方程的M文件,源代码为:
1 | function z=fun(x,y) |
调用Runge-Kutta法求解微分方程,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | R = |
8.3 MATLAB中微分方程的求解
在MATLAB中,提供了多种数值求解常微分方程的命令,来求解多种关于常微分方程的问题,如初值问题、延迟微分方程和微分的边界问题。
8.3.1 显性常微分方程
在数学理论中,显性常微分方程具有如下形式:

在以上公式中,
都是以变量t 为参数的向量,其中
就是该常微分方程的初值条件,微分方程需要求解的是y (t )。
尽管显性常微分方程在形式上具有统一性,但是在微分方程的性质上有很大的区别,因此MATLAB对于求解常微分方程提供了多个命令:ode45、ode23、ode113、ode15s、ode23s、ode23t和ode23tb等。以下对各函数的用法及刚性作说明。
● ode45函数:高阶(4~5)的显式单步龙格-库塔法求解微分方程组,其可以求解中等精度要求的非刚性问题。
● ode23函数:低阶(2~3)的显式单步龙格-库塔法求解微分方程组,其可以求解弱刚性、低精度要求或者原函数不光滑(比如不连续)等问题。
● ode113函数:可变阶(1~13)的多步Adams-Bsahforth-Moulton PECE求解微分方程组。其可用于求解中等精度或者较高精度要求的非刚性问题,还包括原函数较难计算的情况。但是不适用于原函数不光滑的情况(即不连续或者低阶导数不连续)。
● ode15s函数:可变阶(1~5)的隐式多步法求解微分方程组,其适用于中等精度要求的刚性问题。在使用ode45函数求解失败或者计算速度低时,用户可以尝试用这个函数。
● ode23s函数:修正的隐式单步Rosenbrock二阶法求解微分方程组,其适用于低精度要求或者原函数不连续的刚性问题。
● ode23t函数:低阶的梯形法求解适当刚性的微分方程和微分代数方程。
● ode23tb函数:低阶的方法求解难度较大的微分方程。
- 刚性和非刚性方程组
对于常微分方程,在求解过程中需要接触到一个十分重要的概念——刚性(stiffness),一个常微分方程组的刚性将直接决定求解方法和精度。如果微分方程的Jacobian矩阵的特征值相差悬殊,则这个方程组被称为刚性方程组。对于刚性方程组,为了能够保持解法的稳定,步长选取会很困难,因此有些方法将无法用来求解刚性方程组;而有些方法由于对方程组的刚性要求不严,则可以用来求解刚性方程组。
具体来讲,MATLAB中常见的方法对刚性方程组的适用范围为:
● 刚性方程组:ode15s、ode23s、ode23b和ode23t(适合轻微刚性)。
● 非刚性方程组:ode45、ode23和ode113。
在MATLAB中,用来求解显性常微分方程组的各种命令的调用格式完全一致,为了叙述方便,以上各种函数的调用方式主要如下所示:
1 | [T,Y] = solver(odefun,tspan,y0) |
其中,T是输出的变量采样点系列;Y是对应的函数的数值解;TE为一个时间序列;YE为解决时间序列的算法;IE为输出变量序列;sol为一个结构体,用来评估解决方案;solver指求解微分方程的MATLAB函数;odefun为定义微分方程组的函数,其可以用函数inline或者一个函数文件来定义;tspan为变量的求解区间;y0为初始条件;options为求解过程控制参数,其用odeset函数来定义;[t0,tf]为一个区间。
【例8-8】 使用MATLAB中的ode45命令来求解非刚性方程组的数值解:

其中,初始条件为:
。
根据需要,编写非刚性常微分方程组的M文件,源代码为:
1 | function dy = rigid(t,y) |
调用ode45求解非刚性常微分方程组,代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图8-4所示。
1 | T = |

图8-4 常微分方程组的数值解
【例8-9】 求带有附加参数的非刚性微分方程组:

其中,
。试用MATLAB函数描述该微分方程,并且绘制出α =15,β =20,γ =0.6,
,初始条件x (0)=–2.121304,y (0)=–0.066170,z (0)=2.881090时的时间响应曲线和相空间曲线。
根据需要,选定附加参数为α 、β 、γ 、a 、b ,编写M文件,源代码为:
1 | function xd=li8_10a(t,x,flag,alpha,beta,gamma,a,b) |
调用ode45函数求解微分方程,并绘制时间响应图:
1 | >> ts=0.15; |
运行程序,输出如下,效果如图8-5所示。
1 | t = |

图8-5 时间响应曲线

图8-6 相空间曲线
通过带有附加参数的微分方程M文件,可以在不改变li8_10a.m文件的情况下,当参数α 、β 、γ 、a 、b 发生改变时,很方便地得到微分方程的数值解。如选择α =10、β =15、γ =0.7、a =–120/7、b =–75/7,则可用下面代码直接求出数值解:
1 | >> ts=0.15; |
运行程序,效果如图8-7所示。

图8-7 改变附加参数值得到的时间响应曲线
- 设置允许误差属性
前面介绍的需要求解的微分方程比较简单,因此在求解过程中并没有设置解法器参数options,但是如果需要求解的微分方程比较复杂,则需要根据情况来设置相应的参数。在MATLAB中,可以设置各种解法器属性的参数,例如允许误差参数、输出参数、Jacobian矩阵参数和步长参数等。
在MATLAB中提供了odeset函数用于设定解法器的各种属性,其常用调用格式为:
options = odeset(‘name1’,value1,’name2’,value2,…)
options为返回一个结构体,其中包含了求解过程控制参数;name1, name2,…为属性名称;value1,value2,…为属性名称对应的取值。其中属性名称及其含义如表8-1所列。
表8-1 允许误差的属性设置

注意: 关于微分方程计算误差理论比较复杂,需要了解的是,对于同一个微分方程的问题,设置不同的误差属性,会直接影响方程的求解时间和效率。
【例8-10】 设置允许误差属性,重新求解例8-9中的非刚性微分方程组。
1 | >> clear all; |
运行程序,输出如下:
1 | 设置属性后消耗的时间: |
从以上结果可以看出,通过设置误差属性,求解该微分方程所用时间为0.380316s,使用默认的误差属性所用的时间为0.195412s。
比较两种方法的精度,代码为:
1 | >> size1=size(T1) |
从以上结果可看出,使用设置误差属性后的时间间隔数为85,使用默认属性的时间间隔数为77,因此,设置误差后的精度比默认情况要高。
绘制设置解法器后的数值解图形,代码为:
1 | >> tspan=[0 12]; %定义微分方程求解的时间区间 |
运行程序,效果如图8-8所示。

图8-8 设置属性后的图形
从图8-8可以看出,该图形和默认属性条件下求解的图形在外观上没有太大的区别,这是因为精度差别不能在外观上显示比较出来。
- 输出参数属性设置
在MATLAB中,解法器输出(Solver Output)参数如表8-2所列。
表8-2 解法器输出的属性参数

【例8-11】 设置解法器输出的属性,重新求解例8-9中的非刚性微分方程组。
使用默认属性,代码为:
1 | >> clear all; |
运行程序,效果如图8-9所示。

图8-9 默认输出条件下的图形
重新设置输出属性,并求解微分方程,代码为:
1 | >> options=odeset('OutputFcn',@odephas3,'Stats','on'); |
运行程序,输出如下,效果如图8-10所示。
1 | 19 successful steps |

图8-10 修改输出属性后的图形
查看默认函数的程序代码。如果希望使用第一种方法编写绘图函数,首先需要分析默认函数的程序代码,以函数“odeplot”为例,其默认的保存路径为…MATLABR2011a\toolbox\ matlab\funfun,其源代码为:
1 | function status = odeplot(t,y,flag,varargin) |
可以从上面的程序代码中选择相应的位置,修改图形的相关属性,然后保存函数,就可以设置用户自定义的函数。
- 解法器的其他属性设置
关于解法器的其他属性,不再一一详细介绍,感兴趣的读者可以查询MATLAB的联机帮助文档。下面选择一个比较综合的例子说明如何设置属性来求解具体的实例。
【例8-12】 求解小球反弹的轨迹模型,该小球在反弹后速度变为下落速度的90%,使用微分方程来求解小球运动的轨迹。
已知反弹球公式为:

根据需要,编写反弹球公式的M文件,源代码为:
1 | function dydt = fli8_13(t,y) |
为微分方程的求解过程编写“定位事件”函数,源代码为:
1 | function [value,isterminal,direction] = events(t,y) |
调用相关解法器,求解微分方程,并绘制小球运动轨迹图,源代码为:
1 | >> clear all; |
运行程序,效果如图8-11所示。

图8-11 小球运动轨迹效果图
下面通过一个示例演示各个ode求解器的用法。
【例8-13】 分别考虑用ode45、ode15s、ode23及ode23s求解微分方程初始问题:

首先建立微分方程组的M文件,代码如下:
1 | function dx=li8_14fun(t,x) |
建立精确解的M文件,代码如下:
1 | function y=li8_14funB(x) |
其实现的MATLAB代码如下:
1 | >> options=odeset('RelTol',1e-6); |
比较各个方法所需要耗费的机时和求解过程中状态变量的规模大小,显然ode15s与ode23s花费的计算时间最少,仅仅需要将求解时间区域分割为几十个单元;而ode45与ode23在达到同种精度的情形下,需要比前者多出大约3~5倍的计算时间。
1 | >> yt1=li8_15funB(x1); |
![]() |
![]() |
| 图8-12 ode45求解刚性微分方程的误差局部图 | 图8-13 ode15s求解刚性微分方程的误差图 |
![]() |
![]() |
| 图8-14 ode23求解刚性微分方程的误差图 | 图8-15 ode23s求解刚性微分方程的误差图 |
8.3.2 隐式微分方程
隐式微分方程就是不能转换成显式常微分方程组的微分方程,在MATLAB中提供了ode15i函数用于求解隐式微分方程。其调用格式为:
1 | [T,Y] = ode15i(odefun,tspan,y0,yp0) |
其中,参数yp0是导数y’的初始条件,其他参数的含义与别的ode系列函数的参数含义相同。
【例8-14】 求解下面隐式微分方程的数值解:

初始条件为
。
根据需要,定义隐式微分方程的M文件,源代码为:
1 | function D = li8_15a(t,x,xp) |
调用ode15i函数求解隐式微分方程组,代码为:
1 | >> clear all; |
运行程序,效果如图8-16所示。

图8-16 隐式微分方程曲线
【例8-15】 求解隐式微分方程组:

其初始值为
,试求该隐式微分方程的数值解。
选择状态变量x =[x 1 ,x 2 ,x 3 ,x 4 ],其中
,则原隐式微分方程可转换为:

根据需要,编写隐式微分方程转换后的微分方程的M文件,源代码为:
1 | function f=li8_16a(t,x,xd) |
调用ode15i求解隐式微分方程,并绘制该方程解的时间曲线,代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图8-17所示。
1 | sol = |

图8-17 隐式微分方程的时间状态图
8.3.3 微分代数方程的求解
常微分方程的数值解法主要是针对能够转换成一阶微分方程组的类型,对于某些方程组中含有代数方程的问题,就无能为力,必须借助微分代数方程的特殊解法。
微分代数方程是指在微分方程中,某些变量间满足某些代数方程的约束,其一般形式为

其中,M (t ,x )矩阵通常是奇异矩阵。在MATLAB语言中提供了ode15s来求解。
【例8-16】 求解下面的微分方程的数值解。

其初始条件为
。
分析:其中最后一个方程为一个代数方程,来约束4个分量之间的关系,而前3个方程是典型的一阶微分方程。这个问题的方程可以转为下面的形式:

根据需要,编写代数微分方程的M文件,源代码为:
1 | function dx=li8_17a(t,x) |
调用ode15s函数求解代数微分方程,并绘制其对应时间状态曲线,代码为:
1 | >> clear all; |
运行程序,效果如图8-18所示。

图8-18 代数微分方程的时间状态图
需要注意的是:在例8-16中可以使用函数ode15s和ode23t得到正确的结果,其他ode系列函数,如ode23s、ode23tb、ode45、ode23和ode113不能得到正确的结果。并且odefun的表示方法需要使用符号@,而用户把语句“[t,x] = ode15s(@li8_17a,tspan,x0,options);”改为“[t,x] = ode15s(‘li8_17a’,tspan,x0,options);”,则会弹出如下错误:
1 | ??? SWITCH expression must be a scalar or string constant. |
【例8-17】 用ode15i求解下面隐式代数方程:

即可得到一个隐式微分方程形式,分量x 1 可用1-x 2 来计算。设y 1 =x 2 ,y 2 =x 3 ,即隐式微分方程可转化为:

根据需要,编写转化后的微分方程M文件,源代码为:
1 | function D = li8_18a(t,y,yp) |
调用ode15i求解隐式微分方程,并绘制其对应的时间状态图,代码为:
1 | >> clear all; |
运行程序,效果如图8-19所示。

图8-19 隐式微分代数方程的时间状态图
从例8-17可以发现求解代数微分方程的另一个思路是:把其中的代数方程转化为另外一种形式,即用其他分量表示其中的一个分量,再把这个结果带入其他微分方程进行消元处理,从而可能得到一个隐式微分方程组,再调用ode15i函数来计算。
8.3.4 加权常微分方程
加权常微分方程的通用形式为:

在该方程中,M (t ,y )被称为加权函数,是一个矩阵。矩阵中的元素包含了y 和t 两个变量,并且一般无法转换为一维函数,否则就可以直接转换为右侧的函数表达式。
【例8-18】 求解以下加权常微分方程,其中:

同时,微分方程函数如下:

在以上方程组中,(X ,Y )表示是物体的坐标数值,θ 表示物体运动的角度,同时对应的初始数值为y 0 =[0;4;2;20;π/2;2]。
根据需要,建立微分方程的mass属性M文件,源代码为:
1 | function M = mass(t,y,m1,m2,L,g) |
建立微分方程的M文件,源代码为:
1 | function dydt = li8_19a(t,y,m1,m2,L,g) |
调用ode45函数求解微分方程,并绘制其时间状态曲线,代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图8-20所示。
1 | t = |

图8-20 微分方程的数值解
8.3.5 延迟微分方程
在数学理论中,延迟微分方程具有以下形式:

在该函数表达式中,时间跨度区间为
都为常数,表示的是正的时间延迟。
在MATLAB中提供了dde23函数用于求解延迟微分方程,其调用格式为:
sol = dde23(ddefun,lags,history,tspan)
sol = dde23(ddefun,lags,history,tspan,options)
其中,sol为输出的求解结果,其为结构数据;sol.x表示时间变量采样值;sol.y表示函数值分量的取值;ddefun表示延迟微分方程;lags表示时间延迟常数;history表示在求解时间区间上的变量值的函数,如果是一个函数形式,可以用MATLAB的函数文件形式定义,如果是变量则直接赋值即可;tspan是求解时间范围;options是控制过程参数的结构体,其由函数ddeset来设置,即options=ddeset,用法类似函数odeset。
【例8-19】 求解下面具有混沌状态的延迟微分方程:

其中,在t ≤0时,x (t )=0.6,两个延迟常数分别为
,试求该方程在区间[0 199]的相位图。
首先建立具有混沌状态的延迟微分方程的M函数,代码如下:
1 | function dydt=li8_20fun(t,y,z) |
其实现的MATLAB代码如下:
1 | >> clear all; |
运行程序,输出如下,效果如图8-21所示。
1 | sol = |

图8-21 延迟微分方程组的相位图
【例8-20】 求解下面延迟微分方程的解。

其中,x 1 (t )=x 2 (t )=x 3 (t )=0。
根据需要,建立延迟微分方程的M文件,源代码为:
1 | function dx=li8_21a(t,x,lags) |
调用dde23函数求解延迟微分方程,代码为:
1 | >> clear all; |
运行程序,效果如图8-22所示。

图8-22 延迟微分方程组的求解结果
8.4 常微分方程的仿真
在MATLAB中,可以利用Simulink仿真工具对常微分方程进行求解,并对该方程描述的动态系统进行仿真。
DEE是Simulink中的一个模块,在命令窗口中运行dee,就会出现该模块界面,如图8-23所示。

图8-23 DEE模块界面
其中,界面正中的Differential Equation Editor是模型编辑模块,下方deedemol、deedemo2、deedemo3、deedemo4是4个系统自带的实例。
下面通过一个具体的例子介绍如何使用DEE模块进行常微分方程的数值求解和动态仿真。
【例8-21】 求解Lorenz模型的状态方程:

其中,其初值为x 1 (0)=x 2 (0)=0.01,x 3 (0)=0.1。
其实现步骤为:
(1)在图8-23的DEE界面中,单击【File】菜单下的【New】子菜单下的【Model】选项,弹出新的模型编辑窗口,如图8-24所示。

图8-24 模型编辑窗口
(2)将DEE界面中的Differential Equation Dditor拖入模型编辑窗口,在命令窗口中输入Simulink,在Simulink界面中选择Sinks下面的XY Gragh模块,并将其拖入编辑窗口中,效果如图8-25所示。

图8-25 添加模块的编辑窗口
(3)在模型编辑窗口中双击Differential Equation Dditor模块,进行方程的定义、初始值设置和输出设置,效果如图8-26所示,定义完毕后,单击Done按钮保存。

图8-26 定义方程参数
(4)在模型编辑窗口中将Differential Equation Dditor模块与XY Gragh模块连接在一起,如图8-27所示。

图8-27 连接模块
(5)在模型编辑窗口中单击XY Gragh模块,在打开的对话框中进行输出图形设置,如图8-28所示。

图8-28 XY Gragh模块参数设置
(6)在模型编辑窗口中单击【Simulation】菜单下的【Configuration Paramenters】选项,进行仿真属性设置。其中最常用的是Solver(进行仿真时间、方程求解算法等,如图8-29所示)和Data Import/Export(输入数据、输出数据等,如图8-30所示)。

图8-29 Solver的参数设置

图8-30 Data Import/Export的参数设置
(7)在模型编辑窗口中单击【Simulation】菜单下的【Start】选项,开始进行仿真,单击Pause按钮可以暂停,单击Stop按钮可以停止,仿真效果如图8-31所示。

图8-30 Data Import/Export的参数设置
8.5 常微分方程的边界问题
一般情况下,微分方程的边界问题可能有解,也可能无解,可能有唯一解,也可能有无数解。在本节中主要讨论的问题局限于有唯一解的范围内。在有唯一解的情况下,求解边界问题有3种基本的方法:
- 叠加法:假设微分方程和边界条件都是线性的,问题可以转换为可以使用ode类命令求解的初值问题。
- 试射法:问题转换为对缺漏的初值的搜索问题,一旦缺漏的初值被确定,问题就会转换为初值问题。
- 松弛法:首先猜测满足边界条件的区间网点上的解值,然后利用微分方程进行迭代改善。
在MATLAB中提供了bvp4c命令用于求解边界问题,该命令使用的是有限元方法,属于松弛法,所得到的精度比较均匀。将常微分方程组整理成以下形式:

同时,满足的边界条件为g (y (a ),y (b ))=0。其中a 和b 是微分方程求解区间的上限和下限,也就是y 在[a ,b ]中进行数值求解。
更一般的情况是,MATLAB还可以求解带有未知参数的微分方程,其具体形式为:

其中,参数满足的边界条件为g (y (a ),y (b ),p )=0,变量p 是未知参数,需要通过边界条件来充分决定。
MATLAB中求解微分方程的相关命令介绍如下。
1)bvpinit函数
该函数用于生成bvp4c命令所必需的猜测数据网格,其调用格式为:
1 | solinit = bvpinit(x,yinit) |
其中,变量x的含义是对指定边界区间[a,b]上的初始网格;yinit则是对数值解的初始猜测数值,可以是常数向量或者函数向量。当yinit是常数向量时,表示解分量中所在所有初始网格点上的猜测值都会取yinit;当yinit是函数向量时,表示在解向量所有分量所在的网点上取值为函数值。
2)bvp4c函数
该函数用于给出微分方程边界问题的数值解,其调用格式为:
1 | sol = bvp4c(odefun,bcfun,solinit) |
其中,odefun表示计算导数的M函数文件,其格式为dydx=odefun(x,y),或者包含未知参数的格式dydx=odefun(x,y,p);bcfun是描述边界条件的函数,其具体格式为res=bcfun(ya,yb),或者包含未知参数的格式res=bcfun(ya,yb,p);solinit表示的是对方程解的猜测解,它是一个结构体,包含x、y和p三个属性,可以由bvpinit命令获得。
3)bvpval函数
该函数用于计算微分方程积分区间内任何一点的解值,其调用格式为:
1 | sxint=bvpval(sol,xint) |
其中,sol为bvp4c的输出变量,xint则是需要计算区间的参数数值。
【例8-22】 求解以下微分方程:

其中,方程的边界条件为
。
根据相关的数学知识可知,该微分方程有解析解,表达式为
,因此在此可以将数值求解得到的数值和该表达式中的数值进行对比。
根据需要,编写微分方程的M文件,源代码为:
1 | function dydx = li8_23a(x,y) |
根据需要,编写边界条件的M文件,源代码为:
1 | function res = li8_23b(ya,yb) |
调用bvp4c函数求解微分方程的边界问题,代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图8-32所示。
1 | sol = |

图8-32 微分方程求解的图形效果
【例8-23】 求解以下微分方程:

其边界条件为
。
根据需要,编写微分方程的M文件,源代码为:
1 | function dydx = li8_24a(x,y,lambda) |
根据需要,编写边界条件的M文件,源代码为:
1 | function res = li8_24b(ya,yb,lambda) |
根据需要,编写初始值的M文件,源代码为:
1 | function yinit = li8_24c(x) |
调用bvp4c函数求解微分方程的边界问题,代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图8-33所示。
1 | sol = |

图8-33 微分方程的数值解图
第9章 偏微分方程
偏微分方程(PDE)在19世纪得到迅速发展,那时的许多数学家对数学物理问题的解决做出了贡献。到现在,偏微分方程已经是工程及理论研究不可或缺的数学工具(尤其是在物理学中),因此解偏微分方程也成为工程计算中的一部分。
MATLAB可以求解一般的偏微分方程,也可以用偏微分方程工具箱中给出的相应函数求解。
9.1 偏微分方程组求解
MATLAB中提供了pdepe函数,可以直接求解如下形式的偏微分方程:

偏微分方程可以编写下面的函数描述,其入口为:
[c,f,s]=pdefun(x,t,u,ux)
其中,pdefun为函数名。这样,由给定的输入变量即可计算出c,f,s三个函数。
边界条件可以用下面的函数描述为:

这样的边界值函数可以用如下的MATLAB函数描述:
[pa,qa,pb,qb]=pdebc(x,t,u,ux)
除了这两种函数外,还应该写出初始条件的函数。偏微分方程初始条件的数学描述为u(x,t0)=u0。另外,需要一个简单的函数来描述,编写简单函数u0=pdeic(x)即可。
还可以选择x和t的向量,再加上描述的这些函数,就可以用pdepe函数求解次偏微分方程。pdepe函数的调用格式为:
sol=pdepe(m,@pdefun,@pdeic,@pdebe,x,t)
【例9-1】 求解下面的偏微分方程:

其中,
,且满足初始条件
及边界条件:

根据需要,编写偏微分方程的M文件,源代码为:
1 | function [c,f,s] = li9_1a(x,t,u,DuDx) |
根据需要,编写初始值的M文件,源代码为:
1 | function u0 = li9_1b(x) |
根据需要,编写边界条件的M文件,源代码为:
1 | function [pl,ql,pr,qr] = li9_1c(xl,ul,xr,ur,t) |
调用pdepe函数求解偏微分方程,其代码为:
1 | >> clear all; |
运行程序,效果如图9-1及图9-2所示。
![]() |
![]() |
| 图9-1 u1(t,x)效果图 | 图9-2 u2(t,x)效果图 |
9.2 偏微分方程的边界求解
9.2.1 边界条件概述
边界条件是解偏微分方程所不可缺少的,常用的边界条件有如下两种:
(1)Dirichlet边界条件:
。
(2)Neumann边界条件:
。
其中n 为边界
外法向单位向量,g 、q 、h 和r 为在边界
上定义的函数。Dirichlet边界条件也称为第一类边界条件;Neumann边界条件称为第三类边界条件;如果q =0,则称为第二类边界条件。对于特征值问题仅仅限于齐次条件:g =0,r =0;对于非线性椭圆情况,系数g 、q 、h 、r 可以与u 有关;对于抛物型与双曲线型偏微分方程,系数可以是关于t 的函数。
对于偏微分方程组,Dirichlet边界条件为:

其中,μ 的计算要使得Dirichlet边界条件满足。
9.2.2 边界条件设置
边界条件的一般形式为:

是外法线方向。有M 个Dirichlet条件,且矩阵h 是
。广义的Neumann条件包含一个要计算的Lagrange乘子μ 。若M =0,即为Neumann条件;若M =N ,即为Dirichlet条件;若M <N ,即为混合边界条件。
边界条件也可以通过M文件的编写来实现,如果边界条件的M文件为pdebound,那么它的编写必须满足如下调用格式:
[q,g,h,r]=pdebound(p,e,u,time)
该边界条件的M文件在边界e上算出q、g、h、r的值,其中p、e是网格数据,且仅需要e是网格边界的子集;输入变量u和time分别用于非线性求解器和时间步长算法;输出变量q、g必须包含每个边界中点的值,即size(q)=[ N2 ne](N是方程组的维数,ne是e中边界数,size(h)=[N ne]);对于Dirichlet条件,相应的值一定为零;h和r必须包含在每条边上的第1点的值,接着是在每条边上第2点的值,即size(h)=[N2 2*ne](N是方程组的维数,ne是e中边界数,size(r)=[N–2*ne]),当M<N时,h和r一定有N–M行元素是零。
下面是MATLAB的偏微分方程工具箱自带的一个区域为单位正方形、其左右边界为u=0、上下边界为u的法向量导数为0的M文件源程序:
1 | function [q,g,h,r]=squareb3(p,e,u,time) |
该M文件中的pdeexpd函数为一个估计表达式在边界上的值的函数。
9.2.3 区域设置及网格化
在利用MATLAB求解偏微分方程时,可以利用M文件来创建偏微分方程定义的区域,如果该M文件名为pdegeom,则它的编写要满足下面的法则。
该M文件必须能用下面的3种调用格式:
- ne=pdegeom
- d=pdegeom(bs)
- [x,y]=pdegeom(bs,s)
其中,输入变量bs是指定的边界线段,s为相应的线段弧长的近似值。输出变量ne表示几何区域边界的线段数。输出变量d为一个区域边界数据的矩阵。d的第一行是每条线段起始点的值;第二行是每条线段结束点的值;第三行是沿线段方向左边区域的标识值,如果标识值为1,则表示选定左边区域,如果标识值为0,则表示不选左边区域;第四行是沿线段方向右边区域的值,其规则同上。输出变量[x,y]是每条线段的起点和终点所对应的坐标。
【例9-2】 画一个心形线所围成区域的M文件,心形线的函数表达式为:

分析:在此将这条心形线段分为4段:第一段的起点为
,终点为
;第二段的起点为
,终点为
;第三段的起点为
,终点为
;第四段的起点为
,终点为
。
该M文件的源代码为:
1 | function [x,y]=cardg(bs,s) |
为了验证所编写的M文件的正确性,在MATLAB命令窗口中输入:
1 | >> nd=cardg |
有了区域的M文件,接下来要做的就是网格化,创建网格数据。在MATLAB中提供了initmesh函数用于创建网格数据。其调用格式为:
[p,e,t]=initmesh(g):返回一个三角形网格数据,其中g可以是一个分解几何矩阵,也可以是M文件。
[p,e,t]=initmesh(g,’PropertyName’,PropertyValue,…):在上面命令功能的基础上加上属性设置,其属性如表9-1所列。
表9-1 initmesh属性

其中,initmesh函数的输出参数含义为:p、e、t是网格数据。p为节点矩阵,其第1行和第2行分别是网格节点的x坐标和y坐标;e为边界矩阵,其第1行和第2行是起点和终点的索引,第3行和第4行是起点和终点参数值,第5行是边界线段的顺序数,第6行和第7行分别是子区域左边和右边的标识;t为三角形矩阵,其前三行按逆时针方向给出三角形顶点的次序,最后一行给出子区域的标识。
在创建好初始网格数据后,还可以对其进行优化与加密。在MATLAB中提供了jigglemesh函数用于对网格进行优化处理,提供了refinemesh函数用于对网格进行加密处理。
jigglemesh函数的调用格式为:
p1=jigglemesh(p,e,t):通过调整节点位置来优化三角形网格,以提高网格质量,返回调整后的节点矩阵p1。
p1=jigglemesh(p,e,t,’PropertyName’,PropertyValue,…):在上面命令功能的基础上加上属性设置,属性如表9-2所列。
表9-2 jigglemesh属性

【例9-3】 初始化MATLAB自带的lshapeg网格,并对其进行优化处理。
1 | >> clear all; |
![]() |
![]() |
| 图9-3 初始化网格 | 图9-4 优化后的网格 |
refinemesh函数的调用格式为:
[p1,e1,t1]=refinemesh(g,p,e,t):返回一个被几何区域g、节点矩阵p、边界矩阵e和三角形矩阵t指定的经过加密的三角形网格矩阵。
[p1,e1,t1]=refinemesh(g,p,e,t,’regular’):使用规则加密法进行加密,即所有指定的三角形单元都被分为4个形状相同的三角形单元。
[p1,e1,t1]=refinemesh(g,p,e,t,’longest’):使用最长边加密法,即把指定的每个三角形单元的最长边二等分。
[p1,e1,t1]=refinemesh(g,p,e,t,it):如果it为行向量,则为要加密的子区域的表;如果it为列向量,则为一个要加密的三角形表格。
[p1,e1,t1]=refinemesh(g,p,e,t,it,’regular’):使用规则加密法进行加密。
[p1,e1,t1]=refinemesh(g,p,e,t,it,’longest’):使用最长加密法进行加密。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u):不仅加密网格,而且还用线性插值的方法将u扩展到新的网格上。u的行数与p的列数对应,u1的行数与p1元素一样多,u的每一列分别被进行内插值。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u,’regular’):使用规则加密法进行加密。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u,’longest’):使用最长加密法进行加密。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u,it):如果it为行向量,则为要加密的子区域的表;如果it为列向量,则为一个要加密的三角形表格。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u,it,’regular’):使用规则加密法进行加密。
[p1,e1,t1,u1]=refinemesh(g,p,e,t,u,it,’longest’):使用最长加密法进行加密。
除此之外,MATLAB还提供了pdemesh函数用于绘制三角形网格图,其调用格式为:
pdemesh(p,e,t):绘制由网格数据p、e、t指定的网格图。
pdemesh(p,e,t,u):用网格图绘制节点或三角形数据u。如果u为列向量,则组装节点数据;如果u为行向量,则组装三角形数据。
h=pdemesh(p,e,t):绘制由网格数据p、e、t指定的网格图,并返回一个轴对象句柄。
h=pdemesh(p,e,t,u):用网格图绘制节点或三角形数据u,并返回一个轴对象句柄。
【例9-4】 对于MATLAB自带的cardg网格数据进行3次加密处理。
1 | >> clear all; |
运行程序,效果如图9-5所示。

图9-5 网格数据的加密处理效果
9.3 二阶偏微分方程
除了前面介绍的一类偏微分方程外,MATLAB还有自己的偏微分方程工具箱,可以比较规范地求解各种常见的二阶偏微分方程。
9.3.1 椭圆型偏微分方程
椭圆型偏微分方程的一般表示形式为:

在MATLAB中提供了adaptmesh(自适应网格法)函数与assempde函数进行对椭圆型方程求解。
adaptmesh函数调用格式如下:
[u,p,e,t]=adaptmesh(g,b,c,a,f):求解椭圆偏微分方程,其中g为几何区域,b为边界条件,输出变量u为解向量,p、e、t为网格数据。
[u,p,e,t]=adaptmesh(g,b,c,a,f,’PropertyName’,PropertyValue,):PropertyName为属性名,PropertyValue为相应的属性值,其属性如表9-3所列。
表9-3 adaptmesh属性

【例9-5】 利用adaptmesh函数求解扇形区域上的Laplace方程,其在弧上满足Dirichlet条件
,在直线上满足u =0,并与精确解进行比较。
1 | >> clear all; |
运行程序,输出如下,效果如图9-6所示。
1 | Number of triangles: 197 |

图9-6 扇形Laplace方程pdemesh求解
在MATLAB中还提供了assempde函数用于求解椭圆型偏微分方程,其调用格式如下:
u=assempde(b,p,e,t,c,a,f):根据从线性方程组中消去Dirchlet边界条件(约束处理)的边界点来组装和求解椭圆型偏微分方程。
u=assempde(b,p,e,t,c,a,f,u0):u0为初始条件,用于非线性求解。
u=assempde(b,p,e,t,c,a,f,u0,time):u0为初始条件,用于非线性解,time用于时间步长算法。
u=assempde(b,p,e,t,c,a,f,time):time用于时间步长算法。
[K,F]=assempde(b,p,e,t,c,a,f):用刚度弹性逼近Dirichlet边界条件来组装偏微分方程,K、F分别为刚度矩阵和方阵右边的函数矩阵,它有有限元法解为u=K\F。
[K,F]=assempde(b,p,e,t,c,a,f,u0):u0为初始条件,用于非线性解。
[K,F]=assempde(b,p,e,t,c,a,f,u0,time):u0为初始条件,用于非线性解,time用于时间步长算法。
[K,F]=assempde(b,p,e,t,c,a,f,u0,time,sdl):sdl为子区域标识选项表,其作用是依表中所标识的子区域来限制组装过程。
[K,F]=assempde(b,p,e,t,c,a,f,time):time用于时间步长算法。
[K,F]=assempde(b,p,e,t,c,a,f,time,sdl):time用于时间步长算法,sdl为子区域标识选项表。
[K,F,B,ud]=assempde(b,p,e,t,c,a,f):从线性方程中删去Dirichlet边界条件的边界点来组装偏微分方程问题,在非Dirichlet条件点上的解为u1=K/F,而完整的解为u=B*u1+ud。
[K,F,B,ud]=assempde(b,p,e,t,c,a,f,u0):u0为初始条件,用于非线性。
[K,F,B,ud]=assempde(b,p,e,t,c,a,f,u0,time):u0为初始条件,用于非线性,time为用于时间步长算法。
[K,F,B,ud]=assempde(b,p,e,t,c,a,f,time):time为用于时间步长算法。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f):给出一个偏微分方程问题的分解表达式。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f,u0):u0为初始条件。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f,u0,time):u0为初始条件,time用于时间步长算法。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f,u0,time,sdl):u0为初始条件,time用于时间步长算法,sdl为子区域标识选项表,其作用是依表中所标识的子区域来限制组装过程。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f,time):time用于时间步长算法。
[K,M,F,Q,G,H,R]=assempde(b,p,e,t,c,a,f,time,sdl):time用于时间步长算法;sdl为子区域标识选项表,其作用是依表中所标识的子区域来限制组装过程。
u=assempde(K,M,F,Q,G,H,R):将分解表达式分解成单个的矩阵或向量的形式,然后从方程组中删去Dirichlet边界条件的边界点,再解偏微分方程问题。
[K1,F1]=assempde(K,M,F,Q,G,H,R):根据带有弹性系数的固定Dirichlet边界条件来分解表达式成单个的矩阵或向量。
[K1,F1,B,ud]=assempde(K,M,F,Q,G,H,R):从线性方程组中删去Dirichlet边界条件的边界点来分解表达式成单个的矩阵或向量形式。
【例9-6】 利用assempde函数求解例9-5中的Laplace方程。
1 | >> clear all; |
运行程序,输出如下,效果如图9-7所示。
1 | 第一次加密的最大误差: |

图9-7 扇形Laplace方程assempde求解
9.3.2 抛物型偏微分方程
抛物型偏微分方程的一般形式为:

根据上面的叙述,如果c 为常数,则该方程可以更简单地表达为:

在MATLAB中提供了parabolic函数用于求解抛物线型偏微分方程,其调用格式如下:
u1=parabolic(u0,tlist,b,p,e,t,c,a,f,d):用有限元法求解在区域Ω上,具有网格数据p、e、t,并带有边界条件b和初始值u0的抛物型偏微分方程(组)。其中tlist为时间列表,u1中每一列都是tlist中所对应的解。b为边界条件,可以依赖于时间t,p、e、t为网格数,c、a、f、d为方程的系数。
u1=parabolic(u0,tlist,b,p,e,t,c,a,f,d,rtol):rtol为通过了偏微分方程求解器的相对误差。
u1=parabolic(u0,tlist,b,p,e,t,c,a,f,d,rtol,atol):atol为通过了偏微分方程求解器的绝对误差。
u1=parabolic(u0,tlist,K,F,B,ud,M):求带有初始条件u0的常微分方程的解
,
。
u1=parabolic(u0,tlist,K,F,B,ud,M,rtol):rtol为通过了偏微分方程求解器的相对误差。
u1=parabolic(u0,tlist,K,F,B,ud,M,rtol,atol):atol为通过了偏微分方程求解器的绝对误差。
【例9-7】 在几何区域
,当
时,u (0)=1,其他区域上u (0)=0,且满足Dirichlet边界条件u =0,求在时刻0, 0.005, 0.01,… , 0.1处热传导方程
的解。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图9-8所示。
1 | 96 successful steps |

图9-8 解的网格表面图
注意: 在边界条件的表达式和偏微分方程的系数中,符号t用来表示时间,变量t通常用来存储网格的三角矩阵。事实上,可以用任何变量来存储三角矩阵,但在偏微分方程工具箱的表达式中,t总表示时间。
9.3.3 双曲型偏微分方程
双曲型偏微分方程的一般形式为:

如果c 为常数,则可以将该方程得化为:

在MATLAB中提供了hyperbolic函数用于求解双曲线型偏微分方程,其调用格式如下:
u1=hyperbolic(u0,ut0,tlist,b,p,e,t,c,a,f,d):求解满足初始值u0和初始导数ut0,边界条件为b的双曲型偏微分方程(组),解矩阵u1中的每一行对应于p的列所给出的坐标处的解,u1中的每一列对应着tlist中的时刻的解。p、e、t为网格数,e、a、f、d为方程的系数。
u1=hyperbolic(u0,ut0,tlist,b,p,e,t,c,a,f,d,rtol):rtol为相对误差。
u1=hyperbolic(u0,ut0,tlist,b,p,e,t,c,a,f,d,rtol,atol):atol为绝对误差。
u1=hyperbolic(u0,ut0,tlist,K,F,B,ud,M):求解初始值为u0和ut0的常微分方程问题:

u1=hyperbolic(u0,ut0,tlist,K,F,B,ud,M,rtol):rtol为相对误差。
u1=hyperbolic(u0,ut0,tlist,K,F,B,ud,M,rtol,atol):atol为绝对误差。
【例9-8】 已知正方形区域
上的波动方程为:

边界条件为:当x =±1时,u =0;当y =±1时,
。
初始条件为:
。
求该方程在时间t =0,1/6,1/3,…,29/6,5时的值。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下,效果如图9-9所示。
1 | 462 successful steps |

图9-9 解的网格表面图
从上面3种类型方程可以看出,它们直接的区别在于u函数对t的导数阶次。如果对t没有求导,则可以理解为其值为常数,故称为椭圆型偏微分方程。如果取u对时间的一阶导数,则一阶导数与u对x的二阶导数直接构成了抛物型关系,故称其为抛物型偏微分方程。如果对t取二阶导数,则可以称之为双曲型偏微分方程。
9.3.4 非线性椭圆型方程
对于非线椭圆型偏微分方程组的模型如下:

其中
是平面上的有界区域,c 、a 、f 是关于u 的函数。
在MATLAB中提供了pdenonlin函数用于求解非线性椭圆型方程,其调用格式如下:
[u,res]=pdenonlin(b,p,e,t,c,a,f):求定义在Ω上的特征值偏微分方程的解,b为边界条件,p、e、t为区域的网格数据,c、a、f为方程的系数,u为解向量,res为牛顿步残差向量的范数。
[u,res]=pdenonlin(b,p,e,t,c,a,f,’PropertyName’, ‘PropertyValue’,…):PropertyName为属性名,PropertyValue为对应的属性值,其取值如表9-4所列。
表9-4 pdenonlin属性

【例9-9】 求解非线性椭圆型方程:

方程系数为
。
其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,效果如图9-10所示。

图9-10 非线性椭圆型方程求解图
9.3.5 特征值型偏微分方程
MATLAB可以直接求解的另一类特征值型偏微分方程为:

如果c为常数,该方程还可以简化成:

在MATLAB中提供了pdeeig函数用于求解特征方程的偏微分方程,其调用格式如下:
[v,l]=pdeeig(b,p,e,t,c,a,d,r):用有限元法求定义在Ω上的特征值偏微分方程的解,其中b为边界条件,p、e、t为区域的网格数据,c、a、d为方程的系数,r为实轴上的一个区间端点构成的向量,输出变量l为实部在区间r上的特征值所组成的向量,v为特征向量矩阵,v的每一列都是p所对应的节点处的解值的特征向量。
[v,l]=pdeeig(K,B,M,r):产生下面稀疏矩阵特征值问题的解:
,其中λ 的实部在区间r中。
【例9-10】 求解方程
在L型区域上的小于100的特征值及其相应的特征模态,并演示第1个特征及第15个特征的模态。
其实现的MATLAB代码如下:
1 | >> clear all; |
运行程序,输出如下,效果如图9-11及图9-12所示。
1 | Basis= 10, Time= 0.08, New conv eig= 0 |
![]() |
![]() |
| 图9-11 第1特征模态效果图 | 图9-12 第15特征模态效果图 |
9.4 偏微分方程的PDE图形界面
9.4.1 PDE图形界面概述
MATLAB偏微分方程工具箱提供了一个界面,可以求解二元偏微分方程
。求解区域可以用该界面提供的画圆、椭圆、矩阵及多边形等工具任意绘制,也可以由若干个简单集合进行并集、交集、差集等构成所需的求解区域。完成求解区域的绘制后,还可以用该界面提供的功能将原求解区域用三角形的形式自动绘制出网格。
在MATLAB命令窗口中输入pdetool,将启动偏微分方程求解界面,如图9-13所示。

图9-13 偏微分方程求解界面
偏微分方程求解界面分为如下几个部分。
1)系统菜单
偏微分方程工具箱有较全面的系统菜单,其中大部分实用功能均可以由工具栏实现,工具栏不能实现的部分多为一些工具箱的设置与文件处理的功能。后面将根据实际需要介绍系统菜单的若干功能。
2)工具栏
工具栏内各个按钮的详细内容如图9-14所示,工具栏能实现从求解区域设定、微分方程参数描述、求解到结果表示在内的一整套实际功能。工具栏右侧的列表框还给出了MATLAB能够直接使用的一些常用微分方程类型。

图9-14 偏微分方程求解工具栏
3)集合编辑(Set formula)
用户可以在求解区域用不同的几何形状画出若干集合,而集合编辑区域允许用户用加减法等表示集合的并、交和差集运算,更精确地描述求解区域。
4)求解区域
为该程序界面下部的区域,用户可以在这个部分绘制出问题的求解区域,微分方程的解也可以在这个区域内用二维的形式表示出来。MATLAB还支持三维表示,但需要打开新图形窗口。
9.4.2 绘制偏微分方程求解区域
下面演示在偏微分方程求解界面下描述求解区域的方法。首先用工具栏中提供的椭圆绘制和矩形绘制功能绘制如图9-15所示的一些区域,并在集合编辑框将原来的内容修改为(R1+E1+E2)–C1,表示从矩形R1、椭圆E1、E2的并集中剔除掉C1。单击工具栏中
按钮就可以得到求解区域。选择【Boundary】菜单下的【Remove All Subdomain Borders】菜单项,则将消除若干相邻区域中间的分隔线,得出如图9-16所示的区域图。
![]() |
![]() |
| 图9-15 求解区域图 | 图9-16 实际求解区域 |
有了求解区域,就可以单击按钮将求解区域用三角形式划分成若干网格,如图9-17所示。如果感觉网格不够密,则可以单击菜单栏中的【Mesh】菜单下的【Refine Mehs】选项,对网格进行加密,可以得到如图9-18所示的更密的网格图。值得指出的是,一般情况下,网格越密,计算的结果越精确,但代价是计算的时间越长。
![]() |
![]() |
| 图9-17 求解区域网格绘制 | 图9-18 加密网格的效果图 |
9.4.3 偏微分方程边界条件设置
求解边界在偏微分方程界面下用
表示。一般地,偏微分方程工具箱支持的边界条件包括Dirichlet条件和Neumann条件。这两个条件在9.2.2节已经进行描述,在此只介绍用图形界面设置边界条件。
在图9-13界面中单击【Boundary】菜单下的【Specify Boundary Condition】选项,将打开一个如图9-19所示的对话框,用户可以在这个对话框中描述边界条件。如果想使得边界上各点的函数值为0,则可以将该对话框的r栏值设为0。

图9-19 边界条件设置对话框
设置了求解区域的边界条件,并选择了合适的偏微分方程后,单击工具栏的等号按钮(=)就可以立即得出微分方程的解。
9.4.4 用图形界面求解偏微分方程
下面将通过例子来演示实际偏微分方程的求解过程。
【例9-11】 试求解双曲线型偏微分方程:

其求解过程为:
(1)由给定的偏微分方程可以得出c=1、a=2、f=8、d=1。单击偏微分方程界面工具栏的PDE图标,打开一个如图9-20所示的对话框,左侧有各种常见的偏微分方程类型。选择其中的Parabolic选项,就能将给定偏微分方程的参数输入到该对话框中。

图9-20 偏微分方程参数设置对话框
(2)如果想求解该偏微分方程,则可以单击工具栏中的等号按钮,这样就能得到偏微分方程的解,如图9-21所示。其中,图形为伪彩色图形,其颜色表示u(x,y)的值。

图9-21 偏微分方程的解
注意: 这时给出u(x,y)的值为在t=0时的函数值。
(3)用户还可以修改微分方程的边界条件。例如,在图9-19所示的对话框,仍采用Dirichlet条件,令边界上所有的u值为4,则可以将该对话框中r值填写为4。再求解偏微分方程,得到的效果如图9-22所示。

图9-22 改变边界条件后的解
(4)微分方程的结果还可以用其他很多方式显示。单击工具栏中的三维图标
则将打开一个如图9-23所示的对话框,如果再选择“Contour”选项则可绘制等值线图,如果选择“Arrows”选项,将计算并绘制引力线。选择两个选项,将得出如图9-24所示的计算结果。

图9-23 绘制选择界面

图9-24 等值线与引力线效果图
(5)另外还应该注意,在图9-23所示的对话框中,Property的各个项目均有列表框,如第一项的默认值为u,表明所有的分析都是针对
函数的,在绘制时显示u (x ,y )。如果想显示其他的内容,则可以单击右侧的
图标打开列表框,从中选择其他的分析内容,直到选择用户自定义栏目。
如果单独选择“Height(3D-plot)”,则将另外打开一个图形窗口,绘制出网格型三维图形,如图9-25所示。

图9-25 三维网格线表示
9.4.5 用图形界面求解函数参数的偏微分方程
前面介绍的偏微分方程c、a、d、f均为常数,而在实际的偏微分方程中,经常会遇到量为函数的情况。偏微分方程工具箱目前能处理的问题是含有非线性系数的椭圆偏微分方程问题,在系数字符串中允许使用x、y直接表示微分中的
,或x、y用变量ux和uy表示
,这样就可以描述任意的非线性系数。
【例9-12】 假设偏微分方程为:

其中边界为0,试求解该偏微分方程。
观察该方程可以发现,其满足椭圆型偏微分方程,其中:

且在求解边界上u 的值为0。
使用偏微分工具箱,打开如图9-26所示的对话框,选择椭圆型偏微分方程(Elliptic)选项,在c参数栏目中填写1./sqrt(1+ux.2+uy.2),在a和f栏目中分别填写x.2+y.2和exp(-x.2-y.2)。

图9-26 偏微分方程参数设置对话框
在PED界面的菜单栏中单击【Solve】菜单下的【parameters】选项,弹出Solve parameters参数对话框,从中选定Use nonlinear solver属性,效果如图9-27所示(注意,该属性只适用于椭圆型偏微分方程求解)。

图9-27 Solve parameters参数对话框
再单击工具栏内的等号,则可以求解该方程,得出如图9-28及图9-29所示的解。
![]() |
![]() |
| 图9-28 等值线与引力效果 | 图9-29 三维网格线图 |
9.5 偏微分方程的其他函数
前面介绍了偏微分方程的边界设置函数、初始化函数、加密函数及偏微分方程的图形化界面,下面将对偏微分方程的其他函数作简单介绍。
9.5.1 图形界面函数
MATLAB偏微分方程工具箱提供了很多图表界面函数,下面将分别给予介绍。
- pdecirc函数
该函数用于绘制圆,其调用格式为:
pdecirc(xc,yc,radius)
pdecirc(xc,yc,radius,label)
用于绘制一个以(xc,yc)为中心,以radius为半径的圆。如果pdetool GUI处于被激活状态,可自动激活,且该圆画在一个空的几何模型中。可选项label给圆命名(否则将选第一个默认值作为该圆名)。在pdetool中几何描述矩阵的状态将被更新,以包含该圆。可用“Draw”菜单下的命令“Export Geometry Description”从pdetool输出几何描述矩阵,几何描述矩阵的格式在decsg的入口处定义。
【例9-13】 在PDE界面中绘制一个圆心为(0,0),半径为1的圆。
1 | >> pdecirc(0,0,1) |
运行程序,效果如图9-30所示。

图9-30 圆形
- pdeellip函数
该函数用于绘制椭圆,其调用格式为:
pdeellip(xc,yc,a,b,phi)
pdeellip(xc,yc,a,b,phi,label)
绘制以(xc,yc)为中心,以a、b为半轴的椭圆。椭圆的旋转(弧度)由phi给出。如果pdetool GUI处于被激活状态,可自动激活,且椭圆画在一个空的几何模型中。可选项label给椭圆命名(否则将选第一个默认值作为该椭圆名)。在pdetool中几何描述矩阵的状态将被更新,以包含该椭圆。可用“Draw”菜单下的命令“Export Geometry Description”从pdetool输出几何描述矩阵,几何描述矩阵的格式在decsg的入口处定义。
【例9-14】 绘制中心点为(0,0),长轴为1,短轴为0,旋转度为0.3的椭圆。
1 | >> pdeellip(0,0,1,0.3,pi/4) |
运行程序,效果如图9-31所示。

图9-31 椭圆绘制
- pdemdlcv函数
该函数用于将PDE工具箱1.0版本的M文件转化为PDE工具箱1.0.2格式,其调用格式为:
pdemdlcv(infile,outfile):将PDE工具箱中1.0版本的输入文件转换为PDE工具箱1.0.2版兼容的M文件。转化后M文件存为输出文件。如果输出文件中缺“.m”扩展名,将自动加上。如果想用由PDE工具箱1.0产生的M文件,必须首先用pdemdlev进行转化。
- pdepoly函数
该函数用于绘制多边形,其调用格式为:
pdepoly(x,y)
pdepoly(x,y,label)
绘制一个多边形,顶点坐标由向量x和y决定。如果pdetool的GUI没有打开,这时将自动打开,多边形将被画在一个空白的几何模板上。可选项label将为多边形命名(否则将选择一个默认名)。pdetool中的几何描述矩阵将会更新,以包括这个多边形。
【例9-15】 绘制一个L形的平面多边形。
1 | >> pdepoly([-1 0 0 1 1 -1],[0 0 1 1 -1 -1]); |
运行程序,效果如图9-32所示。

图9-32 L形多边形
- pderect函数
该函数用于绘制矩形,其调用格式为:
pderect(xy)
pderect(xy,label)
矩形的顶点坐标由xy=[xmin,xmax,ymin, ymax]确定。如果pdetool GUI处于被激活状态,可自动激活,且矩形画在一个空的几何模型中。可选项label给矩形命名(否则将选第一个默认值作为该矩形名)。pdetool中的几何描述矩形将会更新,以包括这个矩形。
【例9-16】 绘制3个正方形连在一起的L形平面。
1 | >> pderect([-1 0 -1 0]) |
运行程序,效果如图9-33所示。

图9-33 三个矩形
- pdecont函数
该函数用于快速绘制等高线,其调用格式为:
pdecont(p,t,u):绘制PDE节点或三角形数据u的10条水平曲线。
pdecont(p,t,u,n):用n个平面作图。
pdecont(p,t,u,v):用给定的v个平面作图。
h=pdecont(p,t,u):为已有的坐标轴对象返回句柄。如果u为一个列向量,则假定为节点数据;如果u为一个行向量,则假定为三角形单元数据。用函数pdeprtni将三角形数据转换为节点数据。PDE问题的几何条件由网格数据p和t给出。
h=pdecont(p,t,u,n):用n个平面作图。
h=pdecont(p,t,u,v):用给定的v个平面作图。
如果想更多地控制等高线作图,可用pdeplot替代pdecont。
【例9-17】 在以L形定义的几何层中画方程
解的等高线,Dirichlet使用边界条件u=0(在
)。
1 | >> [p,e,t]=initmesh('lshapeg'); |
运行程序,效果如图9-34所示。

图9-34 等高线图
- pdegplot函数
该函数用于绘制PDE几何图形,其调用格式为:
pdegplot(g):绘制一个PDE问题的几何图形。g用于描述PDE问题的几何条件,g为一个分解矩阵,也可以是一个几何M文件名。
h=pdegplot(g):返回绘制坐标轴对象的句柄。
【例9-18】 绘制L形平面的几何图形。
1 | >> pdegplot('lshapeg') % lshapeg为MATLAB自带的M文件 |
运行程序,效果如图9-35所示。

图9-35 L形平面的几何图形
9.5.2 几何处理函数
在偏微分处理工具箱中提供了若干函数用于实现几何处理。下面分别给予介绍。
- ecsg函数
该函数用于将固定几何区域分解为最小区域,其调用格式为:
dl=decsg(gd,sf,ns)
dl=decsg(gd)
[dl,bt]=decsg(gd)
[dl,bt]=decsg(gd,sf,ns)
[dl,bt,dl1,bt1,msb]=decsg(gd)
[dl,bt,dl1,bt1,msb]=decsg(gd,sf,ns)
该函数自己构造固定几何区域(CSG),并自动地构造出一些最小的区域。
- pdearcl函数
该函数用于将弧长描述转换为参数表达,其调用格式为:
pp=pdearcl(p,xy,s,s0,s1):输入一个弧长描述的曲线,则返回由参数描述的pp。p是包括参数值的单调行向量,xy是一个两行矩阵,给出曲线上p上相应的点。曲线的第一点由弧长值s0给出,终点由弧长值s1给出。返回时,pp包含相应弧长s描述的参数值。弧长s、s0和s1可以是弧长的仿射变换长度。
- poimesh函数
该函数用于在矩形面上构造规则网格,其调用格式为:
[p,e,t]=poimesh(g,nx,ny):在一个由g描述的矩形区域上构造规则网格。构造的方法是将“x边”分成nx份,将“y边”分成ny份,在断点处加上(nx+1)*(ny+1)个点。与x轴夹角较小的边称为“x边”。
[p,e,t]=poimesh(g,n)或[p,e,t]=poimesh(g):取nx=ny=n。三角形网格由网格数据p、e和t描述,关于它们的详细描述可参阅initmesh,为了较好地使用函数poisoly,nx和ny中的较大者应是2的幂。如果g描述的不是一个矩形,p的返回值为0。
- wgeom函数
该函数用于写一个几何描述文件。其调用格式为:
fid=wgeom(dl,mn):输出一个几何M文件,名字为“mn.m”。几何M文件等价于分解的几何矩阵dl。
9.5.3 通用函数
在偏微分方程处理工具箱中提供了若干通用函数,下面分别给予介绍。
- pdeadgsc函数
该函数根据相对容差的标准选择三角形单元,其调用格式为:
bt=pdeadgsc(p,t,c,a,f,u,errf,tol):返回限于bt内的三角形编号索引,从而利用自适应精化网格对三角形单元予以细化。PDE问题的几何条件由网格数据p、t给出。c、a、f是PDE的系数。u为当前解,以一列向量的形式给出。errf为误差指标,同于pdimps的计算结果。tol为一个相对容差参数。设cmax、amax、fmax、umax分别为c、a、f、u的最大值,f为所包含几何区域的最小二乘法边界值,则scale=max(fmax*12,amaxumax12,cmax*umax)使得tol独立于方程和几何条件。
- pdeadworst函数
该函数根据最坏标准选择三角形,其调用格式为:
bt=pdeadworst(p,t,c,a,f,u,errf,wlevel):返回需要被精制的三角形的号数,用于adaptmesh函数选择三角形,以便进一步精制。PDE问题的几何描述由p和t给出。c、a和f是PDE方程的系数。u为当前解,以列向量的形式给出。errf为误差指标,同于pdimps的计算结果。wlevef为相对最大误差的误差水平,介于0和1之间。选择三角形的标准是errf>wlevel*max(errf)。
- pdecgrad函数
该函数用于求出PDE解的通量,其调用格式为:
[cgxu,cgyu]=pdecgrad(p,t,c,u)
[cgxu,cgyu]=pdecgrad(p,t,c,u,time)
[cgxu,cgyu]=pdecgrad(p,t,c,u,time,sdl)
返回在每个三角形中心求出的通量
,cgxu的第i 行包括:

cgyu的第i 行包括:

在cgxu和cgyu中,对每个三角形而言,t中都有一列向量。PDE问题的几何条件由数据网格p和t给出。数据网格的具体描述可在initmesh输入时获得。PDE问题的系数可由不同的方法给出,所有选择的完整列表在assempde输入时给出。如果c依赖于时间t,标量可选项time用于类抛物线和抛物线问题。可选项sdl将计算限定于序列sdl的子域中。
- pdegrad函数
该函数用于求PDE方程解的梯度,其调用格式为:
[ux,uy]=pdegrad(p,t,u):计算u在每个三角形中心的梯度。ux的1行~N行为
;uy的1行~N行为
。PDE问题的几何描述通过网格数据p和t给出。
[ux,uy]=pdegrad(p,t,u,sdl):选项sdl限制计算只在sdl列出的子域上进行。
- pdejmps函数
该函数用于估计误差,其调用格式为:
errf=pdejmps(p,t,c,a,f,u,alfa,beta,m):计算误差指数方程。p、t为网格数据。c、a、f为PDE的系数。c、a、f必须扩展,以使列向量与三角形单元描述方式一致。u是偏微分方程的解矢量。计算每个三角形x的误差指数E(K)的公式为:

其中,
为边界
的单位外法向矢量。
- pedsmech函数
该函数用于计算结构力学的张量函数,其调用格式为:
ux=pdesmech(p,t,c,u,’PropertyName’,PropertyValue,…):返回每一个三角形单元中点处张量表达式,这个张量是应用结构力学中的平面应变及平面应力。输入参数包括偏微分方程的解u、网格参数、偏微分方程系数。泊松比参数主要用于计算剪切应力及剪切应变。表9-5列出附加参数及其取值。
表9-5 附加参数及取值

张量表达式中各项的意义为:
;
;
;
;- exx,x轴方向的应变;
- eyy,y轴方向的应变;
- exy,剪应变;
- sxx,x方向的应力;
- xyy,y方向的应力;
- e1,第一主应变;
- e2,第二主应变;
- s1,第一主应力;
- s2,第二主应力;
- 在平面应力条件下,
; - 在平面应变条件下,
。
- pdetriq函数
该函数用于三角质量测试,其调用格式为:
q=pdetriq(p,t):输入网格数据,则返回一个三角形的质量度量。三角形网格由网格数据p、e、t给出。三角形的品性由下列公式计算:

这里q 为面积,h 1 、h 2 和h 3 分别是三角形3条边的边长。如果g >0.6,则三角形的品性是可取的。当h 1 =h 2 =h 3 时,q =1。
- pdebound函数
该函数用于生成边界M文件,其调用格式为:
[q,g,h,r]=pdebound(p,e,u,time):计算边界e的q、g、h及r的值。矩阵p、e是数据网格,e只需为边界网格的子集。输入量u和time分别用于非线性求解及时间序列算法。
- pdegeom函数
该函数用于建立几何M文件,其调用格式为:
ne=pdegeom
d=pdegeom(bs)
[x,y]=pdegeom(bs,s)
给定已知边界参数的区域是二维的,设区域及边缘符号为唯一正数,边缘各部分不能互相重叠。整个二维问题的表述可包含几个不可分割的部分,且各部分有公共边缘。每个区域的边界可由几个边缘片组成。所有边缘各部分的连接处必须与边缘各部分中点相一致。有时称边缘部分为边界部分。
说明几何问题时有如下选择。
以函数decsg建立一个分解几何矩阵,此项工作可由pdeto01自动完成。用分解几何矩阵将边缘部分限制为直线、圆或椭圆。在工具箱中,几何M文件可由分解矩阵替代。
建立一个几何M文件。通过建立自己的几何M文件,可以得到一个与数学函数吻合得很好的几何图形。以下是一个如何建立心形线的例子:
ne=pdegeom:ne为边缘分割线数。
d=pdegeom(bs):为只有一列说明每个边缘分割的向量矩阵,该矩阵被指定在ba中。其中:
- 第一行包含参数初始值;
- 第二行包含参数终值;
- 第三行包含左边区域的符号(左边是相对于从起始行1到结束行2设定的方向而言的);
- 第四行包含右边区域的符号。
所有区域联结处的余角赋值为0。
[x,y]=pdegeom(bs,s):建立边缘分割部分各点的坐标。bs指定各边缘分割,s为与之相应的参数值。bs可以是标量,参数s需与曲线长度近似成比例。所有最小区域在边界至少有两个边缘分割,最好有3个边缘分割。
【例9-19】 用函数cardg定义一个心形线几何图形:

cardg.m函数的源代码为:
1 | function [x,y]=cardg(bs,s) |
用函数pdearcl来建立参数s与弧长成正比,可以通过以下代码来验证函数:
1 | >> pdegplot('cardg'), axis equal |
运行程序,效果如图9-36所示。

图9-36 根据建立的cardg函数绘制的心形图
可通过以下代码解决PDE——
=1问题,其几何图形由心形线定义,用Dirichlet边界条件:
1 | >> u=assempde('cardb',p,e,t,1,0,1); |
运行程序,效果如图9-37所示。

图9-37 PDE效果图
注意: 参数s必须与曲线长度近似成正比。所有最小区域在其边界处必须有至少两个边缘分割,最好有3个边缘分割。
第10章 最优化设置
随着社会的进步,历史的发展,在实际工作中又面临这样一些问题:在工程设计中,怎样选取参数才能使得设计既满足要求又能降低成本?在资源分配中,怎样的分配方案既能满足各方面的基本要求,又能获得好的经济效益?在生产计划安排中,选择怎样的计划方案才能提高产值和利润?在原料配比问题中,怎样确定各种成分的比例才能提高质量、降低成本?在城建规划中,怎样安排工厂、机关、学校、商店、医院、住宅和其他单位的合理布局,才能方便群众,有利于城市各行各业的发展?在军事指挥中,怎样确定最佳作战方案,才能有效地消灭敌人,保存自己,有利于战争的全局?这一系列的实际问题最终促成了优化这门数学分支的建立。
事实上,最优化是古老的课题。长期以来,人们对最优化问题进行探讨和研究。早在17世纪,英国伟大科学家牛顿发明微积分的时代,就已经看出极值问题,后来又出现拉格朗日乘数法。1847年法国数学家Cauchy研究了函数值沿什么方向下降最快的问题,提出了最速下降法。1939年前苏联数学家JI.B.KaHTOPOBHq给出了解决燃料问题和运输问题这两种线性规划问题的求解方法。然而,优化成为一门独立的学科是在20世纪40年代末,是在1947年Dantzig提出求解一般线性规划问题的单纯形法之后。随着计算机的广泛应用,目前,优化已成为一门十分活跃的学科。
10.1 优化参数设置
在优化工具箱中,每个求解命令都有相应的优化参数选项options,它是一个结构参数,通过这些参数的不同设置,可以满足用户不同的要求。
10.1.1 设置优化参数
对于求解优化问题各种命令,都可以对其中的优化参数进行设置,从而达到所预期的效果。例如可以通过设置参数Display,使得函数显示算法每一步的迭代结果,可以通过设置参数MaxIter的值,来改变算法所允许迭代的最大次数等。
在MATLAB中提供了optimset函数用于设置优化参数,其调用格式为:
options = optimset(‘param1’,value1,’param2’,value2,…):创建一个名为options的优化参数结构体,并设置其参数param的值为value,如果选择用系统默认值,则只需将参数的值设为[]。
optimset:列出一个完整的优化参数列表及相应的可选值。
options = optimset:创建一个名为options的优化参数结构体,其成员参数的取值为系统的默认值。
options = optimset(optimfun):创建一个名为options的优化参数结构体,其所有参数名及值为优化函数optimfun的默认值。
options = optimset(oldopts,’param1’,value1,…):将优化参数结构体oldopts中参数param1改为value1,并将更改后的优化参数结构体命名为options。
options = optimset(oldopts,newopts):将已有的优化参数结构体oldopts与新的优化参数结构体newopts合并,newopts中的任意非空参数值将覆盖oldopts中的相应参数值。
【例10-1】 列出所有优化参数列表。
1 | >> optimset |
10.1.2 获取优化参数
在实际应用中,如果想查看某个优化参数的值,可以通过optimget函数来获取,其调用格式为:
val = optimget(options,’param’):获取优化参数结构体options中参数param的值。
val = optimget(options,’param’,default):如果参数param在options中没有定义,则返回其默认值default。
10.2 线性规划
线性规则问题的求解方法有表上作业法、图解法和单纯形法,然而在决策变量比较多的时候,上述方法的求解过程都是比较复杂的,使用MATLAB求解线性规划问题却比较容易。
10.2.1 MATLAB线性规划函数
以数学形式表述线性规划问题,其标准形式为:

或用矩阵形式简写为:

其中,
称为技术系数矩阵,
称为资源系数向量,
称为价值系数向量,
称为决策向量。
但在实际问题中,建立的线性规则数学模型并不一定都有式(10-1)的形式,例如有的模型还有不等式约束、对自变量x 的上下界约束等,这时,可以通过简单的变换将它们转化成式(10-1)的标准形式。
在MATLAB中提供了linprog函数用于求解线性规划问题,其调用格式如下:
x = linprog(f,A,b):求minf’*x在约束条件A.x≤b下线性规划的最优解。
x = linprog(f,A,b,Aeq,beq):等式约束Aeq.x=beq,如果没有不等式约束A.x≤b,则置A=[],b=[]。
x = linprog(f,A,b,Aeq,beq,lb,ub):指定x的范围lb≤x≤ub,如果没有等式约束Aeq.x=beq,则置Aeq=[],beq=[]。
x = linprog(f,A,b,Aeq,beq,lb,ub,x0):x0为给定初始值。
x = linprog(f,A,b,Aeq,beq,lb,ub,x0,options):options为指定的优化参数,如表10-1所列。
表10-1 options优化参数

[x,fval] = linprog(…):fval为返回目标函数的最优值,即fval=c’x。
[x,fval,exitflag] = linprog(…):exitflag为终止迭代的错误条件,其参数如表10-2所列。
表10-2 exitflag的值及说明

[x,fval,exitflag,output] = linprog(…):output为关于优化的一些信息,其结构及说明如表10-3所列。
表10-3 output结构及说明

[x,fval,exitflag,output,lambda] = linprog(…):lambda为输出各种约束对应的Lagrange乘子(即为相应的对偶变量值),它是一个结构体变量,其结构及说明如表10-4所列。
表10-4 lambda结构及说明

10.2.2 线性规则的MATLAB实现
下面通过示例来演示MATLAB在线性规则中的应用。
【例10-2】 对下列非线性方程按线性规划问题进行求解:

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Residuals: Primal Dual Duality Total |
【例10-3】 某工厂计划生产甲、乙两种产品,主要材料有钢材3500kg、铁材1800kg,专用设备能力2800台时,材料与设备能力的消耗定额及单位产品所获利润如表10-5所列。问如何安排生产,才能使该厂所获利润最大?
表10-5 材料与设备能力的消耗及单位产品所获利润

首先建立模型,设甲、乙两种产品计划生产量分别为x 1 、x 2 (件),总的利润为f (x )(元)。求变量x 1 、x 2 的值为多少时,才能使总利润
最大?
依题意可建立数学模型为:

因为linprog是求极小值问题,所以上述模型可变为:

根据上述模型,其实现的MATLAB代码如下:
1 | >> clear all; |
运行程序,输出如下:
1 | Optimization terminated. |
当决策变量
时,规划问题有最优解,此时目标函数的最小值是fval=56250,即当不生产甲产品,只生产乙产品450件时,该厂可获最大利润为56 250元。
【例10-4】 工程项目投资问题。某公司有一批资金想投资到5个项目中,各工程项目的净收益(投入资金的百分比)如表10-6所列。
表10-6 工程项目的净收益表

由于一些原因,公司决定用于项目A的投资不大于其他各项投资之和,而用于项目B和项目D的投资要大于或等于项目C和项目E的投资。试确定投资分配方案,使该公司收益达到最大。
设x 1 ,x 2 ,x 3 ,x 4 ,x 5 分别表示项目A,B,C,D,E的投资百分数,由于各项目百分数之和等于100%,所以有:
x 1 +x 2 +x 3 +x 4 +x 5 =1
根据题意可建立下面的模型:

将该模型转换为目标最小化,即

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Optimization terminated. |
可见,5个项目的投资百分数分别为0、25%、50%、25%、0时可使该公司获得最大的收敛,且最大收益为13.5%。
10.3 非线性规划
非线性规划问题也是运筹学的重要分支之一,广泛应用于最优化设计、管理科学及系统控制等领域。
当目标函数或约束条件中有一个或多个为非线性规划函数,则称这样的规划问题为非线性规划(Nonlinear Programming)。工程应用中所遇到的问题大量是非线性的,其数学模型为:

根据目标函数和约束条件的不同,MATLAB提供了fminbnd、fmincon、quadprog、fseminf、fminimax、fgoalattain及lsqlin等函数来求解不同类型的非线性规划问题。
10.3.1 无约束非线性规划
对于无约束优化问题,读者可以根据自己的需要选择合适的算法,通过MATLAB编程求解,也可利用MATLAB提供的fminsearch函数与fminunc函数求解。
- fminsearch函数
fminsearch函数可以用来求解目标函数不可导的问题,包括不连续,在最优解附近出现奇异值等问题,只能给出局部最优解。另外fminsearch函数只能求解实数最优问题。其调用格式为:
x = fminsearch(fun,x0):x0为初始点,fun为目标函数的表达式字符串或MATLAB自定义函数的函数柄,返回目标函数的局部极小点。
x = fminsearch(fun,x0,options):options为指定的优化参数,如表10-7所列,可以利用optimset命令来设置这些参数。
表10-7 fminsearch函数的优化参数及说明

[x,fval] = fminsearch(…):fval为最优值。
[x,fval,exitflag] = fminsearch(…):exitflag为返回算法的终止标志,它的取值及说明如表10-8所列。
表10-8 exitflag的值及说明

[x,fval,exitflag,output] = fminsearch(…):output为输出关于算法的信息变量,其结构及说明如表10-9所列。
表10-9 output的结构及说明

【例10-5】 求下面函数在区间[–1.2,1]内的最小值。

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
- fminunc函数
fminunc函数在进行无约束优化问题求解时,要求判断目标函数在优化变量处的梯度和Hessian矩阵,其仅适用于函数为连续的情况,并只能用来求解优化变量为实数的问题,当优化变量为复数时,需要将问题分解成实部和虚部分别进行无约束优化求解。fminunc函数的调用格式为:
x = fminunc(fun,x0):x0为初始点,fun为目标函数的表达式字符串或MATLAB自定义函数的函数柄,x为返回目标函数的局部极小点。
x = fminunc(fun,x0,options):options为指定的优化参数,如表10-10所列。
表10-10 fminunc函数的优化参数及说明


[x,fval] = fminunc(…):fval为返回相应的最优值。
[x,fval,exitflag] = fminunc(…):exitflag为返回算法的终止标志,它的取值及说明如表10-11所列。
表10-11 exitflag的值及说明

[x,fval,exitflag,output] = fminunc(…):output为输出关于算法的信息变量,它的结构及说明如表10-12所列。
表10-12 output的结构及说明

[x,fval,exitflag,output,grad] = fminunc(…):grad为输出目标函数在解x处的梯度值。
[x,fval,exitflag,output,grad,hessian] = fminunc(…):hessian为输出目标函数在解x处的Hessian矩阵。
【例10-6】 分别用fminunc函数与fminsearch函数求解无约束优化问题:

(1)利用fminunc求解无约束优化问题。根据需要,建立目标函数的M文件,源代码为:
1 | function f = li10_5a(x) |
调用fminunc函数求解无约束优化问题,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
在fminunc函数中,可以设置options结构体选项,考虑目标函数的梯度和Hessian矩阵,输入以下代码,同样可以得到相同的计算结果:
1 | function [f,g] = li10_5b(x) |
(2)利用fminsearch函数求解无约束优化问题,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
10.3.2 有约束非线性规划
有约束条件的优化情况比无约束条件的优化情况要复杂得多,处理起来也更困难,种类也比较繁杂。限于篇幅,这里不能将所有的约束优化都进行讨论,只对fminbnd函数及fmincon函数进行介绍。
- fminbnd函数
fminbnd函数用于求解单变量约束优化问题。单变量约束优化问题的标准形式为:
minf (x )
s.t. a <x <b
即为求目标函数在区间(a,b)上的极小点。fminbnd函数的调用格式为:
x = fminbnd(fun,x1,x2):返回目标函数fun在区间(x1,x2)上的极小值。
x = fminbnd(fun,x1,x2,options):options为指定的优化参数选项,如表10-7所列。
[x,fval] = fminbnd(…):fval为返回相应的目标函数值。
[x,fval,exitflag] = fminbnd(…):exitflag为输出终止迭代的条件信息,其取值与说明如表10-13所列。
表10-13 exitflag的值及说明

[x,fval,exitflag,output] = fminbnd(…):output为输出关于算法的信息变量,其结构及说明如表10-9所列。
【例10-7】 计算下面函数在(-2,2)内的最小值:

首先,建立目标函数的M文件,源代码为:
1 | function y=li10_6a(x) |
调用fminbnd函数求解非线性规划,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
- fmincon函数
非线性规划优化问题的标准形式为:

其中,f (x )为目标函数,它可以是线性函数,也可以是非线性函数;c (x )为非线性向量函数;A 为矩阵;b ,lb,ub为向量。
在MATLAB中提供了fmincon函数用于求解多元函数的极小值,其调用格式如下:
x = fmincon(fun,x0,A,b):从x0开始,在A*x≤b的约束条件下找到函数的最小值。x0可为标量、向量或矩阵。
x = fmincon(fun,x0,A,b,Aeq,beq):在Aeq* x=beq与A*x≤b的条件下,找到函数的最小值。如果没有不等式存在,则A,b可以为空“[]”。
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub):定义了x上下界,lb≤x≤ub。如果没有等式存在,Aeq,beq可以为空“[]”。
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon):nonlcon中定义了c(x)与ceq(x),函数在c(x)≤0与ceq(x)=0的约束下求最小值。如果没有变量、边界,则lb与ub可以为空“[]”。nonlcon函数的定义为:
function [c,ceq] = mycon(x)
其中:c = …为x处的非线性不等式约束;ceq = …为x处的非线性等式约束。
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options):options为指定的优化参数,其取值及说明如表10-14所示,可通过optimset函数对其进行设置。
表10-14 优化参数options的取值及说明

[x,fval] = fmincon(…):x为返回的最优解,fval为最优解的目标函数。
[x,fval,exitflag] = fmincon(…):exitflag为返回的终止迭代条件信息,其取值及说明如 表10-15所示。
表10-15 exitflag的取值及说明

[x,fval,exitflag,output] = fmincon(…):output为返回关于算法的信息变量,其结构及说明如表10-16所示。
表10-16 output的结构及说明

[x,fval,exitflag,output,lambda] = fmincon(…):lambda为输出各个约束所对应的Lagrange乘子,其结构及说明如表10-17所示。
表10-17 lambda的结构及说明

[x,fval,exitflag,output,lambda,grad] = fmincon(…):grad为输出目标函数在最优解x处的梯度。
[x,fval,exitflag,output,lambda,grad,hessian] = fmincon(…):hessian为输出目标函数在最优解x处的Hessian矩阵。
【例10-8】 求解在约束条件
下,函数
的最小值的最优解及最优解的数值。
转换约束条件,将以上约束条件转换为如下形式:

根据需要,建立目标函数的M文件,源代码为:
1 | function f = li10_7a(x) |
调用fmincon函数求解最小值,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Warning: Trust-region-reflective algorithm does not solve this type of problem, using |
从以上优化条件中,可以看出各种具体的优化信息,进而进行优化分析。在该优化结果中,output的iterations参数显示了迭代次数为12。
重新设置优化条件,进行优化运算。将最优问题的约束条件修改为以下关系:

同时,将初值设置为[1,1,1],然后进行优化,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Warning: Trust-region-reflective algorithm does not solve this type of problem, using |
从以上条件可以看出,当修改了关于优化的各种属性后,优化问题会发生质的改变,因此在进行优化求解问题的时候,需要特别注意优化求解的条件。
【例10-9】 求解下面函数的最小值:

其初始值为x0=[0 1 1]。
根据需要,建立非线性目标函数的M文件,源代码为:
1 | function y=li10_8a(x) |
根据需要,定义非线性约束等式M文件,源代码为:
1 | function [c,ceq]=li10_8b(x) |
调用fmincon求解非线性规划问题,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
10.3.3 二次规划问题
二次规划问题是最简单的约束非线性规划问题,其研究成果比较成熟,较容易求解。通常把约束条件全为线性且目标函数是二次函数的最优化问题称为二次规划问题。
二次规划问题的数学模型为:

在MATLAB中提供了quadprog函数用于求解二次规划问题,其调用格式为:
x = quadprog(H,f,A,b):返回向量x及解x处的目标函数值,约束条件为Ax≤b。
x = quadprog(H,f,A,b,Aeq,beq):返回向量x及解x处的目标函数,约束条件为Ax≤b及Aeqx=beq。
x = quadprog(H,f,A,b,Aeq,beq,lb,ub):返回向量x及解x处的目标函数,约束条件为Ax≤b。定义变量的下界lb和上界ub。
x = quadprog(H,f,A,b,Aeq,beq,lb,ub,x0):返回向量x及解x处的目标函数,约束条件为Ax≤b。定义变量的下界lb和上界ub,并设置初始值为x0。
x = quadprog(H,f,A,b,Aeq,beq,lb,ub,x0,options):返回向量x及解x处的目标函数,约束条件为Ax≤b。定义变量的下界lb和上界ub,设置初始值为x0,并根据options参数指定的优化参数进行优化计算,如表10-18所列。
表10-18 优化参数options的取值及说明

[x,fval] = quadprog(…):除了返回最优解x外,还返回目标函数最优值fval。
[x,fval,exitflag] = quadprog(…):同时输出终止迭代的条件信息exitflag,其取值及含义如表10-19所列。
表10-19 quadprog函数中exitflag的取值及说明

[x,fval,exitflag,output] = quadprog(…):同时输出关于算法的信息变量output,其内容与表10-3相同。
[x,fval,exitflag,output,lambda] = quadprog(…):同时输出各个约束所对应的Lagrange乘子lambda,它是一个结构体变量,其结构及说明如表10-4所列。
【例10-10】 求解下面二次规划问题:

先将目标函数以矩阵形式表示为:

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | First-order Total relative |
在以上二次规划问题中,求得的最优解为(0.6667,1.3333),对应的函数数值为–8.2222,同时对应的拉格朗日系数为(3.1111,0.4444,0.0000)。
【例10-11】 求解下面的二次规划问题:

将上述二次规划写成如下形式:

先将目标函数以矩阵形式表示,即有:

其实现的MATLAB代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Optimization terminated. |
所以,原二次规划问题的最优值为6.9423。
10.3.4 最小最大值规划
最小最大值的优化问题是一个比较特殊的问题,其表示的是从一系列最大值中选取最小的数值,相当于求解以下优化问题:

在以上目标函数中,
。在MATLAB中提供了fminimax函数用于求解最大最小化问题,其调用格式如下:
x = fminimax(fun,x0):fun为目标函数,x0为初始点。
x = fminimax(fun,x0,A,b):A、b满足线性不等式约束Ax≤b,若没有不等式约束,则取A=[],b=[]。
x = fminimax(fun,x,A,b,Aeq,beq):Aeq、beq满足等式约束Aeqx=beq,若没有,则取Aeq=[],beq=[]。
x= fminimax(fun,x,A,b,Aeq,beq,lb,ub):lb、ub满足lb≤x≤ub,若没有界,可设lb=[],ub=[]。
x = fminimax(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon):nonlcon参数的作用是通过接受向量x来计算非线性不等式约束C(x)≤0和等式约束Ceq(x)=0分别在x处的C和Ceq,通过指定函数柄来使用,定义如下:
1 | function [c1,c2,gc1,gc2]=nonlcon(x) |
x = fminimax(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options):options为指定优化的参数选项,如表10-14所列。
[x,fval] = fminimax(…):fval为返回目标函数在x处的值,即fval=[f1(x),f2(x),…,fn(x)]‘。
[x,fval,maxfval] = fminimax(…):maxfval为fval中的最大元。
[x,fval,maxfval,exitflag] = fminimax(…):exitflag为输出终止迭代的条件信息,其取值及含义如表10-20所列。
表10-20 exitflag的值及说明

[x,fval,maxfval,exitflag,output] = fminimax(…):output为输出关于算法的信息变量,其结构及说明如表10-21所列。
表10-21 output的结构及说明

[x,fval,maxfval,exitflag,output,lambda] = fminimax(…):lambda为输出各个约束所对应的Lagrange乘子,它是一个结构体变量,其取值及说明如表10-22所列。
表10-22 lambda的结构及说明

【例10-12】 求解下面的函数最小最大值问题:

其中:

根据需要,编写目标函数的M文件,源代码为:
1 | function f = li10_11a(x) |
调用fminimax函数求解最小最大值问题,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
重新设置优化问题,代码为:
1 | >> x0 = [0.1; 0.1]; |
运行程序,输出如下:
1 | x = |
10.3.5 “半无限”多元函数规划
“半无限”多元函数优化问题的数学模型描述为:

其中,c (x )与ceq(x )表示非线性不等式与等式约束;
表示线性不等式和等式约束;
为关于优化变量x 与w 变量的函数关系,w 为长度大于2的向量,即
。
在MATLAB优化工具箱中,提供了fseminf函数用于求解“半无限”多元函数优化问题,其调用格式如下:
x = fseminf(fun,x0,ntheta,seminfcon)
x = fseminf(fun,x0,ntheta,seminfcon,A,b)
x = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq)
x = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq,lb,ub)
x = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq,lb,ub,options)
[x,fval] = fseminf(…)
[x,fval,exitflag] = fseminf(…)
[x,fval,exitflag,output] = fseminf(…)
[x,fval,exitflag,output,lambda] = fseminf(…)
其中,ntheta为
约束条件的个数,seminfcon参数用来定义
和非线性约束条件,返回非线性不等式和等式约束以及K i 的大小。exitflag的取值与说明与表10-15相同。fseminf函数其余各个参数含义与线性规划函数linprog的参数含义完全一致。
【例10-13】 求解如下“半无限”多元约束优化问题:

其中,“半无限”约束
为:

对于“半无限”多元约束优化问题的求解,首先建立目标函数的M文件,代码如下:
1 | function f=li10_12a(x) |
建立半无限约束条件及非线性约束的M文件,代码如下:
1 | function [c,ceq,K1,K2,s]= li10_12b (x,s) |
其实现的MATLAB代码如下:
1 | >> clear all; |
运行程序,输出如下:
1 | x = |
10.3.6 多目标规划
在实际工程应用中,对于一个设计系统的评价与衡量,通常不止一个指标。比如对于电机设计而言,给定一组电机设计参数后,通常要求电机启动转矩大、启动电流小、电机气隙磁场谐波含量低、电机运行效率高等一系列的性能指标。这种含有多个不同优化目标的问题称为多目标规划问题。在运筹学中,多目标规划问题属于比较复杂的一类优化问题,通常没有固定的求解算法;而且对于求解结果,也不容易评价其优化性能。
多目标规划问题的标准形式为:

其中,
既可以为线性函数,也可以为非线性函数。
在MATLAB中,将目标函数作为约束条件来处理,即将多目标规划转化为下面的形式来求解:

其中,γ 为一个松弛因子标量;F (x )为多目标规划中的目标函数向量;x 、b 、beq、lb、ub为向量;A 、Aeq为矩阵;c (x )、Ceq(x )为返回向量的函数,它们既可以为线性函数,也可以为非线性函数;weight为权重向量,用于控制对应的目标函数与用户定义的目标函数值的接近程度;goal为用户设计的与目标函数相应的目标函数值向量。
在MATLAB中提供了fgoalattain函数用于求解多目标规划,其调用格式如下:
x = fgoalattain(fun,x0,goal,weight):以x0为初始点,求解无约束的多目标规划问题。其中,fun为目标函数向量;goal为想要达到的目标函数值向量;weight为权重向量,一般取weight=abs(goal)。
x = fgoalattain(fun,x0,goal,weight,A,b):以x0为初始点,求解有线性不等式约束A*x≤b的多目标规划问题。
x = fgoalattain(fun,x0,goal,weight,A,b,Aeq,beq):以x0为初始点,求解有线性不等式约束A*x≤b与等式约束Aeq*x=beq的多目标规划问题。
x = fgoalattain(fun,x0,goal,weight,A,b,Aeq,beq,lb,ub):以x0为初始点,求解有线性不等式约束与等式约束以及界约束lb≤x≤ub的多目标规划问题。
x = fgoalattain(fun,x0,goal,weight,A,b,Aeq,beq,lb,ub,nonlcon):nonlcon函数为编写的非线性约束函数,其格式如下:
function [c,ceq] = mycon(x)
其中,c = …为x处的非线性不等式约束;ceq = …为x处的非线性等式约束。
x = fgoalattain(fun,x0,goal,weight,A,b,Aeq,beq,lb,ub,nonlcon,… options):options为指定的优化参数,其取值及说明如表10-23所列。
表10-23 优化参数options的取值及说明

[x,fval] = fgoalattain(…):x为返回的最优解,fval为返回多目标函数在x处的函数值。
[x,fval,attainfactor] = fgoalattain(…):attainfactor为解x处的目标规划因子。
[x,fval,attainfactor,exitflag] = fgoalattain(…):exitflag为输出终止迭代的条件信息,其取值及说明如表10-24所列。
表10-24 exitflag的取值及说明

[x,fval,attainfactor,exitflag,output] = fgoalattain(…):output为输出关于算法的信息,其结构及含义如表10-22所列。
[x,fval,attainfactor,exitflag,output,lambda] = fgoalattain(…):lambda为输出目标函数在解x处的Hessian矩阵H,其结构及含义如表10-23所列。
【例10-14】 求解以下的多目标最小化问题:

初始化控制矩阵为K0 = [-1 -1; -1 -1],目标函数的特征值为goal = [-5 -3 -1]。
根据需要,建立评价目标函数的M文件,源代码为:
1 | function F = li10_13a(K,A,B,C) |
调用fgoalattain函数求解多目标规划,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | Attainment Max Line search Directional |
10.3.7 最小二乘拟合规划
给定数据
,设拟合函数的形式为:

其中,
为已知的线性无关函数。求系数
,使得

则称相应的

为最小二乘拟合函数。
特别是,若

则称S (x )为n 次最小二乘拟合多项式。
在MATLAB中提供了lsqcurvefit函数用于解决最小二乘曲线拟合问题,其调用格式如下:
x = lsqcurvefit(fun,x0,xdata,ydata):fun为拟合函数;(xdata,ydata)为一组观测数据,满足ydata=fun(xdata,x);以x0为初始点求解该数据拟合问题。
x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub):以x0为为初始点求解该数据拟合问题,lb、ub为向量,分别是变量x的下界与上界。
x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub,options):options为指定优化参数,其参数如表10-25所列。
表10-25 options优化参数及其说明

[x,resnorm] = lsqcurvefit(…):在上面命令功能的基础上,输出变量resnorm = sum((fun(x,xdata),ydata).^2),即在x处残差的平方和。
[x,resnorm,residual] = lsqcurvefit(…):输出变量residual=r(x)。
[x,resnorm,residual,exitflag] = lsqcurvefit(…):exitflag为终止迭代的条件信息,其取值如表10-26所列。
表10-26 exitflag的取值及说明

[x,resnorm,residual,exitflag,output] = lsqcurvefit(…):output为输出关于变量的信息,其取值如表10-27所列。
表10-27 output的结构及说明

[x,resnorm,residual,exitflag,output,lambda] = lsqcurvefit(…):lambda为输出的Lagrange乘子。
[x,resnorm,residual,exitflag,output,lambda,jacobian] = lsqcurvefit(…):jacobian为输出在解x处的Jacobian矩阵。
【例10-15】 在工程实验中,得到下面一组数据:
ti:0 0.5 1 1.5 2 2.5 3 3.5 4
yi:0 3.2 4.0 4.5 5.8 6.9 8.1 9.9 10.8
求系数a、b、c、d,使得函数

根据需要,建立目标函数的M文件,源代码为:
1 | function f=li10_14a(x,ti) |
调用lsqcurvefit函数求解最佳拟合函数,代码为:
1 | >> clear all; |
运行程序,输出如下:
1 | x = %最优解 |
从而得拟合函数为:
f (t )=0.6009+0.1567cost +2.6252sint +0.7939
参考文献
[1] 徐瑞,黄兆东,阎凤玉.MATLABR2007科学计算与工程分析.北京:科学出版社,2007
[2] 刘会灯,朱飞.MATLAB编程基础与典型应用.北京:人民邮电出版社,2008
[3] 刘正君.MATLAB科学计算与可视化仿真宝典.北京:电子工业出版社,2009
[4] 魏巍.MATLAB应用数学工具箱技术手册.北京:国防工业出版社,2004
[5] 张德丰.MATLAB数值分析与应用.北京:国防工业出版社,2006
[6] 肖伟,刘忠,曾新勇,吕兰兰.MATLAB程序设计与应用.北京:清华大学出版社,2005
[7] 薛定宇,陈阳泉.高等应用数学问题的MATLAB求解.北京:清华大学出版社,2004
[8] 汪卉琴,刘目楼.数值分析.北京:冶金工业出版社,2004
[9] 隋思涟,王岩.MATLAB语言与工程数据分析.北京:清华大学出版社,2009
[10] 吴礼斌,李柏年.数学实验与建模.北京:国防工业出版社,2007
[11] 胡守信,李柏年.基于MATLAB的数学实验.北京:科学出版社,2004
[12] 范金城,梅长林.数据分析.北京:科学出版社,2006
[13] 曹卫华,郭正.最优化技术方法及MATLAB的实现.北京:化学工业出版社,2005
[14] 陈杰.MATLAB宝典(第3版).北京:电子工业出版社,2010
[15] 宋叶志,贾东永.MATLAB数值分析与应用.北京:机械工业出版社,2009
[16] 史荣昌,魏丰.矩阵分析.北京:北京理工大学出版社,2005
[17] 李庆扬,王能超,易大义.数值分析.清华大学出版社,2001
[18] 刘卫国.MATLAB程序设计与应用(第2版).北京:高等教育出版社,2006
[19] 苏金明,王永利.MATLAB7.0实用指南(上册).北京:电子工业出版社,2004
[20] 王正林,刘明.精通MATLAB(升级版).北京:电子工业出版社,2010
[21] 王正林,刘明.精通MATLAB7.北京:电子工业出版社,2006
[22] 王正林等.精通MATLAB科学计算(第2版).北京:电子工业出版社,2009
[23] 龚纯,王正林.精通MATLAB最优化计算.北京:机械工业出版社,2009
[24] 黄永安,李文成,高小科.MATLAB7.0/Simulink 6.0应用实例仿真与高效算法开发.北京:清华大学出版社,2008
[25] 董振海.精通MATLAB 7编程与数据库应用.北京:电子工业出版社,2007
[26] 王玉磊,邱罡.从零开始学MATLAB.北京:中国铁道出版社,2010
[27] 龚纯,王正林.MATLAB语言常用算法程序集.北京:电子工业出版社,2008
[28] 董霖.MATLAB使用详解——基础、开发及工程应用.北京:电子工业出版社,2008
[29] 景振毅,张泽兵,董霖.MATLAB 7.0实用宝典.北京:中国铁道出版社,2008




















