Octave简明教程(一)

GNU Octave是一种以高级编程语言为特色的软件,主要用于数值计算和绘图。通过Octave可以非常方便的进行矩阵运算、求解联立方程组、计算矩阵特征值和特征向量等。本篇文档主要内容是Octave基础命令、数据格式、绘制图形、Octave脚本编写、Octave函数编程等内容。另外,此文档会不断补充常见使用场景。

为什么使用Octave

当我们使用C++来处理矩阵运算方面的问题确实显得过于复杂时,C++这样的编程语言不原生的支持一些数学概念或者生成图表。Octave 是专为解决这类问题而设计的,所以很多时候用Octave来编写软件的原型或者数学部分,因为这样能够很快的检验其算法的正确性。

另外GNU Octave自由、免费、而且轻量级。MATLAB的Licence很难获取,故我选择GNU Octave。

官方文档地址

如果是初次使用Octave,英文比较好的话可以直接阅读官方文档 https://octave.org/octave.pdf ,文档里有最详细的介绍,如果只是想了解日常的使用方式那么看这篇文章足矣,如果遇到到其他在本文中没有出现过的场景,我会翻译后补充在本文中。

Octave环境概述

安装Octave

安装Octave可以参考 https://www.gnu.org/software/octave/download ,Mac下直接使用brew安装即可,如果需要GUI界面,可以参考如下方式:

1brew reinstall octave--with-qt

我们通常在命令行界面运行Octave,每个命令依次输入命令行中,并以回车结束。Octave是一门解释型语言,即每个命令通过解释器转化为机器语言。

Octave工作空间

命令行所处的ENV,也就是本次打开Octave的上下文ENV。所以对于Octave有工作空间的概念,一切的函数文件、脚本文件都只对当前的工作空间生效。

通过who命令可以查看本次所处于的工作空间的变量,clear用于清除已经存在的变量,也可以指定变量清除:

 1octave:1> who
 2octave:2> a = 10; b = 20; c = a + b;
 3octave:3> who
 4Variables visible from the current scope:
 5
 6a  b  c
 7
 8octave:4> d = 200;
 9octave:5> who
10Variables visible from the current scope:
11
12a  b  c  d
13
14octave:6> clear
15octave:7> who
16octave:8> d = 200;
17octave:9> clear d
18octave:10> who
19octave:11> clear
20octave:12> a = 10; b = 20; c = a + b;
21octave:13> who
22Variables visible from the current scope:
23
24a  b  c
25
26octave:14> clear b
27octave:15> who
28Variables visible from the current scope:
29
30a  c
31
32octave:16> 

帮助命令

如果你不了解某个 Octave 命令的功能或者是你需要找一个特定的函数,Octave 本身强大的帮助系统会很有用。最基本的使用帮助系统的方式就是:help commandname,比如查看clear命令、查看sin函数:

 1octave:1> help clear
 2'clear' is a built-in function from the file libinterp/corefcn/variables.cc
 3
 4 -- clear
 5 -- clear PATTERN ...
 6 -- clear OPTIONS PATTERN ...
 7     Delete the names matching the given PATTERNs thereby freeing
 8     memory...
 9
10octave:2> help sin
11'sin' is a built-in function from the file libinterp/corefcn/mappers.cc
12 -- sin (X)
13     Compute the sine for each element of X in radians.
14     See also: asin, sind, sinh...

数据载入&保存

退出Octave的交互式环境的时候,你将丢失你所创建的变量。如果你需要在工作的中途退出 Octave,那么你可以保存当前会话的数据并在之后进行重新载入:

 1octave:1> a = [1:10];
 2octave:2> b = [1:0.5:10];
 3octave:3> save anyname
 4octave:4> exit
 5
 6zchanglin@mbp OctaveWK % ls
 7anyname   octave-workspace
 8zchanglin@mbp OctaveWK % cat anyname 
 9# Created by Octave 6.4.0, Thu Jan 27 17:45:40 2022 CST <zchanglin@mbp.local>
10# name: a
11# type: matrix
12# rows: 1
13# columns: 10
14 1 2 3 4 5 6 7 8 9 10
15
16
17# name: b
18# type: matrix
19# rows: 1
20# columns: 19
21 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10

这将整个工作空间上的变量存储到当前目录下一个名为 anyname 的文件中,这样你可以退出 Octave,之后重新启动 Octave 程序,通过输入:load anyname

 1octave:1> load anyname
 2octave:2> a
 3a =
 4
 5    1    2    3    4    5    6    7    8    9   10
 6
 7octave:3> b
 8b =
 9
10 Columns 1 through 14:
11
12    1.0000    1.5000    2.0000    2.5000    3.0000    3.5000    4.0000    4.5000    5.0000    5.5000    6.0000    6.5000    7.0000    7.5000
13
14 Columns 15 through 19:
15
16    8.0000    8.5000    9.0000    9.5000   10.0000
17
18octave:4> 

将重新载入之前保存的命名空间,并从你中断的地方重新开始工作。

同样的如果只是想保存某些变量而非全部保存,只需要在上述命令中加入变量名称即可:

 1octave:1> a = 10; b = 20; c=30;
 2octave:2> save anyname a b;
 3octave:3> exit
 4
 5zchanglin@mbp OctaveWK % octave
 6GNU Octave, version 6.4.0
 7.....
 8
 9octave:1> load anyname;
10octave:2> a
11a = 10
12octave:3> b
13b = 20
14octave:4> c
15error: 'c' undefined near line 1, column 1
16octave:5> 

在上述例子中,可能你注意到了结尾加不加分号的区别,加了分号表示不显示本条指令的结果,加了的话就会展示本条指令的结果,这与MATLAB是一致的。

通用计算

启动 & 执行简单计算

Octave 在 UNIX 环境下通过在终端中输入octave来启动,在启动octave 之后,程序一般会显现如下信息:

 1zchanglin@mbp ~ % octave
 2GNU Octave, version 6.4.0
 3Copyright (C) 2021 The Octave Project Developers.
 4This is free software; see the source code for copying conditions.
 5There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or
 6FITNESS FOR A PARTICULAR PURPOSE.  For details, type 'warranty'.
 7
 8Octave was configured for "x86_64-apple-darwin19.6.0".
 9
10Additional information about Octave is available at https://www.octave.org.
11
12Please contribute if you find this software useful.
13For more information, visit https://www.octave.org/get-involved.html
14
15Read https://www.octave.org/bugs.html to learn how to submit bug reports.
16For information about changes from previous versions, type 'news'.
17
18octave:1> (2+8)/5 * 2 - 3
19ans = 1
20octave:2> a = (2+8)/5 * 2 - 3;
21octave:3> a
22a = 1

各种计算符号的优先级与常规的一致,比如括号有最大优先级,其次为乘方,其次为乘除运算,最后为加减运算。

内建函数与常量

Octave 提供了一系列的常用数学函数,其中的常用部分函数如下所示。像 C++ 中调用函数一样,Octave 通过输入函数名和括号中的输入参数来调用函数,其中自然对数e、圆周率pi 都是Octave已经定义的常量(ans代表上一次的计算结果,就像一个普通的科学计算器一样),例如:

 1octave:1> sin(90 * pi/180)
 2ans = 1
 3octave:2> sin(30 * pi/180)
 4ans = 0.5000
 5octave:3> cos(60 * pi/180)
 6ans = 0.5000
 7octave:4> pi
 8ans = 3.1416
 9octave:5> e
10ans = 2.7183
11octave:6> log(e)
12ans = 1
13octave:7> 2 * ans
14ans = 2
15octave:8> abs(5) + abs(-5)
16ans = 10
17octave:9> 
内建函数 描述 内建函数 描述
cos 余弦函数(弧度制) abs 绝对值函数 (复数取模 )
sin 正弦函数(弧度制) sign 符号函数
tan 正切函数(弧度制) round 四舍五入
cot 余切函数(弧度制) floor 近似为比它小的最大整数
log 以 e 为底的指数函数 ceil 近似为比它大的最小整数
log10 以 10 为底的指数函数 fix 向 0 方向近似
exp 指数函数 rem 求余数
sinh 双曲正弦函数 cosh 双曲余弦函数
tanh 双曲正切函数 coth 双曲余切函数
asin 反正弦函数 acos 反余弦函数
acosh 反双曲余弦函数 asinh 反双曲正弦函数

向量相关的计算

定义向量

构造矩阵或者向量的方法有很多。其中最直接简单的方法就是在一个方括号 [] 中给出其元素,也可以通过已经定义的向量来定义新的向量,中间使用空格隔开或者逗号隔开:

 1octave:1> a=[6 5 4]
 2a =
 3
 4   6   5   4
 5
 6octave:2> b=[3 7];
 7octave:3> c = [a 1 3 4 b]
 8c =
 9
10   6   5   4   1   3   4   3   7
11
12octave:4> d = [a,1,3,4]
13d =
14
15   6   5   4   1   3   4
16
17octave:5> 

有时候我们需要快速的定义向量,可以使用冒号表达式来定义:

 1octave:1> a = [5:10] # 定义元素为5-10的向量,默认步长为1
 2a =
 3
 4    5    6    7    8    9   10
 5
 6octave:2> b = [1:0.5:3] # 中间的0.5表示步长
 7b =
 8
 9   1.0000   1.5000   2.0000   2.5000   3.0000
10
11octave:3> 

定义矩阵

常规方式定义矩阵:

 1octave:1> a = [10, 20, 30; 1, 2, 3] # 定义矩阵a
 2a =
 3
 4   10   20   30
 5    1    2    3
 6
 7octave:2> b = 5:7 # 定义向量b
 8b =
 9
10   5   6   7
11
12octave:3> a = [10, 20, 30; 1, 2, 3; b] # 向量参与矩阵构建
13a =
14
15   10   20   30
16    1    2    3
17    5    6    7
18
19octave:4> 

通过函数定义矩阵与向量

函数 描述
zeros(M, N) 创建一个 M×N 的零矩阵
ones(M, N) 创建一个 M×N 的全1矩阵
rand(M, N) 创建一个 M×N 的随机矩阵
linspace(x1, x2, N) 创建一个 N 个元素的向量, 均匀分布于 x1 和 x2
logspace(x1, x2, N) 创建一个 N 个元素的向量,指数分布与 10x1 和 10x2 之间
 1octave:3> zeros(3, 3)
 2ans =
 3
 4   0   0   0
 5   0   0   0
 6   0   0   0
 7
 8octave:4> ones(2, 2)
 9ans =
10
11   1   1
12   1   1
13
14octave:5> linspace(10, 20, 3)
15ans =
16
17   10   15   20
18
19octave:6> logspace(10, 20, 3)
20ans =
21
22   1.0000e+10   1.0000e+15   1.0000e+20
23
24octave:7> 

显示大矩阵/向量

Octave 无法用单屏显示一个元素超多的向量或者矩阵,有一种READ MORE的模式,通过 more off 命令关闭,

通过 more on 命令开启;比如现在查看一个1000个元素的向量:

 1octave:1> v = 1:1000
 2v =
 3
 4 Columns 1 through 21:
 5      1      2      3      4      5      6      7      8      9     10     11     12     13     14     15     16     17     18     19     20     21
 6 Columns 22 through 42:
 7     22     23     24     25     26     27     28     29     30     31     32     33     34     35     36     37     38     39     40     41     42
 8 Columns 43 through 63:
 9 ......
10-- less -- (f)orward, (b)ack, (q)uit
11# 按q退出
12octave:2> more off

操作向量元素

向量中的元素通过括号() 进行访问,而第一个元素的编号为 1, 而不是像其他编程语言那样从0开始。例如:

 1octave:1> a = [1:10]
 2octave:2> a(5)
 3ans = 5
 4octave:3> a(5) + a(8)
 5ans = 13
 6octave:4> b = a(4:6) # 冒号的表示法同样可以用于声明向量中的元素的范围
 7b =
 8
 9   4   5   6
10
11octave:5> length(b) # 求向量b的长度
12ans = 3

向量/矩阵的计算

使用Octave来对向量或者矩阵进行计算非常方便,不用像C/C++那样写多重for循环,先来看看向量数乘,对向量中所有元素都除以一个数的操作与乘法类似:

 1octave:1> a = 2:6
 2a =
 3
 4   2   3   4   5   6
 5
 6octave:2> 2*a
 7ans =
 8
 9    4    6    8   10   12
10
11octave:3> 2*a
12ans =
13
14    4    6    8   10   12
15
16octave:4> a - 1
17ans =
18
19   1   2   3   4   5
20
21octave:5> a + 2
22ans =
23
24   4   5   6   7   8

两个向量的相乘遵循矩阵的乘法法则,向量乘法并不是对应元素的相乘。如果要进行对应元素的乘除法, 你可以使用 . 运算符,每个算符前的 . 表示为一个元素对元素的计算,比如: $$ \left(\begin{array}{l} a_{1} \ a_{2} \ a_{3} \end{array}\right) \cdot *\left(\begin{array}{l} b_{1} \ b_{2} \ b_{3} \end{array}\right)=\left(\begin{array}{l} a_{1} b_{1} \ a_{2} b_{2} \ a_{3} b_{3} \end{array}\right) $$

 1octave:1> a = 1:5
 2a =
 3
 4   1   2   3   4   5
 5
 6octave:2> b = 6:10
 7b =
 8
 9    6    7    8    9   10
10
11octave:3> a.*b # 向量元素相乘
12ans =
13
14    6   14   24   36   50
15octave:4> a.^2 # 向量元素二次方
16ans =
17
18    1    4    9   16   25
19
20octave:7> a = rand(3,4) # 创建3*4随机矩阵
21a =
22
23   0.592680   0.824473   0.504916   0.893063
24   0.976128   0.249468   0.866887   0.148853
25   0.933072   0.228585   0.069300   0.384276
26
27octave:8> b = rand(4,3) # 创建3*4随机矩阵
28b =
29
30   0.6803   0.1361   0.1822
31   0.5374   0.6651   0.6490
32   0.3831   0.5916   0.1651
33   0.2554   0.3941   0.9914
34
35octave:9> a * b # 矩阵乘法
36ans =
37
38   1.2678   1.2797   1.6118
39   1.1682   0.8703   0.6305
40   0.8823   0.4715   0.7108
41
42octave:10> a.*b # 矩阵元素相乘
43error: product: nonconformant arguments (op1 is 3x4, op2 is 4x3)
44octave:11> c = rand(3,4) # 创建3*4随机矩阵
45c =
46
47   0.042975   0.462963   0.221173   0.524956
48   0.694888   0.486257   0.416091   0.127658
49   0.042671   0.760997   0.251399   0.655109
50
51octave:12> a * c # 矩阵乘法
52error: operator *: nonconformant arguments (op1 is 3x4, op2 is 3x4)
53octave:13> a .* c # 矩阵元素相乘
54ans =
55
56   0.025471   0.381701   0.111674   0.468819
57   0.678300   0.121305   0.360704   0.019002
58   0.039815   0.173952   0.017422   0.251743

Octave绘图初阶

以创建一个以60度为间隔的角度值,并作为 sin 函数的输入作为例子,进行绘图:

 1octave:1> x=[0:pi/3:2*pi]; # 定义X轴数据集
 2octave:2> y = sin(x);
 3octave:3> plot(x,y); # 绘制函数
 4octave:5> xlabel('Angle'); # X轴标注
 5octave:6> ylabel('Value'); # Y轴标注
 6octave:7> title('Graph of y=sin(x)'); # 图表标题
 7octave:8> grid on; # 开启网格
 8octave:10> hold; # 图像保持(避免被下一个函数图形覆盖)
 9octave:11> y2 = sin(x) + 0.5; # 定义另一个函数
10octave:12> plot(x,y2); # 绘制函数
11octave:13> legend('Sine','Sine+0.5'); # 绘制图例
12octave:14> hold;
13octave:15> print('./graph1.png','-dpng'); # 打印当前图表到工作区

plot函数其实有更多的选项,主要是设置线型和颜色。例如,使用红色和圆圈来画出之前的图片,输入:

1plot(x, y,'ro');

Octave提供了print 命令来将图片打印到默认的打印机上。

另外如果需要绘制多幅图表,则使用 figure 命令新建窗口即可。

下表中列出了plot 命令中的颜色和样式选项,可以通过 help plot 命令查看:

w 白色 m 品红 c 青色 r 红色
g 绿色 b 蓝色 y 黄色 k 黑色
. o 圆圈 x x 形 + + 号
* 星号 s 正方形 d 菱形 v 下三角
< 左三角 > 右三角 p 五角星 p 五角星
- 实线 : 虚线 -. 点划线 虚线

Octave Script

对于一些重复输入的命令,完全可以将这一系列的命令存入一个 Octave 脚本之中。这种包含 Octave 命令的文本文件是 Octave 程序的基本形式,当在 Octave 中执行这样的脚本的时候,其效果与将这些命令一行行输入效果是一样的。而且 Octave 脚本是普通的文本文件,方便修改,脚本需要有 .m 作为后缀。需要执行脚本的时候向 Octave 终端输入脚本文件的名称即可,但是无需加上 .m 后缀。

还需要注意的点就是如果执行一个脚本,最好将脚本加入到当前的工作空间中,如果不想手动添加到工作空间,则需要使用 addpath 命令添加脚本所在的工作目录,然后使用 savepath 命令保存即可。

现在定义一个用于计算和绘制整流正弦波的脚本 abssin.m :

1%Script to calculate and plot a rectified sine wave
2t=linspace(0,10,100);
3y=abs(sin(t)); % get abs
4plot(t,y);
5title('Rectified Sine Wave');
6xlabel('t');

命令行执行此脚本如下,为了让使用者容易得到帮助信息,在每个脚本的头几行写上有关该脚本的注释是一个很好的习惯:

 1>> abssin
 2
 3>> help abssin % 查看脚本的帮助文档,其实就是自己定义的注释内容
 4'abssin' is a script from the file ...\OctaveWK\abssin.m
 5
 6Script to calculate and plot a rectified sine wave
 7
 8
 9Additional help for built-in functions and operators is
10available in the online version of the manual.  Use the command
11'doc <topic>' to search the manual index.
12
13Help and information about Octave is also available on the WWW at 
14https://www.octave.org and via the help@octave.org mailing list.

这是一个经过拖拽形成的3D图 假设你使用了很多的脚本之后你会对这些脚本混淆不清。要想知道你拥有哪些脚本,你可以输入 what 命令来获取一个你当前所有的脚本和数据的列表:

1>> what
2M-files in directory xxx\Desktop\OctaveWK:
3
4   abssin.m

Octave 控制语句

使用 Octave 能非常方便地执行向量和矩阵的计算,但是如果要实现更加复杂的功能,还需要引入一些标准的程序语言特性。比如 if…else、if…elseif、switch、for、while 等控制语句。

符号 意义 例子
== 等于 if x == y
~= 不等于(区别于常规) if x ~= y
> 大于 if x > y
>= 大于等于 if x >= y
< 小于 if x < y
<= 小于等于 if x <= y
& if x==1 & y>2
| if x==1 | y>2
~ x ~= y
在命令行界面中执行 if 语句时,Octave 会等到你输入 end 语句之后才执行整个表达式。
1>> a = 10; b = 20;
2>> if a > b
3c = 3
4else
5c = 4
6end
7c = 4

控制语句中又很多的逻辑表达式——表达式根据相应条件具有真或者假的属性。在 Octave 中,逻辑表达式返回值根据真或者假分别返回 1 或者 0,这与C语言一样,0表示假,非0表示真。

下面是 switch 控制的用法,是不是很简单?

 1>>  switch a
 2case 0
 3disp('a is zero');
 4case 1
 5disp('a is one');
 6otherwise
 7disp('a is not a binary digit');
 8end
 9a is one
10>>

很多场景下都是向量或者矩阵运算,但是仍会存在少数情况需要 for 或者 while 来搞定:

 1>> for n=1:5
 2nf(n)=factorial(n);
 3end
 4>> disp(nf)
 5     1     2     6    24   120
 6
 7>> n = 5;
 8>> while n > 0
 9n=n-1
10end
11n = 4
12n = 3
13n = 2
14n = 1
15n = 0
16>>

一下篇文章将介绍 Octave 的函数定义,多返回值的函数,矩阵与向量的常见计算方法以及更多的绘图技巧。