变量

在前面的内容中, 我们已经接触过一些matlab中的变量, 但是仅涉及double类型的向量和矩阵. 这里介绍一些matlab中其他类型的变量及其部分使用方法.matlab变量的总体分类如下:

image-20200701085952368

matlab中提供一些类型之间转换的函数, 下面列举出一些常见的函数, 这些转换函数只需要对它的存在有印象即可, 等到实际应用中有需求时, 可以通过查询文档查看具体使用方法.

  • double(): 将目标变量转换为double类型.
  • single(): 转换为单精度变量.
  • int8(): 转换为8位的整型变量.
  • int16(): 转换为16位的整型变量.
  • int32(): 转换为32位的整型变量.
  • int64(): 转换为64位的整型变量.
  • uint8(): 转换为无符号的8位整型变量.
  • uint16(): 转换为无符号的16位整型变量.
  • uint32(): 转换为无符号的32位整型变量.
  • uint64(): 转换为无符号的64位整型变量.

char & String

char

与C语言相同, Matlab中的char变量实际存储其 ASCII 码值, ASCII编码从0到255.char变量的声明, 要用一对' '包含字符的内容. ' '包含一个字符就是char类型变量, 包含多个字符就是string类型变量.

1
2
3
s1 = 'h'
whos
uint16(s1)

通过执行上述代码, 可以得出 字符h的ASCII编码值为104.

image-20200701091739381

下面给出完整的ASCII码表.

image-20200701091831976

String

String就是一系列的字符,比如:

1
2
s1 = 'Example';
s2 = 'String';

可以通过[ ]形式将字符串拼接起来, 类似于矩阵的拼接.比如s3=[s1 s2].

image-20200701092425303

注意到上面的命令执行结果中两个字符串之间是没有空格的, 指令中的空格只是两个输入变量之间相互区分的作用.如果想要得到带空格的结果字符串, 可以在拼接过程中手动添加空格字符,例如: s4= [s1 ' ' s2],

image-20200701092655604

在矩阵的拼接中, 曾经提到过,只要满足拼接条件, 使用[]的方式可以进行除了横向拼接外的其他形式的拼接,那么若执行s5=[s1;s2]结果如何呢?

image-20200701093711613

由于字符串的长度不一致, 导致无法进行纵向拼接, 可以通过补充字符的方式尝试再拼接一次,s5=[s1;s2 'x']

image-20200701093919808

matlab中的String和C语言中的字符串在处理过程中还是存在一些不同之处, 看下面的例子, 思考其执行的结果.

1
2
str='aardvark';
'a' == str

按C语言的理解, 比较两个字符串是否相等, 显然不相等, 那么应该返回逻辑0值. 但是事实并不是这样,

image-20200701093139375

返回的结果并不是单一的0 ,而是一个由 0 和1 组成的向量, 通过观察可以发现, 返回的结果向量的长度与str长度相同, 进一步可以发现, 在str字符串中字符a的位置在结果向量中是1. 因此, 在matlab中 字符与字符串之间的比较是字符逐一与字符串中的字符进行比较, 相同则返回1, 不同则返回0,返回的结果是一个向量值.为了进一步探究字符与字符串,字符串与字符串之间如何进行比较, 分别执行'aa'==str,'12345678'==str,观察结果.

image-20200701095911453

结论如下:

字符与字符串进行比较: 字符与字符串中的每一个字符逐一进行比较, 相同则返回1, 不同返回0. 最终返回结果是一个向量.

字符串与字符串进行比较: 要求进行比较的字符串长度相同, 对两个字符串对应位置的字符进行比较, 相同则返回1, 不同则返回0. 最终的结果是一个向量.

那么str(str=='a')='Z'的执行结果如何呢? 考虑到str()就是对str字符串进行索引, 索引值就是str=='a'的返回值, 上面已经讨论过, str=='a'的返回值是 一个由0 和1 组成的向量, matlab面对这样一个向量的处理结果是:

image-20200701101139890

似乎和想象中的存在一些差别, 对于普通的索引方式str([1 2 3]),的结果如下:

image-20200701101351191

这和我们的预期相同, 比较上述两种索引方式的区别, 可能的原因是, Matlab对于逻辑值的索引和普通的索引存在处理上的差别, 对于由0和1 组成的向量会优先处理成逻辑向量, 为了验证这一想法, 考虑执行下面两个命令:

image-20200701101630662

显然, 并不是由0和1 组成的向量就是逻辑向量, 根据在其他语言处获得的经验, 我们尝试把数值变量强制转换为逻辑变量, 观察结果.

image-20200701101916211

matlab中字符串对于逻辑值的索引和数值型的索引确实存在区别, 对于逻辑值的索引返回一个向量,其长度等于逻辑向量中1的个数, 字符由原字符串中与逻辑向量中1的位置相对应字符组成

str(str=='a')='Z'的结果为:

image-20200701102506746


练习:

写一个脚本文件, 实现字符串的逆置.

s1=‘I like letter E’ ==> s2=‘E rettel ekil I’

参考结果:

image-20200701110124138

1
2
3
4
5
6
7
8
function y=tran(x)
ii=length(x);
jj=1;
while ii>0
y(jj)=x(ii);
jj=jj+1;
ii=ii-1;
end

Structure

matlab中的结构体与C中的结构体类似 , 都是用来存储一系列的异型变量.结构体的逻辑模型如下图所示:

image-20200701134158068

在matlab中输入下面的代码来写入上图中的信息.

1
2
3
4
5
6
7
student.name = 'John Doe';
student.id = 'jd2@sfu.ca';
student.number = 301073268;
student.grade = [100 75 73; ...
95 91 85.5; ...
100 98 72];
student

多个结构体类型的变量构成结构体数组.其逻辑示意图如下:

image-20200701134903948

对于结构体数组, 其索引方式如之前的其他类型变量类似, 都是通过名称加( )的方式进行索引.因此, 第二个结构变量的输入过程为:

1
2
3
4
student(2).name= 'Ann Lane';
student(2).id= 'aln4@sfu.ca';
student(2).number= 301078853;
student(2).grade= [95 100 90;95 82 97;100 85 100];

输入完成后, matlab中的student变量形式如下:

image-20200701135616629

如果想要获得Ann Lane 第三门课程的成绩信息, 索引两次即可. student(2).grade(1,3)

下面列举一些和结构体有关的matlab内置的函数, 具体用法在需要时查看文档即可.

比如:

  • fieldnames(student)的执行结果: image-20200701141055512
  • rmfield(student,'id')的执行结果: image-20200701141401390

Nesting Structures (结构体嵌套)

结构体中可以继续嵌套结构体, 其逻辑模型如下:

image-20200701141651981

结构体之间的嵌套, 可以使用函数struct进行输入, 也可以使用索引的方式进行输入.下面给出一个例子

1
2
3
4
5
6
7
8
A = struct('data',[1 2 3;4 5 6],'nest',...
struct('testnum','Tset 1',...
'xdata',[4 2 8],'ydata',[3 4 6]));
%结构体A中的第二个字段nest是一个结构体类型
A(2).data=[3 4 5 ; 1 3 5];
A(2).nest.testnum='Test 2';
A(2).nest.xdata=[ 3 4 5];
A(2).nest.ydata=[ 2 4 5];

输入A.nest查看结果:

image-20200701142707967

Cell Array

细胞数组是另一种存储异型数据的数据类型.类似于一个矩阵,但是矩阵的每一个单元存储不同类型的数据.需要使用{ }来声明.其逻辑示意图如下:

image-20200701143019123

对于上述示意图中的细胞数组, 有以下两种输入方式, 但是都需要用到{ },只是形式上有所区别, 关于何时采用何种形式, 在后面的学习中会有更进一步的认识.

1
2
3
4
5
6
7
8
9
10
% 第一种输入方式
A(1,1)= { [1 4 3 ; 0 5 8 ; 7 2 9] };
A(1,2)= {'Anne Smith'};
A(2,1)= {3+7i};
A(2,2)= {-pi:pi:pi};
% 第二种输入方式
A{1,1}= [1 4 3 ; 0 5 8 ; 7 2 9];
A{1,2}= 'Anne Smith';
A{2,1}= 3+7i;
A{2,2}= -pi:pi:pi;

上述两种输入方式只是形式上的区别,对于输入的结果没有任何影响. 实际上,matlab是通过指针来实现在一个矩阵中存放不同的数据类型, 也就是说, 细胞数组实际上是一个指针矩阵, A(1,1)中存放的是其内容的地址.示意图如下:

image-20200701144024761

对于细胞数组的索引方式和普通矩阵的索引方式也有所区别, 比如, 如何才能索引到A(1,1)处的第一个元素1呢?首先想到的就是套娃思想,执行A(1,1)(1,1),A(1,1)(1,1)的执行结果:

image-20200701151459699

对于细胞数组的索引A{1,1}A(1,1)存在着一定的区别:

image-20200701151712084

从上面的结果上来看, 想要索引到第一个矩阵中的第一个元素正确的方法是A{1,1}(1,1):

image-20200701151835135


练习:

建立一个细胞数组, 其中存储的内容如下图.

image-20200701144157479

参考代码:

1
2
3
4
B{1,1}= 'This is the first cell';
B{1,2}= [5+6j 4+5j];
B{2,1}= [ 1 2 3;4 5 6;7 8 9 ];
B{2,2}= {'Tim' , 'Chris'};

我还没有学会字符串数组的创建方法. 在最后一行代码使用B{2,2}= ['Tim' , 'Chris'];时, 总是会被执行成字符串拼接操作, 形成一个字符串. 而目前这种写法, B(2,2)处存放的不是字符串数组, 而是一个细胞数组中存放了两个字符串.

结果如下:

image-20200701150751750

下面列出一些和细胞数组相关的matlab内置函数:

  • cell: 细胞数组
  • cell2mat: 将细胞数组转换为基础数据类型的普通数组
  • cell2struct: 将细胞数组转换为结构体数组
  • celldisp: 显示细胞数组内容
  • cellfun: 对元胞数组中的每个细胞应用函数
  • cellplot: 以图形方式显示细胞数组的结构体
  • cellstr: 转换为字符向量细胞数组
  • iscell: 确定输入是否为细胞数组
  • mat2cell: 将数组转换为在细胞中包含子数组的细胞数组
  • num2cell: 将数组转换为相同大小的细胞数组
  • struct2cell: 将结构体转换为细胞数组

举个例子:

1
2
3
a = magic(3) % magic(3)是生成3为的魔方矩阵, 魔方矩阵是横竖斜相加得数都相同的矩阵.
b = num2cell(a)
c = mat2cell(a, [1 1 1 ] ,3)

效果:

image-20200701153307123

Multidimensional Array

多维数组实际上就是套娃思想, 其逻辑示意图如下:

image-20200701153457907

可以通过下面的代码输入一个三维的细胞数组:

1
2
3
4
5
6
7
8
A{1,1,1} = [1 2 ; 4 5 ];
A{1,2,1} = 'Name';
A{2,1,1} = 2-4i;
A{2,1,1} = 7;
A{1,1,2} = 'Name2';
A{1,2,2} = 3;
A{2,1,2} = 0:1:3;
A{2,2,2} = [4 5]';

在思想上和其他语言中的多维数组应该没什么区别. 输入之后的结果示意图如下:

image-20200701154131687

上面的矩阵输入方式比较复杂,在输入过程中要先考虑好每个索引值之间的相对位置, 很容易造成输入的最终结果和我们的预期结果不一致的情况, 下面介绍cat()函数, cat()函数用来串联数组, 使用语法为C = cat(dim,A1,A2,…,An),dim参数代表拼接的维度参数,一般取1 2 3三个数值, 1表示列的维度,2表示行的维度,3则表示立体空间的第三个维度.比如

1
2
3
4
5
A= [ 1 2 ; 3 4];
B= [ 5 6 ; 7 8];
C= cat(1,A,B)
C= cat(2,A,B)
C= cat(3,A,B)

上述三种cat方式对应的结果分别是:

image-20200701155412212

于是, 对于上面的三维细胞数组的输入就可以转化为 输入两个平面细胞数组, 再对两个二维的细胞数组再第三维上执行cat()函数.

1
2
3
4
5
6
7
8
9
A{1,1} = [1 2;4 5];
A{1,2} = 'Name';
A{2,1} = 2-4i;
A{2,2} = 7;
B{1,1} = 'Name2';
B{1,2} = 3;
B{2,1} = 0:1:3;
B{2,2} = [4 5]';
C = cat(3, A, B)

下面再介绍reshape()函数, 这个函数可以实现把一个r1×c1r_1 \times c_1的矩阵转化为r2×c2r_2 \times c_2的矩阵,但是要满足r1c1=r2c2r_1c_1=r_2c_2.

1
2
A = {'James Bond', [1 2;3 4;5 6]; pi, magic(5)}
C = reshape(A,1,4)

image-20200701160811535

可以看到, A是2维方阵, 而C是1×41\times 4的矩阵.

关于变量的相关内容就介绍这么多, 下面列举一些和变量相关的matlab函数:

  • isinteger: 确定输入是否为整数数组
  • islogical: 确定输入是否为逻辑数组
  • isnan: 确定哪些数组元素为 NaN
  • isnumeric: 确定输入是否为数值数组
  • isprime: 确定哪些数组元素为质数
  • isreal: 确定数组是否为实数数组
  • iscell: 确定输入是否为元胞数组
  • ischar: 确定输入是否为字符数组
  • isempty: 确定数组是否为空
  • isequal: 确定数组相等性
  • isfloat: 确定输入是否为浮点数组
  • isglobal: 判断是否为全局变量
  • ishandle: 测试是否有效的图形或 对象句柄
  • isinf: 确定哪些数组元素为无限值

变量存储

目前为止的学习中, matlab工作区中的变量在每次关闭matlab后就随之删除了, 下次打开matlab时不会再有上次的工作区变量, 在实际的应用中, 变量的存储有着十分重要的意义.下面介绍常用的变量存储于读入的方法, 对于不常用或者用起来不方便的变量存储方法, 可以参考资料链接中的PPT或视频讲解.

把变量存储为matlab格式数据

1
2
3
4
clear;
a= magic(4);
save mydata1.mat % 文件名
save mydata2.mat -ascii % 文件名 编码方式

上述代码执行完毕后 , 我们可以发现在当前工作目录中已经多了两个两个.mat后缀的文件. 可以在windows资源管理器中查看到这两个文件. 对于第三行和第四行代码的区别, 第三行代码只是存储了当前工作区中的变量, 其编码方式没有指定, 默认为matlab的编码方式, 因此用文本编辑器打开时会出现乱码现象. 第四行代码在存储的同时指定了其编码方式 , 因此可以用文本编辑器打开查看其中的内容.

image-20200701163547466

image-20200701163606277

上述代码是存储工作区中的全部变量, 如果想要单独存储某一个变量, 需要执行 save data1.mat name表示存储工作区中的name变量, 如果工作区中没有name变量则会报错.

读入变量使用load()函数:

1
2
load('mydata1.mat')
load('mydata2.mat','-ascii')

将变量存储为Excel表格形式

只需修改扩展名即可.

1
2
save data.xlsx
save data1.xlsx -ascii

和上面类似, data和data1的区别在于能否被其他软件正确解码.

data.xlsx

data1.xlsx

matlab 从Excel表格中读取数据,可以使用xlsread()函数, 可以指定起始读取位置和终止读取位置, 缺省为读取全部.

后面的内容在我的matlab上就开始报错了, 具体原因我还没有找到, 考虑到后面的内容实际应用可能不是很多, 因此这一章的笔记就写到这里了.

1
2
b= xlsread('data.xlsx')
c= xlsread('data.xlsx','B2:D4')

资料链接

参考视频 参考讲义