MATLAB快速入门(七)
一.简介
本篇参考官方入门文档编写
前提准备:
- MATLAB
二. 快速入门(七)
1. 创建网格图和曲面图
关于网格图和曲面图
MATLAB® 在 x-y 平面中的网格上方使用点的 z 坐标来定义曲面图,并使用直线连接相邻的点。mesh
和 surf
函数以三维形式显示曲面图。
mesh
生成仅使用颜色来标记连接定义点的线条的线框曲面图。surf
使用颜色显示曲面图的连接线和面。
MATLAB 通过将索引的 z 数据值映射到图窗颜色图来标记曲面图颜色。
可视化包含两个变量的函数
要显示包含两个变量的函数 z = f (x,y),
- 在此函数的域中,生成分别由重复行和重复列组成的
X
和Y
矩阵。 - 使用
X
和Y
计算此函数并绘制其图形。
meshgrid
函数将一个向量或两个向量(即 x
和 y
)指定的域转换为矩阵 X
和 Y
,以便用于计算包含两个变量的函数。X
的行是向量 x
的副本,Y
的列是向量 y
的副本。
绘制正弦函数
尝试此示例Copy Command Copy Code
此示例说明如何计算和绘制 x 和 y 方向之间的二维 sinc
函数 sin(R)/R。R 是距原点的距离,原点在矩阵的中心。添加 eps
(非常小的值)可防止网格图在 R = 0
处的点出现孔洞。
1 | [X,Y] = meshgrid(-8:.5:8); |
默认情况下,MATLAB 使用当前颜色图来标记网格图颜色。
彩色曲面图
尝试此示例Copy Command Copy Code
此示例说明如何将 sinc
函数绘制为曲面图,指定颜色图并添加颜色栏以便显示数据与颜色的映射。
曲面图与网格图相似,但曲面图的矩形面是彩色的。各个面的颜色由 Z
的值及颜色图(即颜色的有序列表)决定。
1 | [X,Y] = meshgrid(-8:.5:8); |
将曲面图设置为透明
尝试此示例Copy Command Copy Code
此示例展示如何将曲面图的面设置为不同透明度。透明度(称为 alpha 值)可以针对整个对象进行指定,也可以基于 alphamap
(其作用方式与颜色图类似)进行指定。
1 | [X,Y] = meshgrid(-8:.5:8); |
MATLAB 显示一个面 alpha 值为 0.4 的曲面。Alpha 值的范围介于 0(完全透明)和 1(不透明)之间。
使用灯光照亮曲面图
尝试此示例Copy Command Copy Code
本示例展示的曲面图与前面示例所用的曲面图相同,但将其设置为红色,并删除了网格线。然后会在“相机”(相机即为您观察曲面图所处的空间位置)左侧添加一个灯光对象:
1 | [X,Y] = meshgrid(-8:.5:8); |
光照是使用定向光源照亮对象的技术。在特定情况下,此技术能够更清楚地显示曲面图形状的细微差异。光照还可用于增添三维图形的真实感。
操作曲面图
图窗工具栏和相机工具栏提供了以交互方式浏览三维图形的方法。通过从图窗视图菜单中选择相机工具栏可以显示相机工具栏。
下图显示选择了三维旋转工具的两个工具栏。
这些工具使您能围绕曲面图对象移动相机、缩放、添加光照并执行其他查看操作,而不需执行其他命令。
2. 显示图像
图像数据
您可以将二维数值数组显示为图像。在图像中,数组元素决定了图像的亮度或颜色。例如,加载一个图像数组及其颜色图:
1 | load durer |
加载文件 durer.mat
,向工作区添加三个变量。数组 X
是一个 648×509 矩阵,map
是作为此图像的颜色图的 128×3 数组。
MAT 文件(例如 durer.mat
)是用于提供保存 MATLAB® 变量的方法的二进制文件。
X
的元素是介于 1 和 128 之间的整数,用作颜色图 map
的索引。要显示图像,请使用 imshow
函数:
1 | imshow(X,map) |
重新生成阿尔布雷特•丢勒的蚀刻板画。
读取和写入图像
使用 imread
函数可以读取标准图像文件(TIFF、JPEG、PNG 等)。imread
返回的数据类型取决于读取的图像类型。
使用 imwrite
函数可以将 MATLAB 数据写入到各种标准图像格式。
3. 打印图形
打印概述
可以在与计算机连接的打印机上直接打印 MATLAB® 图窗,也可以将图窗导出到 MATLAB 支持的某种标准图形文件格式。打印和导出图窗有两种方法:
- 使用文件菜单下的打印、打印预览或导出设置 GUI 选项。
- 使用
print
命令即可通过命令行来打印或导出图窗。
使用 print
命令可以更好地控制驱动程序和文件格式。使用“打印预览”对话框可以更好地控制图窗大小、比例、位置和页面标题。
从“文件”菜单打印
文件菜单下包含两个与打印相关的菜单选项:
- 打印预览选项可显示一个对话框,用于在预览输出页面时设置要打印的图窗的布局和图窗样式,您可以从此对话框打印图窗。此对话框包含以前包含在“页面设置”对话框中的选项。
- 打印选项可显示一个对话框,用于选择打印机、选择标准打印选项和打印图窗。
使用打印预览可以确定打印输出是否符合您的要求。点击“打印预览”对话框上的帮助按钮将显示如何设置页面的信息。
将图窗导出到图形文件
文件菜单中的导出设置选项可打开一个 GUI,用于设置要保存为图形文件的图窗的文本大小、字体和样式等图形特征。“导出设置”对话框用于定义和应用模板以便自定义和标准化输出。设置之后,您可以将图窗导出为多种标准图形文件格式,例如 EPS、PNG 和 TIFF。
使用 Print 命令
print
命令为发送给打印机的输出类型提供了更大灵活性,并且允许您通过函数和脚本文件来控制打印。结果可以直接发送到默认打印机,也可以存储在特定的输出文件中。可以使用多种输出格式,包括 TIFF、JPEG 和 PNG。
例如,此语句将当前图窗窗口的内容作为 PNG 图形存储在名为 magicsquare.png
的文件中。
1 | print -dpng magicsquare.png |
要以屏幕上的图窗的同等大小保存图窗,请使用下列语句:
1 | set(gcf,'PaperPositionMode','auto') |
要将同一图窗存储为 TIFF 文件(分辨率为 200 dpi),请使用以下命令:
1 | print -dtiff -r200 magicsquare.tiff |
如果在命令行中键入 print
1 |
将在默认打印机上打印当前图窗。
4. 处理图形对象
图形对象
图形对象是用于显示图形的基本元素。这些对象按层次结构组织,如下图所示。
当调用绘图函数时,MATLAB® 使用各种图形对象(例如,图窗窗口、轴、线条、文本等)创建图形。每个对象都具有一组固定的属性,您可以使用这些属性控制图形的行为和外观。
例如,以下语句使用变量 y 中的数据创建条形图,并设置关于条形显示方式的属性:
1 | y = [75 91 105 123.5 131 150 179 203 226 249 281.5]; |
常见图形对象
当调用函数以便创建图形时,MATLAB 会创建图形对象的层次结构。例如,调用 plot
函数会创建下列图形对象:
- 图窗 - 包含轴、工具栏、菜单等的窗口。
- 轴 - 包含表示数据的对象的坐标系
- 线条 - 代表传递至
plot
函数的数据值的线条。 - 文本 - 用于轴刻度线和可选标题及注释的标签。
不同类型的图形使用不同对象来表示数据。由于存在许多种图形,因此也存在许多数据对象类型。其中一些用于一般用途,例如线条和矩形,还有一些是用于高度专业的用途,例如误差条、颜色栏和图例。
访问对象属性
绘图函数可返回用于创建图形的对象。例如,以下语句将创建一个图形并返回由 plot
函数创建的线条对象:
1 | x = 1:10; |
使用 h
来设置线条对象的属性。例如,设置它的 Color
属性。
1 | h.Color = 'red'; |
此外,也可以在调用绘图函数时指定线条属性。
1 | h = plot(x,y,'Color','red'); |
可以查询线条属性以便查看当前值:
1 | h.LineWidth |
查找对象的属性
要查看对象的属性,请输入:
1 | get(h) |
MATLAB 将返回包含对象属性及当前值的列表。
要查看对象属性及可能的值信息,请输入:
1 | set(h) |
设置对象属性
可使用 set
函数一次设置多个属性。
设置现有对象的属性
要对多个对象的同一属性设置相同值,请使用 set
函数。
例如,下面的语句绘制一个 5×5 矩阵(创建五个线条对象,每列各一个),然后将 Marker
属性设置为正方形,并将 MarkerFaceColor
属性设置为绿色。
1 | y = magic(5); |
在本示例中,h
是一个包含五个句柄的向量,图形中的每个线条(共五个)各一个句柄。set
语句将所有线条的 Marker
和 MarkerFaceColor
属性设置为相同值。
要对一个对象设置属性值,请对句柄数组建立索引:
1 | h(1).LineWidth = 2; |
设置多个属性值
如果要将每个线条的属性设置为不同值,您可以使用元胞数组存储所有数据,并将其传递给 set
命令。例如,创建绘图并保存线条句柄:
1 | figure |
假定您要为每个线条添加不同标记,并使标记的面颜色与线条的颜色相同。您需要定义两个元胞数组,一个包含属性名,另一个包含属性所需的值。
prop_name
元胞数组包含两个元素:
1 | prop_name(1) = {'Marker'}; |
prop_values
元胞数组包含 10 个值:Marker
属性有 5 个值,MarkerFaceColor
属性有 5 个值。请注意,prop_values
是一个二维元胞数组。第一个维表示值应用于 h
中的哪个句柄,第二个维表示值分配给哪个属性:
1 | prop_values(1,1) = {'s'}; |
MarkerFaceColor
始终分配到相应线条的颜色的值(通过获取线条 Color
属性获得)。
定义元胞数组之后,调用 set
以便指定新属性值:
1 | set(h,prop_name,prop_values) |
用于处理对象的函数
此表列出了处理对象时常用的函数。
函数 | 用途 |
---|---|
allchild |
查找指定对象的所有子级。 |
ancestor |
查找图形对象的前代。 |
copyobj |
复制图形对象。 |
delete |
删除对象。 |
findall |
查找所有图形对象(包括隐藏句柄)。 |
findobj |
查找具有指定属性值的对象的句柄。 |
gca |
返回当前轴的句柄。 |
gcf |
返回当前图窗的句柄。 |
gco |
返回当前对象的句柄。 |
get |
查询对象的属性的值。 |
ishandle |
如果值是有效对象句柄,则为 True。 |
set |
设置对象的属性的值。 |
传递参数
可定义专用绘图函数以简化自定义图形的创建过程。通过定义函数,可以像 MATLAB 绘图函数一样传递参数。
下面的示例显示了一个 MATLAB 函数,该函数在输入参数 x
指定的范围中计算数学表达式,然后绘制结果。第二次调用 plot
函数会将结果的 mean
值绘制为红线。
该函数基于计算值修改 y 轴刻度。加入轴标签和标题后,即完成了图形自定义。
1 | function plotFunc(x) |
定义输入参数的值,并调用此函数。
1 | x = -10:.005:40; |
查找现有对象的句柄
findobj
函数可用于通过搜索具有特定属性值的对象来获取图形对象的句柄。使用 findobj
,您可以指定任何属性组合的值,这样可以方便地从多个对象中选取一个对象。此外,findobj
还可识别正则表达式。
查找特定类型的所有对象
由于所有对象都具有标识对象类型的 Type
属性,因此可以查找特定对象类型的所有匹配项的句柄。例如,
1 | h = findobj('Type','patch'); |
查找所有补片对象的句柄。
查找具有特定属性的对象
您可以指定多个属性以便缩小搜索范围。例如,
1 | plot(rand(5),'r:') |
查找所有红色点线的句柄。
1 | h = |
限制搜索范围
通过将起始图窗或轴的句柄作为传递的第一个参数,您可以在对象层次结构中指定起点。例如,
1 | h = findobj(gca,'Type','text','String','\pi/2'); |
仅在当前坐标区中查找 π/2。
5. 控制流
条件控制 - if、else、switch
条件语句可用于在运行时选择要执行的代码块。最简单的条件语句为 if
语句。例如:
1 | % Generate a random number |
通过使用可选关键字 elseif
或 else
,if
语句可以包含备用选项。例如:
1 | a = randi(100, 1); |
再者,当您希望针对一组已知值测试相等性时,请使用 switch
语句。例如:
1 | [dayNum, dayString] = weekday(date, 'long', 'en_US'); |
对于 if
和 switch
,MATLAB® 执行与第一个 true 条件相对应的代码,然后退出该代码块。每个条件语句都需要 end
关键字。
一般而言,如果您具有多个可能的离散已知值,读取 switch
语句比读取 if
语句更容易。但是,无法测试 switch
和 case
值之间的不相等性。例如,无法使用 switch
实现以下类型的条件:
1 | yourNumber = input('Enter a number: '); |
条件语句中的数组比较
了解如何将关系运算符和 if
语句用于矩阵非常重要。如果您希望检查两个变量之间的相等性,您可以使用
1 | if A == B, ... |
这是有效的 MATLAB 代码,并且当 A
和 B
为标量时,此代码会如期运行。但是,当 A
和 B
为矩阵时,用 A == B
不会测试二者是否相等,而会测试二者相等的位置;结果会生成另一个由 0 和 1 构成的矩阵,并显示元素与元素的相等性。
1 | A = magic(4); |
检查两个变量之间的相等性的正确方法是使用 isequal
函数:
1 | if isequal(A, B), ... |
isequal
返回 1
(表示 true
)或 0
(表示 false
)的标量逻辑值,而不会返回矩阵,因此能被用于 if
函数计算表达式。通过使用上面的 A
和 B
矩阵,您可以获得
1 | isequal(A,B) |
下面给出另一示例来重点介绍这一点。如果 A
和 B
为标量,下面的程序永远不会出现“意外状态”。但是对于大多数矩阵对(包括交换列的幻方矩阵),所有元素均不满足任何矩阵条件 A > B
、A < B
或 A == B
,因此将执行 else
子句:
1 | if A > B |
有几个函数对减少标量条件的矩阵比较结果以便用于 if
非常有用,这些函数包括
1 | isequal |
循环控制 - for、while、continue、break
此部分涵盖为程序循环提供控制的 MATLAB 函数。
for
for
循环按预先确定的固定次数重复一组语句。匹配的 end
用于界定语句结尾:
1 | for n = 3:32 |
内部语句的终止分号禁止了循环中的重复输出,循环后的 r
显示最终结果。
最好对循环进行缩进处理以便于阅读,特别是使用嵌套循环时:
1 | for i = 1:m |
while
while
在逻辑条件的控制下将一组语句重复无限次。匹配的 end
用于界定语句结尾。
下面是一个完整的程序,用于演示如何使用 while
、if
、else
和 end
来寻找区间对分法求多项式的零。
1 | a = 0; fa = -Inf; |
结果生成多项式 x3 - 2x - 5 的根,即
1 | x = |
在 if
语句部分中讨论的与矩阵比较相关的注意事项同样适用于 while
语句。
continue
continue
语句将控制传递给它所在的 for
循环或 while
循环的下一迭代,并跳过循环体中的任何其余语句。此道理同样适用于嵌套循环中的 continue
语句。也就是说,执行会从遇到 continue
语句的循环开头继续。
下面的示例演示的 magic.m
循环计算文件中的代码行数目的 continue
循环,并跳过所有空行和注释。continue
语句用于前进到 magic.m
中的下一行,而不会在遇到空行或注释行时增加行计数:
1 | fid = fopen('magic.m','r'); |
break
break
语句用于提前从 for
循环或 while
循环中退出。在嵌套循环中,break
仅从最里面的循环退出。
下面对前述部分中的示例进行了改进。使用此 break
的优点是什么?
1 | a = 0; fa = -Inf; |
程序终止 - return
此部分包含用于在程序运行完成之前终止程序的 MATLAB return
函数。
return
return
终止当前命令序列,并将控制权返回给调用函数或键盘。此外,return
还用于终止 keyboard
模式。被调用的函数通常在到达函数末尾时将控制权转交给调用它的函数。您可以在被调用的函数中插入一个 return
语句,以便强制提前终止并将控制权转交给调用函数。
向量化
提高 MATLAB 程序的运行速度的一种方法是向量化构造程序时所使用的算法。其他编程语言可使用 for
循环或 DO
循环,而 MATLAB 可使用向量或矩阵运算。下面提供了一个与创建算法表相关的简单示例:
1 | x = 0.01; |
相同代码段的向量化版本为
1 | x = .01:.01:10; |
对于更复杂的代码,向量化选项并不总是这么明显。
预分配
如果无法向量化某段代码,可以通过预分配存储输出结果的任何向量或数组来提高 for
循环的运行速度。例如,此代码使用函数 zeros
来预分配在 for
循环中创建的向量。这显著提高了 for
循环的执行速度:
1 | r = zeros(32,1); |
如果未经过上述示例中的预分配,MATLAB 解释器会在每次遍历循环时将 r
向量增大一个元素。向量预分配避免了此步骤,并提高了执行速度。
6. 脚本和函数
概述
MATLAB® 提供了一个强大的编程语言和交互式计算环境。您可以使用此语言在 MATLAB 命令行中一次输入一个命令,也可以向某个文件写入一系列命令,按照执行任何 MATLAB 函数的相同方式来执行这些命令。使用 MATLAB 编辑器或任何其他文件编辑器可以创建您自己的函数文件。按照调用任何其他 MATLAB 函数或命令的相同方式来调用这些函数。
两种程序文件:
- 脚本,不接受输入参数或返回输出参数。它们处理工作区中的数据。
- 函数,可接受输入参数,并返回输出参数。内部变量是函数的局部变量。
如果您是新 MATLAB 程序员,您只需在当前文件夹中创建您希望尝试的程序文件。当您创建的文件越来越多时,您可能希望将这些文件组织到其他文件夹和个人工具箱,以便将其添加到您的 MATLAB 搜索路径中。
如果您复制多个函数名称,MATLAB 会执行在搜索路径中显示的第一个函数。
要查看程序文件(例如,myfunction.m
)的内容,请使用
1 | type myfunction |
脚本
当调用脚本时,MATLAB 仅执行在文件中找到的命令。脚本可以处理工作区中的现有数据,也可以创建要在其中运行脚本的新数据。尽管脚本不会返回输出参数,其创建的任何变量都会保留在工作区中,以便在后续计算中使用。此外,脚本可以使用 plot
等函数生成图形输出。
例如,创建一个名为 magicrank.m
的文件,该文件包含下列 MATLAB 命令:
1 | % Investigate the rank of magic squares |
键入语句
1 | magicrank |
使 MATLAB 执行命令、计算前 30 个幻方矩阵的秩,并绘制结果的条形图。执行完文件之后,变量 n
和 r
将保留在工作区中。
函数
函数是可接受输入参数并返回输出参数的文件。文件名和函数名称应当相同。函数处理其自己的工作区中的变量,此工作区不同于您在 MATLAB 命令提示符下访问的工作区。
rank
提供了一个很好的示例。文件 rank.m
位于文件夹
1 | toolbox/matlab/matfun |
您可以使用以下命令查看文件
1 | type rank |
下面列出了此文件:
1 | function r = rank(A,tol) |
函数的第一行以关键字 function
开头。它提供函数名称和参数顺序。本示例中具有两个输入参数和一个输出参数。
第一个空行或可执行代码行前面的后续几个行是提供帮助文本的注释行。当键入以下命令时,会输出这些行
1 | help rank |
帮助文本的第一行是 H1 行,当对文件夹使用 lookfor
命令或请求 help
时,MATLAB 会显示此行。
文件的其余部分是用于定义函数的可执行 MATLAB 代码。函数体中引入的变量 s
以及第一行中的变量(即 r
、A
和 tol
)均为函数的局部变量;他们不同于 MATLAB 工作区中的任何变量。
本示例演示了 MATLAB 函数不同于其他编程语言函数的一个方面,即可变数目的参数。可以采用多种不同方法使用 rank
函数:
1 | rank(A) |
许多函数都按此方式运行。如果未提供输出参数,结果会存储在 ans
中。如果未提供第二个输入参数,此函数会运用默认值进行计算。函数体中提供了两个名为 nargin
和 nargout
的数量,用于告知与函数的每次特定使用相关的输入和输出参数的数目。rank
函数使用 nargin
,而不需要使用 nargout
。
函数类型
MATLAB 提供了多种不同函数用于编程。
匿名函数
匿名函数是一种简单形式的 MATLAB 函数,该函数在一个 MATLAB 语句中定义。它包含一个 MATLAB 表达式和任意数目的输入和输出参数。您可以直接在 MATLAB 命令行中定义匿名函数,也可以在函数或脚本中定义匿名函数。这样,您可以快速创建简单函数,而不必每次为函数创建文件。
根据表达式创建匿名函数的语法为
1 | f = @(arglist)expression |
下面的语句创建一个求某个数字的平方的匿名函数。当调用此函数时,MATLAB 会将您传入的值赋值给变量 x
,然后在方程 x.^2
中使用 x
:
1 | sqr = @(x) x.^2; |
要执行 sqr
函数,请键入
1 | a = sqr(5) |
主函数和局部函数
任何非匿名函数必须在文件中定义。每个此类函数文件都包含一个必需的主函数(最先显示)和任意数目的局部函数(位于主函数后面)。主函数的作用域比局部函数更广。因此,主函数可以从定义这些函数的文件外(例如,从 MATLAB 命令行或从其他文件的函数中)调用,而局部函数则没有此功能。局部函数仅对其自己的文件中的主函数和其他局部函数可见。
函数部分中显示的 rank
函数就是一个主函数的示例。
私有函数
私有函数是一种主函数。其特有的特征是:仅对一组有限的其他函数可见。如果您希望限制对某个函数的访问,或者当您选择不公开某个函数的实现时,此种函数非常有用。
私有函数位于带专有名称 private
的子文件夹中。它们是仅可在母文件夹中可见的函数。例如,假定文件夹 newmath
位于 MATLAB 搜索路径中。newmath
的名为 private
子文件夹可包含只能供 newmath
中的函数调用的特定函数。
由于私有函数在父文件夹外部不可见,因此可以使用与其他文件夹中的函数相同的名称。如果您希望创建您自己的特定函数的版本,并在其他文件夹中保留原始函数,此功能非常有用。由于 MATLAB 在标准函数之前搜索私有函数,因此在查找名为 test.m
的非私有文件之前,它将查找名为 test.m
的私有函数。
嵌套函数
您可以在函数体中定义其他函数。这些函数称为外部函数中的嵌套函数。嵌套函数包含任何其他函数的任何或所有组成部分。在本示例中,函数 B
嵌套在函数 A
中:
1 | function x = A(p1, p2) |
与其他函数一样,嵌套函数具有其自己的工作区,可用于存储函数所使用的变量。但是,它还可以访问其嵌套在的所有函数的工作区。因此,举例来说,主函数赋值的变量可以由嵌套在主函数中的任意级别的函数读取或覆盖。类似地,嵌套函数中赋值的变量可以由包含该函数的任何函数读取或被覆盖。
全局变量
如果您想要多个函数共享一个变量副本,只需在所有函数中将此变量声明为 global
。如果您想要基础工作区访问此变量,请在命令行中执行相同操作。全局声明必须在函数中实际使用变量之前进行。全局变量名称使用大写字母有助于将其与其他变量区分开来,但这不是必需的。例如,在名为 falling.m
的文件创建一个新函数:
1 | function h = falling(t) |
然后,以交互方式输入语句
1 | global GRAVITY |
通过上述两条全局语句,可以在函数内使用在命令提示符下赋值给 GRAVITY
的值。然后,您可以按交互方式修改 GRAVITY
并获取新解,而不必编辑任何文件。
命令与函数语法
您可以编写接受字符参数的 MATLAB 函数,而不必使用括号和引号。也就是说,MATLAB 将
1 | foo a b c |
解释为
1 | foo('a','b','c') |
但是,当使用不带引号的命令格式时,MATLAB 无法返回输出参数。例如,
1 | legend apples oranges |
使用 apples
和 oranges
作为标签在绘图上创建图例。如果您想要 legend
命令返回其输出参数,必须使用带引号的格式:
1 | [legh,objh] = legend('apples','oranges'); |
此外,如果其中任一参数不是字符向量,必须使用带引号的格式。
小心
虽然不带引号的命令语法非常方便,但在某些情况下可能会出现使用不当的情形,而 MATLAB 并不会产生错误信息。
在代码中构造字符参数
带引号的函数格式可用于在代码中构造字符参数。下面的示例处理多个数据文件,即 August1.dat
、August2.dat
等。它使用函数 int2str
,该函数将整数转换为字符以便生成文件名:
1 | for d = 1:31 |