2.4 M文件
MATLAB神经网络超级学习手册
M文件有两种形式:脚本文件(Script File)和函数文件(Function File)。脚本文件通常用于执行一系列简单的MATLAB命令,运行时只需输入文件名字,MATLAB就会自动按顺序执行文件中的命令。
函数文件和脚本文件不同,它可以接受参数,也可以返回参数,在一般情况下,用户不能靠单独输入其文件名来运行函数文件,而必须由其他语句来调用,MATLAB的大多数应用程序都以函数文件的形式给出。
2.4.1 M文件概述
MATLAB提供了极其丰富的内部函数,使得用户可以通过命令行调用就可以完成很多工作,但是想要更加高效地利用MATLAB,离不开MATLAB编程。
用户可以通过组织一个MATLAB命令序列完成一个独立的功能,这就是脚本M文件编程;而把M文件抽象封装,形成可以重复利用的功能块,这就是函数M文件编程。因此,MATLAB编程是提高MATLAB应用效率,把MATLAB基本函数扩展为实际的用户应用的必经之道。
M文件是包含MATLAB代码的文件。M文件按其内容和功能可以分为脚本M文件和函数M文件这两大类。
1.脚本M文件
它是许多MATLAB代码按顺序组成的命令序列集合,不接受参数的输入和输出,与MATLAB工作区共享变量空间。脚本M文件一般用来实现一个想对独立的功能,比如对某个数据集进行某种分析、绘图,求解某个已知条件下的微分方程等。用户可以通过在命令窗口直接键入文件名来运行脚本M文件。
通过脚本M文件,用户可以把为实现一个具体功能的一系列MATLAB代码书写在一个M文件中,每次只需要键入文件名即可运行脚本M文件中的所有代码。
2.函数M文件
它也是为了实现一个单独功能的代码块,但它与脚本M文件不同的是需要接受参数输入和输出,函数M文件中的代码一般只处理输入参数传递的数据,并把处理结果作为函数输出参数返回给MATLAB工作区中指定的接受量。
因此,函数M文件具有独立的内部变量空间,在执行函数M文件时,需指定输入参数的实际取值,而且一般要指定接收输出结果的工作区变量。
MATLAB提供的许多函数就是用函数M文件编写的。尤其是各种工具箱中的函数,用户可以打开这些M文件查看。实际上,对应特殊应用领域的用户,如果积累了充足的专业领域应用的函数,就可以组建自己的专业领域工具箱。
通过函数M文件,用户可以把为实现一个抽象功能的MATLAB代码封装成一个函数接口,在以后的应用中重复调用。
MATLAB中的M文件一般包括以下5部分结构。
(1)函数声明行。
这一行只出现在M文件的第一行,通过function关键字表明此文件是一个M文件,并指定函数名、输入和输出参数。
(2)H1行。
这是帮助文字的第一行,给出M文件帮助最关键的信息。当用lookfor查找某个单词相关的函数时,lookfor只在H1行中搜索是否出现指定单词。
(3)帮助文字。
这部分对M文件更加详细的说明,解释M文件实现的功能,M文件中出现的各变量、参数的意义,以及操作版权详细信息等。
(4)M文件正文。
这是M文件实现功能的MATLAB代码部分,通常包括运算、赋值等指令。
(5)注释部分。
这部分出现的位置比较灵活,主要是用来注释M文件正文的具体运行过程,方便阅读和修改,经常穿插在M文件正文中间。
2.4.2 局部变量与全局变量
无论在脚本文件还是在函数文件中,都会定义一些变量。函数文件所定义的变量是局部变量,这些变量独立于其他函数的局部变量和工作空间的变量,即只能在该函数的工作空间引用,而不能在其他函数工作空间和命令工作空间引用。但是如果某些变量被定义成全局变量,就可以在整个MATLAB 工作空间进行存取和修改,以实现共享。因此,定义全局变量是函数间传递信息的一种手段。
用命令global定义全局变量,其格式如下。
global A B C
将A、B、C这3个变量定义为全局变量。
在M文件中定义全局变量时,如果在当前工作空间已经存在相同的变量,系统将会给出警告,说明由于将该变量定义为全局变量,可能会使变量的值发生改变。为避免发生这种情况,应该在使用变量前先将其定义为全局变量。
提示:
在MATLAB中对变量名是区分大小写的,因此为了在程序中分清楚而不至于误声明,习惯上可以将全局变量定义为大写字母。
【例2-27】全局变量的使用。
解:在Commond Window窗口输入以下命令。
function y=myt(x)
global a;
a=a+9;
y=cos(x);
然后在命令窗口声明全局变量赋值调用。
>> global a
>> a=2
a =
2
>> myt(pi)
ans =
-1
>> cos(pi)
ans =
-1
>> a
a =
11
通过例2-27可见,用global将a声明为全局变量后,函数内部对a的修改也会直接作用到MATLAB工作区中,函数调用一次后,a的值从2变为11。
2.4.3 M文件的编辑与运行
MATLAB语言是一种高效的编程语言,可以用普通的文本编辑器把一系列MATLAB语句写在一起构成MATLAB程序,然后存储在一个文件里,文件的扩展名为.m,因此称为M文件。这些文件都是由纯ASCII码字符构成的,在运行M文件时只需在MATLAB命令窗口下输入该文件名即可。
在MATLAB的编辑器中建立与编辑M文件的一般步骤如下。
1.新建文件
(1)最简单的方法是单击 MATLAB主界面工具栏上的图片 13图标。
(2)在Commond Window窗口输入edit语句建立新文件,或输入edit filename语句,打开名为filename的M文件,在弹出文件不存在的提示框中,单击“Yes”按钮,则建立名为filename 新的M文件。
(3)选择MATLAB主界面的Home→New子菜单,在其下拉菜单中选择“Script”项。
(4)如果已经打开了文件编辑器后需要再建立新文件,可以用编辑器的菜单或工具栏上相应的图标进行操作。
提示:
还可以使用“Ctrl+N”的快捷方式打开一个新的M文件。
2.打开文件
(1)单击MATLAB主界面工具栏上的图片 14图标,弹出Open窗口,选择已有的M 文件,单击“打开”按钮,如图2-8所示。
(2)输入edit filename语句,打开名为filename的M文件。
3.编辑文件
虽然M文件是普通的文本文件,在任何的文本编辑器中都可以编辑,但MATLAB系统提供了一个更方便的内部编辑器(Editor),如图2-9所示。
对于新建的M文件,可以在MATLAB的Editor窗口编写新的文件;对于打开的已有M文件,其内容显示在Editor窗口,用户可以对其进行修改。
在编辑的过程中可以使用类似于其他文本编辑器(如Word)的“复制”(Copy)菜单、工具栏的编辑图标和快捷键等,值得注意的是,除了注释内容外,所有MATLAB的语句都要使用西文字符。
4.保存文件
M文件在运行之前必须先保存。其方法如下。
单击编辑器工具栏上的图片 17图标:对于新建的M文件,则弹出“保存文件”(Save file as)对话框,选择存放的路径、文件名和文件保存类型(不选择时为M 文件),单击“保存”按钮,即可完成保存;对于打开的已有M文件,则直接完成保存。
使用“Ctrl+S”的快捷方式。等同于单击编辑器工具栏上的图片 18图标。
选择工具栏Save下拉菜单中的“Save As…”选项,可以在弹出“保存文件”(Select file for Save as)对话框中,重新选择存放的目录、文件名进行保存。
5.运行文件
脚本文件可直接运行,而函数文件还必须输入函数参数。
(1)在命令窗口输入要运行的文件名即可开始运行,需要注意的是,在运行前,一定要先保存文件,否则运行的是保存前的程序。
(2)如果在编辑器中完成编辑后需要直接运行,可以直接用鼠标单击图片 19图标。
(3)按F5键则保存程序并直接运行;如果是新建M文件,则弹出“保存文件”对话框,用户保存文件后直接运行。
2.4.4 脚本文件
脚本文件是M文件中最简单的一种,不需要输入顿号输出参数,用命令语句可以控制MATLAB命令工作空间的所有数据。
在运行过程中,产生的所有变量均是命令工作空间变量,这些变量一旦生成,就一直保存在内存空间中,除非用户执行clear命令将它们清除。运行一个脚本文件等价于从命令窗口中顺序运行文件里的语句。由于脚本文件只是一串命令的集合,因此只需像在命令窗口中输入语句那样,依次将语句编辑在脚本文件中即可。
【例2-28】编程计算向量元素的平均值。
解:在MATLAB编辑窗口输入以下命令。
a=input('输入变量:a=');
[b,c]=size(a);
if ~((b==1)|(c==1))|(((b==1)&(c==1))) %判断输入是否为向量
error('必须输入向量')
end
average=sum(a)/length(a) %计算向量a所有元素的平均值
将其保存为pingjun.m,运行之,如果输入行向量[1 2 3],则运行结果如下。
>> pingjun
输入变量:a=[1 2 3]。
average =
2
如果输入的不是向量,如[1 2; 3 4],则运行结果如下。
>> pingjun
输入变量:a=[1 2; 3 4],则运行结果如下。
Error using pingjun (line 4)
这是因为必须输入向量。
2.4.5 函数文件
如果M文件的第一个可执行语句以function开始,该文件就是函数文件,每一个函数文件都定义一个函数。事实上,MATLAB 提供的函数命令大部分都是由函数文件定义的,这足以说明函数文件的重要。
从使用的角度看,函数是一个“黑箱”,把一些数据送进去,经加工处理,把结果送出来。从形式上看,函数文件区别于脚本文件之处在于脚本文件的变量为命令工作空间变量,在文件执行完成后保留在命令工作空间中;而函数文件内定义的变量为局部变量,只在函数文件内部起作用,当函数文件执行完后,这些内部变量将被清除。
【例2-29】编写函数 average( )用于计算向量元素的平均值。
解:在MATLAB编辑窗口输入以下命令。
function y=average(x)
[a,b]=size(x); % 判断输入量的大小
if~((a==1)|(b==1))| ((a==1)& (b==1)) % 判断输入是否为向量
error('必须输入向量。')
end
y=sum(x)/length(x); %计算向量x所有元素的平均值
将文件存盘,默认状态下函数名为average_2.m(文件名与函数名相同),函数average接受一个输入参数并返回一个输出参数,该函数的用法与其他MATLAB 函数一样;在MATLAB 命令窗口中运行以下语句,便可求得1~9的平均值。
>> x=1:9
x =
1 2 3 4 5 6 7 8 9
>> average(x)
ans =
5
通常函数文件由以下几个基本部分组成。
(1)函数定义行。函数定义行由关键字function 引导,指明这是一个函数文件,并定义函数名、输入参数和输出参数,函数定义行必须为文件的第一个可执行语句,函数名与文件名相同,可以是MATLAB 中任何合法的字符。
函数文件可以带有多个输入和输出参数,如下。
function [x,y,z]=sphere(theta,phi,rho)
也可以没有输出参数,如下。
function printresults(x)
(2)H1行。H1行就是帮助文本的第一行,是函数定义行下的第一个注释行,是供lookfor查询时使用的。一般来说为了充分利用MATLAB的搜索功能,在编制M文件时,应在H1行中尽可能多地包含该函数的特征信息。由于在搜索路径上包含average 的函数很多,因此用lookfor average 语句可能会查询到多个有关的命令。如下。
>> lookfor average_2
average_2.m: % 函数average_2(x)用以计算向量元素的平均值。
(3)帮助文本。在函数定义行后面,连续的注释行不仅可以起到解释与提示作用,更重要的是为用户自己的函数文件建立在线查询信息,以供help命令在线查询时使用。如下。
>> help average_2
函数 average_2(x)用以计算向量元素的平均值。
输入参数x为输入向量,输出参数y为计算的平均值。非向量输入将导致错误。
(4)函数体。函数体包含了全部的用于完成计算及给输出参数赋值等工作的语句,这些语句可以是调用函数、流程控制、交互式输入/输出、计算、赋值、注释和空行。
(5)注释。以%起始到行尾结束的部分为注释部分,MATLAB的注释可以放置在程序的任何位置,可以单独占一行,也可以在一个语句之后,如
%非向量输入将导致错误
[m,n]=size(x); %判断输入量的大小
2.4.6 函数调用
调用函数文件的一般格式如下。
[输出参数表]=函数名(输入参数表)
调用函数时应注意以下几项。
(1)当调用一个函数时,输入和输出参数的顺序应与函数定义时一致,其数目可以按少于函数文件中所规定的输入和输出参数调用函数,但不能使用多于函数文件所规定的输入和输出参数数目。如果输入和输出参数数目多于或少于函数文件所允许的数目,则调用时自动返回错误信息。举例如下。
>> [x,y]=sin(pi)
??? Error using ==> sin
Too many output arguments.
又如:
>> y=linspace(2)
??? Input argument "n" is undefined.
Error in ==> linspace at 21
(2)在编写函数文件调用时常通过nargin、nargout 函数来设置默认输入参数,并决定用户所希望的输出参数。函数nargin 可以检测函数被调用时用户指定的输入参数个数;函数nargout 可以检测函数被调用时用户指定的输出参数个数。
在函数文件中通过nargin、nargout 函数,可以适应函数被调用时,用户输入和输出参数数目少于函数文件中function语句所规定数目的情况,以决定采用何种默认输入参数和用户所希望的输出参数。举例如下。
function y = linspace(d1, d2, n)
%LINSPACE Linearly spaced vector.
% LINSPACE(X1, X2) generates a row vector of 100 linearly
% equally spaced points between X1 and X2.
%
% LINSPACE(X1, X2, N) generates N points between X1 and X2.
% For N < 2, LINSPACE returns X2.
%
% Class support for inputs X1,X2:
% float: double, single
%
% See also LOGSPACE, :.
% Copyright 1984-2004 The MathWorks, Inc.
% $Revision: 5.12.4.1 $ $Date: 2004/07/05 17:01:20 $
if nargin == 2
n = 100;
end
n = double(n);
y = [d1+(0:n-2)*(d2-d1)/(floor(n)-1) d2];
如果用户只指定2个输入参数调用linspace,例如linspace(0,10),linspace 在0~10之间等间隔产生100个数据点;相反,如果输入参数的个数是3,例如,linspace(0,10,50),第3个参数决定数据点的个数,linspace 在0~10等间隔产生50个数据点。同样,函数也可按少于函数文件中所规定的输出参数进行调用。例如对函数size( )的调用。
>> x=[1 2 3 ; 4 5 6];
>> m=size(x)
m =
2 3
>> [m,n]=size(x)
m =
2
n =
3
(3)当函数有一个以上输出参数时,输出参数包含在方括号内。例如,[m,n]=size(x)。注意:[m,n]在左边表示函数的两个输出参数m和n;不要把它和[m,n]在等号右边的情况混淆,如y=[m,n]表示数组y由变量m和n所组成。
(4)当函数有一个或多个输出参数,但调用时未指定输出参数,则不给输出变量赋任何值。举例如下。
function t=toc
% TOC Read the stopwatch timer.
% TOC, by itself, prints the elapsed time (in seconds) since TIC was used.
% t = TOC; saves the elapsed time in t, instead of printing it out.
% See also TIC, ETIME, CLOCK, CPUTIME.
% Copyright(c)1984-94byTheMathWorks,Inc.
% TOC uses ETIME and the value of CLOCK saved by TIC.
Global TICTOC
If nargout<1
elapsed_time=etime(clock,TICTOC)
else
t=etime(clock,TICTOC);
end
如果用户调用toc 时不指定输出参数t,举例如下。
>> tic
>> toc
elapsed_time =
4.0160
函数在命令窗口显示函数工作空间变量elapsed_time 的值,但在MATLAB 命令工作空间里不给输出参数t赋任何值,也不创建变量t。
如果用户调用toc时指定输出参数t,举例如下。
>> tic
>> out=toc
out =
2.8140
则以变量out 的形式返回到命令窗口,并在MATLAB命令工作空间里创建变量out。
(5)函数有自己的独立工作空间,它与MATLAB的工作空间分开。除非使用全局变量,函数内变量与MATLAB其他工作空间之间唯一的联系是函数的输入和输出参数。如果函数任一输入参数值发生变化,其变化仅在函数内出现,不影响MATLAB 其他工作空间的变量。函数内所创建的变量只驻留在该函数工作空间,而且只在函数执行期间临时存在,以后就消失。因此,从一个调用到另一个调用,在函数工作空间以变量存储信息是不可能的。
(6)在MATLAB其他工作空间重新定义预定义的变量(例如pi),它不会延伸到函数的工作空间;反之亦然,即在函数内重新定义预定义的变量不会延伸到MATLAB的其他工作空间中。
(7)如果变量说明是全局的,函数可以与其他函数、MATLAB的Workspace和递归调用本身共享变量。为了在函数内或MATLAB命令工作空间中访问全局变量,全局变量在每一个所希望的工作空间都必须说明。
(8)全局变量可以为编程带来某些方便,但却破坏了函数对变量的封装,所以在实际编程中,无论什么时候都应尽量避免使用全局变量。如果一定要用全局变量,建议全局变量名要长、采用大写字母,并有选择地以首次出现的M文件的名字开头,使全局变量之间不必要的互作用减至最小。
(9)MATLAB 以搜寻脚本文件的同样方式搜寻函数文件。例如,输入cow语句,MATLAB首先认为cow是一个变量;如果它不是,那么MATLAB认为它是一个内置函数;如果还不是,MATLAB检查当前cow.m 的目录或文件夹;如果仍然不是,MATLAB就检查cow.m在MATLAB搜寻路径上的所有目录或文件夹。
(10)从函数文件内可以调用脚本文件。在这种情况下,脚本文件查看函数工作空间,不查看MATLAB的Workspace。从函数文件内调用的脚本文件不必调到内存进行编译,函数每调用一次,它们就被打开和解释。因此,从函数文件内调用脚本文件减慢了函数的执行。
(11)当函数文件到达文件终点,或者碰到返回命令return,就结束执行和返回。返回命令return提供了一种结束函数的简单方法,而不必到达文件的终点。
2.4.7 M文件调试工具
当完成MATLAB代码编写后,用户就可以在命令窗口运行代码(脚本或函数文件)。对于比较简单的代码,一般只要编程习惯较好,都可以一次通过,但对于很多比较复杂的情况,或者用户初学MATLAB编程,一些常见的错误还不能避免,容易在运行时出现错误,这时候,就需要利用MATLAB的调试工具对出现错误的代码进行调试纠错。
MATLAB的Editor窗口是一个综合了代码编写、调试的集成开发环境。MATLAB代码调试过程,主要是通过Editor窗口上的工具栏完成,如图2-10所示。
下面介绍Editor窗口上几种经常用到的工具。
(1)Compare:比较两个M文件的差异,并出具报告,报告格式如图2-11所示。
(2)Insert:在M文件中插入注释、函数或者数据等。
(3)Comment:屏蔽或者取消屏蔽M文件中的内容。
(4)Indent:调整M文件内容的位置。
(5)Run:运行当前M文件,快捷键是F5;当前M文件设置了断点时,运行到断点处暂停。
(6)Run Section:运行当前M文件中用户选中的某一部分程序。
(7)Breakpoints:设置或清除断点。其下拉菜单中的命令如图2-12所示。
当选择该选项下拉菜单中的Set Condition时,会打开条件断点设置对话框,如图2-13所示,该命令用于设置满足断点有效的条件。
当选择Stop on Errors或Stop on Warnings命令时,M文件会在出现某种运行错误或警告时,停止程序运行。
通常的调试过程是先单击Run按钮,运行一遍M文件,针对系统给出的具体的出错信息,在适当的地方设置断点或条件断点,再次运行到断点位置(如图2-14所示),此时MATLAB把运行控制权交给键盘,命令窗口出现“K>>”提示符(如图2-15所示),此时可以在命令窗口查询M文件运行过程中的所有变量,包括函数运行时的中间变量,运行到断点位置后,用户可以逐行运行并实时查询变量取值,从而逐渐找到错误所在并将其排除。
2.4.8 M文件分析工具
通过对M文件进行调试,可以对文件中的编写错误和运行错误进行纠正。完成了调试后,用户编写的M文件就可以正确地运行了,但可能运行效率还不是最优,这就需要通过MATLAB提供的分析工具对代码进行分析,然后有针对性地进行优化。
MATLAB提供的M文件分析工具包括Code Analyzer Report工具和Profiler工具,它们都有图形操作界面,使用简单方便,是MATLAB程序分析优化的必用工具。
1.Code Analyzer Report工具
Code Analyzer Report工具可以分析用户M文件中的错误或性能问题,用户可以先在代码编辑调试器中打开待分析的M文件,然后选择MATLAB工具菜单下的图片 26,即可得到图2-16所示的代码分析报告。
从图2-16中可以看出,Code Analyzer Report分析完成后,会返回一个浏览器界面下的分析报告,报告中包括被分析的M文件的路径,以及若干个分析结果。分析结果的格式是“行号:错误或问题报告”。
实际上,Code Analyzer Report分析得到的报告并不一定必须要消除,要具体问题具体分析。当用户认可某一条分析结果时,可以单击分析结果中的行号。就可以快捷打开相应的M文件并定位到该行,用户就可以方便地修改代码了。
Code Analyzer Report不仅可以分析单个M文件,还可以分析一个文件夹下的所有M文件。在分析结果的主界面下,选择Rerun This Report则分析单个M文件,选择Run Report on Current Folder则分析当前文件夹下的所有M文件。
2.Profiler分析工具
Profiler工具是MATLAB提供的另一个功能强大的代码分析工具。在MATLAB的Commond Window窗口输入profile viewer命令,出现图2-17所示的Profiler图形界面。使用时,用户可以提前在Editor中打开M文件,然后运行Profiler分析工具。
单击图2-17中的“Start Profiling”按钮,就可以分析此M文件,分析结果如图2-18所示。
从图2-18中可见,Profiler分析结果给出了调用函数名称、调用次数、消耗总时间等信息,单击图2-18中的“Self Time”,可以使M文件的分析报告按照Self Time从大到小的方式排列,如图2-19所示。
图2-19显示了文件运行中最消耗时间的部分及其具体耗时信息。用户可以有针对性地修改那些最消耗时间的部分。
提示:
一般来说,应该尽量避免不必要的变量输出,循环赋值前预定义数组尺寸,多采用向量化的MATLAB函数,少采用数组,这些都能够提高MATLAB程序的运行性能。