《MATLAB的程序设计和调试.ppt》由会员分享,可在线阅读,更多相关《MATLAB的程序设计和调试.ppt(62页珍藏版)》请在三一办公上搜索。
1、第四章 MATLAB的程序设计和调试,4.3 脚本文件和函数文件4.3.1 M脚本文件(一)脚本文件的特点:它只是一串按用户意图排列而成的(包括控制流向指令在内的)MATLAB指令集合脚本文件运行后,所产生的所有变量都驻留在MATLAB基本工作空间(Base Workspace)中。只要用户不使用clear指令加以清除,且MATLAB指令窗不关闭,这些变量将一直保存在基本工作空间中。基本空间将随MATLAB的启动而产生;只有关闭MATLAB时,该基本工作空间才被删除。,(二)M脚本文件的编写和运行(1)编写M脚本文件的步骤点击MATLAB指令窗工具条上的New File图标,就可打开MATLA
2、B文件编辑调试器MATLAB Editor/Debugger,其窗口名为untitled,用户即可在空白窗口中编写程序。编辑完程序,点击编辑调试器工具条上的保存图标,在弹出的Windows标准风格的“保存为”对话框中,选择保存文件夹,键入新编文件的文件名,点【保存】键,就完成了文件的保存。(2)运行文件使刚刚保存的文件所在的目录成为当前目录,或让该目录处在MATLAB的搜索路径上。直接在命令窗口键入运行文件的文件名或在编辑器窗口中直接点击工具条上的运行按钮都可运行该M文件。,4.3.2 M函数文件(一)M函数文件的特点从形式上看,与脚本文件不同,函数文件的第一行总是一“function”引导的
3、“函数申明行(Function Declaration line)”。该行还罗列出函数与外界的联系的全部“标称”输入输出宗量。但对“输入输出宗量”的标称数目并没有限制,既可以完全没有输入输出宗量,也可以时任意数目。MATLAB允许使用比“标称数目”较少的输入输出宗量,实现对函数的调用。,从运行上看,与脚本文件不同,每当函数文件运行,MATLAB就会专门为它开辟一个临时工作空间(Context workspace)。该空间称之为函数工作空间(Function workspace)。所有中间变量都存放在函数工作空间中。当执行完文件最后一条指令时,或遇到return指令,就结束该函数文件的运行,同时
4、该临时函数空间及其所有的中间变量就立即被清除。函数空间随具体M函数文件的被调用而产生,随调用的结束而删除。函数空间是相对基本空间独立的、临时的。在 MATLAB整个运行期间,可以产生任意多个临时函数空间。假如在函数文件中,发生对某脚本文件的调用,那么该脚本文件运行产生的所有变量都存放于那函数空间之中,而不是存放在基本空间。,4.3.3 局部变量和全局变量(1)局部(Local)变量 存在于函数空间内部的中间变量,产生于该函数的运行过程中,其影响范围仅限于该函数本身。(2)全局(Global)变量 通过global指令,MATLAB也允许几个不同的函数空间以及基本工作空间共享同一个变量。这种被共
5、享的变量称为全局变量。每个希望共享全局变量的函数或MATLAB基本工作空间,必须逐个用global对其具体变量加以专门定义。没采用global定义的函数或基本工作空间,将无权享用全局变量。,补充说明:如果某个函数的运作使全局变量的内容发生了变化,那么其它函数空间以及基本工作空间中的同名变量也随之变化。除非与全局变量联系的所有工作空间都被删除,否则全局变量依然存在。对全局变量的定义必须在该变量被使用之前进行。建议把全局变量的定义放在函数体的首行位置。虽然MATLAB对全局变量的名字并没有任何特别的限制,但是为了提高M文件的可读性,建议使用大写字符命名全局变量。,4.3.4 M文件的一般结构典型M
6、函数文件的结构如下:函数申明行(Function declaration line):位于函数文件的首行,以MATLAB关键字function开头,函数名以及函数的输入输出宗量都在这一行被定义。H1行(The first help text line);紧随函数声明行之后以号开头的第一注释行。按MATLAB自身文件的规则,H1行包含:大写字体的函数文件名和运用关键词简要描述的函数功能。该H1行供lookfor关键词查询和help在线帮助使用,在线帮助文本(Help text)区:H1行及其之后的连续的以开头的所有注释行构成整个在线帮助文本。它通常包括:函数输入输出宗量的含义;调用格式说明。编写
7、和修改记录:它与在线帮助文本区相隔一个“空”行;也以开头;标志编写及修改M文件的作者和日期;版本记录。它用作软件档案管理。函数体(Function body):为清晰起见,它与前面的注释以“空”行相隔。这部分内容由实现M函数功能的MATLAB指令组成。它接收输入宗量,进行程序流控制,得到输出宗量。其中为阅读、理解方便,也配置适当的空行和注释。若仅从运算的角度看,唯“函数申明行”和“函数体”两部分是构成M函数文件所必不可少的。,4.3.6 子函数和私用函数1.子函数 MATLAB允许一个M函数文件包含多个函数的代码。其中第一个出现的那个函数称为主函数(Primary function),该文件中
8、的其他函数则称为子函数(Subfunction)。保存时所用函数名与主函数定义名相同。外部程序只能对主函数进行调用。,子函数的性质:每个子函数的第1行是其自己的函数申明行。在M函数文件内,主函数的位置不可改变,但子函数的排列次序可以任意改变。子函数智能被处于同一文件的主函数或其它其函数调用。在M函数文件中,任何指令通过“名字”对函数进行调用时,子函数的优先级仅次于内装函数。同一文件的主函数、子函数的工作空间都是彼此独立的。各函数间的信息,或通过输入输出变量传递,或通过全局变量传递,或通过跨空间指令传递。help,lookfor等帮助指令都不能提供关于子函数的任何帮助信息。,2.私用函数 所谓私
9、用函数,是指位于private目录上的M文件函数。它有如下性质:私用函数的构造与普通M函数完全相同。私用函数只能被private直接父目录上的M文件所调用,而不能被其它目录上的任何M文件或MATLAB指令窗中的命令所调用。M文件中,任何指令通过“名字”对函数进行调用时,私用函数的优先级虽低于内装函数和子函数,但高于其它任何目录上的函数。help,lookfor等指令都不能提供关于私用函数的任何帮助信息。,4.3.7 MATLAB的搜索过程 假设MATLAB在一个文件中碰到指令cow时,它将按以下步骤逐步进行检索:(1)检查cow是否一个变量名;如果不是,执行下一步;(2)检查cow是不是内建函
10、数(Built-in Function);假如不是,执行下一步;(3)检查cow是不是cow所在的M文件中的一个子函数;假如不是,再往下执行(4)检查cow是不是cow所在的M文件中的一个私用函数(先找cow.p,然后是cow.m);假如不是,再往下执行;,(5)检查cow是不是当前目录上的文件(先找cow.p,然后是cow.m);假如不是,再往下执行;(6)检查搜索路径上是否有cow存在(先找cow.p,然后是cow.m)。MATLAB将使用最先找到的那个cow。如果一直找不到cow,MATLAB就给出错误提示信息。,4.4 MATLAB控制流4.4.1 for循环结构for循环结构的语法形
11、式:for x=array(commands)end说明:循环体的执行次数由for指令后面的数组array的列数决定。在for后面的表达式中的数组可以伪任何合法的MATLAB数组。循环结构可以嵌套使用。为了得到高效代码,应尽量提高代码的向量化程度,而避免使用循环结构。为了得到高效代码,在循环指令之前应尽量对数组进行预定义。,【例7.3.1-1】一个简单的for循环示例。for i=1:10;x(i)=i;end;x,4.4.2 while循环结构while循环结构的语法形式为:while expression(commands)End说明:在while和end之间的“组命令”被称为循环体。当M
12、ATLAB碰到while指令时,首先检测expression的值,如其值为逻辑真(非0),则执行组命令。当组命令执行完毕,继续检测表达式的值,若表达式值仍为真,循环执行组命令;而一旦表达式值为假时,结束循环。,【例7.3.2-1】Fibonacci数组的元素满足Fibonacci 规则:,;且。现要求该数组中第一个大于10000的元素。a(1)=1;a(2)=1;i=2;while a(i)=10000 a(i+1)=a(i-1)+a(i);i=i+1;end;ia(i),4.4.3 if-else-end分支结构指令形式1:if expression(commands)end指令形式2:if
13、 expression(commands1)else(commands2)end指令形式3:if expression1(commands1)elseif(expression2)(commands2)else(commandsk)end,说明:表达式有时由多个逻辑表达式组成,MATLAB将尽可能少的检测子表达式的值。例如,表达式为(子表达式1|表达式2),当MATLAB检测到子表达式1的值为真时,它就认为表达式值为真,而不再对表达式2进行检测。又如表达式1&表达式2)当MATLAB检测到子表达式1的值为假时,它就认为表达式值为假的,从而跳过该结构。if指令判决和break指令的配合使用,可以
14、强制终止for循环或while循环。,【例7.3.3-2】用for循环指令来寻求Fibonacc数组中第一个大于10000的元素。n=100;a=ones(1,n);for i=3:n a(i)=a(i-1)+a(i-2);if a(i)=10000 a(i),break;end;endi,4.4.4 switch-case结构语法结构:switch ex case test1(commands1)case test2 case testk(commandsk)otherwise(commands)end,说明:switch指令后面的表达式应为一个标量或者为一个字符串。对于标量形式的表达式,比
15、较这样进行:表达式检测值i。而对于字符串,MATLAB将调用函数strcmp来实现比较:strcmp(表达式,检测值i)。case指令后面的检测值不仅可以为一个标量值或一个字符串,还可以为一个元胞数组。如果一个检测值是一个元胞数组,MATLAB将把表达式的值和该元胞数组中的所有元素进行比较,如果元胞数组中的某个元素和表达式的值相等,MATLAB认为此次比较结果为真,从而执行与该检测值相应的一组命令。,【例7.3.4-1】学生的成绩管理,用来演示switch结构的应用。clear;for i=1:10;ai=89+i;bi=79+i;ci=69+i;di=59+i;end;c=d,c;Name=
16、Jack,Marry,Peter,Rose,Tom;Mark=72,83,56,94,100;Rank=cell(1,5);S=struct(Name,Name,Marks,Mark,Rank,Rank);for i=1:5 switch S(i).Marks case 100 S(i).Rank=满分;case a S(i).Rank=优秀;case b S(i).Rank=良好;case c S(i).Rank=及格;otherwise S(i).Rank=不及格;endenddisp(学生姓名,得分,等级);disp()for i=1:5;disp(S(i).Name,blanks(6)
17、,num2str(S(i).Marks),blanks(6),S(i).Rank);end;,4.4.5 try-catch结构语法结构:try(commands1)catch(commands2)end说明:只有当MATLAB在执行组命令1时出现了错误后,组命令2才会被执行。可调用lasterr函数查询出错原因。如果函数lasterr的运行结果为一个空串,则表明组命令1被成功执行了。当执行组命令2时又出错,MATLAB将终止该结构,【例7.3.5-1】try-catch结构应用实例:对魔方阵的行进行援引,当“行下标”超出魔方阵的最大行数时,将改向对最后一行的援引,并显示“出错”警告。clea
18、r,N=4;A=magic(3);try A_N=A(N,:)catch A_end=A(end,:)endlasterr,4.4.6 控制程序流的其它常用指令1.return指令 在被调函数中插入了return指令,可以强制MATLAB结束执行该函数并把控制转出。2.input和keyboard(1)input常用格式:vinput(message)%将用户键入的内容赋给变量vvinput(message,s)%将用户键入的内容作为字符串赋给变量v,说明:指令中message是将显示在屏幕上的字符串,这是必不可少的。对于第一种调用格式,用户可以输入数值、字符串元胞数组等各种形式的数据。对于第
19、二种调用格式,不管键入什么,总以字符串形式赋给变量v。(2)keyboard 当程序遇到keyboard时,MATLAB将“控制权”交给键盘,用户可以从键盘输入各种合法的MATLAB指令,只有当用户使用return指令结束输入后,“控制权”才交还给程序。,4.pause指令pause 暂停执行文件,等待用户键入任意键继续pause(n)%在继续执行之前,暂停n秒5.break指令 break指令导致包含有该指令的while、for指令的终止,不必等待循环的自然结束。,6.error和warning指令error(message)%显示出错信息message,终止程序。errortrap错误发生
20、后,程序继续执行与否分双位开关。lasterr显示MATLAB自动判断的最新出错原因,并终止程序。warning(message)显示警告信息message,程序继续执行。lastwarn显示MATLAB自动给出的最新警告,程序继续运行。,4.5变量的检测传递和限权使用函数4.5.1 输入输出宗量检测函数nargin 在函数体内用于获取实际输入宗量;nargout 在函数体内用于获取实际输出宗量;nargin(fun)%获取fun指定函数的标称输入宗量数;nargout(fun)%获取fun指定函数的标称输出宗量数;inputname(n)%在函数体内使用,给出第n各输入宗量的实际调用变量名,
21、4.5.2“变长度”输入输出宗量varargin“变长度”输入宗量列表varargout“变长度”输出宗量列表说明:编写M函数文件时,函数申明行中的“变长度”宗量必须被放置在“普通”宗量之后在编写M函数文件时,varargin的长度随分配到的输入变量数而变;,varargin,varargout的工作机理varargin本身是个元胞数组;M函数文件被调用时,函数输入变量的分配原则是:首先,输入变量依先后次序逐个对应分配给 M函数文件输入宗量列表中那些被明确定义的“普通”输入宗量;然后,把剩余的输入变量一次逐个分配到varargin元胞数组的元胞中。因此varargin元胞数组的长度取决于分配到
22、的输入变量数。所谓“变长度”,就是指:varargin的长度随分配到的输入变量数而变。,【例7.5.2-1】变长度宗量使用示例。exm07052_1.mfunction varargout=exm07052_1(r,varargin)vin=length(varargin);Nin=vin+1;error(nargchk(1,Nin,nargin)if nargout6 error(Too many output arguments)endt=0:pi/20:2*pi;x=r*exp(i*t);s=pi*r*r;,if nargout=0 switch Nin case 1 plot(x,b)
23、case 2 r2=varargin1;x2=r2*exp(i*t);plot(x,b);hold on;plot(x2,b);hold off otherwise r2=varargin1;x2=r2*exp(i*t);plot(x,varargin2:end);hold on plot(x2,varargin2:end);hold off end;axis(square),else varargout1=real(x);varargout2=imag(x);varargout5=pi*r*r;varargout6=;if Nin1 r2=varargin1;x2=r2*exp(i*t);v
24、arargout3=real(x2);varargout4=imag(x2);varargout6=pi*(r2-r22);end;end,r1=1;r2=3;x1,y1,x2,y2,s1,s2=exm07052_1(r1);x1,y1,x2,y2=exm07052_1(r1,r2);x1,y1,x2,y2,s1,s2=exm07052_1(r1,r2);r1=1;r2=0.6;subplot(1,3,1),exm07052_1(r1,r2),subplot(1,3,2),exm07052_1(r1,r2,Marker,o)subplot(1,3,3),exm07052_1(r1,r2,Lin
25、eWidth,5,Color,1 0.4 0),4.5.3 跨空间变量传递1.跨空间计算串表达式的值evalin(workspace,expression)%跨空间计算串表达式值evalin(workspace,expression1,expression2)%跨空间计算替代串表达式值说明:workspace可取两个值:base和caller。第一种调用格式的执行机理当workspace取base时,表示计算eval(expression)时,将从基本工作空间中获得变量值,当workspace取caller时,表示计算eval(expression)时,将从主调函数工作空间获得变量值。主调函数
26、是相对被调函数而言的。这里被调函数是指evalin所在的函数。第二种调用格式的执行机理是:先从所在函数空间获取变量值,用eval(expression1)计算原串表达式;如若该计算失败,则再从workspace指定的(基本或主调函数)工作空间获取变量值,再通过eval(expression2)计算替代串表达式。,【例7.5.3.1-1】本例演示:(A)编写绘制正多边形或圆的程序。(B)子函数与(母)函数的关系。(C)各种不同的工作空间。(D)evalin运行机理与eval的异同。(1)exm070531_1.mfunction y1=exm070531_1(a,s)t=(0:a)/a*2*pi
27、;y1=subevalinzzy(4,s);%-subfunction-function y2=subevalinzzy(a,s)t=(0:a)/a*2*pi;ss=a*exp(i*t);switch scase base,caller y2=evalin(s,ss);case self y2=eval(ss);end,(2)clear,a=30;t=(0:a)/a*2*pi;sss=base,caller,self;for k=1:3y0=exm070531_1(8,sssk);subplot(1,3,k)plot(real(y0),imag(y0),r,LineWidth,3),axis
28、square imageend,2.跨空间赋值assignin(workspace,VN,X)%跨空间向VN变量赋值【例7.5.3.2-1】assignin运作机理示范。EXM070532_1.Mfunction y=exm070532_1(x)y=sqrt(x);t=x2;assignin(base,yy,t)clear;x=4;y=exm070532_1(x);disp(blanks(5),x,blanks(5),y,blanks(4),yydisp(x,y,yy),4.6 串演算函数4.6.1 evaly=eval(CEM)%执行CEM指定的计算y=eval(CEM1,CEM1)%执行C
29、EM1指定的计算,如果出错,就执行CEM2y1,y2,=eval(CEM)%执行对CEM代表的函数文件调用,并输出计算结果,说明:Eval指令的输入宗量必须是字符串构成字符串的CEM,可以是MATLAB任何合法的指令、表达式、语句或M文件名。第3种格式中的CEM只能是(包含输入宗量在内的)M函数文件名。,【例7.6.1-1】计算“表达式”串,产生向量值。clear,t=pi;cem=t/2,t*2,sin(t);y=eval(cem),【例7.6.1-2】计算“语句”串,创建变量。clear,t=pi;eval(theta=t/2,y=sin(theta);who,【例7.6.1-3】计算“替
30、代”串。A=ones(2,1);B=ones(1,3);c=eval(B*A,A*B),errmessage=lasterr,【例7.6.1-4】计算“合成”串。CEM=cos,sin,tan;for k=1:3theta=pi*k/12;y(1,k)=eval(CEM1,(,num2str(theta),);endy,4.6.2 fevaly1,y2,=feval(FN,arg1,arg2,)%用参量arg1,arg2等执行函数指定的计算说明:FN只能是函数名在既可以使用eval,又可以使用feval的情况下,feval运行效率更高。,【例7.6.2-1】feval 和eval 运行区别之一
31、:feval的FN绝对不能是表达式。x=pi/4;Ve=eval(1+sin(x)Vf=feval(1+sin(x),x),【例7.6.2-2】feval 和eval 调用区别:feval 的FN只接受函数名。本例两种方法以后者为好。A=rand(2,2);ue,de,ve=eval(svd(A);disp(Results by eval);disp(ue,de,ve);disp(blanks(1)uf,df,vf=feval(svd,A);disp(Results by feval);disp(uf,df,vf),4.6.3 内联函数1.内联函数的创建inline(CE)%把串表达式转化为输
32、入宗量自动生成的内联函数inline(CE,arg1,arg2,)%把串表达式转化为arg1,arg2等指定输入宗量的内联函数inline(CE,n)%把串表达式转化为x,P1,P2,Pn等指定输入宗量的内联函数,说明:CE是字符串;CE必须不包含赋值号“”的表达式。第1种调用格式将自动地对CE进行辨识,把CE中由字母/数字组成的连续字符认做变量,除“预定义变量名(如i,j,pi)”和“常用函数名(如sin,svd)”以外的由字母/数字组成的连续字符将被认做变量。但注意:若连续字符后紧接“左圆括号”,那么将不被当作输入宗量。如x(1),就不会认做输入宗量处理。第2中调用格式是创建内联函数最稳妥
33、、可靠途径。输入宗量字符可表达得更自如。第三种调用格式最简练,但对输入输出宗量的字符限制严格。输入宗量字符只能是x,P1,Pn等。注意:P是大写字母。,2.涉及内联函数性质的指令class(inline_fun)%给出内联函数的类型char(inline_fun)给出内联函数计算公式argnames(inline_fun)给出内联函数的输入宗量vectorize(inline_fun)使内联函数适用“数组运算”规则,【例7.6.3.3-1】演示:内联函数的第一种创建格式;使内联函数适于“数组运算”。clear,F1=inline(sin(rho)/rho)创建一个内联函数f1=F1(2)如何使
34、用内联函数FF1=vectorize(F1)使内联函数适用于向量运算xx=0.5,1,1.5,2;ff1=FF1(xx),【例7.6.3.3-2】演示:第一种内联函数创建格式的缺陷;含向量的多宗量输入的赋值。G1=inline(a*exp(x(1)*cos(x(2),G1(2,-1,pi/3)G2=inline(a*exp(x(1)*cos(x(2),a,x),G2(2,-1,pi/3),【例7.6.3.3-3】演示:产生向量输入、向量输出的内联函数;这种向量函数的调用方法。Y2=inline(x(1)2;3*x(1)*sin(x(2)argnames(Y2)x=4,pi/6;y2=Y2(x)
35、,【例7.6.3.3-4】演示:最简练格式创建内联函数;内联函数可被feval 指令调用。Z2=inline(P1*x*sin(x2+P2),2)z2=Z2(2,2,3)fz2=feval(Z2,2,2,3),4.7 调试和剖析4.7.1 直接调试法将重点怀疑语句行、指令行后的分号“;”删除或改成“,”,使计算结果显示于屏幕。在适当的位置,添加显示某些关键变量值的语句(包括使用disp在内)。利用echo指令,使运行时,在屏幕上逐行显示文件内容。Echo on 能显示M脚本文件;echo FunName on能显示名为FunName的M函数文件。,在原M脚本文或函数文件种的适当位置,添加key
36、board指令。当MATLAB运行至keyboard指令时,将暂停执行文件,并在MATLAB指令窗中出现K提示符。此时用户可以输入指令查看基空间或函数空间中存放的各种变量,也可以输入指令去修改那些变量。在K提示符后键入return指令,结束查看,原文件继续往下执行。通过在原 函数文件首行之前加上百分号,使一个中间变量难于观察的M函数文件变为一个所有变量都保留在基空间中的M脚本文件。,4.7.2 调试器的使用(1)两个函数文件exm070922_1.m,barzzy0.m(2)运行如下指令randn(seed,1),x=randn(1,100);exm070922_1(x);(3)初步分析错误原因(4)断点设置,(5)在指令窗中重新运行前面的指令,进入“动态”调试(6)深入被调文件内部(7)连续执行,直到另一个断点(8)观察这段程序运行后产生的中间结果,确定错误的准确位置。变量值的鼠标观察法指令窗观察法(9)修改程序,停止第一轮调试,重新运行。(10)再一次运行前面的代码,若还有错误,继续按上面的方法进行调试,直到给出正确的运行结果。,