 
        书名:精通MATLAB科学计算与数据统计应用
ISBN:978-7-115-44187-4
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
• 编  著  赵 彬  陈 明 邹风山 孙若怀 张 铮
责任编辑 张 涛
• 人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
• 读者服务热线:(010)81055410
反盗版热线:(010)81055315
在各行各业的工程实践中,有大量的科学计算工作需要完成。传统的计算方式一般需要较长的周期,相比之下开发效率极高的MATLAB是一个更好的选择。在MATLAB中,编程细节被简化,繁琐的实现过程也被略去,用户可以将更多精力集中于所需要处理的核心问题上。
MATLAB科学计算涉及数学、机械、电子、控制和金融等多个领域。本书以MATLAB科学工程计算为立足点,介绍MATLAB在科学计算领域中如何运用庞大的科学函数库来解决一些实际问题。在函数的选择上兼顾各函数的使用频率和专业性,力求典型全面。本书可作为MATLAB课程的教学用书或者线性代数、概率统计等课程的教学辅助书。
自从美国MathWorks公司推出数学软件MATLAB以来,其凭借强大的计算功能,在许多行业得以应用,成为三大数学软件之一。在MATLAB中,用户只需以数学公式的描述方式给出要计算的问题,而无需考虑其实现细节就能解决大部分实际工程的计算问题。另外,MATLAB自带了大量优秀的函数库,实现了大部分常见的算法,用户可以轻松调用而无需自己实现一遍。
在所有的编程语言中,MATLAB也许是完成同一功能时所需代码量相对较少的。MATLAB拥有类似C语言的语法风格,这使得它上手容易。矩阵式的运算,除了带来处理效率的提高以外,也大大简化了编程负担。在C语言中需要定义多维数组才能实现的功能,MATLAB都可以用矩阵做到。这一切都使得MATLAB成为一个工程计算的利器,这就是MATLAB风靡全球的原因。
当我们能够灵活使用预定义函数完成各项任务时,我们才会惊喜地发现,MATLAB比我们想象的都要优秀。
本书的编写宗旨是在向读者介绍知识的同时,培养读者的思维方法,使读者知其然还要知其所以然,并在解决实际问题中能有自己的想法。
全书共分14章,具体内容安排如下。
第1章介绍MATLAB的入门知识,为读者使用MATLAB进行科学计算打好坚实的基础。本章的知识结构:MATLAB基本简介,MATLAB与科学计算之间的联系,以及MATLAB窗口简介和MATLAB程序及其帮助系统。
第2章介绍MATLAB中程序设计的相关内容,包括基本语法、文件I/O和一些实用的编程技巧。MATLAB不仅是一个科学计算的工具,也是一门简易的计算机语言。程序设计是使用MATLAB进行科学计算的基础。
第3章介绍MATLAB中可视化编程的内容。MATLAB可以绘制数据的二维、三维,甚至更多维的图形。本章将全面介绍MATLAB的强大可视化编程方法,其中将介绍二维图形的绘制、三维图形的绘制、图形用户界面工具和一些综合实例。
第4章介绍MATLAB中求微分与积分的方法。微分与积分是大学的必修课程,也是工程实践和科学计算最为基本的工具。本章介绍了极限、微分、积分、梯度、多项式的微分、梯形法求积分、自适应辛普森(Simpleson)积分法、自适应Lobatto积分法和一些综合实例。
第5章介绍MATLAB中插值计算的方法,包括一维函数和二维函数的插值计算。一维插值包括拉格朗日插值、牛顿插值、埃尔米特(Hermite)插值、分段线性插值、分段埃尔米特(Hermite)插值和三次样条插值。二维差值包括最近邻插值、线性插值、双三次插值和散乱节点插值。本章在给出主要插值算法原理的同时,使用MATLAB实现了插值算法。通过本章的学习,读者能灵活使用常见的插值算法解决一维和二维函数的插值问题。
第6章介绍MATLAB中函数逼近的内容,包括泰勒逼近、切比雪夫逼近、勒让德逼近、帕德逼近、傅里叶逼近和综合实例。通过本章的学习,读者能够使用一些逼近函数来解决未知函数曲线的工程问题。
第7章介绍MATLAB中曲线拟合的内容,包括多项式拟合、最小二乘拟合、正交多项式最小二乘拟合、拟合工具箱和综合实例。通过本章的学习,读者能够处理一些有规律的数据,并将数据拟合成为一条已知曲线。
第8章介绍MATLAB中求解线性方程组的内容,包括求逆法、矩阵分解法、迭代法和综合实例。在自然科学和工程技术中,可以利用相关函数直接求解一些简单的线性方程组,而且可以通过简单的编程来求解一些复杂的线性方程组。通过本章的介绍,读者既能应用MATLAB中相应的函数求解线性方程组,又能通过编程,灵活使用迭代法和其他的特殊解法来求解线性方程组。
第9章介绍MATLAB中求解非线性方程组的内容。非线性方程的解法大体上有:搜索法、二分法、简单迭代法、牛顿迭代法、弦截法和多项式方程求根。通过本章的学习,读者能够熟练掌握MATLAB中可求解非线性方程的相关函数,而且能通过编程实现多种求解非线性方程的数值算法。
第10章介绍MATLAB中概率统计的随机数生成、随机变量的统计值、参数估计、假设检验和回归等。MATLAB中的统计工具箱(Statistics Toolbox)包含了200多个用于概率统计方面的功能函数,且具有简单的接口操作。通过本章的学习,读者能够利用MATLAB的强大工具箱来解决概率统计问题,这无论是对理论研究还是对科学工程实施都是非常重要的。
第11章介绍MATLAB中求解微分方程组的内容,包括常微分方程、偏微分方程——有限差分法、PDE工具箱和综合实例。常微分方程作为微分方程的基本类型之一,在自然科学界与工程界有很广泛的应用。通过本章的学习,读者能够熟练使用MATLAB的求解函数和求解器,以及通过编程进行常微分方程的求解。
第12章介绍MATLAB中优化计算的内容,主要介绍了一些常见线性规划、整数规划、贪心算法、遗传算法、模拟退火算法、粒子群算法、MATLAB优化工具箱和神经网络的最优化问题,从而使得用户面对各种不同的复杂问题时可以有更多的选择。通过本章的学习,读者不仅能使用MATLAB最优化工具箱来快速解决最优化的实际问题,而且能学会分析优化算法,从而提高分析和解决问题的能力。
第13章介绍MATLAB中C/C++与MATLAB混合编程的内容,包括MATLAB调用C/C++、C/C++调用MATLAB、使用动态链接库和一些综合实例。这些技术的出现,扩展了MATLAB的应用范围,不仅给开发人员提供了方便,而且也提高了MATLAB的竞争力。
第14章介绍MATLAB中工程计算案例精粹,包括零件参数的最优化设计、柴油机故障诊断、街头抽奖游戏解谜和Delta并联机器人建模。通过MATLAB工程计算案例,读者能对MATLAB软件平台、工具箱、高效率的数值运算及符号运算功能有更好的了解。
读者应具备一定的数学基础,包括主要的高等数学知识、少量的线性代数基本概念、对于概率理论主要思想的理解。
本书所有MATLAB实例的源代码均可从box.ptpress.com/y/44187下载。虽然本书中的所有例子都已经在Windows XP、Windows 7和Windows 8等操作系统下的MATLAB 2006到MATLAB R2014a的各个版本中测试通过,但由于笔者水平的局限,也有存在Bug的可能,或很可能存在更加优化的算法或更加合理的程序结构没有提出。如发现任何上述问题,请您不吝告知本书的作者(zhangtao@ptpress.com.cn),以便我们进行改进。
首先要感谢我的授业恩师——沈阳新松机器人自动化股份有限公司的邹风山院长和沈阳工业大学的刘振宇教授,是他们引导我进入了机器人科学研究的领域。笔者自从学会MATLAB之日起,就借助MATLAB解决了很多与机器人相关的实际工程性问题。
感谢我的同事:甘戈、张中泰、孙若怀和张鹏。在业余时间帮我校对此书、验证程序、编写代码。感谢我的领导为本书的编写提出了很多宝贵意见。能够完成此书,离不开我的父母、妻子赵雪和儿子赵梓辰给我的支持和鼓励,在此向他们表示由衷的感谢。
最后还要衷心地感谢关心和喜欢本书的读者们。热爱MATLAB是我撰写此书的最初动力,能让大家学习到其内容和知识也是不断完善该书的核心源泉。由于作者的水平有限,书中的内容有些需要完善,希望读者来信,让我从反馈中得到创作的灵感。
本书旨在推广MATLAB软件在科学计算中的应用,倘若读者能够从本书中有所收获,实属笔者之幸。
作 者
目前,多数高校将MATLAB作为本科生和研究生专业技能课程,该课程的重要性不言而喻。MATLAB在教学过程中包含理论讲授,多媒体演示和实验教学。MATLAB强大的仿真分析功能作为一种实验辅助手段使学生能够更快速、更准确地完成相关实验内容,不仅能够快速得到实验的结果,而且提高了学习效率。MATLAB作为一种实用工具激发了学生对工程学科的学习兴趣,使他们有足够的自信和能力来适应其他专业课程的学习。
本书不仅介绍MATLAB技术在科学计算领域中的应用,而且向读者展示如何运用该工具去解决经典理论问题和大量现实中的工程实践问题。
本章将介绍MATLAB的入门知识,为读者使用MATLAB来进行科学计算打好坚实的基础。同时,通过本章的学习,读者能够了解MATLAB的基本框架和程序安装方法。
MATLAB是“矩阵实验室”的英文简称,其代表了美国MathWorks公司出品的商业数学软件。MATLAB具有算法开发、数据可视化、数据分析以及数值计算等高级计算技术。
MATLAB将数值分析、矩阵计算、数据可视化以及非线性动态系统的建模和仿真等诸多强大功能集成在一个易于使用的视窗环境中,为科学研究、工程设计、科学计算以及必须进行有效数值计算的众多科学领域提供了一种全面的解决方案,并在很大程度上摆脱了传统非交互式程序设计语言的编辑模式,代表了当今国际科学计算软件的先进水平。
MATLAB、Mathematica和Maple并称为当今世界的三大数学软件,在各大公司、科研机构和高校中日益普及,得到了广泛应用。MATLAB是科学计算、符号运算和图形处理等多种功能强有力的实现工具,其自身也因此得到了迅速发展,功能不断扩充,版本不断更新。
在20世纪70年代中期,时任美国新墨西哥大学计算机科学系主任的Cleve Moler教授出于减轻学生编程负担的动机,为学生设计了一组调用LINPACK和EISPACK的FORTRAN子程序库。这两个程序库具有“具有通俗易用”的接口,是MATLAB的雏形。
经过几年的校际流传,在工程师John Little的积极推动下,由John Little、Cleve Moler和Steve Bangert一起合作,于1984年成立了MathWorks公司,并把MATLAB正式推向市场。从那时起,MATLAB的内核采用C语言编写。此后,它又添加了丰富多彩的图形处理、多媒体、符号运算以及与其他流行软件的接口功能,使得MATLAB更受欢迎。
MATLAB以商品形式出现后,仅短短几年,就以其良好的开放性和运行的可靠性,使原先控制领域里的封闭式软件包(如英国的UMIST,瑞典的LUND和SIMNON,德国的KEDDC)纷纷被淘汰,而改以MATLAB为平台加以重建。进入20世纪80年代,MATLAB已经成为国际控制界公认的标准计算软件。
在经历了多年的发展后,如今的MATLAB已经成为国际最为流行的科学计算和工程应用的软件工具之一,同时它也成为了一种全新的高级编程语言,可以说它是第四代计算机语言。其特点是:拥有更丰富的数据类型和结构、更友善的面向对象特性、更快速精良的图形可视化界面、更广博的数学和数据分析资源以及更多的应用开发工具。就影响力而言,至今仍然没有哪一种计算软件可以与MATLAB相匹敌。
自从20世纪90年代以来,在大学校园里,诸如线性代数、自动控制理论、数理统计、数字信号处理、图像处理、模拟与数字通信、时间序列分析、动态系统仿真等课程的教科书都把MATLAB作为主要工具进行介绍。MATLAB已经是硕士生、博士生必须掌握的基本工具。在国际学术界,MATLAB已经被确认为准确、可靠的科学计算标准软件。在许多国际一流学术刊物上,都可以看到MATLAB的影子。
在设计研究单位和工业部门,MATLAB被作为进行高效研究、开发的首选软件工具。如美国National Instruments公司的信号测量、分析软件LabVIEW,Cadence公司的信号和通信分析设计软件SPW等,它们或者直接构建在MATLAB之上,或者以MATLAB为主要支撑。
MATLAB自问世以来,由于其强大的功能而得到广泛使用。MATLAB作为设计和研发上的首选工具,其应用范围包括科学计算、建模仿真、生物医学、信号与信息处理和自动控制系统等领域。MATLAB是一种包含大量计算工具和算法的集合,方便用户直接找到想要的各种计算功能。这些函数包括从最基本的函数到诸如矩阵、特征向量、傅里叶变换、符号运算、工程优化工具以及动态仿真建模等。
MATLAB提供了极其强大和广泛的预定义函数库,这样就使得技术工作变得简单高效,如果没有需要的函数,用户还可进行任意扩充。由于MATLAB语言库函数与用户文件的形式相同,用户文件可以像库函数一样被随意调用,所以用户可任意扩充库函数。
MATLAB语言和C语言的语法类似,但是比C语言更为简便,更加符合科学技术人员的工作方式。这种设计使得即使不懂C语言和非计算机专业的人,也能使用该工具进行研发和设计。这也是MATLAB为什么这么受欢迎的最重要原因之一。
MATLAB不仅可以使用自身的解释器,还可以将用户的MATLAB程序自动转换为独立于MATLAB运行的C/C++代码,还允许用户在其他平台中调用MATLAB的库函数。另外,MATLAB还提供了和“.NET”、Java语言的接口,并支持COM调用。
MATLAB的图形可视能力在数学软件中是首屈一指的。MATLAB提供了将工程和科学数据可视化所需的全部图形功能,包括二维和三维绘图可视化函数、用于交互式创建图形的工具以及将结果输出为常用图形格式的功能。
如图1-1所示,在MATLAB中,不管函数多么复杂,它的图形不需要通过过多复杂的编程就能得到富于感染力的表现。MATLAB有比较完备的图形标识指令,可以通过添加多个坐标轴,更改线的颜色、粗细和标记,添加批注、LaTeX和图例,以及绘制形状来对图形进行自定义。
(a)示例图片1
(b)示例图片2
图1-1 MATLAB的数据可视化能力
MATLAB软件包含诸多工具,限于篇幅,这里当然不能把所有工具都一一列出,本节只是从MATLAB应用的领域对MATLAB的工具箱进行简单的分类。一般来说,MATLAB的工具箱可以用来完成以下工作:(1)集成数学符号、分析、统计与优化;(2)信号处理与通信;(3)图像处理与计算机视觉;(4)测试与测量;(5)计算金融;(6)并行计算;(7)数据库访问与报告;(8)代码生成和验证。
下面列出与科学计算相关的工具箱。
(1)集成数学符号、分析、统计与优化:
(2)并行计算:
(3)数据库访问与报告:
MATLAB与科学计算相互结合的魅力特点可归为以下几点。
本章节将介绍MATLAB的安装开发环境、窗口,读者可学习MATLAB的安装、MATLAB的集成开发环境、以及MATLAB窗口的使用方法。
下面介绍在Windows 7上安装MATLAB R2014a的方法,其他系统上的安装过程与之类似。
(1)将提前准备好的“Mathworks.Matlab.R2014a.iso”安装包解压到指定目录下,可任意选择目录,硬盘空间足够即可。解压后,会出现图1-2所示的安装文件目录。
图1-2 解压后的MATLAB文件目录
(2)双击setup.exe进行安装,跳过欢迎界面后,出现图1-3所示的界面。因为考虑到存在没有网络的情况,安装中选择“使用文件安装密钥”单选项(不需要Internet连接),单击“下一步”按钮。
图1-3 MATLAB安装界面
(3)进入图1-4所示界面,选择“是”单选项以接受许可协议,单击“下一步”按钮。
图1-4 安装协议
(4)如图1-5所示,选择“我已有我的许可证的文件安装密钥”单选项并输入安装密钥,单击“下一步”按钮。
图1-5 输入MATLAB密钥
(5)如图1-6所示,选择安装目录,这里建议选用默认的安装目录。如果想更改安装目录,单击“浏览”按钮,设置其他安装目录,其他安装目录不能有中文。单击“下一步”按钮。
图1-6 MATLAB安装的第五步
(6)图1-7所示界面可以方便用户选择想要安装的产品。当然因为初学者对大部分MATLAB产品并不太了解,为了使得MATLAB功能完整,请选择默认的安装,单击“下一步”按钮。
图1-7 典型安装或者自定义安装
(7)进入图1-8所示的界面,选中相应复选框以将快捷方式添加到桌面和“开始”菜单中的“程序”文件夹,单击“下一步”按钮。
图1-8 建立快捷方式
(8)进入图1-9所示的界面,单击“安装”按钮开始安装。
图1-9 确认安装
(9)安装完成后会进入图1-10所示的界面,单击“下一步”按钮。
图1-10 安装完毕确认
(10)进入图1-11所示的界面,选中“激活MATLAB”复选框,单击“下一步”按钮。
图1-11 激活MATLAB
(11)如图1-12所示,由于上面选择的是无网络安装,这里选中“不使用Internet手动激活”复选框,单击“下一步”按钮。
图1-12 不使用网络激活MATLAB
(12)如图1-13所示,单击“浏览”按钮选择正确的授权文件,单击“下一步”按钮。
图1-13 选择许可文件
(13)如图1-14所示,单击“完成”按钮完成安装。
图1-14 激活MATLAB
双击MATLAB的快捷方式,即可启动MATLAB R2014a,进入MATLAB的集成开发环境,如图1-15所示。
图1-15 MATLAB的集成开发环境
可通过如下方法退出MATLAB:
启动MATLAB之后,如图1-16所示,出现的工作界面就是MATLAB的主窗口。
图1-16 MATLAB的主窗口
在MATLAB的主窗口中,默认打开的子窗口有:(1)命令行窗口(Command Window);(2)命令历史记录窗口(Command History);(3)当前文件夹(Current Folder);(4)工作区(Workspace);(5)文本编辑器(File Editor);(6)图形窗口(Figure Window);(7)帮助窗口(Help)等。
在默认设置下,命令行窗口自动显示于MATLAB工作界面的中部,如图1-17所示。命令行窗口是用户和MATLAB进行交互的主要场所。MATLAB命令行窗口的最上面一行是系统初始的提示信息。MATLAB具有良好的交互性,当在提示符输入一段正确的运算式,只要按回车(Enter)键,命令窗口中就会直接显示运算结果。
图1-17 命令行窗口(Command Window)
命令历史记录窗口(Command History)用于记录用户在命令行窗口中的操作,是按逆序排列的。在默认设置下,命令历史记录窗口自动显示在MATLAB工作界面的右下侧,如图1-18所示。历史命令窗口显示用户在命令窗口中所输入的每条命令,并且标明使用时间,方便用户查阅。如果用户想再次执行某条已经执行过的命令,那么只需要在历史命令窗口中双击该命令。这些命令会一直存在下去,直到它被人为删除。若想要在命令历史记录窗口删除一个或多个命令,可以先选择对象,然后单击右键,这时就有一个弹出菜单出现,选择“Delete Section”命令,即可删除。
图1-18 命令历史记录窗口
在默认设置下,当前文件夹窗口自动显示于MATLAB工作界面的左上侧,如图1-19所示。当前文件夹窗口显示着当前用户工作所在的路径,它不仅可以显示当前目录的文件,还可以提供搜索。通过上面的目录选择下拉菜单,用户可以轻松地选择已经访问过的目录。单击右侧的按钮,可以打开路径选择对话框,在这里用户可以设置和添加路径,也可以通过此窗口最上面一行的超链接来改变路径。
图1-19 当前文件夹窗口
在默认设置下,工作区窗口自动显示于MATLAB工作界面的左下角,与当前文件夹窗口处于同一列,可以通过按住工作区窗口或当前文件夹窗口进行移动来调整其位置,工作区窗口如图1-20所示。
图1-20 工作区窗口
用MATLAB编写的程序存储于文件中,称为M文件。根据调用方式的不同,M文件可分为两类:命令文件(Script File)和函数文件(Function File)。图1-21所示为文本编辑器窗口,该窗口显示了用户所编辑的程序。
图1-21 文本编辑器窗口
MATLAB允许程序员为他们的程序建立一个交互式的用户图形界面。利用MATLAB的这种功能,程序员可以设计出能被无经验的用户操作的复杂数据分析程序。图1-22、图1-23所示的图像窗口主要用于显示MATLAB图像。它所显示的图像可以是数据的二维或三维坐标图、图片或用户图形接口。
图1-22 拉格朗日插值
图1-23 埃尔米特插值
初学者经常把某个自己编写的M程序放在当前工作空间的某个子目录下,但执行时MATLAB却找不到这个程序,其实这是搜索路径设置的问题。MATLAB的一切操作都是在它的搜索路径中进行的。
如果用户在MATLAB提示符后输入一个名字,那么MATLAB将按以下顺序寻找这个名字:(1)查看这个名字是否是一个变量名。如果它是一个变量,MATLAB将会显示出这个变量的值;(2)查看它是否是内建函数或命令。如果是,则执行对应的函数或命令;(3)检查它是不是在当前目录下的一个M文件。如果是,则执行对应的函数或命令;(4)检查它是不是在MATLAB搜索路径的所有目录下的一个M文件。如果是,则执行对应的函数或命令。
注意
由于系统首先搜索变量名,如果函数或命令名与某个变量名同名,那么这个函数或命令将变得无法访问。这是初学者易犯的错误之一。
用户可以使用下面的2种方法启动图1-24所示的“设置路径”对话框,随时检查和修改搜索路径:
图1-24 路径工具
MATLAB还包括一个特殊的命令—which命令,它能帮助我们找到正在执行的文件版本和路径,这在检查文件名冲突方面是非常有用的。
这个命令的格式是:which filename。
filename代表所要加载的函数名。
例如,加载的函数是perms.m。
>> which perms.m    %返回perms.m文件所在的路径
C:\Program Files\MATLAB\R2010b\toolbox\matlab\specfun\perms.m在命令行窗口输入path命令,可以得到MATLAB的所有搜索路径,如图1-25所示。
>> path图1-25 所有搜索路径
使用MATLAB的时候,可以在命令行窗口内直接书写MATLAB命令,也可以将代码保存到M文件中,然后运行该文件。使用MATLAB主界面菜单“文件”→“新建”→“M-File”可以打开一个文本编辑器编辑M文件。
在M文件编辑器的菜单中,选取“Debug”→“Run”即可运行M文件及MATLAB的代码文件。在路径设置正确的情况下,在命令行窗口中直接输入M文件的名称可以运行M文件中的代码。M文件的取名要以英文字母开头,用字母和数字组成,不要取中文文件名称,也不要在文件名称中使用特殊字符。M文件不能和MATLAB系统函数重名。
启动MATLAB文本编辑器建立新的M文件有3种方法。
打开已有的M文件也有3种方法。
【实例1.1】用图形窗口形式重新绘制正弦、余弦曲线。
>> clear all;  %%清除所有的变量,包括全局变量
>> clc; %%清除工作窗里的内容
>>x=linspace(0,2*pi,60);  %%将产生从0到2*pi以60点均等分的数组
>>y=sin(x);  %%创建函数关系
>>z=cos(x);
>>H1=figure;  %%控制画图的窗口
>>plot(x,y);  %%二维曲线绘图
>>title('sin(x)');  %%给已经画出的图加一个标题
>>axis([0 2*pi -1 1]);  %%设置轴的样式,包括坐标轴范围、可读比例等
>>H2=figure;  %%控制画图的窗口
>>plot(x,z);  %%二维曲线绘图
>>title('cos(x)');
>>axis([0 2*pi -1 1]);效果如图1-26、图1-27所示。
图1-26 绘制正弦曲线
图1-27 绘制余弦曲线
【实例1.2】用图形窗口形式重新绘制正切和余切曲线。
>> clear all;  %%清除所有的变量,包括全局变量
>> clc;  %%清除工作窗里的内容
>>x=linspace(0,2*pi,60);  %%将产生从0~2×pi以60点均等分的数组
>>t=sin(x)./(cos(x)+eps);  %%创建函数关系
>>ct=cos(x)./(sin(x)+eps);
>>H3=figure;  %%控制画图的窗口
>>plot(x,t);  %%二维曲线绘图
>>title('tangent(x)');  %%给已经画出的图加一个标题
>>axis([0 2*pi -40 40]);  %%设置轴的样式,包括坐标轴范围、可读比例等
>>H4=figure;  %%控制画图的窗口
>>plot(x,ct);  %%二维曲线绘图
>>title('cotangent(x)');
>>axis([0 2*pi -40 40]);效果如图1-28、图1-29所示。
图1-28 绘制正切曲线
图1-29 绘制余切曲线
将帮助窗口单独设置为一个小节,可见其重要性。MATLAB的输入命令和函数极多,有时候很难记住。为了方便用户的使用,MATLAB提供了帮助系统功能。
借助这一功能,用户可以很容易地查询相关函数的使用方法和相关信息。可以选择如下方法进入MATLAB的帮助系统,如图1-30所示。
图1-30 帮助窗口
 。
。熟练的用户可以使用更为快速的方式,即命令窗口查询帮助,这些帮助主要可以分为help系列和lookfor系列。
>> help图1-31所示为当前帮助系统所有项目目录名称,该窗口显示了函数说明目录。
图1-31 当前帮助系统所有项目目录名称
>>lookfor diff图1-32所示为输入完命令后显示的帮助窗口。
图1-32 帮助窗口
(1)通用命令(表1-1):
表1-1 MATLAB的通用命令
| 命 令 | 命 令 说 明 | 命 令 | 命 令 说 明 | 
|---|---|---|---|
| cd | 显示或改变工作目录 | hold | 图形保持开关 | 
| dir | 显示目录下内容 | disp | 显示变量或文字内容 | 
| type | 显示文件内容 | path | 显示搜索目录 | 
| clear | 清理内存中的变量 | save | 保存内存变量 | 
| clf | 清理当前图像窗口 | load | 加载指定文件的变量 | 
| clc | 清理命令窗口 | diary | 日志文件命令 | 
| echo | 命令行窗口信息显示开关 | ! | 调用DOS命令 | 
| pack | 整理内存 | quit | 退出MATLAB | 
(2)常用操作技巧(表1-2):
表1-2 MATLAB的常用操作技巧
| 命 令 | 命 令 说 明 | 命 令 | 命 令 说 明 | 
|---|---|---|---|
| ↑ | Ctrl+p,调用上一行 | Home | Ctrl+a,光标置于当前行开头 | 
| ↓ | Ctrl+n,调用下一行 | End | Ctrl+e,光标置于当前行末尾 | 
| ← | Ctrl+b,光标左移一个字符 | Esc | Ctrl+u,清除当前输入行 | 
| → | Ctrl+f,光标右移一个字符 | Del | Ctrl+d,删除光标处的字符 | 
| Ctrl+ ← | Ctrl+l,光标左移一个单词 | Backspace | Ctrl+h,删除光标前的字符 | 
| Ctrl+ → | Ctrl+r,光标右移一个单词 | Alt+ Backspace | 恢复上一次删除 | 
(3)标点(表1-3):
表1-3 MATLAB的相关标点
| 标 点 | 定 义 | 标 点 | 定 义 | 
|---|---|---|---|
| : | 冒号,具有多种功能 | . | 小数点,小数点及域访问符等 | 
| ; | 分号,行分隔及取消运行显示等 | … | 续行符 | 
| , | 逗号,列分隔及函数参数分隔符等 | % | 百分号,注释标记 | 
| () | 括号,指定运算过程中的先后次序等 | ! | 惊叹号,调用操作系统 | 
| [] | 方括号,矩阵定义的标志等 | = | 等号,赋值标记 | 
| {} | 大括号,定义单元数组等 | ‘’ | 单引号,字符串标示及矩阵转置等 | 
作为一种强大的工具,MATLAB体现了与它价值相符的优点。MATLAB编程简单,使用方便,只要入门就很好掌握,即使语法有问题,调试起来也是非常容易的。MATLAB的矩阵和向量操作功能是其他语言无法比拟的。
在MATLAB环境下,数组的操作与数的操作一样简单,基本数据单元是不需要指定维数的,不需要说明数据类型的矩阵,而其数学表达式的表示方式和运算规则与我们日常的使用习惯相同。学习MATLAB是有一定方法的,其中最重要的就是基础知识扎实。
前面已经介绍了MATLAB的应用范围之广,可以应用到多个行业当中去。鉴于此,要想真正学好MATLAB,需要弄清楚所在行业的相关现状。只有将MATLAB的技术应用到该行业当中去,才能使得书本上的知识不过于抽象,不容易理解。只有把理论和实际相互结合,才能把书本上的知识学好。
在学习的过程中,要把MATLAB当作一种工具,而不仅仅是一种语言。MATLAB的编程语言只是MATLAB与用户交互的桥梁,认清楚这一点很重要。
MATLAB最主要的应用是科学数值计算和最优化问题,MATLAB有足够多的工具箱可解决这些问题。但是在使用这些功能强大的工具箱之前,应该首先注意的是对基础理论知识的掌握,这一点在编写程序的过程中是极其重要的。碰到不会或者概念模糊的问题,需要借助帮助系统来确定使用方法是否正确。
对于较困难的问题,解决的办法是要分解问题,逐一解决。分解就是把实际问题转化为数学模型相关问题。绝大多数问题都可以转化为两类问题:一类是求解问题,一类是最优化问题。这个过程可能很简单,有现成的方法可用;也有可能很复杂,还可能涉及多种转化。
工程问题要解决的就是告诉计算机要做什么,该怎么做。所以用户在根本不知道某个问题该怎么解决的时候,就更加无法写出优秀的程序。鉴于此,要想编写优秀的程序,可以把需要重复执行的程序尽量写成函数,便于修改和维护。
在编写程序的过程中,如果程序出错了,而又查不到语法的错误,断点是个不错的选择。编程中最可怕的错误不是语法错误,而是逻辑错误,因为逻辑错误是最难被纠正的。一个很有用的工具就是断点,断点应该是纠错中最常用的工具。当程序运行到断点之后就会中断,这时用户就可以输入命令查看内存情况等。一步步地跟踪,直到变量值跟预期的不一样,这时就可以很容易地找到错误在什么地方发生了。
MATLAB不仅是一个科学计算的工具,也是一门简易的计算机语言。程序设计是MATLAB进行科学计算的基础。
本章将介绍MATLAB中程序设计的相关内容:基本语法、文件I/O和一些实用的编程技巧。
本节主要介绍与MATLAB相关的一些基本语法,用户可以学习到与标识符、数据类型、运算符、流程控制语句、预定义变量、矩阵与数组和脚本与函数等相关的知识。
标识符是用户编程时使用的名字,也就是代号,用来表示变量和函数。MATLAB中标识符应该遵循如下规则:
MATLAB提供了一些预定义变量,如表2-1所示。这些预定义变量大部分为常量,或者是在系统中有特殊含义和用途的变量。
表2-1 常见的预定义变量
| 预定义变量名 | 含 义 | 
|---|---|
| ans | 保存运算结果,用于没有指定运算结果名称时,将结果赋值给ans | 
| eps | MATLAB定义的正的最小值,表示精确度 | 
| pi | 圆周率的值 | 
| NaN | Not-a-Number,非数,无法定义的一个数 | 
| i/j | 虚数单位,sqrt(-1) | 
| nargin | 函数的输入参数的个数 | 
| nargout | 函数的输出参数的个数 | 
| realmax | 最大的正实数 | 
| realmin | 最小的正实数 | 
| Inf | 无穷大 | 
【实例2.1】预定义变量的使用。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> 0/0  %当分子、分母均为0时,计算结果为NaN
ans =
    NaN
>> 10/0    %当分母为0而分子不为0时,计算结果无穷大
ans =
    Inf
>> pi=10;  %赋予预定义变量新的值
>> 2*pi*4
ans =
    80
>> clear pi
>> pi  %恢复为预定义变量原有的值
ans =
    3.1416MATLAB的语言类似于C语言,但是与C语言相比又有很大的不同,可以说风格接近C语言,但是比C语言更为灵活。MATLAB的语言与C语言相比没有那么强的规范。例如,C语言在使用一个变量时必须先声明该变量,在MATLAB中则不必如此,只需要通过赋值语句就可以进行操作,不需要在使用前声明该变量。下面举例说明。
【实例2.2】声明一个变量。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> sum_11a = 18  %正常声明一个变量并赋值
sum_11a =
    18
>> clc
>> clear all
>> 11a_sum = 20  %非正常声明一个变量(变量名不能以数字开头)并赋值
??? 11a_sum = 20
      |
Error: Unexpected MATLAB expression.【实例2.3】声明多个变量。
%验证MATLAB与Matlab不是一个变量名
%在命令行窗口输入如下命令
>> clc
>> clear all
>> MATLAB = 12.55  %正常声明一个变量并赋值
MATLAB =
   12.5500
>> Matlab = -13.444  %正常声明一个变量并赋值
Matlab =
  -13.4440
>> MATLAB
>> MATLAB =
   12.5500
>> Matlab
>> Matlab =
  -13.4440
%可以看出MATLAB与Matlab不是一个变量名数值计算以矩阵为基础是MATLAB最大的特点和优势。一般来说,所有的数据都是矩阵或数组,标量可视为1×1矩阵,向量可视为1×N或N×1矩阵。二维数组称为矩阵,二维以上数组称为多维数组,有时矩阵也可以指多维数组。
【实例2.4】计算两个矩阵相加和相减的结果。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A=[1,1,1;1,2,3;1,3,6];
>> B=[8,1,6;3,5,7;4,9,2];
>> sum1=A+B
sum1 =
     9     2     7
     4     7    10
     5    12     8MATLAB是一门计算机语言,它处理的对象是数据。MATLAB的基本数据类型有十几种,不同的专业工具箱中还具有特殊的数据类型,并且MATLAB还支持面向对象的编程技术,支持用户自定义的数据类型,每一种类型的数据都是以矩阵或数组形式存储和表现。MATLAB的命令和语法也是以基本的矩阵运算及矩阵扩展运算为基础,用户可以建立整型、浮点型、字符、字符串、逻辑型、结构数组和细胞数组等。
整型是MATLAB最为基本的数值类型。每种类型表示的数据范围如表2-2所示。
表2-2 MATLAB的数据类型与取值范围
| 数 据 类 型 | 表 示 范 围 | 数 据 类 型 | 表 示 范 围 | 
|---|---|---|---|
| int8 | −27~27−1 | uint8 | 0~28−1 | 
| int16 | −215~215−1 | uint16 | 0~216−1 | 
| int32 | −231~231−1 | uint32 | 0~232−1 | 
| int64 | −263~263−1 | uint64 | 0~264−1 | 
如下例所示,当数值超出某个数据类型的范围时,MATLAB将该数据表示成最大或者最小值。
【实例2.5】数据类型超界实例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> int8(-245)   %负数超界
ans =
  -128
>> int8(345)    %正数超界
ans =
  127逻辑型是科学计算经常用到的数据类型之一,所谓逻辑型就是仅仅有“true”和“false”两个数值的一种数据类型。一般来说,逻辑“真”即为“1”,逻辑“假”为“0”。逻辑型数据可以用于逻辑运算。表2-3所示为常用的逻辑运算符或函数。
表2-3 逻辑运算
| 运算符或函数 | 说 明 | 
|---|---|
| && | 逻辑与 | 
| || | 逻辑或 | 
| & | 元素“与”操作 | 
| | | 元素“或”操作 | 
| ~ | 逻辑“非”操作 | 
| xor | 逻辑“异或”操作 | 
| any | 当向量中有非零元素时,返回真 | 
| all | 当向量中都是非零元素时,返回真 | 
| == | 关系操作符,等于 | 
| ~= | 关系操作符,不等于 | 
| < | 关系操作符,小于 | 
| > | 关系操作符,大于 | 
| <= | 关系操作符,小于等于 | 
| >= | 关系操作符,大于等于 | 
| 所有以is开头的函数,cellfun | 测试操作 | 
| strcmp、strncmp、strmpi、strncmpi | 字符串比较函数 | 
虽然逻辑型只有真、假之分,但是参与逻辑运算或者关系运算的不一定必须是逻辑数据。能创建逻辑类型数据、逻辑类型矩阵或者数组的函数主要有以下3个:
注意
参与逻辑运算的操作数不一定必须是逻辑类型的变量或常数,也可以使用其他类型的数据进行逻辑运算,但是运算结果一定是逻辑类型的数据。
【实例2.6】利用函数将一个整型数据转换为逻辑类型数据。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> MATLAB = 12.55   %声明一个变量并赋值
MATLAB =
   12.5500
>> logical (MATLAB)
ans =
    1【实例2.7】利用函数建立逻辑类型数组示范例程。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A = true(2,3)     %生成3行2列的逻辑真的矩阵
A =
     1       1       1
     1       1       1
>> B = false(3,2)    %生成3行2列的逻辑假的矩阵
B =
     0       0
     0       0
     0       0
>> C = eye(3,3)      %产生单位矩阵
C =
     1       0       0
     0       1       0
     0       0       1
>> D = logical(C)    %产生逻辑矩阵D
D =
     1       0       0
     0       1       0
     0       0       1MATLAB中经常会对字符或字符串进行操作。字符串就是一维字符数组,可以通过它的下标对字符串中的任何一个字符进行访问。
字符数组中存放的并非是字符本身,而是字符的ASCII码。MATLAB的字符串处理功能非常强大,提供了许多字符或字符串处理函数,包括字符串的创建、字符串的标识、字符串的比较、字符串的查找以及字符串的转换等。表2-4所示为MATLAB中常用的字符串操作函数。
表2-4 常用的字符串操作函数
| 函 数 | 说 明 | 
|---|---|
| char(S1, S2, …) | 利用现有字符串或者单元数组创建字符数组 | 
| double(s) | 将一个字符串转换成ASCII形式 | 
| cellstr(S) | 利用字符数组创建字符串单元数组 | 
| blanks(n) | 生成长度为n的空字符串 | 
| deblanks(n) | 删除尾部的空格 | 
| eval(S), evalc(S) | 求字符串表达式的值 | 
| ischar(S) | 如果是字符数组,就返回true | 
| iscellstr(S) | 如果是字符串单元数组,就返回true | 
| isletter(S) | 如果是字母,就返回true | 
| isspace(S) | 如果是空格,就返回true | 
| strcat(S1, S2, …) | 将字符串进行水平方向的连接 | 
| strvat(S1, S2, …) | 将字符串进行垂直方向的连接,忽略空格 | 
| strcmp(S1, S2, n) | 如果两个字符串相同,就返回true | 
| strncmp(S1, S2, n) | 如果两个字符串的前n个字符相同,就返回true | 
| strcmpi(S1, S2) | 如果两个字符串相同,就返回true,忽略大小写 | 
| strncmpi(S1, S2, n) | 如果两个字符串的前n个字符相同,就返回true,忽略大小写 | 
| findstr(S1, type) | 在一个字符串中查找另外一个字符串 | 
| strjust(S1, S2) | 将一个字符串数组调整为左对齐、右对齐或居中 | 
| strmatch(S1, S2) | 查找符合要求的字符串的下标 | 
| strrep(S1, S2, S3) | 将字符串S1中出现的S2用S3代替 | 
| strtok(S1, D) | 查找某个字符最先出现的位置 | 
| upper(S) | 将一个字符串转换成大写 | 
| lower(S) | 将一个字符串转换成小写 | 
| num2str(x) | 将数字转换成字符串 | 
| int2str(k) | 将整型转换成字符串 | 
| mat2str(X) | 将矩阵转换成字符串供eval使用 | 
| str2double(S) | 将字符串转换成双精度值 | 
| strinum(S) | 将字符串数组转换成数值数组 | 
| sprint(S) | 创建由格式控制指定的字符串 | 
| sscanf(s) | 按照格式控制指定的格式读取字符串 | 
(1)字符串变量的创建
字符串变量的创建方法是:在命令行窗口中先把待建的字符放在“单引号对”中,再按回车键。(注意,该“单引号对”必须在英文状态下输入,它是MATLAB用来识别字符串变量的唯一标识)。
【实例2.8】字符串变量的创建。
%在命令窗口输入如下命令
>> clc
>> clear all
>> msg =  'You are right!'%创建带有单引号对的字符串
msg =
You are right!
>> a = 'This is an example.'%创建带有单引号对的字符串
a =
This is an example.
>> s='matrix laboratory'
s =
matrix laboratory(2)字符串数组的标识
字符串变量的每个字符(英文字母、空格和标点都是平等的)占据一个元素位,在数组中元素所处的位置用自然数标识。例如:
【实例2.9】提取一个子字符串。
>> b=a(1:4) % 提取一个子字符串
b =
This【实例2.10】字符串的倒排。
>> ra=a(end:-1:1) % 字符串的倒排
ra =
.elpmaxe na si sihT(3)字符串的ASCII码
字符串的存储是用ASCII码来实现的。指令double可以用来获取字符串数组所对应的ASCII码数值数组。指令char可把ASCII码数组变为字符串数组。例如:
【实例2.11】获取字符串数组所对应的ASCII码。
>> d=double(a) 
d =
    84   104   105   115   32   105   115   32   97   110   32   101   120   97   109  
112   108   101   46【实例2.12】把ASCII码数组变为字符串数组。
>> char(d) 
ans =
This is an example.(4)字符串数组的运算
【实例2.13】连接字符串。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> name = strcat('Thomas',' R.',' Lee') %连接字符串
name =
Thomas R. Lee【实例2.14】利用串操作函数创建多行字符串数组。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> D=strvcat('Hello','Yes','No','Goodbye') %利用串操作函数创建多行字符串数组,连接多行字符串,每行长度可不等,自动把非最长字符串最右边补空格,使之与最长字符串的长度相等,会忽略空字符串。
D =
Hello 
Yes 
No 
Goodbye(5)字符串和数组之间的转换
表2-5所示为数值数组和字符串转换函数表。
表2-5 数值数组和字符串转换函数表
| 函 数 | 说 明 | 函 数 | 说 明 | 
|---|---|---|---|
| num2str | 数字转换为字符串 | str2num | 字符串转换为数字 | 
| int2str | 整数转换为字符串 | sprintf | 将格式数据写为字符串 | 
| mat2str | 矩阵转换为字符串 | sscanf | 在格式控制下读字符串 | 
【实例2.15】数值数组和字符串转换示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
%数字转换为字符串示例
>> x = rand(2,3) * 9999; 
>> A = num2str(x, '%10.5e\n') 
A =
2.78470e+003
9.57411e+003
1.57597e+003
5.46827e+003
9.64792e+003
9.70496e+003
%将格式数据写为字符串示例
>> N = sprintf('%6d', [123456])
N =
123456(6)字符串替换和查找
【实例2.16】进行字符串替换。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> claim = 'This is a good example.';
>> new_claim = strrep(claim, 'good', 'great')
new_claim =
This is a great example.【实例2.17】查找str中是否有要查找的字符串,返回出现的位置。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> S = 'Find the starting indices of the pattern string';
>> strfind(S, 'in')
ans =
     2      15      19      45
>> strfind(S, 'In')
ans =
     []
>> strfind(S, ' ')
ans =
     5     9     18     26     29     33     41(7)常用字符串操作函数
【实例2.18】创建由20个空格组成的字符串。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> disp(['xxx' blanks(20) 'yyy'])
xxx                        yyy(8)其他字符串操作函数
【实例2.19】比较两个字符串是否完全相等。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> strcmp('Yes', 'No')
ans =
    0
>> strcmp('Yes', 'Yes')
ans =
    1(9)字符串的显示和打印
【实例2.20】字符串的显示和打印。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> g= 'abcd';
>> disp(g)  %显示变量存储的字符串
abcd
>> h=rand(2,2); %产生2*2随机矩阵
>>s=num2str(h)  %把数值数组转换为字符串数组
s =
0.63236     0.2785
0.09754    0.54688结构数组的创建可以使用两种方法,一种是直接赋值法,另外一种是利用struct函数创建。结构数组可以将一组彼此相关、数据结构相同但类型不同的数据组织在一起。在使用结构数组时,需要注意:
用户可以直接使用struct函数创建结构数组,struct函数可以根据指定域及其相应的值创建结构数组,此函数的一般格式为:
str_array=struct(‘filed1’,{val1},’filed2’, {val2}…)
str_array=struct(‘filed1’,val1,’filed2’, val2…)【实例2.21】创建如图2-1所示的结构数组。
图2-1 在校学生结构数组
%在命令窗口输入如下命令
>> clc
>> clear all
>> student.number='20050731025';
>> student.name='刘志佳';
>> student.course={'高数1' '英语1' '体育1' '物理1' '哲学1' '线代1' '制图1'; '高数2' '英语2' '体育2' '物理2' '哲学2' '线代2' '制图2'};
>> student.score=[90 85 63 70 84 92 65;91 76 82 88 75 87 91];
>> student
student = 
    number: '20050731025'
     name: '刘志佳'
    course: {2x7 cell}
     score: [2x7 double]
>> size(student)
ans =
     1     1【实例2.22】直接赋值法创建结构数组示例。根据上面例题,以结构数组保存员工资料数据。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> employee.name='henry';
>> employee.sex='male';
>> employee.age='25';
>> employee.number='123456789';
>> employee
employee = 
      name: 'henry'
        sex: 'male'
        age: '25'
    number: '123456789'
%在上面结构数组中再扩展一个结构数组
>> employee(2).name='lee';
>> employee(2).sex='female';
>> employee(2).age='23';
>> employee(2).number='987654321';
>> employee
employee = 
1x2 struct array with fields:
      name
      sex
      age
      number【实例2.23】使用struct函数创建结构数组示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
%范例1
>> student=struct('name','henry','age',25,'grade',uint16(1))
student = 
      name: 'henry'
        age: 25
    grade: 1
>> whos
  Name        Size         Bytes  Class     Attributes
  Student   1x1            388  struct 
%范例2
>> student=struct('name',{'richard','jackson'},'age',{25,24},'grade',{2,3})
student = 
1x2 struct array with fields:
    name
    age
    grade
>> whos
  Name         Size          Bytes  Class     Attributes
  Student   1x2              612  struct细胞数组是MATLAB特有的一种数据类型,组成它的元素是细胞,细胞是用来存储不同类型数据的单元。图2-2所示的是2×2细胞数组结构图。细胞数组中每个细胞存储一种类型的MATLAB数组,此数组中的数据可以是任何一种MATLAB数据类型或用户自定义的类型,其大小也可以是任意的。相同数组的第二个细胞的类型与大小可以和第一个细胞完全不同。细胞数组有如下特点。
图2-2 在校学生2×2细胞数组
(1)细胞数组的创建:
【实例2.24】创建细胞数组示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A={[1 4 3;0 5 8;7 2 9], 'Anne Smith';3+7i,-pi:pi/4:pi}
A = 
          [3x3 double]    'Anne Smith'
    [3.0000 + 7.0000i]    [1x9 double]
>> whos A
  Name       Size          Bytes  Class    Attributes
  A       2x2              420  cell【实例2.25】依次创建细胞数组示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A(1,1)={[1 4 3;0 5 3;7 2 9]};
>> A(1,2)={'Anne Smith'};
>> A(2,1)={3+7i};
>> A(2,2)={-pi:pi/4:pi};
>> A
A = 
          [3x3 double]    'Anne Smith'
    [3.0000 + 7.0000i]    [1x9 double]
>> whos A
  Name      Size          Bytes  Class    Attributes
  A        2x2            420  cell【实例2.26】如图2-2是细胞数组的结构示意图,cell(1,1)是字符数组,cell(1,2)、cell(2,1)、cell (2,2)本身也是细胞数组,创建2×2的细胞数组。
%在命令窗口输入如下命令
>> clc
>> clear all
>> student{1,1}=['20050731025';'20050731026'];
>> student{2,1}={'刘志佳';'王玲'};
>> student{1,2}={'高数1' '英语1' '体育1' '物理1' '哲学1' '线代1' '制图1'; '高数2' '英语2' '体育2' '物理2' '哲学2' '线代2' '制图2'};
>> student{2,2}={[90 85 63 70 84 92 65; 91 76 82 88 75 87 91]; [80 95 70 90 64 82 75; 81 66 92 78 85 67 81]};
>> student
student = 
    [2x11 char]    {2x7 cell}
    {2x1  cell}    {2x1 cell}
>> whos student
  Name          Size          Bytes  Class    Attributes
  student       2x2           1670  cell(2)细胞数组的寻访:
细胞数组的寻访和一般数组的寻访类似,对于二维数组A来说,A(2,4)表示的就是数组第2行第4列上的元素。MATLAB设计两种不同的操作:细胞外标识和细胞内编址。
【实例2.27】细胞数组的寻访示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A={20,'matlab';ones(2,3),1:3}
A = 
    [        20]    'matlab' 
    [2x3 double]    [1x3 double]
>> str=A{1,2}   %返回对应细胞内容
str =
matlab
>> class(str)   %返回str的数据类型
ans =
char
>> str2=A(1,2)  %返回对应细胞数组的一个细胞
str2 = 
    'matlab'
>> class(str2)  %返回str2的数据类型
ans =
cell(3)细胞数组的操作函数:
如表2-6所示,和其他数组一样,MATLAB也为细胞数组提供一系列的操作函数。
表2-6 细胞数组中的操作函数
| 函 数 | 说 明 | 函 数 | 说 明 | 
|---|---|---|---|
| cell | 创建空的细胞数组 | num2cell | 将数值数组转换为细胞数组 | 
| cellfun | 对细胞数组的每个细胞执行指定的函数 | deal | 将输入参数赋值给输出 | 
| celldisp | 显示所有细胞的内容 | cell2struct | 将细胞数组转换为结构 | 
| cellplot | 利用图形方式显示细胞数组 | struct2cell | 将结构转换为细胞数组 | 
| cell2mat | 将细胞数组转换为普通的矩阵 | iscell | 判断输入是否为细胞数组 | 
| mat2cell | 将数组矩阵转换为细胞数组 | 
 | 
 | 
【实例2.28】cellfun函数使用示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
%计算几个数据集的平均值
>> C = {1:10, [2; 4; 6], []};
>> Cmeans = cellfun(@mean, C)
Cmeans =
   5.5000    4.0000        NaN
%计算这些数据集的大小
>> [Cnrows, Cncols] = cellfun(@size, C)
Cnrows =
    1     3     0
Cncols =
    10    1     0
%再次计算大小,但将UniformOutput设置为false
>> Csize = cellfun(@size, C, 'UniformOutput', false)
Csize = 
    [1x2 double]    [1x2 double]     [1x2 double]
>> Csize{:}
ans =
    1      10
ans =
    3      1
ans =
    0      0
%在多数据集中找到正值
>> C = {randn(10,1), randn(20,1), randn(30,1)};
>> Cpositives = cellfun(@(x) x(x>0), C, 'UniformOutput',false)
Cpositives = 
    [6x1 double]       [11x1 double]       [15x1 double]
>> Cpositives{:}
ans =
    0.1253
    0.2877
    1.1909
     etc.
ans =
    0.7258
    2.1832
    0.1139
     etc.
ans =
    0.6900
    0.8156
    0.7119
     etc.
% 计算一些数据集中的协方差:
>> C = {randn(10,1), randn(20,1), randn(30,1)};
>> D = {randn(10,1), randn(20,1), randn(30,1)};
>> CDcovs = cellfun(@cov, C, D, 'UniformOutput', false)
CDcovs = 
    [2x2 double]    [2x2 double]    [2x2 double]
>> CDcovs{:}
ans =
    0.8174    0.4885
    0.4885    1.9389
ans =
    1.4762   -0.0664
   -0.0664    0.6126
ans =
    1.0139    0.1562
    0.1562    1.0054MATLAB中主要的运算符包括:算术运算符、关系运算符、逻辑运算符和其他运算符。
算术运算符可以分为矩阵运算符和数组运算符两大类。矩阵运算符遵照线性代数的规则进行运算。数组运算符则遵照对应的元素之间进行运算操作。
表2-7 算术运算符
| 运 算 符 | 运算符类型 | 功 能 | 运 算 符 | 运算符类型 | 功 能 | 
|---|---|---|---|---|---|
| + - | 矩阵运算 | 矩阵加减运算 | + - | 数组运算 | 数组元素的加减运算 | 
| * | 矩阵运算 | 矩阵相乘 | .* | 数组运算 | 矩阵或数组中的对应元素相乘 | 
| / | 矩阵运算 | 矩阵相除 | ./ | 数组运算 | 矩阵或数组中的对应元素相除 | 
| \ | 矩阵运算 | 矩阵左除,左边为除数 | .\ | 数组运算 | 矩阵或数组中的对应元素左乘 | 
| ^ | 矩阵运算 | 矩阵的乘方 | .^ | 数组运算 | 矩阵或数组中所有元素的乘方 | 
| ' | 矩阵运算 | 取转置 | .' | 数组运算 | 取转置 | 
关系运算是同类型数组对应元素之间进行的运算,其运算结果是一个同类型的逻辑数组。关系运算符如表2-8所示。
表2-8 关系运算符
| 运 算 符 | 功 能 | 运 算 符 | 功 能 | 
|---|---|---|---|
| < | 小于 | >= | 大于等于 | 
| <= | 小于等于 | == | 等于 | 
| > | 大于 | ~= | 不等于 | 
当数值超出该类型的取值范围时,MATLAB将该数据表示成最大或者最小值。
元素级(Element-Wise)的逻辑运算符则用于对标量或矩阵元素进行逻辑运算,得到一个结果标量或结果矩阵。MATLAB的逻辑运算符如表2-9所示。
表2-9 逻辑运算符
| 运 算 符 | 功 能 | 运 算 符 | 功 能 | 
|---|---|---|---|
| & | 逻辑与 | xor | 逻辑异或 | 
| | | 逻辑或 | && | 逻辑与 | 
| ~ | 逻辑非 | || | 逻辑或 | 
假设操作数为a和b,则元素级逻辑运算符包括:
MATLAB的其他运算符如表2-10所示。
表2-10 其他运算符
| 运 算 符 | 功 能 | 
|---|---|
| [] | 生成向量或矩阵 | 
| {} | 生成细胞数组 | 
| … | 续行符 | 
| = | 赋值 | 
| ‘’ | 字符串的标记 | 
| . | 结构数组的域访问 | 
| % | 注释 | 
| @ | 函数句柄 | 
| ; | 禁止命令窗口显示结果 | 
MATLAB表达式可以使用任何组合的算术运算符、关系运算符和逻辑运算符等,他们的优先级确定MATLAB表达式的运算顺序。如果两个运算符的优先级相同,则从左向右运算。MATLAB的运算符的优先级从最高到最低如下:
【实例2.29】运算符运用实例。
%在命令行窗口输入如下命令
>> clc
>> clear all
%数值变量的运算
>> 256*233
ans =
        59648【实例2.30】要求计算水在温度0℃、20℃、40℃、60℃、80℃时的黏度,已知水的黏度随温度变化的公式为:
 ,其中当
,其中当 为0℃时,水的黏度值为1.785×10−3 Pa·s。
为0℃时,水的黏度值为1.785×10−3 Pa·s。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> muw0=1.785e-3;   % 定义0<sup>o</sup>C时的黏度值
>> a=0.03368;   %定义两个常数
>> b=0.000221;
>> t=0:20:80;  %定义摄氏温度变量
>> muw=muw0./(1+a*t+b*t.^2) %计算摄氏温度对应黏度值
muw =
    0.0018    0.0010    0.0007    0.0005    0.0003MATLAB作为一种高级程序设计语言,提供了经典的循环结构(for循环和while循环)、选择结构(if)和流程控制语句。用户可以应用这些流程控制语句编写MATLAB程序,实现 多种功能。
结构化程序设计包含3种结构:顺序结构、选择结构和循环结构。与C语言类似,MATLAB也采用if、else、switch和for等关键字来实现选择结构和循环结构。不同的是C语言使用“{}”来标记一个语言块,而MATLAB则使用end关键字来标记语言块。
顺序结构是最简单的程序结构,系统在编译程序时,按照程序的顺序执行。虽然这种程序容易编写,但是结构单一,能够实现的功能有限。
【实例2.31】顺序结构示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> r=1;
>> h=1;
>> s=2*r*pi*h + 2*pi*r^2;  %立柱的表面积
>> v=pi*r^2*h;    %立柱的体积
>> disp('The surface area of the colume is:'),disp(s);
The surface area of the colume is:
  12.5664
>> disp('The volume of the colume is:'),disp(v);
The volume of the colume is:
3.1416MATLAB中的选择结构可以用if、else和switch等关键字来实现。if语句是最常用的,格式比较整齐,便于理解。if关键字的格式如下:
if  expression
    do  task
end
if  expression_1
    do  task_1
else
    do  task_2
end
if  expression_1
    do  task_1
elseif expression_2
    do  task_2
elseif expression_3
    do  task_3
end【实例2.32】判断输入的两个参数是否都大于0,是则打印“a and b are both larger than 0”,否则不打印,程序最后返回“Done”。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> a=input('a=');
a=10
>> b=input('b=');
b=15
>> if a > 0 & b>0
disp('a and b are both larger than 0');
end
disp('Done');
a and b are both larger than 0
Done【实例2.33】计算分段函数的值。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> x=input('请输入x的值:');
请输入x的值:11
>> if x<=0
y= (x+sqrt(pi))/exp(2)
else
y=log(x+sqrt(1+x*x))/2
end
y =
    1.5466【实例2.34】判断输入的学生成绩的所属等级:60以下为不合格,60~89为中等,90以上为优秀。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> n=input('input the score:')
input the score:98
n =
    98
>> if  n>=0 &  n<60 
    A='不合格'
elseif n>=60 & n<89
    A='中等'
elseif n>=90 &n<100
    A='优秀'
else
    A='输入错误'
end
A =
优秀MATLAB中的另一种多选择语句为分支语句。分支语句的结构为:
Switch  分支语句
  case  条件语句
    执行代码块
  case {条件语句1, 条件语句2, 条件语句3,…}
    执行代码块
  otherwise
    执行代码块
end其中的分支语句为一个变量,可以是数值变量或者字符串变量,如果该变量的值与某一条件相符,则执行相应的语句,否则,执行otherwise后面的语句。在每一个条件中,可以包含一个条件语句,也可以包含多个条件,当包含多个条件时,将条件以单元数组的形式表示。
【实例2.35】任意底对数的实现。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> a=input('输入底');
输入底10
>> b=input('输入取对数的值');
输入取对数的值22
>> switch a
   case exp(1)
        y = log(b)
   case 2
        y = log2(b)
   case 10
        y = log10(b)
   otherwise
        y = log(b)/log(a)
end
y =
   1.3424【实例2.36】某商场对顾客所购买的商品实行打折销售,标准如表2-11所示(商品价格用price来表示)。
表2-11 打折价格
| 条 件 | 折 扣 | 条 件 | 折 扣 | 
|---|---|---|---|
| price < 200 | 没有折扣 | 1000<= price<2500 | 8%折扣 | 
| 200 <= price < 300 | 3%折扣 | 2500<= price<5000 | 10%折扣 | 
| 5000 <= price < 1000 | 5%折扣 | 5000<= price | 14%折扣 | 
输入所售商品的价格,求其实际销售价格。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> price=input('请输入商品价格');
请输入商品价格300
>> switch fix(price/100) 
   case {0,1}              %价格小于200
      rate=0;
   case {2,3,4}            %价格大于等于200但小于500
      rate=3/100;
   case num2cell(5:9)      %价格大于等于500但小于1000
      rate=5/100;
   case num2cell(10:24)    %价格大于等于1000但小于2500
      rate=8/100;
   case num2cell(25:49)    %价格大于等于2500但小于5000
      rate=10/100;
   otherwise               %价格大于等于5000
      rate=14/100;
end
price=price*(1-rate)       %输出商品实际销售价格 
price =
   291与C语言类似,MATLAB中有两种循环结构的语句:for循环和while循环。这里面有一点不同的是,MATLAB不含do-while语句。for关键字的格式如下:
for   expression
     do  task
endwhile关键字的格式如下:
while   expression
    do  task
end【实例2.37】用循环结构求解1+2+…+99+100。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> s=0;
>> for i=1:100 
       s=s+i;
  end
>> s
s =
5050【实例2.38】用循环结构求解最小的m,使其满足 。
。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> s=0; 
>> m=0;
>> while (s<=10000)
    m=m+1; 
    s=s+m; 
 end
>> s
s =
   10011除了之前介绍的几种结构语句外,MATLAB还有一些可以影响程序流程的语句,称为程序流控制语句。
矩阵是MATLAB中最基本的数据结构,用户开始定义一个变量时,首先想到的就是定义一个矩阵。用一个矩阵可以表示多种数据结构,当矩阵是1维时,它表示一个标量;当矩阵只有一行或只有一列时,它表示一个向量。一个二维矩阵能够存储多种数据元素,这些数据元素可以是数值类型、字符串、逻辑类型或者其他MATLAB结构类型。MATLAB为矩阵提供多种运算,这些运算可以提高MATLAB的运算效率。本小节主要首先介绍如何建立一个矩阵,其次介绍矩阵的操作有哪些,最后介绍一些MATLAB中与矩阵相关的常用函数。MATLAB用于创建数组和矩阵的部分函数如表2-12所示。
表2-12 部分用于创建数组和矩阵的函数
| 函 数 名 | 功 能 | 
|---|---|
| zeros(m, n) | 创建m行n列的零矩阵 | 
| ones(m, n) | 创建m行n列的全1矩阵 | 
| eye(m, n) | 创建m行n列的单位矩阵 | 
| rand(m, n) | 创建m行n列服从0~1均匀分布的随机矩阵 | 
| randn(m, n) | 创建m行n列服从标准正态分布的随机矩阵 | 
| magic(n) | 创建n阶魔方矩阵 | 
| linespace(x1, x2, n) | 创建线性等分向量 | 
| linespace(x1, x2, n) | 创建对数等分向量 | 
| diag | 创建对角矩阵 | 
zeros零矩阵生成函数的一般格式为:
B=zeros(n)   %生成n×n全零矩阵
B=zeros(m, n)   %生成m×n全零矩阵
B=zeros(d1, d2, d3…)   %生成d1×d2×d3×…全零矩阵或数组【实例2.39】用zeros生成2×3和3×3的零矩阵。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A=zeros(2,3)
A =
0 0 0
0 0 0
>> B=zeros(3)
B =
0 0 0
0 0 0
0 0 0【实例2.40】用eye生成单位矩阵。
%在命令行窗口输入如下命令
%示例1
>> clc
>> clear all
>> n=3;
>> test1=eye(n)
test1 =
     1     0     0
     0     1     0
     0     0     1
%示例2
>> A=[1,3,2;4,6,7;7,3,8]
A =
     1     3     2
     4     6     7
     7     3     8
>> test2=eye(size(A))
test2 =
     1     0     0
     0     1     0
     0     0     1ones全1矩阵生成函数的一般格式为:
Y=ones(n)   %生成n×n全1矩阵
Y=ones(m, n)   %生成m×n全1矩阵
Y=ones(d1, d2, d3…)   %生成d1×d2×d3×…全1矩阵
Y=ones(size(A))   %生成与矩阵A相同大小的全1矩阵【实例2.41】用ones生成全1矩阵。
%在命令行窗口输入如下命令
%示例1
>> clc
>> clear all
>> n=3;
>> test1=ones(n)
test1 =
     1     1     1
     1     1     1
     1     1     1
%示例2
>> a=magic(3)
a =
     8     1     6
     3     5     7
     4     9     2
>> b=ones(size(a))
b =
     1     1     1
     1     1     1
     1     1     1randn生成正态分布随机函数的一般格式为:
Y=randn (n)   %生成n×n正态分布随机矩阵
Y= randn(m, n)   %生成m×n正态分布随机矩阵
Y= randn(d1, d2, d3…)   %生成d1×d2×d3×…正态分布随机矩阵
Y= randn(size(A))   %生成与矩阵A相同大小的正态分布随机矩阵【实例2.42】产生均值为0.6,方差为0.1的四阶矩阵。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> mu=0.6;
>> sigma=0.1;
>> test=mu+sqrt(sigma)*randn(4)
test =
    0.1826    1.0545    0.8091    0.4419
    0.5134    0.5913    1.2057    0.8266
    0.6860    0.8922    0.6496    1.0229
    1.0710    0.4984    0.5050    1.2722MATALB的M文件分为两种,一种是脚本文件,一种是函数文件。
函数句柄是一个可被调用的MATLAB函数的关联,基于这种关联,用户在任何情况下都可以通过函数句柄调用MATLAB函数,即使是超出函数正常的调用范围仍然可以。函数句柄主要有以下四个用途。
函数句柄(Function Handle)是MATLAB的一种数据类型。引入函数句柄是为了使feval及借助于它的泛函指令工作得更可靠。特别在反复调用的情况下更显效率,使“函数调用”像“变量调用”一样方便灵活,提高函数调用的速度,提高软件的可重用性,扩大子函数和私用函数的可调用范围,迅速获得同名重载函数的位置、类型信息。
MATLAB中函数句柄的使用使得函数也可以成为输入变量,并且能很方便地调用,提高了函数的可用性和独立性。例如:
【实例2.43】函数句柄实例。
建立M文件f1。
function y=f1(X)
x1=X(1);x2=X(2);
y=X.*2;建立M文件ftest。
function Y=ftest(f,X)
x1=X(1)
x2=X(2)
F=f([x1,x2])
Y=F.*3;
%在MATLAB窗口输入:
>> Y=ftest(@f1,[2,1])
%得到以下输出:
x1 =
    2
x2 =
    1
F =
    4    2
Y =
        12    6为了实现MATLAB和其他格式文件的信息交互,同时实现MATLAB计算结果的保存,加强MATALB的应用功能,MATLAB提供了许多关于文件输入输出的函数,使用这些函数可以方便地实现各种格式文件的读写。
load命令的格式如下:
S = load(filename)
S = load(filename, variables)
S = load(filename, '-mat', variables)
S = load(filename, '-ascii')【实例2.44】把一个4列矩阵保存为一个ASCII文件,然后把数据重新载入。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> a = magic(4);
>> b = ones(2, 4) * -5.7;
>> c = [8 6 4 2];
>> save -ascii mydata.dat a b c
>> clear a b c
>> load mydata.dat  127save命令的格式如下:
save(filename)
save(filename, variables)
save(filename, '-struct', structName, fieldNames)
save(filename,…, '-append')
save(filename, …, format)
save(filename, …, version)【实例2.45】把一个4列矩阵保存为一个ASCII文件。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> savefile = 'pqfile.mat';
>> p = rand(1, 10);
>> q = ones(10);
>> save(savefile, 'p', 'q')当文件以文本形式打开时就要对文本文件进行读写操作。文本文件的写操作是由函数fprintf来实现的。
函数fprintf的调用格式如下:
fprintf(fileID, format, A, …) 
fprintf(format, A, …)
count = fprintf(…)【实例2.46】在屏幕上打印多个值和文字文本。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> B = [8.8  7.7 ; …
     8800 7700];
>> fprintf('X is %4.2f meters or %8.3f mm\n', 9.9, 9900, B)
X is 9.90 meters or 9900.000 mm
X is 8.80 meters or 8800.000 mm
X is 7.70 meters or 7700.000 mm【实例2.47】将双精度值转换为整数值,并打印到屏幕上。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> a = [1.02 3.04 5.06];
>> fprintf('%d\n', round(a));
1
3
5【实例2.48】将一个函数表写入到一个名为“exp.txt”的文本文件中。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> x = 0:.1:1;
>> y = [x; exp(x)];
%打开文件的写权限
>> fid = fopen('exp.txt', 'w');
>> fprintf(fid, '%6.2f %12.8f\n', y);
>> fclose(fid);
%查看文件的内容
>> type exp.txt
  0.00   1.00000000
  0.10   1.10517092
  0.20   1.22140276
  0.30   1.34985881
  0.40   1.49182470
  0.50   1.64872127
  0.60   1.82211880
  0.70   2.01375271
  0.80   2.22554093
  0.90   2.45960311
  1.00   2.71828183文本文件的读操作由函数fscan来实现。
函数fscan的调用格式如下:
A = fscanf(fileID, format)
A = fscanf(fileID, format, sizeA)
[A, count] = fscanf(…)【实例2.49】跳过在文件中的特定字符,然后返回数值。
%在命令行窗口输入如下命令
>> clc
>> clear all
%创建一个温度文件
>> tempstr = '78°F 72°F 64°F 66°F 49°F';
>> fid = fopen('temperature.dat', 'w+');
>> fprintf(fid, '%s', tempstr);
%返回到文件的头
>> frewind(fid);
%读文件中的数据
>> degrees = char(176);
>> num_temps = fscanf(fid, ['%d' degrees 'F'])
num_temps =
   78
   72
   64
   66
   49
>> fclose(fid);【实例2.50】读取“4.jpg”文件,并且进行平移变换。
%在M文件中写入程序
clc;
clear all;
Soft_gray=imread('C:\Documents and Settings\Administrator\桌面\ 4.jpg');  %读入图像
[M,N]=size(Soft_gray);  %获取图像尺寸
figure(1);
subplot(1,2,1);
imhist(Soft_gray);
for i=1:1:M
    for j=1:1:N
        if Soft_gray(i,j)>25
            Soft_gray(i,j)=1;
        else
           Soft_gray(i,j)=0;
        end
    end
end
L=logical(Soft_gray);
subplot(1,2,2);
imshow(L);
Z=input('please input yidong:')
se=translate(strel(1),[Z,Z]);  %平移处理
J=imdilate(L,se);
figure(2);
subplot(1,2,1);
imshow(J);
subplot(1,2,2);
imshow(L);执行效果如图2-3和图2-4所示。
图2-3 显示灰度
图2-4 读取图像进行平移
【实例2.51】利用双峰法求阈值,并将结果图像保存。
% 双峰法是一种简单的阈值分割方法,即如果灰度级直方图呈现明显的双峰状,
% 则选双峰之间的谷底所对应的灰度级作为阈值分割。
%在M文件中写入程序
clc;
clear all; 
close all;
I = imread('C:\Documents and Settings\Administrator\桌面\张志佳_数字图像处理程序合集111\张志佳_数字图像处理程序合集\双峰法求阈值\4.jpg');
if ndims(I) == 3
     I = rgb2gray(I);
end
fxy = imhist(I, 256); %统计每个灰度值的个数
figure; plot(fxy); %画出灰度直方图
p1 = {'Input Num:'}; p2 = {'180'};
p3 = inputdlg(p1,'Input Num:1~256',1,p2);
p = str2num(p3{1}); p = p/255;
bw = im2bw(I, p); %小于阈值的为黑,大于阈值的为白
figure;
imshow(bw);执行效果如图2-5和图2-6所示。
图2-5 双峰阈值
图2-6 待保存的图像
使用MATLAB语言进行编程时,有很多需要注意的地方,例如应尽量减少循环结构的使用以提高效率,应采用良好的编程风格以提高正确率和可读性等。本小节将从高效开发技巧、提高代码效率、向量化编程和并行计算等方面介绍MATLAB的实用编程技巧。
M文件如果是函数,保存的文件名要与函数名一致。不过容易被疏忽的是,M文件的命名应尽量避免只使用简单的英文单词,最好是由大小写英文、数字、下划线等组成(原因是简单的单词命名容易与MATLAB内部函数名同名,结果会出现一些莫名其妙的错误)。
调试程序时,经常要屏蔽掉一整段程序,也就是相当于将其标示为注释。有两个办法:一种是选定后按“Ctrl + R”和“Ctrl + T”组合键。一种是在段首加“if 0”,段尾加“end”,中间的程序都会不执行,也就相当于作为注释了。
写M文件时,选中某段程序内容,按“Ctrl + I”组合键,让MATLAB自动对齐程序。这样程序看起来很有层次,用户也容易发现程序中的错误。
按“Ctrl+F2”组合键生成标签,按“Ctrl + G”组合键跳至某一行。
如果不小心使程序进入死循环,或者计算时间太长,可以使用Ctrl+C来中断。MATLAB这时可能正疲于应付,响应会有些滞后。
经典方法是用“if 0”,但缺点是不够直观,作为注释的内容仍然保持代码的颜色。现在可以用“%”和“{”的组合来实现同样的效果。输入“%{”后,后面的代码都会变绿,在注释结束的地方再加上“%}”。也可以选中要作为注释的内容,单击右键,选择,“Comment”命令(Uncomment去掉注释标记),或使用快捷键“Ctrl+R”。将光标放在需要注释的行中,按“Ctrl+R”,将该行变为注释。取消注释的方法与此类似,快捷键为“Ctrl+T”。
与help命令不同,帮助文档MATLAB Help中对命令的描述更详细,往往还有一些例子,更便于理解。
清除命令“clc”可以清除窗口中的所有输入和输出信息,不影响命令的历史记录。如果开了多个绘图窗口,用“close all”命令可以将它们一起关掉。“clear”可以清除工作区中的无用变量,尤其是一些特别大的矩阵,不用时及时清理,可以减少内存占用。“clear all”清除所有的变量,将工作区清空,当重新开始一次算法验证时,最好执行一次该命令,让工作区中的变量一目了然。
窗口中,按上下光标键可以将历史记录中的命令复制到输入位置,便于快速重新执行。如果输入命令的前几个字母如“[row, col] =”,再使用光标键,则只会选择以这些字母开始的命令。
如果记不清楚命令的名称,可以输入开头的几个字母,然后按“Tab”键,当只有一个以这些字母开头的命令时,系统将自动补全命令名,否则显示一个命令名列表,方便从中选择。当然,只在命令行窗口中有效。
MATLAB内置了一些文件操作命令,例如cd(切换工作目录)、dir(同ls,显示目录内文件列表)等。dir命令可以返回目录中的文件和文件夹列表,存放在一个结构体数组中。如果需要对一些数据文件进行批处理,而文件名又没有一定的规律,用户可能需要借助于这个命令。
向量化编程是MATLAB语言的精髓所在,善用向量化编程,用户可以从代码的运行效率明显改善中获得成功的快乐。
传统的流行观点大致如下。
MATLAB引进了JIT(just in time)技术和加速器(accelerator),循环体本身已经不是程序性能提高的瓶颈了。
MATLAB的矩阵元素索引有两类:一类是数值索引,另一类是逻辑索引。前者又可以分为线性索引和下标索引。就运行效率来说,逻辑索引要高于数值索引。
MATLAB的并行计算实质还是主从结构的分布式计算。当初始化MATLAB并行计算环境时,最初的MATLAB进程自动成为主节点,同时初始化多个MATLAB计算子节点。Parfor的作用就是让这些子节点同时运行Parfor语句段中的代码。Parfor运行之初,主节点会将Parfor循环程序之外的变量传递给计算子节点。各子节点运算过程时互不干扰,运算完毕,则应该有相应代码将各子节点得到的结果组合到同一个数组变量中,并返回到MATLAB主节点。当然,最终计算完毕后应该手动关闭计算子节点。
这里讲述的方法仅针对多核机器进行并行计算的情况。设机器的CPU核心数量是CoreNum双核机器的CoreNum2,依次类推。CoreNum不等于核心数量,但是如果CoreNum小于核心数量则核心利用率没有最大化,如果CoreNum大于核心数量则效率反而可能下降。单核机器不适合进行并行计算,否则速度会更慢。下面的一段代码可初始化MATLAB并行计算环境:
%Initialize Matlab Parallel Computing Enviornment by Xaero | Macro2.cn
CoreNum=2; %设定机器CPU核心数量,我的机器是双核,所以CoreNum=2
if matlabpool('size')<=0 %判断并行计算环境是否已然启动
matlabpool('open','local',CoreNum); %若尚未启动,则启动并行环境
else
disp('Already initialized'); %说明并行环境已经启动
end运行成功后会出现如下语句:
Starting matlabpool using the 'local' configuration ... connected to 2 labs.如果运行出错,按照下面的办法检测:
首先运行:
matlabpool size如果出错,说明用户没有安装MATLAB并行工具箱。确认安装了此工具箱后,运行:
matlabpool open local 2;如果出错,证明用户的机器在开启并行计算时的设置有问题。请联系MathWorks的售后服务。
用上述语句启动MATLAB并行计算环境后,在用户的内存里面有CoreNum个MATLAB进程存在,每个进程占用的内存都在百兆以上(可以用Windows任务管理器查看),故完成并行计算后可以将其关闭。关闭的命令很简单:
matlabpool close稀疏矩阵是一种特殊类型的矩阵,即矩阵中包含较多的零元素。对于稀疏矩阵的这种特性,在MATLAB中可以只保存矩阵中非零元素以及非零元素在矩阵中的位置。对于一个含有大量非零元素的大型矩阵,采用这种方法可以大大减少数据占据的内存空间。在用稀疏矩阵进行计算时,通过消除零元素可以减少计算的时间。
对一般矩阵而言,MATLAB保存矩阵内的每一个元素,矩阵中的零元素与其他元素一样,需要同样大小的内存空间。但是对于稀疏矩阵,MATLAB仅保存稀疏矩阵中的非零元素以及其对应的位置。
【实例2.52】稀疏矩阵与一般矩阵的内存占用对比。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> M_FULL = magic(100);
>> M_FULL(M_FULL>50)=0;
>> M_sparse = sparse(M_FULL);
>> whos
  Name            Size            Bytes  Class      Attributes
  M_FULL          100x100          80000  double 
  M_sparse       100x100           1004  double    sparse 
  Tbpath          1x44             88  char由上例可见,稀疏矩阵与一般矩阵的内存占用相差很多倍。
要将一般矩阵转换为稀疏矩阵,可以使用函数sparse,如s=sparse(A),是将矩阵A转换为稀疏矩阵。sparse函数的格式如下:
S=sparse(A)  %将矩阵A转化为稀疏矩阵形式,即由A的非零元素和下标构成的稀疏矩阵S
S=sparse(m, n)     %生成一个m×n的所有元素都是0的稀疏矩阵
S=sparse(i, j, s)  %生成一个由长度相同的向量i,j和s定义的稀疏矩阵S【实例2.53】用sparse函数生成稀疏矩阵。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> S=sparse(1:10,1:10,1:10)
S =
   (1,1)        1
   (2,2)        2
   (3,3)        3
   (4,4)        4
   (5,5)        5
   (6,6)        6
   (7,7)        7
   (8,8)        8
   (9,9)        9
  (10,10)      10
>> S=sparse(1:10,1:10,7)
S =
   (1,1)        7
   (2,2)        7
   (3,3)        7
   (4,4)        7
   (5,5)        7
   (6,6)        7
   (7,7)        7
   (8,8)        7
   (9,9)        7
  (10,10)       7【实例2.54】一般矩阵与稀疏矩阵的转换示例。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A=[0 0 0 1;0 1 0 0;1 2 0 1;0 0 2 0]
A =
     0      0       0       1
     0      1       0       0
     1      2       0       1
     0      0       2       0
>> S = sparse(A)
S =
   (3,1)       1
   (2,2)       1
   (3,2)       2
   (4,3)       2
   (1,4)       1
   (3,4)       1另外,使用函数full则可把稀疏矩阵转换为一般矩阵,其格式如下:
A=full(S)  %将稀疏矩阵S转化为一般矩阵A【实例2.55】将一般矩阵转换为稀疏矩阵,再将稀疏矩阵转换一般矩阵。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A=[0 0 0 1;0 1 0 0;1 2 0 1;0 0 2 0]
A =
    0     0     0     1
    0     1     0     0
    1     2     0     1
    0     0     2     0
>> S = sparse(A)
S =
   (3,1)       1
   (2,2)       1
   (3,2)       2
   (4,3)       2
   (1,4)       1
   (3,4)       1
%在刚才的程序中直接输入
>> B=full(S)
B =
    0     0     0     1
    0     1     0     0
    1     2     0     1
    0     0     2     0【实例2.56】产生一个稀疏矩阵,将稀疏矩阵转换一般矩阵。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> S=sparse(1:5,1:5,4:8)
S =
   (1,1)      4
   (2,2)      5
   (3,3)      6
   (4,4)      7
   (5,5)      8
>> A=full(S)
A =
    4     0     0     0     0
    0     5     0     0     0
    0     0     6     0     0
    0     0     0     7     0
    0     0     0     0     8MATLAB提供spy函数,用于观察稀疏矩阵非零元素的分布视图。下面举例来说明spy函数的用法。
【实例2.57】稀疏矩阵视图示例(见图2-7)。本例中采用spy函数绘制Buckminter Fuller网格球顶的60×60邻接矩阵视图。这个矩阵还可以用来表示碳60模型和足球。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> B = bucky;
>> spy(B)图2-7 稀疏矩阵视图
检索稀疏矩阵的非零元素索引可使用find函数,其格式如下:
K=find(X)  %按行检索X中非零元素的点,若没有非零元素,将返回矩阵
[i, j]= find(X)  %检索X中非零元素的行标i和列标j
[i, j, v]= find(X)  %检索X中非零元素的行标i和列标j以及对应的元素值v【实例2.58】检索稀疏矩阵中非零元素的索引。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> S=sparse(1:6,1:6,4:9)
S =
   (1,1)       4
   (2,2)       5
   (3,3)       6
   (4,4)       7
   (5,5)       8
   (6,6)       9
>> [i,j,v]=find(S)
i =
    1
    2
    3
    4
    5
    6
j =
    1
    2
    3
    4
    5
    6
v =
    4
    5
    6
    7
    8
    9多数MATLAB函数都可以用于处理稀疏矩阵,此时将稀疏矩阵当作一般矩阵看待。但是MATLAB也有专门针对稀疏矩阵的函数。
【实例2.59】稀疏矩阵的组合。
%在命令行窗口输入如下命令
>> clc
>> clear all
>> A=[1 0 0;0 0 1;1 2 0]
A =
     1     0     0
     0     0     1
     1     2     0
>> B=sparse(A)
B =
    (1,1)     1
    (3,1)     1
    (3,2)     2
    (2,3)     1
>> C=[A(:,1),B(:,2)]
C =
   (1,1)      1
   (3,1)      1
   (3,2)      2【实例2.60】汉诺塔问题是印度的一个古老传说。开天辟地的神勃拉玛在一个神庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不知疲倦地把它们一个个地从这根棒搬到另外一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。
(1)新建一个M文件,在M文件中输入如下程序,并保存为move.m。
%建立一个M程序文件
%在程序文件中输入下面程序,并保存为move.m
function move(x,y)
disp([x '-->',y]);(2)新建一个M文件,在M文件中输入如下程序,并保存为hannuo.m。
%建立一个M程序文件
%在程序文件中输入下面程序,并保存为hannuo.m
function hannuo(n,a,b,c)
if (n==1)
move(a,c);
else
hannuo(n-1,a,c,b);
move(a,c);
hannuo(n-1,b,a,c);
end(3)新建一个M文件,在M文件中输入如下程序,并保存为main.m。
%建立一个M程序文件
%在程序文件中输入下面程序,并保存为main.m
n = input('Please input the number of hannuo:');
hannuo(n,'1','2','3');(4)单击“运行”按钮,输出结果如下:
Please input the number of hannuo:5
1-->3
1-->2
3-->2
1-->3
2-->1
2-->3
1-->3
1-->2
3-->2
3-->1
2-->1
3-->2
1-->3
1-->2
3-->2
1-->3
2-->1
2-->3
1-->3
2-->1
3-->2
3-->1
2-->1
2-->3
1-->3
1-->2
3-->2
1-->3
2-->1
2-->3
1-->3