将.NET数据表传递给MATLAB

Mel*_*den 1 c# ado.net matlab matlab-deployment

我正在为Matlab组件构建一个接口层,该组件用于分析由我正在构建的单独.NET应用程序维护的数据.我正在尝试将.NET数据表序列化为数字数组,以传递给MATLAB组件(作为更通用的序列化例程的一部分).

到目前为止,我已经相当成功地传递了数值数据表,但是在尝试添加数据类型列时我遇到了麻烦DateTime.我到目前为止所做的是将值从填充DataTable到双数组中,因为MATLAB只关心双精度,然后直接转换为a MWNumericArray,它本质上是一个矩阵.

这是当前的代码;

else if (sourceType == typeof(DataTable))
{
    DataTable dtSource = source as DataTable;
    var rowIdentifiers = new string[dtSource.Rows.Count];               
    // I know this looks silly but we need the index of each item
    // in the string array as the actual value in the array as well
    for (int i = 0; i < dtSource.Rows.Count; i++)
    {
        rowIdentifiers[i] = i.ToString();
    }
    // convenience vars
    int rowCount = dtSource.Rows.Count;
    int colCount = dtSource.Columns.Count;
    double[,] values = new double[rowCount, colCount];

    // For each row 
    for (int rownum = 0; rownum < rowCount; rownum++)
    {
        // for each column
        for (int colnum = 0; colnum < colCount; colnum++)
        {
            // ASSUMPTION. value is a double
            values[rownum, colnum] = Conversion.ConvertToDouble(dtSource.Rows[rownum][colnum]);
        }
    }
    return (MWNumericArray)values;
}
Run Code Online (Sandbox Code Playgroud)

Conversion.ConvertToDouble 是我自己的例程,它适合NULLS,DBNull并返回double.NaN,因为Matlab将所有NULLS视为NaN.

所以这就是事情; 有没有人知道MATLAB数据类型允许我传入一个具有多种数据类型的连续数组?我能想象的唯一的解决方法包括使用MWStructArrayMWStructArrays,但似乎哈克和我不知道它是如何以及在MATLAB代码工作,所以我想尝试一下,如果我能找到一个更好的解决方案.我已经看过使用了一个MWCellArray,但是当我尝试实例化它时,它给了我一个编译错误.

我希望能够做类似的事情;

object[,] values = new object[rowCount, colCount];
// fill loosely-typed object array
return (MWCellArray)values;
Run Code Online (Sandbox Code Playgroud)

但正如我所说,我得到了一个编译错误,同时将一个对象数组传递给构造函数.

如果我错过任何愚蠢的事情,我会道歉.我已经做了一些谷歌搜索,但有关Matlab到.NET界面的信息似乎有点轻,所以这就是我在这里发布的原因.

提前致谢.

[编辑]

感谢大家的建议.

事实证明,我们特定实现的最快和最有效的方法是将Datetime转换为SQL代码中的int.

但是,在其他方法中,我建议使用MWCharArray方法.它使用最少的烦恼,事实证明我只是做错了 - 你不能把它当作另一种MWArray类型,因为它当然是为了处理你需要迭代它的多种数据类型,坚持MWNumerics或随你随心所欲的任何东西.需要注意的一点是MWArrays是基于1的,而不是基于0的.那个人一直在抓我.

我今天晚些时候会在有空的时候进行更详细的讨论,但现在我没有.再次感谢大家的帮助.

Amr*_*mro 6

正如@Matt在评论中建议的那样,如果要存储不同的数据类型(数字,字符串,结构等等),则应使用此托管API公开的等效单元阵列,即MWCellArray类.

为了说明,我实现了一个简单的.NET程序集.它公开了一个MATLAB函数,它接收一个单元格数组(来自数据库表的记录),并简单地打印它们.这个函数将从我们的C#应用​​程序中调用,该应用程序生成一个样本DataTable,并将其转换为MWCellArray(逐个细胞填充表条目).

诀窍是DataTable通过MWArray-derived类将包含在其中的对象映射到支持的类型.以下是我使用的(查看完整列表的文档):

.NET native type          MWArray classes
------------------------------------------
double,float,int,..       MWNumericArray
string                    MWCharArray
DateTime                  MWNumericArray       (using Ticks property)
Run Code Online (Sandbox Code Playgroud)

关于日期/时间数据的注释:在.NET中,System.DateTime将日期和时间表示为:

自0001年1月1日00:00:00000以来经过的100纳秒间隔的数量

在MATLAB中,这就是DATENUM函数所说的:

序列日期编号表示特定日期和时间的整数和小数天数,其中datenum('Jan-1-0000 00:00:00')返回数字1

出于这个原因,我在C#应用程序中编写了两个辅助函数来转换DateTime"ticks"以匹配MATLAB对序列日期编号的定义.


首先,考虑这个简单的MATLAB函数.它希望收到包含表数据的numRos-by-numCols cellarray.在我的示例中,列是:名称(字符串),价格(双),日期(日期时间)

function [] = my_cell_function(C)
    names = C(:,1);
    price = cell2mat(C(:,2));
    dt = datevec( cell2mat(C(:,3)) );

    disp(names)
    disp(price)
    disp(dt)
end
Run Code Online (Sandbox Code Playgroud)

使用MATLAB Builder NE中的deploytool,我们将上面的内容构建为.NET程序集.接下来,我们创建一个C#控制台应用程序,然后添加对MWArray.dll程序集的引用,以及上面生成的引用.这是我正在使用的程序:

using System;
using System.Data;
using MathWorks.MATLAB.NET.Utility;  // MWArray.dll
using MathWorks.MATLAB.NET.Arrays;   // MWArray.dll
using CellExample;                   // CellExample.dll assembly created

namespace CellExampleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // get data table
            DataTable table = getData();

            // create the MWCellArray
            int numRows = table.Rows.Count;
            int numCols = table.Columns.Count;
            MWCellArray cell = new MWCellArray(numRows, numCols);   // one-based indices

            // fill it cell-by-cell
            for (int r = 0; r < numRows; r++)
            {
                for (int c = 0; c < numCols; c++)
                {
                    // fill based on type
                    Type t = table.Columns[c].DataType;
                    if (t == typeof(DateTime))
                    {
                        //cell[r+1,c+1] = new MWNumericArray( convertToMATLABDateNum((DateTime)table.Rows[r][c]) );
                        cell[r + 1, c + 1] = convertToMATLABDateNum((DateTime)table.Rows[r][c]);
                    }
                    else if (t == typeof(string))
                    {
                        //cell[r+1,c+1] = new MWCharArray( (string)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (string)table.Rows[r][c];
                    }
                    else
                    {
                        //cell[r+1,c+1] = new MWNumericArray( (double)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (double)table.Rows[r][c];
                    }
                }
            }

            // call MATLAB function
            CellClass obj = new CellClass();
            obj.my_cell_function(cell);

            // Wait for user to exit application
            Console.ReadKey();
        }

        // DateTime <-> datenum helper functions
        static double convertToMATLABDateNum(DateTime dt)
        {
            return (double)dt.AddYears(1).AddDays(1).Ticks / (10000000L * 3600L * 24L);
        }
        static DateTime convertFromMATLABDateNum(double datenum)
        {
            DateTime dt = new DateTime((long)(datenum * (10000000L * 3600L * 24L)));
            return dt.AddYears(-1).AddDays(-1);
        }

        // return DataTable data
        static DataTable getData()
        {
            DataTable table = new DataTable();
            table.Columns.Add("Name", typeof(string));
            table.Columns.Add("Price", typeof(double));
            table.Columns.Add("Date", typeof(DateTime));

            table.Rows.Add("Amro", 25, DateTime.Now);
            table.Rows.Add("Bob", 10, DateTime.Now.AddDays(1));
            table.Rows.Add("Alice", 50, DateTime.Now.AddDays(2));

            return table;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由编译的MATLAB函数返回的此C#程序的输出:

'Amro'
'Bob'
'Alice'

25
10
50

     2011            9           26           20           13       8.3906
     2011            9           27           20           13       8.3906
     2011            9           28           20           13       8.3906
Run Code Online (Sandbox Code Playgroud)