65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (58投票s)

2003 年 11 月 19 日

7分钟阅读

viewsIcon

583779

downloadIcon

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,有三种可能的解决方案:

  1. 低级 C API
  2. DDE
  3. 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 的工作空间。根据文档,我们有两个主要工作空间:baseglobal

此解决方案由于 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 库中。

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)
© . All rights reserved.