2011-09-23 157 views
1

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

到目前为止,我已经通过传递数值数据表获得了相当的成功,但在试图添加一列数据类型DateTime时遇到了一些障碍。我一直在做的工作是将DataTable的值填入双精度数组中,因为MATLAB只关心双精度,然后直接转换为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; 
} 

Conversion.ConvertToDouble是我自己的日常迎合空值,为DBNull并返回double.NaN,又因为Matlab的对待所有NULLS为NaN的。

所以,这是事情;有谁知道一个MATLAB数据类型,这将允许我传入一个连续的数组与多个数据类型?我能想到的唯一解决方法包括使用MWStructArraysMWStructArray,但这看起来很诡异,我不确定它在MATLAB代码中的工作情况如何,所以我想尝试找到更优雅的解决方案,只要我可以。我看了一下使用MWCellArray,但是当我尝试实例化它时,它给了我一个编译错误。

我希望能够做到这样的事情;

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

但正如我所说的,我得到一个编译错误与此,也传递一个对象数组到构造函数。

道歉,如果我错过了什么愚蠢的东西。我已经做了一些谷歌搜索,但关于Matlab到.NET接口的信息似乎有点亮,所以这就是我在这里发布它的原因。

在此先感谢。

[编辑]

感谢大家的建议。

原来,我们特定实现的最快和最有效的方法是将Datetime转换为SQL代码中的int值。

但是,在其他方法中,我建议使用MWCharArray方法。它使用最少的大惊小怪,事实证明我只是做错了 - 你不能像另一个MWArray类型那样对待它,因为它当然被设计为处理你需要遍历它的多个数据类型,坚持使用MWNumerics或者无论你在哪里都喜欢你。有一点需要注意的是MWArrays是基于1的,而不是基于0的。那个人一直把我赶出去。

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

+3

您是否试过显式创建一个新的MWCellArray(numRows,numCols),然后遍历嵌套for循环的对象集合,手动设置单元格数组的元素? – Matt

+0

原来是(对我来说)最好的解决方案之一...... –

回答

5

由于@Matt在评论中建议,如果你想存储不同的数据类型(数字,字符串,结构等...),你应该使用相当于这个托管API公开的单元数组,即MWCellArray类。

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

诀窍是将DataTable中包含的对象映射到支持类型的MWArray衍生类。下面是我所使用的那些(检查documentation完整的列表):

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

有关的日期/时间数据的说明:在.NET中,System.DateTime表示日期和时间:

自0001元月 1,已经过去的00的100毫微秒间隔数:00:00.000

而在MATLAB,这是什么DATENUM功能不得不说:

日期以一串数字表示从一个特定的日期和时间,其中datenum(“扬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 

从MATLAB生成器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; 
     } 
    } 
} 

由编译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 
2

一个选择是直接从matlab中打开.NET代码,并使用.net接口直接使用matlab查询数据库,而不是试图通过您描述的这个序列化过程。我在我们的环境中多次做到这一点,取得了巨大成功。在这样的努力下 Net.addAssembly是你最大的朋友。

详情在这里。 http://www.mathworks.com/help/matlab/ref/net.addassembly.html

第二种选择是使用Matlab Cell Array的。你可以设置它,所以列是不同的数据类型,每列形成一个单元格。这是matlab本身在textscan函数中使用的一个技巧。我建议阅读该功能的文档: http://www.mathworks.com/help/techdoc/ref/textscan.html

第三个选项是完全使用textscan。从.net代码中写出一个文本文件,并让textscan处理它的解析。 Textscan是将这类数据转换为matlab的强大机制。您可以将文本扫描指向文件或一串字符串。

0

我试图通过@Amro写的功能,但结果肯定日期不正确。

我想什么:

  1. 在C#创建日期
  2. 使用功能转换到Matlab的日期NUM由@Amro
  3. 使用Matlab中这个数字提供给检查其正确性

它似乎有问题与日期1月1日00:00:00一些年如eg 2014,2015.例如,

DateTime dt = new DateTime(2014, 1, 1, 0, 0, 0); 
double dtmat = convertToMATLABDateNum(dt); 

我从这里得到dtmat = 735599.0。 我在Matlab中使用如下:

datestr(datenum(735599.0)) 

我得到的回报是:

ans = 31-Dec-2013 

当我试图1 2012年1月也没关系。任何建议或为什么发生这种情况?