2011-09-23 130 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月也沒關係。任何建議或爲什麼發生這種情況?