Matlab程序设计

M文件基本操作

Matlab脚本文件是一系列的Matlab指令, 提供程序执行的流程控制, 和其他编程语言很相似. Matlab的脚本文件需要被保存为后缀名为.m的文件, 因此也称M文件.下面介绍一些脚本文件相关的操作.

新建文件.

在Matlab界面里左上角第一个选项即可进入新建脚本界面.新脚本的编辑界面可以停靠在Matlab界面里, 也可以独立存在.

image-20200628153412930

进入文件编辑窗口即可进行文件的编写. 这里先以以下代码为例, 对一些功能做介绍.

1
2
3
4
5
for i=10
x=linspace(0,10,101);
plot(x,sin(x+i));
print(gcf,'-deps',strcat('plot',num2str(i),'.ps'));
end

在编辑器内输入上述代码后, 点击运行即可执行上述代码, 代码保存时应该将其名称改为xxx.m.

image-20200628154146473

下面介绍一些Matlab脚本编辑器的常用功能.

  1. 注释.

    Matlab的注释以%开头, 和其他语言一样, 注释不参与执行, 只是使代码更加容易阅读的作用.为单独一行添加注释, 在该行前面加上%即可. 也可以选中你想要注释掉的代码, 在右键菜单里选择 注释, 快捷键是Ctrl+R.

    image-20200628154659648

  2. 分节.

    matlab中可以使用独占一行的%%两个百分号对代码进行分节. 对代码进行分节后, 可以选择单独一节执行, 而不必整个文件都参与执行. 在调试的过程中有着重要作用.

    image-20200628155044637

  3. 调试.

    鼠标点击行号后面的小横线, 即可把该行处设为断点.

    image-20200628155319995

    在未运行时,断电颜色是灰色的. 添加断点后, 点击运行,程序会运行至断点处停止, 此时可以去Matlab主窗口的工作区中查看相关变量的值是否满足预期估计, 对程序进行适当调整. 可以通过步进,继续来对程序运行进行控制.

    image-20200628155645965

  4. 智能缩进

    Matlab提供智能缩进功能, 让你的代码更加美观易读, 可以通过选中代码块,右键菜单中的智能缩进来实现, 也可以使用工具栏里提供的快捷键实现.

下面介绍一些程序编写时的小提示.

  1. clear all: 清除工作区变量, 防止当前工作区内变量和M文件中的变量发生冲突, 影响结果.
  2. close all: 关闭所有的图片, 在脚本执行过程中绘制的一些图片如果全部显示出来会显得很乱, 可以使用这条语句来关闭.
  3. ;:使用分号可以使当前语句的执行结果不显示, 使脚本执行过程中命令行窗口更整洁整洁.
  4. ...: 换行符, 写在一行不方便阅读时, 可以采用此符号来换行, 在下一行继续编辑即可. Matlab会把以...结尾的行和下一行认为是同一行.
  5. Ctrl+C: 这里的Ctrl+C和windows的不同, 和linux的相同, 终止正在运行的程序的意思.

M文件的流程控制

程序设计语言都会支持流程控制. 最基本的有顺序结构,选择结构,循环结构. 各种语言的流程控制都是大同小异, 基本就是语法上的区别, 在逻辑上都是相同的.

流程控制的关键字主要有一下这些.

  • if,elseif,else:选择满足条件的分支执行.
  • for,while: 循环结构.
  • switch,case,otherwise:选择满足条件的分支执行.
  • try,catch:尝试执行并捕捉错误.
  • break:用于跳出循环结构.
  • continue: 跳过当前层循环, 直接进行下一层循环.
  • end: 结束标志
  • return:函数返回值.

一些常用的比较和逻辑运算符有:<,>,<=,>=,==,~=,&&,||,需要注意的是关于不等于符号~=和C语言中有所不同.

if elseif else分支结构

判断分支的基本结构如下:

1
2
3
4
5
6
7
if condition1
statement1
elseif condition2
statement2
else
statement3
end

下面代码利用了判断分支结构实现了判断一个数是奇数还是偶数.

1
2
3
4
5
if rem(a,2)==0 % rem(a,b)是取余数的函数,rem(a,2)返回的是a对2的余数
disp('a is even') % disp()函数时显示输出函数. display的意思.
else
disp('a is odd')
end

把上述代码保存在Matlab中存储名称为test2.m, 在命令行窗口预设a的值, 再通过命令行窗口输入M文件名称的方式执行M文件.其执行结果如下图.

image-20200628162821227

在判断分支结构中,elseif ,else都是可选项.

switch

switch的使用方法和C语言一样, 其基本语法结构如下.

1
2
3
4
5
6
7
8
9
10
11
switch expression
case value1
statement1
case value2
statement2
.
.
.
otherwise
statement
end

举个例子:

1
2
3
4
5
6
7
8
9
10
switch input_m
case -1
disp('negative 1')
case 0
disp('zero')
case 1
disp('positive 1')
otherwise
disp('other value')
end

while循环

基本语法结构:

1
2
3
while expression
statement
end

下面例子使用while循环实现求小于1010010^{100}的最大的n的阶乘.

1
2
3
4
5
n=1;
while prod(1:n)<1e100 % prod()是product的意思, 这里prod(1:n)表示1一直连乘到n的意思,也就是n的阶乘.
%1e100是科学计数法的表示方法,也就是1*10^100的意思.
n=n+1;
end

执行结果如下:

image-20200628164250801


练习:

使用while循环计算1+2+3+…+999.

1
2
3
4
5
6
7
s=0;
a=1;
while a<=999
s=s+a;
a=a+1;
end
disp(s);

for循环

for循环的基本结构:

1
2
3
for variable=start:increment:end
commands
end

举个例子: 显示2n2^n

1
2
3
4
for n=1:10
a(n)=2^n;
end
disp(a)

其执行结果如下:

image-20200628165609689

变量的预声明

在上述代码的编写过程中, 会发现在变量a的下方 编辑器会用~做警告标识, 把鼠标放置在变量a上可以查看警告的详细信息.

image-20200628170113212

matlab提示我们对变量a预先分配内存.

下面通过两个例子来介绍什么是预先分配内存, 以及预先分配内存与不预先分配内存的区别.

1
2
3
4
5
6
7
tic %计时开始的标志
for ii=1:2000
for jj=1:2000
A(ii,jj)=ii+jj;
end
end
toc %计时结束的标志
1
2
3
4
5
6
7
8
tic %计时开始的标志
A=zeros(2000,2000); %预先声明一个2000行2000列的零矩阵
for ii=1:size(A,1) %size(A,1)返回矩阵的行数
for jj=1:size(A,2) % size(A,2)返回矩阵的列数
A(ii,jj)=ii+jj;
end
end
toc %计时结束的标志

上面两种代码的区别在于,code2预先声明了一个2000行2000列的零矩阵,在迭代过程中只是对矩阵的数值进行修改.那么两种写法的执行时间哪个更快呢?差距有多大?下图是这两段代码在我的笔记本电脑上的执行结果.

image-20200628171344510

其中test5_1对应code1,test5_2对应code2, 显然, code2的写法执行效率远高于code1.


练习:

用循环结构把矩阵A中的负数改变成0

A=[01491425344964]A=\left[\begin{array}{ccc} 0 & -1 & 4 \\ 9 & -14 & 25 \\ -34 & 49 & 64 \end{array}\right]

1
2
3
4
5
for a=1:(size(A,1)*size(A,2))
if A(a)<0
A(a)=0;
end
end

函数

脚本与函数都是包含matlab命令的M文件, 函数有着一些特定的语法结构.下面给出了函数与脚本的各自特点.

image-20200628203335148

可以使用edit(which('mean.m'))命令来查看matlab的内置函数mean()是如何编写的.下图以mean()函数的代码为例, 简要介绍matlab中函数的写法.

image-20200628203829784

首先,在函数的M文件的第一行代码function y=mean(x)中,function是关键字,带有function关键字的M文件就是一个函数文件, y是这个函数的输出值,也就是返回值, mean()是函数名,x是函数的输入变量名称, 在C语言中形参的作用.接下来是许多关于这个函数的功能, 用法的注释. 然后是正式的matlab代码, 也就是实现这个函数功能的代码部分.在写用户定义函数时, 我们只需仿照上述写法即可.需要注意几点:

  1. 关键字: function
  2. 函数名必须和文件名相同
  3. 输入和输出变量是可选项

例题:

写一个用户定义函数, 要求实现计算匀变速运动的最终位置, 其中起始位置是x0x_0,初速度是v0v_0,全程时间是tt,加速度为aa,通过输入上述四个参数, 实现计算物体最终位置.参考公式如下:

x=x0+v0t+12at2x=x_{0}+v_{0} t+\frac{1}{2} a t^{2}

参考代码:

1
2
3
4
5
6
7
function x=ybs(x0,v0,t,a)
% 计算匀变速运动的最终位置
% x0:物体的初始位置
% v0:物体的初速度
% t:物体的运动时间
% a:物体的加速度
x=x0+v0.*t+1/2*a.*t.*t;

在matlab的执行结果如下:

image-20200628210808951

需要注意的是, 上述代码中,计算公式的乘积运算有的地方使用了.*,回顾.**的区别可以发现, 在矩阵的数乘运算中没有区别, 在矩阵与矩阵相互 运算时才有区别.在上述代码中使用.*,即默认了这些变量都是向量形式, 在向量计算中,.*运算只是对应位置做相应的乘积运算.考虑到v0t变量可能是向量,所以这两个变量间的计算应该用.*形式, 以保证计算结果的正确性. 1/2与变量a之间是数乘运算, 因此使用*即可.可以对函数输入向量形式的参数进行验证.

image-20200628211439412

例题:

已知物体运动的初速度和末速度, 起始时间和终止时间, 以及物体的质量, 计算物体的平均加速度和所受外力的大小.

参考公式:

a=v2v1t2t1a=\frac{v_{2}-v_{1}}{t_{2}-t_{1}}

F=maF=ma

参考代码:

1
2
3
function [a, F]=acc(v2,v1,t2,t1,m)
a=(v2-v1)./(t2-t1);
F=m.*a;

执行结果:

image-20200628212810049


练习:

用函数实现以下功能, 输入一个华氏温度, 输出转换后的摄氏温度值, 要求执行函数后无限请求输入值, 当不输入任何值,直接按enter时,程序结束.

参考公式:

C=5/9×(F32)C=5/9 \times(F-32)

你可能会用到的函数:input, isempty,break,disp,num2str

尝试查询文档了解这些函数的用法.

1
2
3
4
5
6
7
function F2C
f=input('请输入华氏温度值:');
while ~isempty(f)
c=5/9*(f-32);
disp(['对应的摄氏温度是:',num2str(c)]);
f=input('请输入华氏温度值:');
end

参考运行结果:

image-20200628215137716


下面介绍一些Matlab默认的函数变量.

  • inputname: 函数输入的变量名称
  • mfilename: 当前正在运行的代码的文件名
  • nargin: 函数输入参数数目
  • nargout: 函数输出的参数数目
  • varargin: 可变长度输入参数列表
  • varargout: 可变长度输出参数列表

函数句柄(function handles)

函数句柄可以通过一行代码来表达一个函数 ,而不需要定义一个M文件. 下面的代码中就用到了函数句柄.

1
2
3
f=@(x) exp(-2*x);
x=0:0.1:2;
plot(x,f(x));

第三行代码中使用了函数f(x),这里的f(x)就相当于第一行代码中的exp(-2*x).通过函数句柄的方式, 不需要建立一个M文件, 就可以定义一个函数.

资料链接

参考视频 参考讲义