Notepad++中优雅编写MATLAB代码的VB.NET自学经历‌

阅读本文需要:想用/正在用MATLAB

本文读完后你将掌握:如何优雅地用NPP开发MATLAB

本文主要内容是我一天内学会的。

cut-off

虽然面临的是完全不同的问题,但这个和上一期那个是同一系列的,都是踩过配置环境相关的坑。有点不同就是:上一期那个是纯粹老师要求,而这一期是我自己一直憋好久憋出来的。

简单交代下动机:MATLAB是用来做科学计算的,但和python这些不一样,本身MATLAB就是个庞然大物,集IDE、命令行、画图等功能于一身。只是这个IDE代码高亮和补全不是很满意,于是我决定用Notepad++(简称NPP)进行开发,然后在MATLAB本体里执行。

当然这不算是个大问题,不过总归是被我玩出点有意思的小花样,还是想秀一下操作。

(友情提示:正片在第2节)

0. 切屏

这个是相对而言是最没有技术含量的。就是开一个NPP写代码,一个MATLAB跑程序,仅此而已。用户体验相对比较差。如果是这么用的话,其实还不如直接在MATLAB自带的编辑器里面写……

(Tips:Win平台,ctrl+TAB是切屏快捷键,会提升一点用户体验)

1. NppExec运行命令行模式的MATLAB

虽然我认为这个不算是非常困难的操作,但是如果没有一些计算机的底子的话,可能发现不了。

MATLAB是可以用命令行模式运行的。这个是很关键的一个问题,因为MATLAB启动速度是比较感人的。比如我这里,直接启动MATLAB大概需要20秒左右的时间。但是,命令行模式运行的话,如果不开笨重的GUI,可以压缩到十秒以内。

在cmd下,运行matlab -h(默认matlab路径已经加入环境变量),可以看到参数列表。这一节感兴趣的是这几个参数:

  • -nosplash: 启动MATLAB时不打开那个logo。(真没什么好看的)
  • -nodesktop:不启动GUI,命令行模式启动MATLAB。值得注意,plot等等画图命令仍然可以用。当然GUI下的变量池、文本编辑器、调试器就么得了。(鱼与熊掌不可兼得)

差不多这样的,当然字体有点丑陋

  • -sd 和 -useStartupFolderPref:两个和初始工作路径相关的参数。-sd加目录字符串是以指定目录打开matlab, -useStartupFolderPref是用MATLAB偏好设置里的目录(当然要提前设置好),二选一即可。(Tips: MATLAB的快捷方式打开属性,也是可以调整起始目录的)
  • -r:启动同时运行一段指令。这个一般有两种用法,一种是你只想执行一条指令,那就把指令打在后面(注意空格的问题,两边加双引号),还有一种是,我后面再进行后续操作,但需要提前配置一些环境,那就可以把这些写成一个m文件,启动时用-r调用。

上一期我们知道,NPP可以F5执行一条NPP指令。NPP指令可以认为约等于一条DOS指令,唯一不同是多了些内置指令(如NPP_SAVE,保存当前文件),和一些环境变量(如$(FULL_CURRENT_PATH)是当前完整路径,注意到这个和%cd%即cmd对环境变量的引用方式不同。)具体内容可以在NPP官方文档(http://docs.notepad-plus-plus.org/)查看。

但是F5只能执行一行指令的蛋疼编译方式还是有点撑不住,所以如果你在用NPP进行开发,郑重向你推荐NPP的插件NppExec在插件-插件管理中找到即可下载。NppExec提供的F6执行可以运行多行代码,可以保存为脚本,还可以在控制台试命令,岂不美哉。

在知道这两件事之后,就可以用F6执行:

NPP_SAVE

matlab -nodesktop -nosplash -sd "$(CURRENT_DIRECTORY)" -r $(NAME_PART)

这样,每次执行后,就会多运行一个MATLAB进程,把代码跑出来。如果你把MATLAB当成一种编程语言来看,那么这种运行方式其实也足够简单了。一键编译运行,还要啥自行车?

只是,MATLAB打开速度还是太慢了(即使不开GUI,白等十几秒也是很难受的),另外,要去查看结果,还是要切到新打开的MATLAB上。如果我们能让MATLAB一直运行,然后在NPP上运行一段程序,给MATLAB一个信号,执行一段指令,再返回NPP,这样把MATLAB当成个服务器来用,全程不需要切出NPP,这样就好了。问题是,这能做到吗?

2. NppExec & MATLAB COM automation API

还真可以,假如你用的是WIndows的MATLAB。

WIndows平台提供所谓COM模型(组件对象模型)技术,可以解决程序间的通信问题。而COM automation是一种COM协议,功能是A程序调用操作B程序的组件。MATLAB恰好有提供这么一套协议的API,也就意味着我们可以用支持COM automation的程序来控制MATLAB(当然,反过来也可以让MATLAB控制Excel之类的程序)文档可以在这里找到:(https://ww2.mathworks.cn/help/matlab/call-matlab-com-automation-server.html?s_tid=CRUX_lftnav)

题外话:如果你看这个教程的相关链接,你会发现Python、Fortran、C/C++、Java等一系列MATLAB的API……Mathworks真是个不会拒绝任何来源的用户的公司呢

如果你已经试过了matlab -h,想必你已经发现了matlab -automation这个参数,它可以让matlab以命令行模式后台运行(当然你可以把它调到前台,看起来普通的-nodesktop没什么两样),同时开启服务器模式。

那么问题来了,我们要如何与MATLAB的COM控件通信呢?API给我们的解决方案就是:用支持COM控件的程序。具体来说,是.NET系的C#VB

我最终选择的是相对比较容易上手的VB进行开发。talk is cheap,先上程序:

' open_matlab.vb

Imports System

Module open_matlab

    Sub Main()

        Dim h As Object

        Dim res As String

        Dim matcmd As String

        h = GetObject(, "Matlab.Application")

        Console.WriteLine("MATLAB & Notepad++")

        Console.WriteLine(" ")

        while True

            Console.Write(">> ")

            matcmd = Console.ReadLine()

            if matcmd.Equals("!!") then

                Exit while

            End if

            res=h.Execute(matcmd)

            Console.WriteLine(res)

        End while

    End Sub

End Module

具体语法先不谈(VB.NET语法在W3school有教程),说两个关键点:

  • h = GetObject(, "Matlab.Application");这一句是获取已经打开的MATLAB服务器的句柄。Matlab.Application是一般的MATLAB主程序的ProgramID,是固定的(可以在文档里查到)。如果需要打开个新的MATLAB服务端,请见文档。
  • res=h.Execute(matcmd);这里res和matcmd都是String类型。很好理解 ,就是把命令送到服务端,再返回结果的。这里有几点说明:1. res会返回MATLAB的一切输出,比如你执行a=1(不带分号),它会按照你MATLAB输出格式那样,返回你【换行a =换行1换行】,都会存在res里。2. 命令行模式下,没有错误输出流(也就是报错的红颜色),取而代之的是在返回值开头会额外加三个问号,表示你写的这什么破程序劳资看不懂3. 虽然命令被执行了,但是你后台那个服务端窗口不会留下任何输出,如果你想不在VB获取输出而切屏到服务端去看,是不可能的。但如果你检查变量池,会发现确实有执行过的痕迹。4. 如果重新连接服务端,只要服务端不关闭,变量池是保持原来的状态的。

那么总归效果如何呢?

我真的觉得海星

这种图窗安排有点像Pycharm的调试模式。上面写代码,下面可以随时执行,非常快乐了。

目前唯一的不足就是:如果输入ctrl+c中断信号,不能像MATLAB控制台一样中断当前命令继续执行,而是直接整个程序被kill了。这个目前还没有解决,可能会麻烦些,应该要深入理解Windows程序消息处理机制。相信VB是可以做到这一点的。这方面有懂的朋友欢迎评论区交流。

顺便附上编译VB用的NppExec脚本:

cd "C:\Users\xxxx\Documents\npp_selfpatch" // 我存NPP脚本的路径

vbc "$(FULL_CURRENT_PATH)"

INPUTBOX "Execute?y/[n]" : n // 提供一个编译后是否直接执行的选项,是个消息框

if $(INPUT)==y goto @exe // 众所周知DOS的分支很坑,所以用goto标签了

if $(INPUT)==Y goto @exe

if 1==1 goto @end

:@exe

"$(CURRENT_DIRECTORY)\$(NAME_PART).exe"

:@end

后记

这么一套操作细想下来还是很普适性的,所有脚本语言都能用类似的方式搞成这个样子(MATLAB还属于调教难度比较大的那种了,Python就更简单,直接运行解释器就完事了)

NppExec下面的也可以搞成shell、ssh等等,总之很有扩展性。

这个automationAPI是我在研究JupyterNotebook时偶然注意到的。我的下一个目标可能就是要在远端Jupyter上运行MATLAB(不过可能有点难)。不过我近期可以做的就是3b1b的那套动画包配置环境的心得,感觉也还是有话要说的。

我的专栏感觉快成了配置环境的专场了啊(苦笑)

另外封面图意外的是MATLAB logo骑在NPP logo上面,暗示了什么?

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空