如何优化你的matlab程序

How to optimize your matlab program

Matlab作为一个全能型软件兼解释型语言,在科研、工程设计、仿真模拟等多个领域都具有不可撼动的地位,曾经有人开玩笑道:“matlab除了不能给你生孩子,其它的都能干。相信在座的各位都或多或少使用过matlab。但是,在功能方面可以说神功大成的matlab其实也有一个比较重大的缺陷,那就是慢。做算法的诸位,包括我本人,我相信对matlab强大的功能印象深刻的同时,也会在无数个瞬间突然产生这样一个念头:

如果matlab更快一点就好了。

不同于编译型语言的汇编,C、C++,Go,Rust,解释型语言是带有先天不足的。解释型语言是由解释器运行的,它的特点是就是自由和慢。由于几乎所有的解释型语言都带有自动垃圾回收,所以我们可以轻松愉快地编写各种代码而不用担心变量的作用域和内存泄露等问题,自动垃圾回收会帮助你解决一切;而这种随心所欲的代价就是,由于需要解释器实时地逐行执行语句,以及执行垃圾回收需要时间而导致的效率低下。

那么,有没有办法让matlab变快一些呢?

一个例子

接下来,我将使用一个经典算法的实现向各位读者介绍如何优化你的matlab。这个算法就是FFT-Fast Fourier Transform,快速傅里叶变换。快速傅里叶变换可以帮助我们对一段任意长度的离散信号进行频域分析,也就是说,它是这样一个有魔力的机器,可以将一段信号输入,吐出来的却是一些频率和幅度均不同的正弦波。其在工程与学术界得到了极其广泛的应用,广泛到这个本来看起来非常不可思议的算法已经事实上成为了大量学术理论和工程应用的基石。要知道,这个理论最开始受到拉格朗日的强烈反对,因为他怎么也想不明白任意一个连续函数是如何能被分解成无数个正弦函数的。

这里有一个非常经典的例子。我使用FL Studio写了一段简单的钢琴曲,将导出的音频文件放进Adobe Audition来看一看:

而这是这段钢琴曲在FL Studio中的样子:

我们可以看到,首先频谱窗口中似乎有一条条的横向条纹,它们的高低位置与FL Studio中的音符位置有一定的对应关系。实际上,这就是一个指定音高的钢琴音色产生的频谱,不同于正弦波,钢琴音色是由很多正弦波叠加产生的,也就是说,它是由各种不同频率的音频分量构成的,我们可以在频谱窗口中清晰地看到这一点:每一条较为清晰的横线就是一个可以被明确分辨的频率分量。FFT算法帮助我们做到了这一点,我们的视角从直观的时间-幅度坐标,转移到相对不直观的频率-幅度坐标。

最原始的办法

现在,我们已经搞明白了算法。假设你是一个新人,你刚刚学会matlab代码要如何编写,此时,你就可以照着算法一步步地实现自己的FFT模块了。在这里我们希望这个FFT模块输入一个N行的列向量,其中每一行都是一个复数。我们不要求N必须是2的幂次方,如果N不足2的幂次方,我们希望FFT能够自行在这个列向量的结尾补0,使其能够达到距离N最近的2的幂次方。

另外,我们也希望能够通过第二个参数手动指定FFT点数,同样的,当输入的列向量的行数N不足最大点数时,自动补0到最大点数,然后再对补0之后的序列做FFT。这样,我们就有了一个比较灵活的FFT模块,供我们下一步的开发和使用了。

喝点咖啡,写点Java

Matlab与Java的关系是及其紧密的。Matlab向Java开放了大量的底层接口,用户在进行开发时可以选择直接将Java代码嵌入Matlab中。只要你的电脑里同时安装了matlab和jdk,无需过多操作,你就可以直接体验java带给你的便利。不过,MATLAB对Java的版本有要求,具体可以到这里查看。推荐大家使用OpenJDK,下载zip版本,这个版本的组件似乎更加齐全。解压后,添加一个环境变量:

1
%JAVA_HOME% = 解压路径

并且将

1
"%JAVA_HOME%\bin"

添加到Path下。如果是windows 11,不必写双引号。

现在,打开一个windows terminal,执行java -version看看结果,如果有输出,且输出的版本与你下载的版本对应,那么你已经把Java配置好了。

然后,打开你的matlab,在命令行执行

1
jenv("system")

matlab就会自动调用你配置好的java。

C语言如何

如果你想试试C语言的mex,体验更加便利的matlab与C语言的交互,你得先配置C语言环境。同样的,matlab不同版本对C语言编译器的版本有要求。官方似乎更推荐Mingw-C,不过我使用了MSVC。具体各个编译器版本,可以到这里查看。

为了防止安装VS这个巨无霸,我参照了这个教程,保证我最小安装一个可用的MSVC编译器,而不用安装动辄数十数百G的整个VS。安装好后,如果一切正常,打开matlab,运行

1
mex -setup cpp

就应该能够成功配置。