1..2..3 种集成 MATLAB 与 .NET 的方法






4.82/5 (58投票s)
2003 年 11 月 19 日
7分钟阅读

583779

26084
一个用于从 .NET 访问 MATLAB 的库,以及对实现它的三种可能方法的比较。
摘要
在本文中,我将描述三种将 .NET Framework 与 MATLAB 集成的可能技术,然后我将选择其中一种并创建一个用于访问 MATLAB 功能的库。最终目标是创建一个 C# 组件,该组件封装一个 M 文件,类似于 MATLAB R13 COM Builder 所做的。此项目唯一的先决条件是安装 MATLAB。
引言
MATLAB 是一个强大的科学工具,用于数学运算,特别是矩阵运算,它有自己的脚本语言,文件扩展名为 *.M。通常它被用作独立程序,但也可以通过 Java、C 和 FORTRAN 等其他语言以两种方式集成。第一种用法是,我们用一种原生语言声明一个新的函数或组件,以增强 MATLAB 的功能,通常是为了提高执行速度;这种方法使用 MEX 系统。第二种用法,也是本文所描述的,是从外部程序(此时是 .NET 框架中的程序)使用 MATLAB 的功能。在这种模式下,Java 语言扮演着特殊的角色,因为从 R12(也称为 6.0)开始,MATLAB 是基于 Java 的(特别是对于多平台 GUI 功能),你可以轻松地以两种方式使用 Java 类。要从外部程序使用 MATLAB,有三种可能的解决方案:
- 低级 C API
- DDE
- COM
我将从最简单、最高级到最困难、最高效的顺序描述这些解决方案,并在 C# 中实现它们。然后,我将使用 C API 接口,首先创建一个调用 C API 的包装类。最后,我将展示一个工具,可以轻松地生成一个封装 M 文件中存储的 MATLAB 算法的 C# 类,并将该功能发布为面向对象的函数集。例如,给定使用内置函数 magic 的以下 m 文件:
function y = mymagic(x) y = magic(x);
想法是创建一个 .NET 库,它提供了编写如下组件的可能性:
class MyMagic {
public static Matrix mymagic(Matrix m);
}
可能的 MATLAB - .NET 绑定
解决方案 1 - COM 方法
MATLAB 将自身公开为 COM 自动化服务器,因此我们可以使用 .NET COM 互操作性来使用它的函数:我们可以直接使用类型库,或者只使用 Dispatch 接口。服务器的 progid 是 Matlab.Application
。
此代码创建服务器并执行命令 cmd
。
m = CreateObject("Matlab.Application")
m.Execute("cmd");
所有从 MATLAB 到我们程序的数据传输都通过 COM 数据类型完成,矩阵以 COM 术语表示为 SAFEARRAY(double)
指针。使用 COM 互操作性,我们可以使用 double
数组。
double [,] MReal;
double [] MImag;
Result = Matlab.Execute("a = [ 1 2 3 ; 4 5 6 ; 7 8 9];");
call m.GetFullMatrix("a", "base", MReal, MImag);
call m.PutFullMatrix("b", "....)
第二个参数 base
是用于查找矩阵变量 a
的工作空间。根据文档,我们有两个主要工作空间:base
和 global
。
此解决方案由于 COM 类型交换而相当慢,所以最好继续寻找其他方法。无论如何,它在文章的源代码中位于名为 COMMATLib 的文件夹下,该文件夹公开了一个 Matrix
类。
解决方案 2 - DDE
动态数据交换 (DDE) 是 Windows 的一个相当古老但强大的服务,它允许应用程序通信和交换数据。它是整个 COM 的前身,因此也是整个 .NET 的祖父。同样,与 COM 解决方案一样,我们有一个客户端(我们的 .NET 程序)和一个服务器(MATLAB DDE 服务器),它们进行通信。
DDE 通信由服务名称(如 Matlab 或 WinWord)、主题(如 System 或 Engine)以及基于数据元素(称为项)的交换来完成。
DDE 交换的问题在于用于交换信息的数据类型,因为它使用了 Windows 剪贴板数据类型。具体来说,MATLAB 支持:
- 操作结果的文本,以及矩阵数据交换(gulp!)
- 用于图像传输的
Metafilepict
; - 用于 MATLAB-Excel 数据交换的
XLTable
;
这次我们创建与 MATLAB 的 DDE 通信,并使用 EngEvalString
项评估表达式;要获取或设置 Matrix
数据,我们使用与矩阵同名的项。
我创建了一个名为 DDEMatlab
的包装类,其接口与 COMMatlab
相同,但这次我们可以交换图片,例如 plot
命令返回的图片。不过,DDE 的真正问题在于矩阵数据交换,它是完全基于文本的。
解决方案 3 - C API
直接访问 MATLAB C API 是性能和功能方面的最佳解决方案,只需使用 P/Invoke 和一些不安全指针操作。
C 库内部使用 Unix 管道或 COM 与主 MATLAB 实例通信,但在这种情况下,数据传输是通过原始内存块而不是 SAFEARRAY
完成的。因此,我们可以使用 C# 的不安全功能,将矩阵高效地从 MATLAB 传输到 MATLAB,只需记住 MATLAB 以列优先顺序存储数据。
本解决方案的结构将在后面介绍,并附有使用示例。
解决方案比较
我测试了这三种解决方案,以查看它们之间的性能差异,但很容易预见到结果:测试是通过写入和读取一个 200x200 元素的矩阵来完成的。下表总结了结果:
解决方案 | 矩阵 | 图形? | 读取时间 | 写入时间 |
DDE | 文本 | 是 | 902ms | 360ms |
DDE 优化 | XLTable |
是 | 60ms | 80ms |
COM | SAFEARRAY(double) |
否 | 30ms | 30ms |
原生 | double* |
待办事项 | 10ms | 20ms |
matnet 库
matnet 库封装了对 MATLAB 引擎的访问,使用经典的 P/Invoke 机制(由 MATInvoke
类公开),并提供以下功能:
- 直接访问以不同格式存储的矩阵(
Matrix
类) - 访问 MAT 文件以加载以二进制格式存储的数据(
MATFile
类) - 表达式求值(
EngMATAccess
类的Evaluate
方法)
示例和用法
matnet 库的基本用法需要创建一个 EngMATAccess
实例,该实例打开与 MATLAB 实例的通信,或者在不存在时启动它。然后用户可以创建 Matrix
类的实例来存储其数据,并向 MATLAB 发送求值命令。
using (EngMATAccess mat = new EngMATAccess())
{
mat.Evaluate("A = [ 1 2 3; 3 5 6]"));
double [,] mx = null;
mat.GetMatrix("A", ref mx);
}
还有两个更有趣的用法示例。
与 Imaging Toolbox 和 Bitmaps 交互
mateng 库还提供了与 Bitmap 作为 MATLAB 矩阵进行交互的可能性,并使用 MATLAB Imaging Toolbox。演示源代码中的 ImageDemo 程序加载一个图像并使用 MATLAB 的 imnoise
函数对其进行处理,在这种情况下,如果没有任何 MATLAB 实例正在运行,问题在于启动时间。MATLAB 在内部以列优先顺序将图像存储为字节类型的三维矩阵,如下面的图所示。也许与 Bitmap
类的集成可以放在一个 matnet.imaging 库中。
通过 DLL 访问
MATLAB 的一个有趣功能是将 M 文件转换为 DLL 库,这些库可以用来非常高效地分发算法。matnet 库还可以用于访问自定义 DLL 库(请参阅示例代码)。当 M 文件转换为 DLL 时,一个名为 AA
的函数被公开为 mlfAA
,带有 Matrix
参数。这些函数可以通过 P/Invoke 访问,例如,一个名为 AA
的 M 文件编译为 AAX.dll:
function x = AA(b)
x = b + 2
可以通过以下类访问:
class MyDLL
{
[DllImport("AAX.dll")]
static extern IntPtr mlfAA(IntPtr a);
static public Matrix mlfAA(Matrix m)
{
return new Matrix(mlfAA((IntPtr)m));
}
}
结论和未来想法
本文介绍了 matnet .NET 库,作为一种从 .NET 应用程序以非常高效的方式访问 MATLAB 功能的方法。该解决方案已与 MATLAB 提供的另外两种解决方案(DDE 和 COM)进行了比较。matnet 库可用于直接处理 MATLAB 或将 M 文件公开为组件,还可以与 imaging toolbox 和 bitmaps 进行交互。
还有一些东西缺失:
- 一个工具 M2NET,可以自动将 M 文件封装为 .NET 组件或用户自定义库
- 将图形和图表提取为
Bitmap
对象 - 使其在 Linux 上与 Mono 一起工作(抱歉,但我没有 Linux 版的 MATLAB)