一、Matlab简介
Matlab名字来源于“矩阵实验室”缩写,是美国MathWorks公司推出的一套以矩阵计算为基础的数学软件。它提供了丰富可靠的矩阵运算、图形绘制、数据处理等功能,可以实现数值分析、优化、统计、微分方程求解、信号处理、图像处理等的计算和图形显示,可解决工程、科学计算和数学学科中许多问题。因此,被广泛应用于自动控制、图像信号处理、生物医学工程、语音处理、信号分析、时间序列分析与建模、优化设计等领域。
Matlab功能强大、简单易学、编程效率高,几乎可以完成所有的数学建模的编程需要,是数学建模必备软件。
![](https://pic3.zhimg.com/80/v2-389e48c82c2b22b767fb92387b513836_720w.jpg)
图1 Matlab 2015a操作界面
![](https://pic2.zhimg.com/80/v2-cb639e2d0a3c005291346045f57cc2a1_720w.jpg)
:设置当前路径,访问当前路径下的文件,只需相对路径即可;
Current
Folder:显示当前路径下的文件;
Command
Windows:命令窗口,一般用来调试逐段代码;
Workspace:工作空间,显示当前内存变量;
Command
History:命令历史窗口,可以选中部分代码,右键创建M-文件。
![](https://pic2.zhimg.com/80/v2-c2666f1584480bb0cb926494c77c1825_720w.jpg)
:打开代码编辑窗口,创建、编辑、运行M-文件。
![](https://pic1.zhimg.com/80/v2-6d886de95103ad5946ca1a5ea3987fcc_720w.jpg)
二、基础语法
1.
变量
命名规则:字母开头,任意字母、数字、下划线的组合,尽量避免与Matlab自带名称冲突;
变量直接起名,赋值使用即可;
特殊变量:eps——浮点数 的误差限;
pi——π
inf或Inf——正无穷大;
NaN——非数,例如洛必达法则的未定式;
i或j——虚数单位,故要尽量避免用i或j作为循环变量;
ans——存储未赋值的运算结果
syms x y——声明符号变量x, y
2.
基本函数
sin, cos, tan,
cot, asin, acos, atan——三角函数与反三角函数;
exp(x)——e
x
log2, log, log10——以2, e, 10为底的对数函数;
sqrt, abs——平方根,绝对值
floor, ceil,
fix, round——取整函数,分别是向负无穷、正无穷、向0取整和四舍五入
3.
基本格式与算符
format short/long/rat/hex——设置短浮点(4位小数)、长浮点(15位小数)、分数、十六进制显示
format short e——短浮点×10的幂次显示,如pi=3.1416e+00
+-*/^\——算术运算符:加、减、乘、除、乘幂、左除
== ~= < > <= >=——关系运算符:等于、不等于、小于、大于、小于等于、大于等于
& | ~——逻辑运算符:与、或、非
4.
学会使用帮助
help 或doc 函数名
二、Matlab向量化编程思想
Matlab是以向量、矩阵为基本元素的,所以要编写真正的Matlab程序必须抛弃“C语言那种单数值、元素化考虑问题”的思路,转以向量、矩阵为最小单位来考虑问题。也就是说,Matlab的编程思想是——向量化编程,即面向向量或矩阵。
这样做的好处,至少有两个:
(1) 代码大大简化,易编程、清晰可读性强;
(2) 执行效率也更高。
下面针对Matlab中常见的向量化处理问题方法,举例加以说明:
1. 整体操作“大块数据”
Matlab为同型的数据块(向量或矩阵)的整体做运算提供了“点运算”。
比如,A.*C 和 A./C 表示A与C的对应位置的各元素做 * 和 / 运算得到与它们同型的一个新矩阵。
例1 物理实验利用测得的电压电流具体数据,验证欧姆定律R=U/I.
代码1(C语言风格)
U = [0.89, 1.20, 3.09, 4.27, 3.62, 7.71, 8.99, 7.92, 9.70, 10.41]; I = [0.028, 0.040, 0.100, 0.145, 0.118, 0.258, 0.299, 0.257, 0.308, 0.345]; L = length(U); S = 0; for k = 1:L R(k) = U(k)/I(k); S = S + R(k); end R = S/L
运行结果:R = 30.5247
代码1’(Matlab风格)
U = [0.89, 1.20, 3.09, 4.27, 3.62, 7.71, 8.99, 7.92, 9.70, 10.41]; I = [0.028, 0.040, 0.100, 0.145, 0.118, 0.258, 0.299, 0.257, 0.308, 0.345]; R = U./I; R = mean(R)
运行结果:R = 30.5247
2. 尽量把“C语言风格的循环”向量化实现
例2 计算1 + 1/3 + … + 1/99
代码2(C语言风格)
s = 0; for k=1:2:99 s = s + 1/k; end s
运行结果:s = 2.9378
代码2’(Matlab风格)
k=1:2:99; s = sum(1./k)
运行结果:s = 2.9378
注意:代码2’中,不要写成 “for k=1:2:99”, 否则k就是变化的一个数值而不是向量。
例3. 用间距为0.1的水平线和垂直线均匀分割x∈[-5,5]×[-2.5,2.5]的矩形域,在所有水平线和垂直线交点上计算函数z=sin|xy|的值,并图示。
(1)求出各网格点的函数值
代码3(C语言风格)
x=-5:0.1:5; y=(-2.5:0.1:2.5)'; N=length(x); M=length(y); for ii=1:M for jj=1:N X0(ii,jj)=x(jj); Y0(ii,jj)=y(ii); Z0(ii,jj)=sin(abs(x(jj)*y(ii))); end end
代码3’ (Matlab风格)
[X,Y]=meshgrid(-5:0.1:5, -2.5:0.1:2.5); Z=sin(abs(X.*Y));
(2) 画图
surf(X,Y,Z) %画三维图形 xlabel('x') %标记坐标轴 ylabel('y') shading interp %用插值处理色彩 view([190,70]) %旋转一定角度观看图形
运行结果:
![](https://pic3.zhimg.com/80/v2-362b3daf5356daa4b8c49d89c6738f26_720w.jpg)
3. 尽量使用Matlab现成的“矩阵操作语法、矩阵函数或工具箱”
Matlab提供了大量非常便捷的矩阵操作语法、矩阵函数、以及各种工具箱,优先使用它们来完成程序。
操作矩阵的函数,比如
[m n]=size(A)——返回矩阵A的“型”,m行n列
length(A)——返回行数或列数中最大的那个
mean(A)——返回A中所有元素平均值
sum(A)或sum(A,1)——返回A各列元素之和,各行之和用sum(A,2)
[Y I] = max(A)——Y=A各列元素的最大值; I=各列最大值所在行
sort(A)——矩阵各列按递增排序,递减排序加参数 ‘descend’
unique(A)——返回矩阵A中不重复的值(去掉重复元素)
等等………..这些函数已经实现了通常所需要的各种操作,所以完全没有必要再去按C语言的思路去自己重写代码。
==================================================
2.矩阵运算技巧:
Matlab里面应该多用向量运算,把循环语句转变为向量运算会省很多时间,程序也更简洁易读。
如,一个名叫array数组里面,你要将里面大于1的都变成0,就不必用到循环:
方法一:利用布尔索引。
array(array>1)=0;
%把大于1小于3的变成0。
array(and(array>1,array<3))=0;
方法二:find函数
array=rand(1,100);
[m n]=find(array>0.5);
array(n)=0;
%%
array=rand(1,100);
[mn]=find(array>0.5&array<0.7);
array(n)=0;
方法3: 重视eval函数的应用,可以方便的把string表达式转化为命令语句执行,而且是唯一可以同时申请多变量的函数语句:
for i=1:5
string=strcat('a',num2str(i),'=','magic','(',num2str(i),')')
eval_r([string])
end
=======================================
3.MATLAB 里面加快程序运行速度的方法。
1. 向量化。养成看到for就浑身不舒服的本能反应。
2. 矩阵如果太大了会爆内存则千万别向量化,老老实实用循环吧。有些3-4纬的矩阵,用循环处理起来甚至快一些。
3. 循环竖着走比横着走快。
4. 不少内置函数都有大量的error check。直接用profiler找出真正干活的。
5. 不少内置函数在网上都有人提供了更快的版本的,当然功能弱一些,正好符合提速的需求。
6. 视情况,有时可以把变量强行变成single,速度暴增。
7. 利用copy on write的特点,丢进函数的变量能不对其修改就不要修改。
8. matlab就是个高级计算器,不要拿干来处理文件,往数据库里塞数据这种活。eval, object之类的东西能别碰就别碰,尽量保持着every is an array of double的模式。
9. 不要把代码全塞到一行。不但难看有时候还慢一些。
1. 循环向量化
2. 利用函数的矩阵输入功能批量处理
3. 必须用for且费时的地方改成单层parfor,要是循环次数比cpu核数还少反而会拖慢程序
4. 非常大的矩阵的运算可以用gpuArray(这个在matlab 深度学习工具箱中深有体会)
5. 能用矩阵不要用cell,速度慢且占内存巨多
6. 对调用频繁且费时的地方尝试生成c ,写成mex
7. 按编译器提示先初始化矩阵大小(但我大部分时候还是懒得预先算矩阵大小…)
8. Matlab 是可以多开的,如果parfor不能改或者懒得改可以“人肉parfor”,也就是把一个for拆成几段然后多开几个matlab 一起执行,最后再合并结果,比较暴力哈哈
9. 费时的程序最后加个email发送程序,跑完直接把结果发邮箱里
2.用句柄函数
搜索也很费事,所以多用句柄函数和内在函数
搜索速度如下:
句柄函数>内在函数>当前目录函数>其它目录函数
调用方法:
比如
ans=feval('@fun',传入变量1,....)
比
ans=fun(args)
运行速度快的多
编译的时候,句柄函数会直接把路径给内存了,不会执行全路径搜索
3.pre-allocation提高运算速度
虽然matlab是动态语言,但是【预先分配变量】可以明显提高运算速度。
例如:section1中预定义了A = zeros() ,比 section2 的运算速度快了近40倍。
![](https://pic4.zhimg.com/80/v2-6ae664016c59231424d22d4fdab73257_720w.jpg)
4.arrayfun 函数
1. 关于向量化
大家都知道,如果用一个函数对一个矩阵中的每一个元素进行求值,那么就要用到 .*, ./之类
function r = fmat(x)
r = x.^2 + 1./x;
end
A = [1 2 3 4];
fmat(A)
上面这样就可以做到用fmat对A每一个元素分别求值。但不是所有的函数都像fmat这样,下面这种情况就不行:
function r = fmat2(x)
if x > 0
r = x.^2;
else
r = 1./x;
end
fmat2(A) % 会出错
可以看到,因为上面fmat2 里面有判断语句,就不能把整个矩阵作为输入参数。我知道的解决方法有3种:
=======================================
值得说一说的是第二种和第三种。arrayfun只是比用for更加简洁,速度上没有太大差别。但是,用逻辑矩阵的话,就比前两种快10倍。逻辑矩阵是向量化的利器。比如 A>0 就会返回一个逻辑矩阵,里面全是1, 0 。并且, 逻辑矩阵可以当作索引, A(A>0) 就把所有A>0 的数返回。
5. 类型转换
matlab中一共有4种类型:func(函数句柄), num(数值), sym(符号), str(字符)
- 在数值运算中,使用func, num
- 需要输入输出出,要用到str
- 进行符号运算(符号微分,积分)时,用sym
我们使用matlab,一般有这么个过程:
- 先进行公式推导,这时要用sym, symfun类型
- 再进行数值计算,这里要用普通的func, 和num 类型
- 最后与GUI界面交互的时候,要用str类型
这里介绍几个用于转换的函数
str2func('@(x,y)sin(x*y)') % str -> @func 返回一个函数句柄 syms x y fs(x,y) = x^2+sin(x*y); fh=matlabFunction(fs); % symfun -> @func 返回一个函数句柄 !!!强烈推荐 fh = @(x)x.^2+sin(x); fun2str(fh) % @func ->str 函数句柄变为字符
6. 三维画图
作图第一步,对 x, y 划分网格,用的是 meshgrid 。这样画出来的图在一个立方体的范围内,但是有时候我们要显示一个圆柱体内的三维图形这时候画网格可以用 cylinder
[x, y] = cylinder(linspace(0,10,100),200);
% linspace(0,10,100)指在半径[0, 10]上划分为100份,参数200指的是在圆周方向上 200等分
z = sin(x) + cos(y);
mesh(x, y, z);
7.如何在Matlab中使用等待栏?
想需要为一段时间的操作准备一个等待栏?这是代码:
h = waitbar(0,'Please wait...'); for i=1:counterend waitbar(i/waitbarcounter) Atemp = At+i*step; handle = @(M) 1/M^2*((2/(gamma+1))*(1+(gamma-1)*M^2/2))^((gamma+1)/(gamma-1))-(Atemp/At)^2; Mach = fzero(handle, 5); Aplot(i) = Atemp/At; Tplot(i) = Tc / (1+(gamma-1)*Mach^2/2); Mplot(i) = Mach; plot(Aplot, Tplot) end close(h)
8. 如何设置程序错误断点?
在程序开头 加上一句命令: dbstop if error
可以把这个命令写在主函数最开头,免得每次跑程序都要在命令窗口敲多麻烦
如果运行出现错误,matlab会自动停在出错的那行,并且保存所有相关变量。再也不用设断点了。如果再配合两把宝剑,会更好用:dbup 和 dbdown。这两个命令在程序错误并断点之后在命令行输入,用于在workspace间切换查看变量调试。dbup是跳到上层workspace,dbdown是返回。
bsxfun
强大的、万能的、不同维数的矩阵扩展混合运算,从此告别矩阵运算中的for循环
另,matlab里所有以fun为后缀的命令都很好用,arrayfun,cellfun,structfun,等等
@() 匿名函数
使用函数式编程,在编写以数学公式为主的程序中比传统编程方法好得多
set(gca,...)等
所有与画图相关的命令都包含了千奇百怪的属性和参数,非常实用,如著名的 set(gca,...)
$ $
画图中的标题、注释等文字内容是可以直接使用latex格式的,只须在包含latex命令的部分前后用$框起来即可
slice
高维切片,要在三维空间中表现三个以上变量的函数关系,必备此命令
9 巧用eval函数
1. eval
当处理海量数据,进行计算分析的时候,你就需要打开不同文件夹提取和保存数据。这种情况下,eval函数可以大大提高程序的灵活性。如下:input文件夹下有10个子文件夹a1,a2,...,a10,没个文件夹下都有3个mat文件:Press_l,X_l和Y_l。分别读取数据并对其进行处理,然后输出结果文件:XL_l和Patch_l。代码如下:
clear
clc
number=10;%文件数
%创建输出文件夹 C:\Z目录下output文件夹
system('mkdir C:\Z\output')
for i=1:number %打开不同文件夹下相同的数据
eval(['load C:\Z\input\a',num2str(i),'\Press_l.mat']);
eval(['load C:\Z\input\a',num2str(i),'\X_l.mat']);
eval(['load C:\Z\input\a',num2str(i),'\Y_l.mat']);
...%计算过程 要输出结果 XL_l 和 Patch_l
...
name=['mkdir C:\Z\output\a',num2str(i)];%在同一目录下生成输出文件
system(name);%生成C:\Z\output目录下a*文件夹
str1=['C:\Z\output\a',num2str(i),'\XL_l.mat'];
str2=['C:\Z\output\a',num2str(i),'\Patch_l.mat'];
eval(['save ',str1,' XL_l']);
eval(['save ',str2,' Patch_l']);
end
可能有人要说了,我的文件夹名字不规律,怎么办。简单,将你的文件夹名字存到一个cell数组内,然后调用胞元就可以了。代码如下:
clear
clc
str={'a1','b2','c3','d4','e5'};
number=size(str,2);%文件数
%创建输出文件夹 C:\Z目录下output文件夹
system('mkdir C:\Z\output')
for i=1:number %打开不同文件夹下相同的数据
eval(['load C:\Z\input\',str{1,i},'\Press_l.mat']);
eval(['load C:\Z\input\',str{1,i},'\X_l.mat']);
eval(['load C:\Z\input\',str{1,i},'\Y_l.mat']);
...%计算过程 要输出结果 XL_l 和 Patch_l
...
name=['mkdir C:\Z\output\' str{1,i}];%在同一目录下生成输出文件
system(name);%生成C:\Z\output目录下a*文件夹
str1=['C:\Z\output\',str{1,i},'\XL_l.mat'];
str2=['C:\Z\output\',str{1,i},'\Patch_l.mat'];
eval(['save ',str1,' XL_l']);%输出XL_l
eval(['save ',str2,' Patch_l']);%Patch_l
end
可能还有人说了,我的文件夹太多,不能一一列举出来怎么办?也好办,用dir函数读取目录下的所有文件夹的名字就可以了。代码如下:
clear
clc
filename=dir('C:\Z');
number=size(filename,1);%文件数
%创建输出文件夹 C:\Z目录下output文件夹
system('mkdir C:\Z\output')
for i=1:number %打开不同文件夹下相同的数据
eval(['load C:\Z\input\',filename(i,1).name,'\Press_l.mat']);
eval(['load C:\Z\input\',filename(i,1).name,'\X_l.mat']);
eval(['load C:\Z\input\',filename(i,1).name,'\Y_l.mat']);
...%计算过程 要输出结果 XL_l 和 Patch_l
...
name=['mkdir C:\Z\output\' filename(i,1).name];%在同一目录下生成输出文件
system(name);%生成C:\Z\output目录下a*文件夹
str1=['C:\Z\output\',filename(i,1).name,'\XL_l.mat'];
str2=['C:\Z\output\',filename(i,1).name,'\Patch_l.mat'];
eval(['save ',str1,' XL_l']);%输出XL_l
eval(['save ',str2,' Patch_l']);%Patch_l
end
怎么样,是不是好用到哭!你以为eval函数的功能仅此而已的话,那你又错了!例如,经常会遇到需要求解带参数的方程,而且该方程不能显示表达。如公式:,k取一系列的值(1~100),求相应的自变量x的值。代码如下:
clc
clear
sym x %定义符号变量
K=1:1:100; %参数赋值
number=size(K,2);
X=zeros(number,1); %定义输出结果
for i=1:number
k=K(i);
str=['x^3+',num2str(sqrt(k)),'*x^(1/2)-',num2str(k),'^2'];
a=solve(str,'x','Real', true);
eval(a)
X(i,:)=ans;
end
eval函数的妙用绝不仅仅是这些,当你要重复做一些事的时候,变量名稍有些不同,动一动脑筋,eval函数一般都能解决
size:获取数组的行数和列数
length:数组长度(即行数或列数中的较大值)
numel:元素总数。
快捷键:
ctrl + C: 中断正在跑的程序
ctrl + R: 多行注释
ctrl + T: 多行去除注释
ctrl + i : 自动缩进对齐
shift + TAB: 多行向右缩进
TAB: 自动补全
清理
>> clc % 清空Command Window
>> close all % 关闭所有图片窗口
>> close(h) % 关闭图片窗口h (e.g., h = figure(1))
>> clf % 清理当前图片窗口
>> clear % 清空所有变量
>> clear var1 var2 % 清理变量var1 var2 (注意用空格分隔)
>> clearvars -except var3 var4 % 理除var3 var4以外的全部变量
close all;clear all;clc;关闭之前所有图片;清除所有变量;清除命令行窗口为空白。在程序开头写上这三句话有助于新程序不受之前代码影响。
ctrl+i:排版选中的代码。ctrl+h:替换变量。ctrl+r:批量注释代码。ctrl+t:批量恢复已注释代码。
%:注释。%%+解释:声明以下代码为整体。…:续行,一行代码过长,可在中间写…,下一行接着写。
surf:画三维图片,加“shadding interp”图片更好看,加“colorbar”图片结果含义更清楚。imagesc:surf的二维形式,在需要复制结果图时候复制这个函数的图,要不然复制surf的图有可能会使MATLAB死机。
saveas:surf后加这句话可将图片保存至指定目录。
isnan和isinf:找矩阵中nan和inf。
find:找矩阵特定值,[row,col]=find(a==1),返回矩阵a中所有1的行和列。
plotyy:一张figure画两种坐标刻度的曲线。
set:set(gcf,)设置figure属性,set(gca,)设置坐标轴属性,set(gch,)设置句柄属性。在代码最后一行随便加句话,断点设置在此,运行就停在这里,鼠标放在哪个变量上就可以看到该变量值。
查询
[注意] help, doc, edit 命令也可用于自定义函数,其帮助程度取决于该自定义函数的注释规范程度
>> help matlab_fun % Matlab内置函数matlab_fun的帮助(简略)
>> doc matlab_fun % Matlab内置函数matlab_fun的说明文档(详细)
>> edit matlab_fun % 打开内置函数matlab_fun的script (source code)
>> pwd % 当前文本路径
>> which some_fun % 找出build-in函数或自定义函数的具体路径
>> class(var) % 获取变量var的类型
>> dir() % 当前路径下的所有文件
>> dir(’some_path\’) % 某路径下的所有文件
>> dir(’some_path\*.m’) % 某路径下所有的matlab文件(同理,.jpg, .csv文件等等)
杂的
>> addpath(genpath(pwd)) % 添加当前目录的所有子目录到搜索路径中
% 程序运行完毕后提示音
>> beep on;
>> for i = 1:1e3; end % script: 运行完毕后有提示音
>> beep
% 程序运行时间
>> tic
>> for i = 1:1e3; end % script 运行时间
>> t = toc
% 程序运行出错时停止
>> dbstop if error
>> MyScript % MyScript中的函数出错时,停止在错误处,而不是返回错误并且中断
1,which命令,可以找到命令所在的具体路径
例如:
>> which fft built-in (D:\MATLAB\R2008b\toolbox\matlab\datafun\@logical\fft) % logical method
另外,新版的matlab在命令行双击tab能自动补全。
2,获得一个变量的类型,用class函数
例如:
>> class([0 1]) % double >> class('test') % char
进度条+完成提示音。
h = waitbar(0,'Text'); %进度条
for i=1:100
pause(.1);
waitbar(i/100);
end
close(h);
beep; % 提示音
如何加快运算速度以及书写可读性?
1.尽量调用matlab已有函数,相信我,你不会比它写得好的
2.凡是需要重复计算的内容,写成子程序然后调用,这一点非常重要!
3.能矩阵运算就不要for循环,能用parfor时更佳
4.点乘运算真是太方便了
5.三个点让代码换行,让代码更简洁
6.多用空格分开变量,如 x = 5;相信我,写多了之后,代码更好看
7.不同区域用 %% 分块,爽得不能呼吸
8.system函数,调用外部软件,如OpenSees,很好用!
设置运行完后自动关机:
system('shutdown -s -t 900 -f')
放在程序最后一句的位置,然后去睡觉
采用doc命令获得详细的帮助文档
如输入:doc sort