第四章-MATLAB编程基础-MATLAB基础与编程入门-教学课件_第1页
第四章-MATLAB编程基础-MATLAB基础与编程入门-教学课件_第2页
第四章-MATLAB编程基础-MATLAB基础与编程入门-教学课件_第3页
第四章-MATLAB编程基础-MATLAB基础与编程入门-教学课件_第4页
第四章-MATLAB编程基础-MATLAB基础与编程入门-教学课件_第5页
已阅读5页,还剩311页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第四章MATLAB编程基础4.1概述4.2流程控制4.3脚本文件4.4函数文件4.5M文件调试4.6M文件性能分析4.7本章小结第四章MATLAB编程基础4.1概述14.1概述MATLAB提供了完整的编写应用程序的能力,这种能力通过一种被称为M语言的高级语言来实现。这种编程语言是一种解释性语言,利用该语言编写的代码仅能被MATLAB接受,被MATLAB解释、执行。其实,一个M语言文件就是由若干MATLAB的命令组合在一起构成的,这些命令都是在前面章节中介绍的合法的MATLAB命令。和C语言类似,M语言文件都是标准的纯文本格式的文件,其文件的扩展名为.m。4.1概述MATLAB提供了完整的2使用M文件最直接的好处就是可以将一组MATLAB命令组合起来,通过一个简单的指令就可以执行这些命令。这些命令可以完成某些MATLAB的操作,也可以实现某个具体的算法。其实,MATLAB产品族中包含的工具箱就是由世界上在相应专业领域内的顶尖高手,利用M语言开发的算法函数文件集合。读者也可以结合自己工作的需要,为自己的MATLAB开发具体的算法和工具箱。MATLAB的函数主要有两类,一类被称为内建(Build-in)函数,这类函数是由MATLAB的内核提供的,能够完成基本的运算,例如三角函数、矩阵运算的函数等。另外一类函数就是利用高级语言开发的函数文件,这里的函数文件既包括用C语言开发的MEX函数文件,又包含了M函数文件。有关MEX函数文件的内容已经超出了本书的内容,将在《MATLAB外部编程接口》一书中详细讲述。使用M文件最直接的好处就是可以将一组MATL3如前所述,MATLAB的M语言文件是纯文本格式的文件,利用任何一种纯文本编辑器都可以编写相应的文件,例如Windows平台下的记事本、UltraEdit等软件,或者Unix平台下的Emacs软件等。同样,为了方便编辑M文件,MATLAB也提供了一个编辑器,叫作meditor,它也是系统默认的M文件编辑器。运行meditor的方法非常简单,在MATLAB命令行窗口中键入下面的指令就可以打开meditor: >>edit这时MATLAB将启动meditor,然后创建一个未命名的空白文件,如图4-1所示。如前所述,MATLAB的M语言文件是纯文本格4图4-1meditor的运行界面图4-1meditor的运行界面5这时用户就可以直接在编辑器中键入MATLAB指令,开发M语言文件了。此外,运行meditor还可以通过“File”菜单中“New”子菜单下的“M-File”命令来实现,或者直接单击MATLAB用户界面工具栏上的新建按钮完成同样的工作。M语言文件可以分为两类,其中一类是脚本文件,另外一类叫作函数文件。本章将分别介绍这两类文件的编写方法。这时用户就可以直接在编辑器中键入MATLAB64.2流程控制4.2.1选择结构如前所述,当人们判断某一条件是否满足,根据判断的结果来选择不同的解决问题的方法时,就需要使用选择结构。和C语言类似,MATLAB的条件判断可以使用if语句或者switch语句。4.2流程控制4.2.1选择结构7if语句if语句的基本语法结构有三种,分别如下:(1)if(关系运算表达式) MATLAB语句end这种形式的选择结构表示,当关系运算表达式计算的结果为逻辑真的时候,执行MATLAB语句,这里的MATLAB语句可以是一个MATLAB表达式,也可以是多个MATLAB表达式。在MATLAB语句的结尾处,必须有关键字end。if语句8 (2)if(关系运算表达式) MATLAB语句Aelse MATLAB语句Bend这种选择结构表示,当关系运算表达式的计算结果为逻辑真的时候,执行MATLAB语句A,否则执行MATLAB语句B,在语句B的结尾必须具有关键字end。 (2)if(关系运算表达式)9(3)if(关系运算表达式a) MATLAB语句Aelseif(关系运算表达式b) MATLAB语句Belse(关系运算表达式c)

end这种选择结构可以判断多条关系运算表达式的计算结果,然后按照执行的逻辑关系执行相应的语句。读者可以根据类似的C语言知识或者前面两种选择结构的介绍判断这种结构的执行方式。…(3)if(关系运算表达式a)…10

例子4-1if语句的使用——if_examp.m。读者通过本例子将同时了解meditor的基本使用方法。打开meditor,然后键入下面的指令:001 clearall002003 I=1;004 J=2;005006 ifI==J007 A(I,J)=2;008 elseifabs(I-J)==1009 A(I,J)=?1;010 else011 A(I,J)=0;012 end例子4-1if语句的使用——if_ex11注意:在键入程序时,不要将行号(001~012)也敲进去,在这里设置行号的主要目的是为了便于讲解和分析程序。所有的指令键入完毕后,将文件保存,读者可以将其保存为任何名字,不过文件名必须由英文字符和数字组成,将文件的扩展名设置为.m,并且将文件保存在MATLAB的搜索路径下,例如MATLAB当前的工作路径。然后在MATLAB的命令行中,键入刚才保存的文件名,不过,这时不要将扩展名也一同键入,MATLAB就会依次执行这些指令。注意:12运行例子4-1的方法和效果如下:>>if_exampA=0-1例子4-1代码的核心是006~012行的部分,这部分展示了if-elseif-else-end语句组合的使用方法。请读者仔细察看,并且通过修改程序003和004行中对I和J的赋值来察看整个语句的执行情况。和C语言类似,if-elseif-else的语句结构也可以嵌套地使用,也就是可以存在这样的语句结构:运行例子4-1的方法和效果如下:13if(关系表达式a) if(关系表达式b)MATLAB语句A elseMATLAB语句B endelse if(关系表达式c)MATLAB语句C elseMATLAB语句D endendif(关系表达式a)14注意:在使用嵌套的选择结构时,需要小心if语句和end关键字的配对。例子4-2嵌套使用的if结构——if_examp2.m。001 clearall002 003 if1004 disp('Is1')005 else006 disp('Not1')007 end008注意:15009 I=1;010 ifI011 ifI<2012 disp('Iisbiggerthan0butlessthan2')013 end014 else015 ifI>-2016 dis('Iislessthan0butbiggerthan-2')017 end018 end009 I=1;16该程序的运行方法和效果如下:>>if_examp2Is1Iisbiggerthan0butlessthan2在例子4-2中,主要说明了嵌套的if结构和在关系表达式中使用常量的方法。在代码的003行,if语句的关系表达式为常数1,这个时候if语句将始终认为非零值为逻辑真,所以,程序执行了004行的代码。同样,在程序的009行,if语句的关系表达式为变量I,若I的数值为非零值,则if语句判断其为逻辑真,所以,代码的016行只有在I为0时,才可能被执行。该程序的运行方法和效果如下:17switch语句另外一种构成选择结构的关键字就是switch。在处理实际问题的时候,往往要处理多个分支,这时如果使用if-else语句处理多分支结构往往使程序变得十分冗长,从而降低了程序的可读性。switch语句就可以用于处理这种多分支的选择,它的基本语法结构如下:switch语句18switch(表达式) case常量表达式a:MATLAB语句A case常量表达式b:MATLAB语句B

case常量表达式m:MATLAB语句M otherwise:MATLAB语句Nend…switch(表达式)…19在switch语句之后的表达式可以是一个数值类型表达式或者是一个数值类型的变量,当这个表达式的值同case后面的某一个常量表达式相等时,则执行该case后面的常量表达式后面的语句。注意:MATLAB的switch和C语言的switch语句结构不同。在C语言中,每一个case后面的语句中必须包含类似break语句的流程控制语句,否则程序会依次执行符合条件的case语句后面的每一个case分支。但是在MATLAB中就不必如此,程序仅仅执行符合条件的case分支。在switch语句之后的表达式可以是一个数值20例子4-3switch结构使用示例——switch_examp.m。001 clearall002 003 algorithm=input('Enteranalgorithminquotes(ode23,ode15s,etc:)');004 005 switchalgorithm006 case'ode23'007 str='2nd/3rdorder';008 case{'ode15s','ode23s'}009 str='stiffsystem';010 otherwise011 str='otheralgorithm';012 end013 disp(str);例子4-3switch结构使用示例——switch_ex21该文件的运行方法和效果如下:>>switch_exampEnteranalgorithminquotes(ode23,ode15s,etc:)'ode23'2nd/3rdorder>>switch_exampEnteranalgorithminquotes(ode23,ode15s,etc:)'ode4'otheralgorithm该文件的运行方法和效果如下:22例子4-3中需要用户在执行程序的过程中输入一个字符串,switch语句根据用户的输入判断执行相应的case分支。若没有符合条件的case分支,则switch执行otherwise后面的语句。若switch结构中没有定义otherwise及其相应的代码,则程序不会进行任何操作,而是直接退出switch结构。提示:在处理以字符串变量或者常量参与的关系判断操作时,使用switch结构要比if-else结构效率高一些。由于MATLAB的switch结构没有C语言的fall-through特性,所以,如果需要针对多个条件而使用同一个case分支的时候,需要使用元胞数组与之配合,参见例子4-4。例子4-3中需要用户在执行程序的过程中输入一个23例子4-4switch结构使用示例——switch_examp2.m。001 clearall002003 var=input('InputaNumer:');004 switchvar005 case1006 disp('1')007 case{2,3,4}008 disp('2or3or4')009 case5010 disp('5')011 otherwise012 disp('somethingelse')013 end例子4-4switch结构使用示例——switch_ex24例子4-4运行的方法和效果如下:>>switch_examp2InputaNumer:11>>switch_examp2InputaNumer:32or3or4>>switch_examp2InputaNumer:7somethingelse例子4-4运行的方法和效果如下:25例子4-4代码的核心部分为007行,这里使用元胞数组增加判断条件的个数,当输入的数字为2、3或者4时,switch结构将使用同一个case分支进行判断、计算。注意:从代码的完整性和可靠性角度出发,在使用switch语句时,一定要包含otherwise分支,这是一种良好的编程习惯。例子4-4代码的核心部分为007行,这里使用264.2.2循环结构在解决很多问题的时候需要使用循环结构,例如求解数列的和或者进行某种迭代法求解数值方程时,都需要循环结构配合完成计算。在MATLAB中,包含两种循环结构,一种是循环次数不确定的while循环,而另一种是循环次数确定的for循环。4.2.2循环结构27

1.while循环结构while语句可以用来实现“当”型的循环结构,它的一般形式如下:while(表达式)MATLAB语句end当表达式为真时,循环将执行由语句构成的循环体,其特点是先判断循环条件,如果循环条件成立,即表达式运算结果为“真”,再执行循环体。循环体执行的语句可以是一句也可以是多句,在MATLAB语句之后必须使用关键字end作为整个循环结构的结束。另外,在循环过程中一定要能够改变关系表达式或者布尔类型变量的值,或者使用其他方法来跳出循环,否则会陷入死循环(无法正常退出的循环叫作死循环)。1.while循环结构28例子4-5使用while语句求解 。001 i=1;002 sum=0;003 while(i<=1000)004 sum=sum+i;005 i=i+1;006 end007 str=['计算结果为:',num2str(sum)];008 disp(str)例子4-5使用while语句求解 。29例子4-5的运行结果为>>while_example计算结果为:500500例子4-5的002~006行使用了while循环结构,在循环结构中进行了累加的操作。需要注意的是,在MATLAB中没有类似C语言的++或者+=等运算操作符,因此在进行诸如累加或者递减的运算时,不得不给出完整的表达式。另外,例子4-5求数列和的算法的运算效率很低,在MATLAB中不要使用这样的结构完成类似的运算,而需要采用向量化的计算。例子4-5的运行结果为30注意:while循环结构的关系表达式可以是某个数据变量或者常量,这时,将按照非零值为逻辑真进行相应的操作。另外,在进行上述操作时,若数据变量为空矩阵,则while语句将空矩阵作为逻辑假处理,也就是说,在whileAMATLAB语句S1end结构中,若A为空矩阵,则MATLAB语句S1永远不会被执行。注意:31

2.for循环结构使用for语句构成循环是最灵活、简便的方法,不过,使用for语句循环需要预先知道循环体执行的次数,所以这种循环一般叫作确定循环。在MATLAB中for循环的基本结构如下:forindex=start:increment:end MATLAB语句end其中,index的取值取决于start和end的值,一般地,这里通常使用等差的数列向量,参见例子4-6。2.for循环结构32例子4-6使用for语句求解 。001 sum=0;002 fori=1:1000003 sum=sum+i;004 end 005 str=['计算结果为:',num2str(sum)];006 disp(str)例子4-6使用for语句求解 。33例子4-6运行的结果为>>for_example计算结果为:500500在例子4-6中,002行的代码使用了确定次数的for循环结构,循环次数使用行向量进行控制,而且索引值i按照默认的数值1进行递增。在for循环语句中,不仅可以使用行向量进行循环迭代的处理,也可以使用矩阵作为循环次数的控制变量,这时循环的索引值将直接使用矩阵的每一列,循环的次数为矩阵的列数,参见例子4-7。例子4-6运行的结果为34例子4-7for循环示例。001 A=rand(3,4);002003 fori=A004 sum=mean(i)005 end例子4-7运行的结果为>>for_matricessum=0.2728sum=0.6649sum=0.4275sum=0.5220例子4-7for循环示例。35例子4-7尽管只有短短的几行,但是在003行使用了一个矩阵作为循环的索引值,于是,循环结果就分别计算矩阵的每一列元素的均值。和其他高级语言类似,MATLAB的循环结构也可以进行嵌套使用,使用嵌套的循环需要注意for关键字和end关键字之间的配对使用,请读者根据高级语言的一般特性来推断其运行的方式,这里就不再赘述了。例子4-7尽管只有短短的几行,但是在003行364.2.3break语句和continue语句在循环结构中还有两条语句会影响程序的流程,这就是break语句和continue语句,这两条语句的基本功能如下:●当break语句使用在循环体中的时候,其作用是能够在执行循环体的时候强迫终止循环,即控制程序的流程,使其提前退出循环,它的使用方法是 break;●continue语句出现在循环体中的时候,其作用是能够中断本次的循环体运行,将程序的流程跳转到判断循环条件的语句处,继续下一次的循环,它的使用方法是 continue;4.2.3break语句和continue语句37例子4-8break语句示例——break_example.m。001 i=0;002 j=0;003 k=0;004 fori=1:2005 forj=1:2006 fork=1:2007 if(k==2)008 disp('退出循环');009 break;010 end例子4-8break语句示例——break_exampl38011 str=sprintf('I=%d,J=%d,K=%d',i,j,k);012 disp(str);013 end014 end015 end016 disp('程序运行结束');011 str=spri39例子4-8的运行结果如下:>>break_exampleI=1,J=1,K=1退出循环I=1,J=2,K=1退出循环I=2,J=1,K=1退出循环I=2,J=2,K=1退出循环程序运行结束例子4-8的运行结果如下:40break语句的作用是退出当前的循环结构运行,所以在例子4-8中,位于最内层循环的break语句执行的结果是退出了最内层的循环k,位于外层的循环i和j还是都运行完毕了。break语句的作用是退出当前的循环结构运行41例子4-9continue语句示例。001 i=0;002 fori=1:6003 if(i>3)004 continue005 else006 str=sprintf('I=%d',i);007 disp(str);008 end009 end010 str=sprintf('循环结束I=%d',i);011 disp(str);例子4-9continue语句示例。42例子4-9的运行结果如下:>>continue_exampleI=1I=2I=3循环结束I=6continue语句的作用在例子4-9中得到了充分说明,该语句终止当前的循环,然后继续下一次循环运算,直到所有的循环迭代运算结束为止。例子4-9的运行结果如下:434.2.4提高运算性能M语言和其他的高级语言不同,由于采用了解释型语言,所以M语言的执行效率肯定低于编译型语言(例如C语言)。然而,随着MATLAB版本的不断升级,再加之合理利用MATLAB向量运算等特点可以较大幅度地提高M语言代码的执行效率。在本小节结合一些具体的例子来讲述M语言编程以及MATLAB软件本身在提高程序执行效率方面的一些特性。4.2.4提高运算性能44

1.向量化运算首先,希望读者牢记这样一点,MATLAB最初的目的是提供便利的矩阵数据操作能力。所以在大多数的应用程序中,不要使用循环结构操作矩阵的元素,应直接使用矩阵元素的索引或者矩阵运算的函数,这样做不仅能够提高代码的执行效率,而且还能够提高程序的可读性,这就是所谓的向量化的运算,也就是说,尽量将使用while循环或者for循环的语句结构转换成等价的向量或者矩阵运算,以提高程序的运算速度,参见例子4-10。1.向量化运算45例子4-10向量化运算——array_vs_loops.m。001 Mass=rand(5,10000);002 Length=rand(5,10000);003 Width=rand(5,10000);004 Height=rand(5,10000);005 006 [rows,cols]=size(Mass);007 008 disp([char(10),'使用数组运算:'])009 tic010 Density=Mass./(Length.*Width.*Height);011 toc例子4-10向量化运算——array_vs_loops.46012013 disp([char(10),'使用循环结构:'])014 tic;015 forI=1:rows016 forJ=1:cols017 Density(I)=Mass(I,J)/(Length(I,J)*Width(I,J)*Height(I,J));018 end019 end020 toc01247例子4-10比较了循环结构和数组运算的执行效率,程序中分别在010行使用数组运算和在015~019行使用循环结构完成了同样的工作。程序的运行结果如下:>>array_vs_loops使用数组运算:elapsed_time= 0使用循环结构:elapsed_time= 0.0100例子4-10比较了循环结构和数组运算的执行效48

2.预分配存储空间另外一种能够提高运算效率的方法就是进行内存变量存储空间的预分配,首先察看例子4-11。例子4-11内存预分配的例子——pre_allocate.m。001 disp([char(10),'使用内存预分配:'])002 pre_allo=zeros(10000,1);003 tic;004 forI=1:10000005 pre_allo(I)=rand(1);006 end2.预分配存储空间49007 toc008 009 disp([char(10),'不使用内存预分配:'])010 tic;011 forJ=1:10000012 not_pre_allo(J)=rand(1);013 end014 toc007 toc50例子4-11的执行结果如下: >>pre_allocate使用内存预分配:elapsed_time= 0.0900不使用内存预分配:elapsed_time= 0.3410例子4-11的执行结果如下:51上面两种不同的运算惟一的区别就是程序002行,执行这行语句之后,MATLAB自动分配了10000个连续的内存空间用于存储数据,MATLAB将一次创建足够的存储空间,然后依次赋值。而后者not_pre_alloc变量没有进行相应的操作,所以带来了两次运算结果的不同。在不使用内存预分配的运算中,MATLAB是如何进行操作的呢?当I=1时,MATLAB将使用一小块长度为一个单元大小的内存保存一位随机数。当I=2时,MATLAB寻找一块两单元大小的内存区,一个单元放第一个随机数,第二个放另外一个随机数。…上面两种不同的运算惟一的区别就是程序002行52当I=10000时,MATLAB寻找一块容纳10000单元的内存区存放以前的9999个随机数,同时把最新的一个随机数加入进去。代码运行的结果造成了存储空间的浪费,降低了程序的执行速度。所以,在编写M语言程序的时候需要尽量使用内存的预分配,而少使用或者不使用数组内存空间的自动扩充方式。MATLAB针对不同的数据类型有不同的内存预分配函数,见表4-1。当I=10000时,MATLAB寻找53表4-1内存预分配函数表4-1内存预分配函数54表4-1中说明了不同数据类型所要使用的内存预分配函数,其中结构类型的数组需要两个函数配合使用,利用struct函数构造结构,而使用repmat函数创建数组。对于非双精度类型的数据,例如整数类型或者单精度类型,进行内存的预分配时,需要使用相应的构造函数或者类型转换函数,例如: Y=int16(zeros(1:10000));在上面的表达式中创建了连续的10000个16位整数的存储空间。当预先分配的内存空间无法容纳数据时,则可以通过repmat函数来扩充数组的存储空间。表4-1中说明了不同数据类型所要使用的内存预55

3.MATLAB加速器尽管利用了上述的特性可以明显提高M语言的运行效率,但是在同等条件下,M语言的效率还是无法和第四代高级编程语言的执行效率相媲美,于是,在MATLAB6.5版本中,新增加了MATLAB性能加速器这样一个新特性。MATLAB性能加速器能够明显改善循环结构、内建函数调用等方面的运行效率,特别是在处理循环迭代次数确定的for循环结构中,其运算速度较早期的MATLAB版本有很大的提高,在表4-2中总结了MATLAB加速器能够发挥作用的M语言元素。3.MATLAB加速器56表4-2加速器能够影响的M语言元素表4-2加速器能够影响的M语言元素57表4-3性能加速器不起作用的M语言元素表4-3性能加速器不起作用的M语言元素58例子4-12性能加速器说明——jitaccel.m。001 tic002 A=rand(500000,1);003 B=zeros(500000,1);004 B(1)=A(1);005 fori=2:500000006 B(i)=B(i?1)+A(i);007 end008 toc例子4-12性能加速器说明——jitaccel.m。59在MATLAB6.1中:>>jitaccelelapsed_time=5.2780在MATLAB6.5中:>>jitaccelelapsed_time=0.0900若直接使用内建函数,则运行的效果为>>tic;B=cumsum(A,1);tocelapsed_time=0.0200在MATLAB6.1中:60通过比较,可以看出MATLAB性能加速器明显提高了程序的执行效率,在有些情况下,加速器使执行速度提高10~100倍。注意:例子4-12代码运算得到的时间和具体运行MATLAB的计算机的性能有关,不同的计算机环境得到的计算结果不尽相同。另外,MATLAB性能加速器在MATLAB6.5中的默认设置为开启(On)状态。通过比较,可以看出MATLAB性能加速器明显614.3脚本文件脚本文件是最简单的一种M语言文件,在本章前面章节的例子中都使用了脚本文件。所谓脚本文件,就是由一系列的MATLAB指令和命令组成的纯文本格式的M文件,执行脚本文件时,文件中的指令或者命令按照出现在脚本文件中的顺序依次执行。脚本文件没有输入参数,也没有输出参数,执行起来就像早期的DOS操作系统的批处理文件一样,而脚本文件处理的数据或者变量必须在MATLAB的公共工作空间中。4.3脚本文件脚本文件是最简单的一62例子4-13脚本文件示例。001 %注释行002 %M脚本文件示例003 %"flowerpetal"004 %以下为代码行005 %计算006 theta=-pi:0.01:pi;007 rho(1,:)=2*sin(5*theta).^2;008 rho(2,:)=cos(10*theta).^3;009 rho(3,:)=sin(theta).^2;010 rho(4,:)=5*cos(3.5*theta).^3;例子4-13脚本文件示例。63011 fork=1:4012 %图形输出013 subplot(2,2,k)014 polar(theta,rho(k,:))015 end016 disp('程序运行结束!')在MATLAB命令行中运行该脚本文件:>>script_example程序运行结束!011 fork=1:464图4-2例子4-13脚本文件的运行结果图4-2例子4-13脚本文件的运行结果65仔细察看例子4-13的脚本文件,在脚本文件中,主要由注释行和代码行组成。M文件的注释行需要使用%定义符,在%之后的所有文本都认为是注释文本,不过,M文件的注释定义符仅能影响一行代码,类似于C++语言中的“//”。然而在M语言中,没有类似C语言的注释定义符“/*”和“*/”,所以无法一次定义多行注释。给程序添加适当的注释是良好的编程习惯,希望读者能够在日常编程中多多使用。仔细察看例子4-13的脚本文件,在脚本文件中66脚本文件中的代码行都是一些简单的MATLAB指令或者命令,这些命令可以用来完成相应的计算处理数据、绘制图形结果的操作,也可以在脚本文件中调用其他的函数完成复杂的数学运算,在例子4-13中就完成了这些工作。另外,在MATLAB中还有一些指令用来处理程序和用户之间的交互,在表4-4中进行了总结。脚本文件中的代码行都是一些简单的MATLAB指67表4-4脚本文件中常用的MATLAB指令表4-4脚本文件中常用的MATLAB指令68MATLAB一般使用脚本文件作为某种批处理文件,其中,有两个批处理文件经常被MATLAB自动调用,这两个脚本文件分别为startup.m和finish.m。startup.m文件在MATLAB启动时自动被执行,用户可以自己创建并定义编写该文件,例如在文件中添加物理常量的定义、系统变量的设置或者MATLAB搜索路径的设置。当用户安装MATLAB之后,在<MATLABROOT>\toolbox\local路径下有一个M文件,名为Starupsav.m,该文件可以看作是startup.m文件的模板,可以修改该文件,然后将其以文件名startup.m的形式保存在<MATLABROOT>\toolbox\local路径下。MATLAB一般使用脚本文件作为某种批处理文69与startup.m文件相对应的是finish.m文件,该文件在MATLAB退出时自动执行,用户可以自己创建并定义编写该文件,例如在文件中添加保存数据等指令,这样可以将每次退出前的工作结果进行保留。同样,在<MATLABROOT>\toolbox\local路径下有两个文件,分别为finishsav.m和finishdlg.m,这两个文件可以用来作为finish.m文件的模板,相关的具体内容介绍请读者自己察看相应的文件和帮助文档。与startup.m文件相对应的是finish704.4函数文件4.4.1基本结构M函数文件和脚本文件不同,函数文件不仅有自己特殊的文件格式,不同的函数还分别具有自己的工作空间。同其他高级语言类似,M函数文件也有局部变量和全局变量。读者首先需要了解的是函数文件的基本结构,参见例子4-14。4.4函数文件4.4.1基本结构71例子4-14函数文件示例——average.m。001 functiony=average(x)002 %AVERAGE求向量元素的均值003 %语法:004 %Y=average(X)005 %其中,X是向量,Y为计算得到向量元素的均值006 %若输入参数为非向量则出错007 008 %代码行009 [m,n]=size(x);010 %判断输入参数是否为向量例子4-14函数文件示例——average.m。72011 if(~((m==1)|(n==1))|(m==1&n==1))012 %若输入参数不是向量,则出错013 error('Inputmustbeavector')014 end015 %计算向量元素的均值016 y=sum(x)/length(x);011 if(~((m==1)|(n==1))73在MATLAB命令行中,键入下面的指令运行例子4-14的代码:>>z=1:99;>>y=average(z)y=50在MATLAB命令行中,键入下面的指令运行例子4-14的代码74M语言函数文件具有下面的不同部分:*函数定义行。*在线帮助。*注释行。*M语言代码。M语言函数文件具有下面的不同部分:75下面结合例子4-14分别说明这些部分的构成。函数定义行,例子4-14的函数定义行为代码的001行: 001 functiony=average(x)下面结合例子4-14分别说明这些部分的构成。76这一行代码中包括关键字function、函数输出参数y、函数的名称average和函数的输入参数x。需要读者注意的是函数的名称,函数的名称定义要求必须以字符开头,后面可以用字符、数字和下划线的组合构成函数名称。MATLAB对函数名称的长度有限定,读者可以在自己的MATLAB中,通过执行namelengthmax函数获取相应的数值。假设该函数返回的数值为N,若函数的名称长度超过了N,则MATLAB使用函数名称的前N个字符作为函数名称。一般推荐将函数名称用小写的英文字符表示,同时函数的M文件名称最好和函数名称保持一致,若文件名称和函数名称不一致,则调用函数的时候需要使用文件名称而非函数名称。这一行代码中包括关键字function、函数77M函数文件的在线帮助为紧随在函数定义行的注释行。在例子4-14中,average函数的在线帮助为002~006行的注释行。若在MATLAB命令行中键入下面的指令: >>helpaverage在MATLAB的命令窗口中就会出现: AVERAGE求向量元素的均值语法: Y=average(X) 其中,X是向量,Y为计算得到向量元素的均值 若输入参数为非向量则出错M函数文件的在线帮助为紧随在函数定义行的注释78其中,在线帮助中比较重要而且特殊的是在线帮助的第一行,在MATLAB中将这行注释称为H1帮助行,它是在线帮助的第一行,若使用lookfor函数查询函数时,仅查询并显示函数的H1帮助行,例如,在MATLAB命令行中键入下面的指令: >>lookforaverage在MATLAB的命令窗口中就会出现:AVERAGE求向量元素的均值MEANAverageormeanvalue.…其中,在线帮助中比较重要而且特殊的是在线帮助的第一行,在MA79由于H1帮助行的特殊作用,所以在用户自己定义M函数文件时,一定要编写相应的H1帮助行,对函数进行简明、扼要的说明或者解释。例子4-14的008、010、012、015行代码分别是程序具体的注释行,这些注释行不会显示在在线帮助中,主要原因就是这些注释行没有紧随在H1帮助行的后面,其中008行的注释与在线帮助之间有一个空行。其实从008行开始一直到文件的结尾都是M函数文件的代码行,这些代码行需要完成具体的算法,实现用户的具体功能。代码行就是用户开发的算法M语言的实现。由于H1帮助行的特殊作用,所以在用户自己定义804.4.2输入输出参数M语言函数文件的输入、输出参数和其他高级语言的输入、输出参数不同,在定义这些输入、输出参数的时候不需要指出变量的类型,因为MATLAB默认这些参数都使用双精度类型,这样可以简化程序的编写。而且在定义参数时,也没有确定输入参数的维数或者尺寸,也就是说,直接从参数上无法判断输入来的是标量、向量还是矩阵,只有通过程序内部的具体代码来加以判断。M语言的函数文件不仅可以有一个输入参数和一个返回值,还可以为M语言函数文件定义多个输入参数和多个输出参数,见例子4-15。4.4.2输入输出参数81例子4-15多个输入、输出参数的M函数。001 function[avg,stdev,r]=ourstats(x,tol)002 %OURSTATS多输入输出参数示例003 %该函数计算处理矩阵,得到相应的均值、004 %标准差和矩阵的秩005 [m,n]=size(x);006 ifm==1007 m=n;008 end009 %Average010 avg=sum(x)/m;例子4-15多个输入、输出参数的M函数。82011% Sandaddeviation012 stdev=sqrt(sum(x.^2)/m-avg.^2);013 %Rank014 s=svd(x);015 r=sum(s>tol);运行例子4-15,在MATLAB命令行中,键入下面的指令:>>A=[123;456]A=123456011% Sandaddeviation83>>[a,s,r]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000r=2>>ourstats(A,0.1)ans=2.50003.50004.5000>>[a,s]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000>>[a,s,r]=ourstats(A,0.1)84例子4-15的M代码具有两个输入参数、三个输出参数,所以在使用该函数的时候,需要将必要的输入、输出参数写明。注意调用该函数时的语法,将输出参数依次写在一个向量中,若输出参数的个数与函数定义的输出参数个数不一致,则在例子4-15中,将计算得到的前几个输出参数作为返回值,个数等于用户指定的输出参数个数。计算的结果依次赋值给不同的变量。在使用多个输入、输出参数的时候,往往需要判断用户写明的输入、输出参数的个数,若个数与函数定义不符合的时候,将给出错误或者警告信息,这个时候,需要使用函数nargin和nargout来获取函数的输入、输出参数个数,见例子4-16。例子4-15的M代码具有两个输入参数、三个输85例子4-16nargin和nargout示例。001 functionc=testarg(a,b)002 %TESTARG检测输入输出参数个数003 %该函数根据不同的输入输出参数个004 %数进行相应的操作005 if(nargout~=1)006 disp('使用该函数必须指定一个输出参数!');007 return008 end009 switchnargin010 case0例子4-16nargin和nargout示例。86011 disp('使用该函数至少需要一个输入参数!');012 c=[];013 return014 case1015 c=a.^2;016 case2017 c=a+b;018 end011 disp('使用该函数至少需要一个输87运行例子4-16,在MATLAB命令行窗口中,键入下面的指令:>>A=[123];>>B=[235];>>testarg(A,B)使用该函数必须指定一个输出参数!>>C=testarg使用该函数至少需要一个输入参数!C=[]>>C=testarg(A)C=149运行例子4-16,在MATLAB命令行窗口中,键入下面的指令88>>C=testarg(A,B)C=358>>C=testarg(A,B,C)???Errorusing==>testargToomanyinputarguments.>>C=testarg(A,B)89运行例子4-16的代码时,使用不同的输入、输出参数,函数本身和MATLAB系统将自动检测参数的个数,在最后一次调用时,由于使用的输入参数个数超过了函数定义的个数,所以MATLAB给出了错误信息。MATLAB的M函数文件还可以具有个数不确定的输入、输出参数,也就是说,在定义M函数文件的时候,不指明输入、输出参数的个数,而是在程序中通过编写程序完成具体参数的确定,完成该功能主要依靠varargin和varargout函数。运行例子4-16的代码时,使用不同的输入、输90当函数的定义具有以下形式的时候 functiony=function_name(varargin)函数function_name可以接受任意个数的输入参数;而当函数具有下面的形式时 functionvarargout=function_name(n)函数function_name可以输出任意个数的输出参数。可以将varargin函数和varargout函数结合在同一个M文件函数中使用。当函数的定义具有以下形式的时候91例子4-17不确定的输入参数个数。001 functiony=varargin_example(varargin)002 %VARARGIN_EXAMPLE不确定输入参数例子003 str=sprintf('输入参数的个数:=%d',length(varargin));004 disp(str);005 y=0;006 %varargin的类型007 class(varargin)008 fori=1:length(varargin)009 %varargin为元胞数组例子4-17不确定的输入参数个数。92010 if(isnumeric(varargin{i}))011 %将每个为数值数组的输入参数012 %的第一个元素累加求和013 y=y+varargin{i}(1);014 end015 end010 if(isnumeric(varargi93运行例子4-17,在MATLAB命令行中键入下面的指令:>>varargin_example输入参数的个数:=0ans=cellans=0>>varargin_example('a',[123],3,rand(2,5))输入参数的个数:=4ans=cellans=4.0153运行例子4-17,在MATLAB命令行中键入下面的指令:94通过例子4-17的运行结果和例子的代码可以看出varargin函数的使用方法。它相当于在MATLAB的函数入口处开辟了足够大的空间,用于接受各种用户的输入。在使用这个函数的时候,需要在程序中判别函数输入参数的类别,并且从元胞数组中正确提取变量,在MATLAB中将这一过程称之为unpacking。与之相对应的,将函数的输入参数传递给varargout函数被称之为packing,在这一过程中,需要将所有必要的输出参数传递给varargout元胞数组,在传递参数的时候,还需要注意参数的顺序,在例子4-18中介绍了这一过程。通过例子4-17的运行结果和例子的代码可以看95例子4-18不确定的输出参数。001 functionvarargout=varargout_example(varargin)002 %VARARGOUT_EXAMPLE不确定个数的输出参数003 004 %判断输出参数的个数005 %下面注释行中的代码执行有错误006 %str=sprintf('输出参数的个数:=%d',length(varargout));007 %必须使用nargout008 str=sprintf('输出参数的个数:=%d',nargout);009 disp(str);010 if(nargout<=nargin)011 fork=1:nargout012 varargout{k}=varargin{nargin-k+1};013 end014 end例子4-18不确定的输出参数。96运行例子4-18的代码,在MATLAB命令行中,键入下面的指令:>>[ab]=varargout_example(1,2,3,4)输出参数的个数:=2a=4b=3运行例子4-18的代码,在MATLAB命令行中,键入下面的指97例子4-18的第006行代码,若将注释行符号“%”删除,则程序运行会出现错误。在程序中,若需要判断输出参数的个数不能使用length函数,而需要使用nargout函数。另外,在操作输出参数时,需要判断输出参数的个数,根据输出参数的个数完成相应的操作。在使用不确定的输入、输出参数时,还可以像下面的代码行一样使用这两个参数:function[out1,out2]=example1(a,b,varargin)function[i,j,varargout]=example2(x1,y1,x2,y2,flag)若使用varargout和varargin参数,除了必须给定的参数以外,其余的参数是任意数量可变的,具体的操作参阅例子4-19。例子4-18的第006行代码,若将注释行符号98例子4-19可变的输入、输出参数。001 function[x,y,varargout]=vararginout(a,b,c,d,varargin)002 %VARARGINOUT可变的输入输出参数003 str=sprintf('输入参数的个数:=%d',nargin);004 disp(str);005 str=sprintf('输出参数的个数:=%d',nargout);006 disp(str);007 if(nargin<=4)008 error('输入参数必须多于4个');009 end010 %处理输入输出参数例子4-19可变的输入、输出参数。99011 x=a+b+c+d;012 y=a-b+c-d;013 if(nargout>2&&nargin>4)014 for(i=1:nargout-2)015 %这里也许会出错,小心!016 varargout{i}=varargin{end-i-1};017 end018 end011 x=a+b+c+d;100运行例子4-19的代码,在MATLAB命令行中,键入下面的指令:>>vararginout(1,2,3,4,5)输入参数的个数:=5输出参数的个数:=0ans=10>>[a,b,c]=vararginout(1,2,3,4,5,6,7,8)输入参数的个数:=8输出参数的个数:=3a=10b=-2c=6运行例子4-19的代码,在MATLAB命令行中,键入下面的指1014.4.3子函数和私有函数同一个M函数文件中可以包含多个函数。如果在同一个M函数文件中包含了多个函数,那么将出现在文件中的第一个M函数称为主函数(primaryfunction),其余的函数称为子函数(subfunction)。M函数文件的名称一般与主函数的名称保持一致,其他函数都必须按照函数的基本结构来书写,每一个函数的开始都是函数定义行,函数的结尾是另一个函数的定义行的开始或者整个M文件的结尾(最后一个子函数的结尾就是文件结束符)。不过,子函数不像主函数,一般子函数没有在线帮助,子函数的作用范围有限,它只能被那些在定义子函数的M文件中定义的函数(包括主函数和其他子函数)调用,不能被其他M文件定义的函数调用。4.4.3子函数和私有函数102例子4-20子函数应用例子。001 function[avg,med]=newstats(u)%主函数002 %NEWSTATS计算均值和中间值003 n=length(u);004 avg=mean(u,n); %调用子函数005 med=median(u,n); %调用子函数006 007 functiona=mean(v,n) %子函数008 %计算平均值009 a=sum(v)/n;010例子4-20子函数应用例子。103011 functionm=median(v,n) %子函数012 %计算中间值013 w=sort(v);014 ifrem(n,2)==1015 m=w((n+1)/2);016 else017 m=(w(n/2)+w(n/2+1))/2;018 end011 functionm=median(v,n)104运行例子4-20,在MATALB命令行窗口中,键入下面的指令:>>x=1:11;>>[mean,mid]=newstats(x)mean=6mid=6运行例子4-20,在MATALB命令行窗口中,键入下面的指令105在MATLAB中有一类函数被称为私有函数,这类函数被放置在名称为private的子目录中。每一个函数文件都是标准的M语言函数文件,没有特殊的关键字。但是,这些函数仅能被那些位于private子目录的上一层目录中的函数调用。例如,假设在MATLAB的搜索路径中包含路径\ProjectA,那么所有位于\ProjectA\private路径下的函数,只能在其上一层路径\ProjectA中的函数文件中调用。由于私有函数作用范围的特殊性,不同父路径下的私有函数可以使用相同的函数名。由于MATLAB搜索函数时优先搜索私有函数,所以如果同时存在私有函数名func1.m和非私有函数名func1.m,则私有函数func1.m被优先执行。创建私有函数的方法非常简单,只要将那些需要设置为私有的函数都拷贝到一个private子目录中,则这些函数就能被那些位于父层目录中的M函数调用了。在MATLAB中有一类函数被称为私有函数,这106在表4-4中总结了子函数和私有函数的区别。表4-4私有函数和子函数比较在表4-4中总结了子函数和私有函数的区别。表4-4私有107例子4-21私有函数的例子。创建一个新的函数文件,代码如下:001 functionx=pmean(v,n)002 %MEAN私有函数例子003 %将该函数文件保存在pivae子目录中,004 %则该函数仅能在上层目录的函数文件005 %中调用006 disp('私有函数mean');007 x=sum(v)/n;例子4-21私有函数的例子。108图4-3将pmean.m文件保存在private目录下图4-3将pmean.m文件保存在private目录下109接着,修改newstats函数,并将其另存为newstats1.m。001 function[avg,med]=newstats1(u)%主函数002 %NEWSTATS计算均值和中间值003 n=length(u);004 avg=mean(u,n); %调用子函数005 avg1=pmean(u,n) %调用私有函数006 med=median(u,n); %调用子函数007 008 functiona=mean(v,n)%子函数009 %计算平均值010 disp('子函数mean');011 a=sum(v)/n;012 ......接着,修改newstats函数,并将其另存为newstats110然后在MATLAB命令行中,执行newstats1.m函数:>>newstats1(1:10);子函数meanavg= 5.5000私有函数meanavg1= 5.5000然后在MATLAB命令行中,执行newstats1.m函数:1114.4.4局部变量和全局变量同C语言类似,在M语言函数中也存在局部变量和全局变量。所谓局部变量,就是那些在M函数内部声明并使用的变量。这些变量仅能在函数调用执行期间被使用,一旦函数结束运行,则这些变量占用的内存空间将自动被释放,变量的数值也就不存在了。这是由于MATLAB的解释器在解释执行函数的时候,为不同的函数创建不同的工作空间,函数彼此的工作空间相互独立,一旦函数执行完毕,则函数的工作空间就不存在了。在本章前面的例子中,每个例子的函数内部声明使用的变量都是局部变量,所以函数执行完毕后,MATLAB的基本工作空间中没有这些变量存在,参见例子4-22。4.4.4局部变量和全局变量112例子4-22局部变量的例子。001 functionlocal002 %LOCAL察看局部变量的例子003 x=rand(2,2);004 y=zeros(2,2);005 z='函数中的变量';006 u={x,y,z};007 disp(z)008 whos例子4-22局部变量的例子。113运行例子4-22,在MATLAB命令行中,键入下面的指令:>>local函数中的变量Name SizeBytesClassu 1x3256cellarrayx 2x232doublearrayy 2x232doublearrayz 1x612chararrayGrandtotalis31elementsusing332bytes>>whos运行例子4-22,在MATLAB命令行中,键入下面的指令:114通过运行local函数可以看到,所有在函数中创建的变量在函数运行结束后就不存在了。也就是说,局部变量的生存周期仅在函数的活动期间内。与局部变量相对应的就是全局变量。MATLAB将全局变量保存在特殊的工作空间进行统一维护、管理,而将变量声明为全局变量的方法就是在使用变量前,用关键字global声明,例如声明全局变量gXY:>>globalgXY>>whosName SizeBytesClassgXY 0x00doublearray(global)Grandtotalis0elementsusing0bytes通过运行local函数可以看到,所有在函数中115需要强调一点,MATLAB管理、维护全局变量和局部变量使用了不同的工作空间,所以使用global关键字创建全局变量的时候有三种情况:(1)若声明为全局的变量在当前的工作空间和全局工作空间都不存在,则创建一个新的变量,然后为这个变量赋值为空数组,该变量同时存在于局部工作空间和全局工作空间。(2)若声明为全局的变量已经存在于全局工作空间中,则不会在全局工作空间创建新的变量,其数值同时赋值给局部工作空间中的变量。(3)若声明为全局的变量存在于局部工作空间中,而全局工作空间不存在,则系统会提示一个警告信息,同时将局部的变量“挪”到全局工作空间中。需要强调一点,MATLAB管理、维护全局变量116例子4-23全局变量的例子。在MATLAB命令行窗口中,键入下面的指令:>>%创建全局变量并赋值>>globalmyx>>myx=10;>>%变量的信息>>whosNameSizeBytesClassmyx1x18doublearray(global)Grandtotalis1elementusing8bytes例子4-23全局变量的例子。117>>%清除变量>>clearmyx>>%察看信息>>whos>>whosglobalNameSizeBytesClassmyx1x18doublearray(global)Grandtotalis1elementusing8bytes>>%在局部工作空间再次创建变量>>myx=23myx=23>>%变量的信息>>%清除变量118>>whos

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论