MATLAB-程序设计

Matlab_3 程序设计

 M脚本文件
 流程控制
 函数
 文件管理
 调试和优化

M脚本文件

关于脚本语言
http://zh.wikipedia.org/wiki/%E8%84%9A%E6%9C%AC%E8%AF%AD%E8%A8%80

M文件的创建和编辑
Matlab Editor提供文本编辑和运行调试的集成环境。
Editor自动进行文法检查。
Editor自动给出语句格式如循环和条件语句的缩进格式、程序分块等辅助工具。
M文件以扩展名.m标识。

M文件的运行
在命令窗口中输入文件名或Editor中选择直接运行。
M文件代码和在Command Window中逐条输入效果相同,变量在Matlab Workspace中显示。

编写M脚本文件的注意事项:

文件名:
与变量命名规则相同。

行注释:
一行中,百分号%以后的为注释内容。
第一行注释(H1)很重要,用于简要说明文件的用途、功能等。
第一个可执行代码前的注释区可以通过help直接查看。

块注释:
以%{开头的行的至以%}开头的行之间的所有内容,注意这两行不要写其它内容

代码单元:
以%%标识,至下个%%或文件结尾
仅为代码书写、阅读和调试提供方便,不影响运行

续行:
对一个很长表达式,在该行的末尾处用换行符 ‘…’ 表示续行。

%% 例:M-file格式
%(复制以下代码到mfileform.m文件)
% --------------------------------------------------
% H1:简要说明程序功能
% 符号、公式、算法、流程说明
% …
% Matlab版本;程序创建和修改信息
% 以上信息可以用 help filename 查看

%% 变量定义单元
s1 = ‘M文件’;
s2 = ‘推荐格式’;
%…

%% 计算代码单元
output = { [s1 s2] ‘Thank you for your attention.’ } ;
%…

%% 结果处理单元
celldisp(output)
%…

几个控制文件执行的函数:

beep
disp(…)
echo on/off
input
keyboard
pause, pause(n)
waitforbuttonpress

%% copy to demoinput.m
% ----------------------------------------------------
% demo input function

answer = input( ‘is this okay? [y/n]:’, ‘s’);

if( answer == ‘y’ )
disp(‘great, lets go.’)
else
disp(‘anything wrong?’)
end

%% copy to demokeyboard.m
% ----------------------------------------------
% demo keyboard function
% K>> (in debug mode)
% K>> dbcont (return/continue the programm)

x = (-3:3)*pi/3;
y = sin(x)./x;

keyboard; % turn to debug mode

result = mean(y)

% …

程序定时器—timer

% timer函数创建定时器对象

help timer % 了解timer功能

doc timer % 查看timer函数用法

%% 例:延时启动
% 运行结果不回送Word文档

% 设置定时器:20秒后启动应用程序

t = timer( ‘TimerFcn’, ‘mfileform’, ‘StartDelay’, 20 );

start(t) % 启动定时器

%% 设置定时启动

t1 = timer( ‘TimerFcn’, ‘disp(’‘task over!’’)’ );

startat( t1, ‘hh:mm:ss’ ); % start at set time.

startat( t1, now + 1/24/3600*20 ) % start after 20sec.

%% 查找和删除定时器对象

timerfind

delete( t )

delete( t1 )

delete( timerfind ) % delete all

流程控制

Matlab提供的5种流程控制结构:

For
While
If-Else-End
Switch-Case
Try-Catch

For循环

格式
for x = array
( commands…)
end
x: 循环变量,array: 条件数组

For循环根据array的列数确定循环次数。
Array有几列,commands就执行几次。

% 比较下列两段代码的循环次数
n=0;
for i = 1:10
a(i) = sin(i*pi/180);
n = n+1;
end;
n, a

n = 0;
for i = (1:10).’
b(i) = sin(i*pi/180);
n=n+1;
end;
n, b

% 条件数组可以是任何合法的数组
array = randperm(10), % again, array = magic(3)
n=0;
for i = array
a(i) = i.^2;
n = n+1;
end;
n, a

% 循环嵌套(生成pasacal矩阵)
n = 5;
a = ones(5);

for j = 2:n
for i = 2:n
a(i, j) = a(i-1,j)+a(i,j-1);
end
disp(j)
end
a

While循环

格式
while expression
(commands…)
end

expression为条件表达式
expression可以是标量,也可以是表达式。只要expression为True,commands一直执行下去。
如expression为数组,只有数组所有元素为True,commands才一直执行下去。

% 测试N = 1, 10, 1e10的相对浮点精度

iteration = 0; Eps = 1; N = 1;

while (N+Eps)>N
Eps = Eps/2;
iteration = iteration + 1;
end;

iteration
Eps*2

eps(N)

If-Else-End结构

格式
if expression
(commands-1…)
else
(commands-2…)
end
如expression为True执行commands-1,否则执行commands-2。
若无特定任务,else和commands-2可以不写。
如需根据多个条件执行多个操作,用关键字elseif说明。

%
a = rand, b = rand
if a>b
disp(‘a>b’)
end

%
a = rand, b = rand
if a>b
disp(‘a>b’)
else
disp(‘a<=b’)
end

%
a = rand, b = rand, c = rand
if a>b&a>c
disp(‘a is the max’)
elseif b>a&b>c
disp(‘b is the max’)
else
disp(‘c is the max’)
end

循环控制break和continue

关键字break是强制跳转指令,用于跳出For或While循环。
注意,break只能迫使程序跳出一个循环体。
关键字continue用于结束一次循环,程序跳转至下一个循环。

%
Eps = 1; N = 1;
for iteration = 1:1000
Eps = Eps/2;
if (N+Eps)<=N
Eps = Eps*2;
break
end;
end;

iteration
Eps
eps(N)

%
Eps = 1; N = 1;
for iteration = 1:1000
Eps = Eps/2;
if (N+Eps) > N
continue
end;
Eps = Eps*2;
break;
end;

iteration
Eps
eps(N)

Switch-Case结构

根据一个公共的参数的不同取值来执行不同的命令。
格式:
switch expression
case test_expression-1
(commands-1)
case { test_expression2, test_expression3, … }
(commands-2)
otherwise
(commands-2)
end

expression必须是一个标量或一个字符串
一个case中可以同时包含多个参数,只要其一为True就被执行。
注意:多个参数必须写成单元数组形式。

% 例:
No = randi(5)
switch No
case 1
disp(‘the first’)
case {2, 3}
disp(‘the second or third’)
otherwise
disp(‘none’)
end;

Try-Catch结构

捕获程序执行过程中的错误,以便决定对错误的响应。
try
(commands-1)
catch
(commands-2)
end
在commands-1被执行中,如果没有错误,程序直接跳转至end语句。如果有错误就转到catch语句,进行commands-2。

% 例:
a = ones(3, 2)
b = eye(2) % change to eye(3), and run again
try
c = a*b;
catch
c = NaN;
disp(‘matrix dimensions are not comfortable’)
end
c

函 数

函数将相关的函数和命令集中在一个模块中,对复杂问题有很强的解决能力。函数可以理解为一个接受输入参数并输出计算结果的“黑箱”。

Matlab的函数类型:
 主函数(M文件函数)
 子函数(局部函数)
 嵌套函数
 私有函数
 重载函数
 匿名函数
 内联函数

M文件函数

edit mean % 在Editor窗口中打开M文件
edit humps % 查看M文件函数的格式和源代码
edit celldisp % ……

M函数文件的特点:

  1. M函数文件必须以关键字function开头,其后是输出变量、函数名和输入变量。(这些内容通常写在第一行,称为函数声明行)
  2. M函数文件的文件名必须与函数同名。
  3. M函数文件调用时,通常需要输入参数并返回输出参数。
  4. M函数文件中的变量不会在Matlab工作区显示;M函数文件内可以调用M脚本文件,此时M脚本文件所创建的变量全部为函数的内部变量,即不会出现在Matlab 工作区。
  5. 通常,M函数文件中没有关键字return,按顺序执行完所有语句后返回。如遇return语句,函数立即返回。

M函数文件的注释:

  1. 紧跟着声明行的为首行注释(H1),用于对函数功能的简要说明。
  2. 声明行和第一个执行语句之间的为帮助内容,运行help filename查看。

子函数

  1. M函数文件内部可以创建一个或多个子函数
  2. 子函数在主函数体后面定义,规则与M函数相同
  3. 子函数可以被主函数和其它子函数调用,但不能被外部文件直接调用
  4. 主函数和子函数有各自的工作区间,变量传递只能通过子函数的输入输出参数
  5. 子函数可以有注释,由help fun>subfun查看

% --------------------------------------------

function [avg, med] = myarray(u)
% use of subfunction
% to find mean & median of arrays

%% primary function definition
n = length(u);
avg = Mean(u, n);
med = Median(u, n);

%% subfunction-1 definition
function a = Mean(v, n)
% to calculate average.
a = sum(v)/n;

%% subfunction-2 definition
function m = Median(v, n)
% to calculate median.
w = sort(v);
if rem(n, 2) == 1
m = w((n+1) / 2);
else
m = (w(n/2) + w(n/2+1)) / 2;
end

嵌套函数

  1. 定义在M函数体中,可以有任意层嵌套。
  2. 主函数和嵌套函数必须用关键字end标明结束
  3. 嵌套函数有自己的工作区,还可以直接访问主函数中的变量。主函数也可以访问嵌套函数中的任何变量。

私有函数

  1. 保持在名为private的子目录中。(private目录不能加入搜索路径)
  2. 只要在直接父目录下的主函数才能调用私有函数

% …

内联函数
% 由函数inline创建

fun = inline( ‘2*sin(x)+1’, ‘x’)

fun(0)
fun(pi/2)

输入和输出参数

matlab函数对收入和输出参数的数目没有限制,但需要遵循下列规则:

  1. 函数可以没有输入输出参数。
  2. 调用时输入输出参数可以少于函数定义中的数目,但不能超出。
  3. 函数nargin和nargout可以确定调用时实际的输入输出参数数目。
  4. 函数执行时,输入参数存储在临时建立的函数工作区,函数执行结束后,该工作区将被清除。
  5. 如函数声明行将varargin作为输入参数,则函数调用时可以接受任意数目的输入变量。(varargin是预先定义的单元数组。)
  6. 如声明行中将varargout作为作为最后一个参数,在函数调用时可以接受任意多个输出变量。

%----------------------------------------------------------------------
function [ x y ] = fn ( a, b )
% 函数nargin/nargout的使用

%% 检测输入参数
if( nargin==0 )
beep;
disp(‘输入错误!正确的输入参数数目为1或2。’);
return % 输入错误,直接返回
end;

if( nargin == 1)
b = 0; % 缺省设置的第二个输入参数值
end;

%% 函数的主体
x = a + b ; % 计算第一个输出参数
if( nargout > 1 ) % 是否有第二个输出参数
y = a*b; % 计算第二个输出参数
end;

% ---------------------------------------------------------------------
function [r, varargout] = fv(a, varargin)
% 可变输入输出varargin/varargout的使用

%% 确定输入输出的参数数目
Nin = nargin-1;

if( nargout==0) Nout = 0; % 避免出现负数
else Nout = nargout - 1;
end;

% celldisp(varargin) % 显示单元体varargin的内容,test only

if( Nin<0)
disp(‘输入参数至少1个!’);
return;
end;

% 回显参数数目,test only
fprintf(‘输入参数共计%d个,可变输入参数%d个\n’, nargin, Nin);
fprintf(‘输出参数共计%d个,可变输出参数%d个\n’, nargout, Nout);

%% 函数的主体
r = a;

for i = 1:Nin
r = r + varargin{i}; % 提取(输入)单元体varargin内容
end;

% ……

for i = 1:Nout
varargout{i} = r + i; % 填写(输出)单元体varargou内容
end;

全局变量

如函数中一个变量被声明为global,则该变量可以被其它函数、Matlab工作区和函数自身反复调用。要访问global变量,在每个工作区都需声明。

全局变量会给程序调试带来困难,慎用。

  1. 采用函数输入输出变量传递参数,代替全局变量;
  2. 使用永久变量代替全局变量。

% ----------------------------------------------------------
function g1 (num)
% use of global variable

global globalvar

if nargin > 0
globalvar = num;
end

fprintf(‘Global variable in function %s is %d\n’, …
‘g1’, globalvar);

% another example
% -----------------------------------------------------
function mytic
% my version of tic

% start the timer
global StopWatch
StopWatch = clock;

% -----------------------------------------------------
function t = mytoc
% my version of toc

% read the timer
global StopWatch
if nargout < 1
elapsed_time = etime(clock, StopWatch)
else
t = etime(clock, StopWatch);
end

永久变量

函数中persistent变量,只能被声明该变量的函数调用,不能被其它函数或脚本调用。

% 了解Matlab的内存管理
% 内存管理函数:pack, inmem, mlock, mulock, mislocked
% clear all/functions 清除永久变量

% -----------------------------------------

function out = fpersistent
% 使用persistent变量:记录函数被调用的次数。

persistent p

if( isempty§ )
p = 1;
else
p = p+1;
end;

out = p;

命令/函数二元性

命令和函数的差异:
1) 命令没有输出参数。
2) 命令的输入参数直接跟在命令名的后面,而函数输入参数写在()内。

二元性:
如不要求输出参数,命令参数写成字符串放在()内,命令可视为函数调用。
如不要求函数的输出,且输入为字符串,函数也可以命令的方式调用。

% 下面的两条语句等同
clear functions
clear( ‘functions’ )

% 多参数同样适用
which -all sin
which(’-all’, ‘sin’)

% 命令不能有输出参数
info = which(’-all’, ‘sin’)
info = which -all sin %

% 查看info的内容
class(info)
info{2}
celldisp(info)

函数的传递

当需要将一个函数信息作为参数传递时,需要对函数进行标识。

早期的标识方法:
1)内联函数直接用函数名;
2)M函数用函数名字符串。

%上述是过时的标识方法,目前仍然可以使用。
% 现在推荐使用函数句柄进行标识。

fun = inline(‘sin(x)’, ‘x’)

quad( fun, 0, pi ) % quad积分函数

quad( ‘sin’, 0, pi )

函数句柄

函数句柄是Matlab定义的基本数据类型,其主要功能:
1) 用操作符@,创建和标志匿名函数。
2) 函数句柄记录一个函数(所有类型)的详细信息。(可由函数functions查看)
3) 可以标识子函数、私有函数和嵌套函数。

% @操作符
h = @sin
h(0), h(pi/2)

quad(h, 0, pi)
quad(@sin, 0, pi)

% 函数functions返回函数的详细详细
functions(@myfun)
functions(@sin)
functions(@mean)

% 例:获得子函数的句柄
% ------------------------------------------
function out = myfunhandle ( s )
% create and return subfunhandles

switch s
case 1
out = @sub1;
case 2
out = @sub2;
otherwise
out = [ ] ;
disp(‘undefined.’); %
end

%%
function y = sub1( x )
% Equ: y = x + 1
y = x + 1;

%%
function y = sub2( x )
% Equ: y = x*x
y = x.^2;

匿名函数(anonymous function)

匿名函数可以在命令行或M文件中创建。
创建格式:
function_handle = @(x1, x2, …) expression
@表示左边是一个函数句柄
x表示函数自变量
function_handle为标识该匿名函数的句柄

%
h = @(x) x.^2 + 1;
h(2)
h(1:5)

% 匿名函数定义中可以无输入参数
hn = @( )datestr(now, 31);
hn( ) % 正确的调用
hn % 仅返回函数句柄自身

% 函数句柄单元数组
% 书写格式同数组,写成紧凑格式。可以用()包含一个句柄。

a = { @(x)x.^2, @(x)sin(x), @(x, y)x+y }

a{1}(3)
a{3}(2, 5)

% 使用结构体

h = struct( ‘a’, @(x) x.^2, ‘b’, @sin )

h.a(1:5)
h.b(pi/2)

匿名函数中的变量

% 匿名函数创建中,可以调用任何Matlab函数,也可以使用当前工作区的变量。
a = 5;
h = @(x) a*sin(x)
h(pi/2)

% 注意:函数句柄只是捕捉创建匿名函数时引用的变量值。
%当变量值改变时,函数句柄不会发生变化。
a = 10;
h(pi/2)

% 如果程序中a值经常变化,可以定义多元匿名函数
h = @(x, a) a*sin(x)
h( pi/2, 10)

% 匿名函数的自变量可以写成向量形式%

f = @(x) [x(1)+1; x(2)+100 ]

f( [1, 2] )

% 例:创建计算下列积分的匿名函数

% 方法1:
c = 2;
f = @(x) (x.^2 + c*x + 1);
quad( f, 0, 1)

% 方法2:(多重匿名函数)
g = @© (quad(@(x) (x.^2 + c*x + 1), 0, 1));

g(2)

文件管理

% Matlab支持多种格式的文件读写。

help fileformats % 查看文件类型和相应的功能函数

% Matlab数据文件—save & load
% 命令save将Matlab工作区的变量存储为.mat格式的数据文件。
% 命令load将.mat文件中数据的导入工作区。
% 可以在Workspace窗口中直接操作。

a = eye(4)
b = ones(3,3,3)
save data00 b

% Excel文件—xlsread & xlswrite
% Office 2007文件需写扩展名.xlsx
% 可以在Current Folder窗口直接读取。

a = magic(5)
xlswrite(‘mydata.xlsx’, a);

data = xlsread(‘mydata.xlsx’)

% 其它:
% 二进制数据文件和格式化ASCII文件
% ……
% 联机文档HelpUsers’ GuideData Import and Export

Matlab界面中的路径和目录管理

Current Folder窗口的功能:
1) 查看、预览和搜索当前目录中的文件;
2) 检查当前目录中M文件的语法错误;
3) 设置Matlab搜索路径。

Workspace窗口的功能:
1) 查看工作区变量;
2) 查看堆栈中变量(调试模式下);
3) 在Viable Editor查看中修改变量内容。
4) save和load功能;
5) 快捷图形功能。

Matlab搜索路径管理:
1) File菜单Set Path下完成添加、删除、排序等操作。
2) 使用 组函数。

调试和优化

语法检查:mlint
代码调试:debug
程序剖析:profile
代码优化:
内存使用
向量化运算
JIT加速器

在程序执行中,出现的错误(bug)大致分为两类:

  1. 语法错误
  2. 运行错误

语法错误检查:

Matlab的mlint、mlintrpf函数可以检查代码的语法问题:

mlint * % 检查文件*.m
mlintrpt % 检查当前目录下的所有M文件。

% 在Matlab的Current Folder中,可以简便实现语法检查功能。
% Matlab新版本中推荐使用checkcode检查文法错误。

运行错误检查:

计算程序中,最常见的运行错误是计算结果出现Inf、NaN和 [ ]。

对于较简单的问题,可以使用以下的方法:
1) 将M函数中的一些分号去掉,在命令窗口中直接查看变量的值。
2) 在文件中添加disp、keyboard等语句,控制和查看程序执行的中间状态。
3) 将M函数先转换为M脚本,在Matlab工作区直接查看变量。

对于较复杂的问题,可以使用Matlab通过的Debug工具:

  1. Matlab提供了一组调试函数,利用doc debug可以查看这些函数用法和功能。
  2. 利用Editor/Debug图形化工具更为方便。

% 例:使用debug调试函数
% ------------------------------------------------

function avg = myfun( arg )
% demo of function’s debug.

x = arg/10;

y = 1./(x-0.55).^2;

avg = mean( y );

% …

程序剖析

程序剖析器(profiler)提供函数执行时间的报告,以便用户对代码进行优化。
剖析报告给出了函数运行的用时情况,包括子函数、每条语句的执行时间。

doc profile % 查看profile的功能

% 剖析函数myfun的使用
profile on % 开启剖析器
proftest ; %
profile off % 关闭剖析器
profsave % 将剖析结果以html格式保持

% 也可以直接点击Matlab桌面的图标进行函数剖析。

%% -------------------------------------------------------
% profile demo
% solve linear equ. ax=b and plot the residuals

%% define the coefficients.
a = rand(1000);
b = rand(1000,1);

%% solve the problem.
x1 = a\b;
x2 = inv(a)*b;

%% check the residuals.
r1 = ax1 - b;
r2 = a
x2 - b;

%% plot the results.
plot( [r1, r2] );
legend(‘direct mldivide’, ‘two-step’);

代码优化

  1. 预先分配数组内存。
  2. 变量赋值,程序中不要改变数据类型。
  3. 将复杂程序的功能分解为若干函数。
  4. 尽量使用向量化运算。
  5. 尽量使用JIT加速器。

% ---------------------------------------------------
% 是否预先分配数组内存的运行时间测试

%%
clear
tic
x = 0;
for i = 2:1000
x(i) = x(i-1) + 1;
end
t = toc;
fprintf(‘time = %f without preallcolated\n’, t);

%%
clear
tic
x = zeros(1, 1000); % preallocated memory
for i = 2:1000
x(i) = x(i-1) + 1;
end
t = toc;
fprintf(‘time = %f with preallocated\n\n’, t);

向量化运算

The MATLAB software uses a matrix language, which means it is designed for vector and matrix operations. You can often speed up your code by using vectorizing algorithms that take advantage of this design. Vectorization means converting for and while loops to equivalent vector or matrix operations.

Matlab中的很多函数支持向量化运算。
对于矩阵和多维数组,注意列优先原则。

!很多实际的问题是无法实现向量化运算的。
% 例:x(i+1) = x(i)+1;

% -------------------------------------------------------
% 向量化运算的时间测试
%%
clear
N = 1e4;
tic
% y = zeros(1,N); % jit@
for i = 1:N
y(i) = sin(i);
end;
t = toc;
fprintf(‘time = %f with for-loop\n’, t);

%%
clear
N = 1e4;
tic
y = sin(1:N);
t = toc;
fprintf(‘time = %f with vectorization\n\n’, t);

关于JIT加速器

使用JIT加速器(just-in-time accelerator)的条件:

1) For循环索引号是标量。
2) If, switch, while等语句只含标量操作。
3) 变量预先定义,过程中不改变数据类型。
4) 变量均已预先分配内存。
5) 数据类型:double, logical, char, <64bits-int。
6) 数组最高为三维。
7) 函数只能用内置函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值