说明
仅记录个人需要部分,仅作个人使用
Ref:《Matlab编程基础与工程应用》(ISBN:978-7-111-57391-3)
一、预备知识
本文假设读者熟悉C++、Python的基本语法,假设读者了解简单的数学知识。
二、基本语法
2.1 句法结构
Matlab程序由语句组成,语句允许嵌套(类同C++中的$a=1,b=2;$、$a+=(b+=c);$等),语句间由空白($space,tab,enter$及其组合)分隔。
Matlab语句可分为有值语句和无值语句(类同C++中$a=1$是有值的,$break$是无值的)。
Matlab中语句结尾可用零个或一个分号,因此不必区分表达式与语句(C++中语句=表达式+分号),唯一区别是不带分号的有值语句会实时显示结果。
Matlab中续行符、单行注释符、多行注释符分别使用$...,\%,\%\{\cdots\%\}$,相当于C++中的$\backslash,//,/*\cdots */$。
Matlab中支持命令行编程和$.m$文件编程,相当于Python中的命令行编程和$.py$文件编程。
Matlab中支持显式类型转化与隐式类型转化,显式类型转化类同Python中的$int(a)$,但不允许在目标类型外加小括号(Python允许$(int)(a)$)。
2.2 变量相关
Matlab是弱类型语言,变量无需声明即可使用,且可在不同时段指代不同类型,语法类同Python。
Matlab合法变量名与C++规则完全类似,除了不能以下划线开头。
Matlab数据类型可以分为基本数据类型和复合数据类型。
基本数据类型包括:整数($int8,int16,int32,int64,uint8,uint16,uint32,uint64$)、实数($single,double$)。
复合数据类型包括:矩阵、广义矩阵(元胞)、字符串、结构体。
Matlab中也有命题类型(称作$logical$,类同C++中的$bool$),允许用非零值和零值分别表示真命题和假命题,允许在代码中使用$true$和$false$(只能全部小写),但默认存储为$logical$类型的$1$和$0$。
2.3 矩阵
Matlab中的矩阵相当于C++中的数组,矩阵可以有任意有限维,但通常只使用到二维。
Matlab中所有单个的基本数据都能看作$1\times 1$矩阵,为叙述方便有时也称$1\times n$矩阵、$n\times 1$矩阵为行向量、列向量,后文不再区分。
矩阵的生成:
①列举法(分号或回车分行,逗号或空白分列)
1 I=[1 0 0;0 1 0;0 0 1]; 2 X=[1,2,3 3 4,5,6 4 7,8,9];
②冒号表达式
的 表达式$a:b$返回$1\times max\{0,b-a+1\}$矩阵$[a,a+1,a+2,\cdots,b],a,b\in Z$
的 表达式$a:k:b$返回$1\times max\{0,\lfloor\frac{b-a}{k}\rfloor+1\}$矩阵$[a,a+k,a+2k,\cdots,a+rk],a,b,k\in R,r\in N$,其中$a+rk\le b$且$a+(r+1)k>b$
③构造函数
的 $linspace(a,b,n)$返回$1\times n$线性等差矩阵$[a,a+\frac{b-a}{n},a+\frac{2(b-a)}{n},\cdots,b],a,b\in R,n\in N^{*}$
的 $logspace(a,b,n)$返回$1\times n$对数等比矩阵$[10^{a},10^{a+\frac{b-a}{n}},10^{a+\frac{2(b-a)}{n}},\cdots,10^{b}],a,b\in R, n\in N^{*}$
的 $eye(n)$返回$n\times n$单位矩阵
的 $ones(n,m)$返回$n\times m$全$1$矩阵
的 $zeros(n,m)$返回$n\times m$全$0$矩阵
的 $pascal(n)$返回$n\times n$帕斯卡矩阵($a_{ij}=C_{i+j-2}^{i-1}=C_{i+j-2}^{j-1}$)
的 $magic(n)$返回$n\times n$矩阵,所有元素是$1,2,3,\cdots,n^{2}$的一个排列,且各行各列的和均为$\frac{n(n^{2}+1)}{2}$
的 $rand(n,m)$返回$n\times m$随机矩阵,元素范围为$(0,1)$
的 $randn(n,m)$返回$n\times m$随机矩阵,随机数服从$N(0,1)$
的 $randi(M,n,m)$返回$n\times m$随机矩阵,元素范围为${1,2,3,\cdots,M}$
的 $randperm(n)$返回$1\times n$随机矩阵,所有元素是$1,2,3,\cdots,n$的一个排列
的 $diag(A)$返回$1\times n$矩阵,元素取自矩阵$A$的主对角线(即$a_{i1}=A_{ii}$)
的 $tril(A)$返回由$A$得到的下三角矩阵(右上角置零)
的 $triu(A)$返回由$A$得到的上三角矩阵(左下角置零)
矩阵的访问:
矩阵访问使用索引访问,索引使用单个圆括号(方括号已被用于矩阵的表示)内添加逗号分隔的每个维度下标组成的行向量或列向量,返回原矩阵的子矩阵,注意$Matlab$中下标从$1$而非$0$开始。例如,访问矩阵$A=[1,2,3;4,5,6;7,8,9]$中所有行第三列的元素,使用$A([1:3],[3])$,返回$[3;6;9]$,注意因为单个基本类型和零维矩阵等价,所以其中的$[3]$也可写为$3$,即$A(3,[2,3])$。如果矩阵在某一维取所有的下标,可以用单个冒号代替行列向量,如对前述的$A$使用$A([1,3],:)$,返回$[1,2,3;7,8,9]$。
矩阵的扩展:
矩阵可以扩展为更高维度,对$n$维矩阵超过$n$的维度访问并赋值,会自动扩展矩阵的维度,没有被访问赋值的元素默认初始值为零。例如,对矩阵$A=[1,2;3,4]$使用$A(1,[1,2],3)=[4,5]$,会把矩阵$A$扩展为三维,第一层是$[1,2;3,4]$,第二层是$[0,0;0,0]$,第三层是$[4,5;0,0]$。
当我对上述三维矩阵尝试使用$[[1,2;3,4];[0,0;0,0];[4,5;0,0]]$生成时,会发现得到的结果为二维矩阵$[1,2;3,4;0,0;0,0;4.5;0,0]$而非三维矩阵,进一步测试发现$[[2],[[[3,3]]]]$的结果为$[2,3,3]$。对此我认为可以这么理解,$Matlab$中的矩阵默认是二维的,中括号只是一个运算符,作用相当于强制类型转换为矩阵,这就能解释为什么在一个矩阵外面嵌套任意有限多个中括号,值均不变。
对于零元素很多的矩阵,$Matlab$提供了一种节省内存的存储方法,即只存储非零元素的值和位置,称作稀疏矩阵。使用$sparse(R,C,V,n,m)$返回$n\times m$稀疏矩阵,向量$R,C,V$对应元素分别表示非零元素的行下标、列下标和值,$R,C,V$同时缺省时矩阵没有非零元,$m,n$缺省时自动选取最小的行和列。例如$sparse([1,1,2],[3,2,1],[1,4,2],3,3)$生成的矩阵为$[0,4,1;2,0,0;0,0,0]$。稀疏存储和完全存储的矩阵可以直接进行运算。
2.4 广义矩阵
矩阵同C++的数组类似,要求每个元素类型相同,但Matlab也允许元素类型不同的广义矩阵,也称作元胞。将矩阵的中括号改为大括号,便能得到元胞。
元胞的生成:
①列举法(分号或回车分行,逗号或空白分列)
1 A={\'Hello World\',[2:4:10];13,[1;2]} 2 B={{2,3} 5 3 [23,4] \'23\'}
②赋值法(矩阵也可以类似生成,不过没有必要)
1 a(1,1)={[1,2,3]} 2 a(1,2)={\'hello\'} 3 a(2,1)={[0:1:2]} 4 a(2,2)={18} 5 %a={[1,2,3],\'hello\';[0:1:2],18}
③构造函数
的 $cell(d_{1},d_{2},\cdots,d_{r})$返回$d_{1}\times d_{2}\times\cdots d_{r}$空广义矩阵。特别地,若$r=1$,返回$d_{1}\times d_{1}$空广义矩阵。
元胞的访问:
元胞访问使用索引访问,获取子元胞的规则和矩阵类似,使用圆括号加逗号分隔的下标向量。
1 a={{2,3},{3,4};{5},{1,2,3}} 2 b=a(2,2) 3 %b={{1,2,3}}
每个嵌套最底层的元胞都是一个矩阵(见后文元胞的扩展),而又可以通过索引访问矩阵的子元素,因此对元胞连用两次括号便能得到矩阵子元素,不过Matlab规定以此法访问两个括号分别使用大括号和小括号,访问结果仍是元胞。
1 a={{2,3},{3,4};{5},{1,2,3}} 2 b=a{2,2}(3) 3 %b={[3]}
元胞的扩展:
元胞扩展规则与矩阵相同,访问超出当前大小的部分自动扩展,且默认补齐空元胞。
与2.3中类似地使用${{1,2;3,4};{0,0;0,0};{4,5;0,0}}$得到二维元胞,但使用${{2},{{{3,3}}}}$却得到${{2},{3,3}}$而非矩阵中类似的${2,3,3}$。对此可以得到这样一种理解,矩阵的元素均为矩阵,元胞的元素均为元胞,但矩阵可以再分,可以通过逗号直接拼接成一个矩阵,而元胞不可再分(矩阵$[2,3]$中有两个元素,但元胞${{2,3}}$中只有一个元素),中括号相当于强制类型转化为矩阵,大括号相当于强制类型转化为元胞,矩阵嵌套任意有限多次结果不变,但元胞嵌套最内层默认不可再分(元胞${{2,3}}$中只有一个元素${[2,3]}$,但元胞${2,3}$相当于${{[2]},{[3]}}$有两个元素),嵌套最底层的元胞都是一个矩阵,因此元胞可看作矩阵的另一种扩展。
2.5 矩阵操作
数学函数:
的 三角、反三角函数($sin(),cos(),tan(),cot(),sec(),csc(),asin(),acos(),atan(),acot(),asec(),acsc()$)
的 双曲、反双曲函数($sinh(),cosh(),tanh(),coth(),sech(),csch(),asinh(),acosh(),atanh(),acoth(),asech(),acsch()$)
的 幂、指数、对数函数($exp(),log(),log2(),log10(),sqrt(),pow2(),realpow(,),reallog(),realsqrt(),nextpow2()$)
的 $realpow(A,B)$传入两个矩阵,对应元素作幂运算
的 $nextpow2(A)$传入矩阵,对每个元素$a$取结果$\lceil log_{2}a\rceil$
1 a=[1 2;3 4]; 2 b=nextpow2(a); 3 %b=[0 1;2 2]
复数函数($abs(),angle(),real(),conj(),complex(,)$):
的 $angle(A)$传入复矩阵,对每个元素取弧度制辐角
的 $conj(A)$传入复矩阵,对每个元素取共轭
的 $complex(A,B)$传入两个实矩阵,对应元素分别作为复数的实部和虚部
整数函数($fix(),round(),floor(),ceil(),sign(),rem(,),mod(,)$):
的 $fix()$向零取整,$round()$向最近的整数取整;$rem(,)$返回值符号为正,$mod(,)$返回值符号与第二个参数相同
1 a=[11 -13;17 -19]; 2 b=[3 3;-3 -3]; 3 c=rem(a,b); 4 d=mod(a,b); 5 %c=[2 -1;2 -1] 6 %d=[2 2;-1 -1]
矩阵函数($size(),length(),ndims(),numel(),cat(,,,\cdots,),disp(),reshape()$):
的 $size()$返回矩阵各维度尺寸组成的向量,$length()$返回各维度尺寸的最大值,$ndims()$返回矩阵维数,$numel$返回矩阵元素数
的 $cat(n,A_{1},A_{2},\cdots,A_{m})$合并$m$个矩阵,$n=1$时返回$[A_{1};A_{2};\cdots;A_{m}]$,$n=2$时返回$[A_{1},A_{2},\cdots,A_{m}]$,$n=3$时扩展为三维
1 a=[1 2;3 4]; 2 b=[5 6;7 8]; 3 c=cat(1,a,b); 4 d=cat(2,a,b); 5 e=cat(3,a,b); 6 %c=[1 2;3 4;5 6;7 8] 7 %d=[1 2 5 6;3 4 7 8] 8 %e(:,:,1)=[1 2;3 4] 9 %e(:,:,2)=[5 6;7 8]
矩阵运算:
的 $\',inv(),^,*,+,-,/,\backslash,det(),rank(),eig(),trace()$
矩阵分解($chol(),lu(),svd(),qr()$):
的 $chol(A)$传入正定矩阵,进行$Cholesky$分解,返回上三角矩阵$R$,使得$A=R*R\'$
的 $lu(A)$传入方阵,进行$LU$分解,返回三个矩阵$[L,U,P]$,使得$A*P=L*U$
的 $svd(A)$传入方阵,进行奇异值分解,返回三个矩阵$[U,S,V]$,使得$A=U*S*V,UU\'=U\'U=VV\'=V\'V=E$且$S$是对角元素降序排列的非负对角矩阵
的 $qr(A)$传入方阵,进行正交三角分解,返回两个矩阵$[Q,R]$,使得A=Q*R$且$Q$是正交矩阵,$R$是和$A$大小相同的上三角矩阵
稀疏存储:
的 $sparse(A)$传入矩阵,转化为稀疏存储;$full(A)$传入矩阵,转化为完全存储
的 $speye(n)$返回$n\times n$单位稀疏矩阵
2.6 字符串
字符串是特殊的$1\times n$矩阵,但不大区分字符和字符串的差别(类似Python),最小单元也是字符串。
Matlab中字符串有两种类型,$char$和$string$,不加声明时系统默认选择$char$存储。
Matlab中字符串支持单引号和双引号的混用,规则类同Python。
字符串生成:
①列举法(单引号列举默认存储为$char$类型,双引号列举默认存储为$string$类型,二者可以显示类型转化)
1 a=\'23\' 2 b="23" 3 %class(a)=\'char\' 4 %class(b)=\'string\' 5 %expression a==b equals true
②构造函数
的 $blanks(n)$生成$1\times n$全由空格组成的字符串,存储方式为$char$
的 $deblank(s)$传入字符串,返回$s$删除尾部空格后的字符串,存储方式与$s$相同
的 $upper(s)$传入字符串,返回$s$大写全部字母后的字符串,存储方式与$s$相同
的 $lower(s)$传入字符串,返回$s$小写全部字母后的字符串,存储方式与$s$相同
的 $strcat(s_{1},s_{2},\cdots,s_{r}$传入若干字符串,返回水平拼接的字符串,参数中有$string$时以$string$存储,否则以$char$存储
的 $strvcat(s_{1},s_{2},\cdots,s_{r}$传入若干字符串,返回$r\times 1$字符串矩阵,存储方式为$char$
字符串访问:
因为字符串本质上就是矩阵,所以访问方式与矩阵的索引访问相同。
字符串存储方式:
1 a=[\'23,\'233\'] 2 %a=[\'23233\'\' 3 b=[\'23\',"233"] 4 %b=["23","233"] 5 c=["23",\'233\'] 6 %c=["23","233"] 7 d=["23","233"] 8 %d=["23","233"] 9 10 x=int32(\'abc123\') 11 %x=[97,98,99,49,50,51] 12 y=double(\'abc123\') 13 %y=[97,98,99,49,50,51] 14 z=int32("abc123") 15 %Syntax Error 16 w=double("abc123") 17 %w=NaN
上述结果可以归纳出,$char$存储方式与$string$存储方式最大的不同点在于,$char$类型可以再分而$string$类型不可再分。换言之,$string$类型相当于将所含字符封装为一个整体。两个$char$用逗号隔开,逗号的作用是拼接(相当于C++中$string$类型的加号),而两个$string$或一个$char$一个$string$用逗号隔开,只发生在矩阵中列举两个元素,且存储方式会全部使用$string$。$char$类型字符串可以按$Unicode$编码将每个字符转化为数值类型,但$string$类型不支持。
2.7 结构体
Matlab中的结构体类同C++的$struct$,但由于Matlab是弱类型语言,在使用时直接赋值便可生成。
结构体生成:
①赋值法
1 student.name=\'Linda\' 2 student.age=9 3 student.ID=\'001\' 4 student.sex=\'female\'
的 结构体也可以作为矩阵的元素,形成结构体数组,生成方法相同。
1 student(1).name=\'Linda\' 2 student(1).sex=\'female\' 3 student(2).name=\'Sam\' 4 student(2).sex=\'male\'
②构造函数
的 $struct(c_{1},\{ v_{1}\},c_{2},\{ v_{2}\}\cdots,c_{r},\{ v_{r}\})$返回字段类型分别为$c_{1},c_{2},\cdots,c_{r}$、字段值分别为$v_{1},v_{2},\cdots,v_{r}$的结构体
结构体访问:
单个结构体的访问方式使用点,与C++相同。
因为结构体数组本质上就是矩阵,所以访问方式与矩阵的索引访问相同。
2.8 常量相关
Matlab中常量定义使用$global$,相当于C++中的$const$,但不能同时声明和赋值,赋初始值只能分成两个语句。
1 global e 2 e=exp(1)
固定变量:
的 $ans$返回最近一次没有赋值给其他变量的操作结果,仅限于命令行编程(即如果一个操作没有赋值,会默认赋值给$ans$)
的 $i$或$j$返回虚数单位
的 $pi$返回圆周率
的 $eps$返回浮点数相对精度,值约为$2.2204e-16$
的 $Inf$或$inf$返回无穷大
的 $nan$或$NaN$返回不定值
的 $realmax$返回最大正浮点数,值约为$1.7977e308$
的 $realmin$返回最小正浮点数,值约为$2.2251e-308$
的 $nargin$返回实际传入的参数个数,仅限于函数
的 $nargout$返回实际传出的参数个数,仅限于函数
可以发现以上常量都是可以被赋为其他值的,因此这些量可以看作系统默认赋值。
1 a=eps 2 %a=2.2204e16 3 eps=[2,3,4] 4 a=eps 5 %a=[2,3,4]
2.9 控制结构
循环结构($break;$和$continue;$语句规则与C++相同):
①$for$循环
1 for 变量=矩阵 2 循环体 3 end
②$while$循环
1 while 命题 2 循环体 3 end
选择结构:
①$if-elseif-else$选择
1 if 命题1 2 代码块1 3 elseif 命题2 4 代码块2 5 elseif 命题3 6 代码块3 7 …… 8 elseif 命题m 9 代码块m 10 else 11 代码块(m+1) 12 end
②$switch-case$选择
1 switch 表达式0 2 case 表达式1 3 代码块1 4 case 表达式2 5 代码块2 6 …… 7 case 表达式m 8 代码块m 9 otherwise 10 代码块(m+1) 11 end
三、数值计算
Matlab中用向量存储多项式。对于多项式$F(x)=a_{n}x^{n}+a_{n-1}x^{n-1}+\cdots+a_{1}x+a_{0},a_{0}\ne 0$,根据代数基本定理,其有$n$个复根,分别记作$c_{1},c_{2},\cdots,c_{n}$。$F(x)$的$n+1$个系数唯一确定多项式$F(x)$,因此$[a_{n},a_{n-1},\cdots,a_{0}]$可以刻画$F(x)$,称作$F(x)$的系数矩阵;$F(x)$的$n$个复根也唯一确定多项式$F(x)$,因此$[c_{1},c_{2},\cdots,c_{n}]$也可以刻画$F(x)$,称作$F(x)$的零点矩阵。系数矩阵(元素有序)和零点矩阵(元素无序)是多项式的两种表示,既可以用行向量也可以用列向量。
多项式操作:
的 $roots(A)$传入系数矩阵,返回零点矩阵
的 $poly(A)$传入零点矩阵,返回系数矩阵
的 $polyval(A,x)$传入系数矩阵和实数,返回多项式在该点的值
的 $polyvalm(A,X)$传入系数矩阵和矩阵,返回多项式以该矩阵为自变量的取值
的 $residue(P,Q)$传入两个系数矩阵,进行部分分式展开,返回$1\times 3$矩阵
的 一般地,若$\frac{P(x)}{Q(x)}=\sum_{i=1}^{n}\frac{r_{i}}{x-p{i}}+k(x)$,$residue(P,Q)$返回$[[r_{1},r_{2},\cdots,r_{n}];[p_{1},p_{2},\cdots,p_{n}];K]$
的 例如$\frac{x^{2}+2x+2}{x+1}=\frac{1}{x+1}+x+1$,进行$P=[1,2,2];Q=[1,1];[r,p,k]=residue[P,Q]$后$r=[1];p=[-1];k=[1,1]$
的 $polyder(A)$传入系数矩阵,返回求导后的多项式的系数矩阵
的 $polyint(A,b)$传入系数矩阵和实数,返回多项式积分后零次项取$b$的多项式的系数矩阵
的 $conv(P,Q)$传入两个系数矩阵,返回乘积多项式的系数矩阵
的 $deconv(P,Q)$传入两个系数矩阵,返回商多项式的系数矩阵
的 $polyfit(X,Y,n)$传入样本点横纵坐标向量和整数,返回最小二乘意义下$n$次拟合多项式的系数矩阵
四、符号计算
4.1 符号变量
符号生成:
①列举法($syms+$空格分隔的符号名)
1 sym x y z
②构造函数
1 sym(\'x\'); 2 sym(\'x\',\'real\');%实型 3 sym(\'x\',\'unreal\');%非实型
4.2 符号矩阵
1 syms a b c d m; 2 3 A=[a b;c d]; 4 B=det(A); 5 C=inv(A); 6 %B=a*d-b*c 7 %C=[d/(a*d-b*c),-b/(a*d-b*c);-c/(a*d-b*c),a/(a*d=b*c)] 8 9 A=[a b c d;b c d a;c d a b;d a b c]; 10 s=sum(A(1,:)); 11 A(4,4)=m; 12 %s=a+b+c+d 13 %A=[a b c d;b c d a;c d a b;d a b m];
4.3 符号微分
的 $diff(y,\'t\')$返回$\frac{\partial y}{\partial t}$
的 $diff(y,\'t\',n)$返回$\frac{\partial^{n}y}{\partial t^{n}}$
4.4 符号积分
的 $diff(f,t)$返回$\lmoustache fdt$,积分常数取零
的 $diff(f,t,a,b)$返回$\lmoustache_{a}^{b}fdt$
1 syms x y z; 2 syms a b c; 3 4 z=a*x^2+b*x*y+c/x; 5 p=int(z,x); 6 q=int(z,y); 7 r=int(z,c,-1,1); 8 9 %p=(a*x^3)/3 + c*log(x) + (b*x^2*y)/2 10 %q=(b*x*y^2)/2 + (a*x^2 + c/x)*y 11 %r=2*a*x^2 + 2*b*y*x
4.5 符号累加
的 $symsum(f,a,b)$返回$\sum_{i=a}^{b}f(x)$,$x$是默认自变量
的 $symsum(f,t,a,b)$返回$\sum_{i=a}^{b}f(t)$
1 syms x,y,z; 2 3 y=symsum(1/x^2,x,1,inf); 4 z=symsum(1/x^4,x,1,inf); 5 6 %y=pi^2/6 7 %z=pi^4/90
4.6 符号泰勒展开
的 $taylor(f,t,a,\'order\',n)$返回$f(t)$在$t=a$处$n$阶泰勒展开式
1 syms x,y; 2 3 y=taylor(exp(x),x,1,\'order\',4); 4 5 %y=exp(1) + exp(1)*(x - 1) + (exp(1)*(x - 1)^2)/2 + (exp(1)*(x - 1)^3)/6
4.7 符号极限
的 $limit(f,x,a)$返回$\lim\limits_{x\to a}f(x)$
的 $limits(f,x,a,\'right\')$返回$\lim\limits_{x\to a^{+}}f(x)$
的 $limits(f,x,a,\'left\')$返回$\lim\limits_{x\to a^{-}}f(x)$
1 syms k x; 2 a=limit(sin(k*x)/x,x,0) 3 %a=k
4.8 符号方程组
的 $solve(\'e_{1}\',\'e_{2}\',\cdots,e_{n},x_{1},x_{2},\cdots,x_{n})$传入$n$个等于零符号表达式,返回符号方程组的解结构体
1 syms x y a b 2 s=solve(x+y-a,x-y-b,x,y) 3 %s.x=a/2+b/2 4 %s.y=a/2-b/2
4.9 符号表达式操作
的 $expand(A)$传入符号矩阵,对每个元素去括号展开后返回
的 $factor(A)$传入符号矩阵,对每个元素因式分解后返回
的 $collect(A)$传入符号矩阵,对每个元素合并同类项后展返回
的 $simplify(A)$传入符号矩阵,对每个元素化简后返回