将 .NET 数据表传递给 MATLAB
我正在为 Matlab 组件构建一个接口层,该组件用于分析由我也在构建的单独 .NET 应用程序维护的数据。我正在尝试将 .NET 数据表序列化为要传递给 MATLAB 组件的数值数组(作为更通用的序列化例程的一部分)。
到目前为止,我在传递数字数据表方面已经相当成功,但在尝试添加数据类型 DateTime
的列时遇到了障碍。到目前为止,我一直在做的是将 DataTable 中的值填充到双精度数组中,因为 MATLAB 只真正关心双精度,然后直接转换为 MWNumericArray code>,本质上是一个矩阵。
这是当前的代码;
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
是我自己的例程,它满足 NULLS、DBNull 并返回 double.NaN,同样是因为 Matlab 将所有 NULLS 视为 NaN。
所以事情是这样的;有谁知道 MATLAB 数据类型可以让我传入具有多种数据类型的连续数组吗?我能想到的唯一解决方法是使用 MWStructArrays
的 MWStructArray
,但这看起来很老套,而且我不确定它在 MATLAB 代码中的工作效果如何,所以我如果可以的话,我想尝试找到一个更优雅的解决方案。我尝试过使用 MWCellArray,但是当我尝试实例化它时,它给了我一个编译错误。
我希望能够做类似的事情;
object[,] values = new object[rowCount, colCount];
// fill loosely-typed object array
return (MWCellArray)values;
但正如我所说,我遇到了编译错误,也将对象数组传递给构造函数。
如果我错过了任何愚蠢的事情,我深表歉意。我已经进行了一些谷歌搜索,但是有关 Matlab 到 .NET 接口的信息似乎有点少,所以这就是我将其发布在这里的原因。
提前致谢。
[编辑]
感谢大家的建议。
事实证明,对于我们的具体实现来说,最快、最有效的方法是在 SQL 代码中将 Datetime 转换为 int。
但是,在其他方法中,我建议使用 MWCharArray 方法。它使用最少的麻烦,事实证明我只是做错了 - 你不能像对待另一个 MWArray 类型一样对待它,因为它当然是为了处理你需要迭代它的多种数据类型而设计的,坚持使用 MWNumerics 或无论您喜欢什么,都可以。需要注意的一件事是 MWArray 是从 1 开始的,而不是从 0 开始的。那个人一直在追赶我。
今天晚些时候,当我有时间时,我将进行更详细的讨论,但现在我没有。再次感谢大家的帮助。
I'm building an interface layer for a Matlab component which is used to analyse data maintained by a separate .NET application which I am also building. I'm trying to serialise a .NET datatable as a numeric array to be passed to the MATLAB component (as part of a more generalised serialisation routine).
So far, I've been reasonably successful with passing tables of numeric data but I've hit a snag when trying to add a column of datatype DateTime
. What I've been doing up to now is stuffing the values from the DataTable
into a double array, because MATLAB only really cares about doubles, and then doing a straight cast to a MWNumericArray
, which is essentially a matrix.
Here's the current code;
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
is my own routine which caters for NULLS, DBNull and returns double.NaN, again because Matlab treats all NULLS as NaNs.
So here's the thing; Does anyone know of a MATLAB datatype that would allow me to pass in a contiguous array with multiple datatypes? The only workaround I can conceive of involves using a MWStructArray
of MWStructArrays
, but that seems hacky and I'm not sure how well it would work in the MATLAB code, so I'd like to try to find a more elegant solution if I can. I've had a look at using an MWCellArray
, but it gives me a compile error when I try to instantiate it.
I'd like to be able to do something like;
object[,] values = new object[rowCount, colCount];
// fill loosely-typed object array
return (MWCellArray)values;
But as I said, I get a compile error with this, also with passing an object array to the constructor.
Apologies if I have missed anything silly. I've done some Googling, but information on Matlab to .NET interfaces seems a little light, so that is why I posted it here.
Thanks in advance.
[EDIT]
Thanks to everyone for the suggestions.
Turns out that the quickest and most efficient way for our specific implementation was to convert the Datetime to an int in the SQL code.
However, of the other approaches, I would recommend using the MWCharArray approach. It uses the least fuss, and it turns out I was just doing it wrong - you can't treat it like another MWArray type, as it is of course designed to deal with multiple datatypes you need to iterate over it, sticking in MWNumerics or whatever takes your fancy as you go. One thing to be aware of is that MWArrays are 1-based, not 0-based. That one keeps catching me out.
I'll go into a more detailed discussion later today when I have the time, but right now I don't. Thanks everyone once more for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
正如 @Matt 在评论中建议的那样,如果你想存储不同的数据类型(数字、字符串、结构等...... ),您应该使用此托管 API 公开的等效元胞数组,即 MWCellArray 类。
为了说明这一点,我实现了一个简单的 .NET 程序集。它公开了一个 MATLAB 函数,该函数接收元胞数组(数据库表中的记录),并简单地打印它们。该函数将从我们的 C# 应用程序中调用,该应用程序会生成示例
DataTable
,并将其转换为MWCellArray
(逐个单元格填充表条目)。诀窍是将
DataTable
中包含的对象映射到MWArray
派生类支持的类型。以下是我使用的(查看文档有关完整列表):有关日期/时间数据的注释:在 .NET 中,System.DateTime 将日期和时间表示为:
在 MATLAB 中,这就是 DATENUM 函数必须说:
为此,我在 C# 应用程序中编写了两个辅助函数来转换
DateTime
“刻度”以匹配序列日期数字的 MATLAB 定义。首先,考虑这个简单的 MATLAB 函数。它期望接收一个包含表数据的 numRos-by-numCols 元胞数组。在我的示例中,列是:名称(字符串)、价格(双精度)、日期(DateTime)
使用 deploytool 来自 MATLAB Builder NE,我们将上述内容构建为 .NET 程序集。接下来,我们创建一个 C# 控制台应用程序,然后除了上面生成的程序集之外,还添加对 MWArray.dll 程序集的引用。这是我正在使用的程序:
由已编译的 MATLAB 函数返回的此 C# 程序的输出:
As @Matt suggested in the comments, if you want to store different datatypes (numeric, strings, structs, etc...), you should use the equivalent of cell-arrays exposed by this managed API, namely the MWCellArray class.
To illustrate, I implemented a simple .NET assembly. It exposes a MATLAB function that receives a cell-array (records from a database table), and simply prints them. This function would be called from our C# application, which generates a sample
DataTable
, and convert it into aMWCellArray
(fill table entries cell-by-cell).The trick is to map the objects contained in the
DataTable
to the supported types by theMWArray
-derived classes. Here are the ones I used (check the documentation for a complete list):A note about the date/time data: in .NET, the System.DateTime expresses date and time as:
while in MATLAB, this is what the DATENUM function has to say:
For this reason, I wrote two helper functions in the C# application to convert the
DateTime
"ticks" to match the MATLAB definition of serial date numbers.First, consider this simple MATLAB function. It expects to receive a numRos-by-numCols cellarray containing the table data. In my example, the columns are: Name (string), Price (double), Date (DateTime)
Using deploytool from MATLAB Builder NE, we build the above as a .NET assembly. Next, we create a C# console application, then add a reference to the
MWArray.dll
assembly, in addition to the above generated one. This is the program I am using:The output of this C# program as returned by the compiled MATLAB function:
一种选择是直接从 matlab 打开 .NET 代码,并让 matlab 使用 .net 接口直接查询数据库,而不是尝试执行您描述的序列化过程。我在我们的环境中多次这样做,并取得了巨大成功。在这样的努力中
Net.addAssembly
是你最好的朋友。详细信息在这里。
http://www.mathworks.com/help/matlab/ref/net .add assembly.html
第二个选择是使用 Matlab 元胞数组。您可以对其进行设置,使列具有不同的数据类型,每列形成一个单元格。这是 matlab 本身在 textscan 函数中使用的技巧。我建议在这里阅读该函数的文档:
http://www.mathworks.com/help/techdoc/ref/textscan.html
第三种选择是完全使用textscan。从 .net 代码中编写一个文本文件,然后让 textscan 处理它的解析。 Textscan 是将此类数据输入 matlab 的非常强大的机制。您可以将 textscan 指向一个文件或一堆字符串。
One option, is to just open up .NET code directly from matlab, and have matlab query the database directly, using your .net interface instead of trying to go through this serialization process you describe. I have done this repeatedly in our environment with great success. In such an an endeavor
Net.addAssembly
is your biggest friend.Details are here.
http://www.mathworks.com/help/matlab/ref/net.addassembly.html
A second option would be to go with Matlab Cell Array's. You can set it up, so the columns are different data types, each column forming a cell. That is a trick matlab itself uses in the textscan function. I'd recommend reading the documentation for that function here:
http://www.mathworks.com/help/techdoc/ref/textscan.html
A third option, is to use textscan completely. Write a text file out from your .net code, and let textscan handle the parsing of it. Textscan is very powerful mechanism for getting this kind of data into matlab. You can point textscan to a file, or to a bunch of strings.
我已经尝试过 @Amro 编写的函数,但某些日期的结果不正确。
我尝试的是:
几年来 1 Jan 00:00:00 的日期似乎存在问题例如2014年、2015年。例如,
我从中得到dtmat = 735599.0。
我在 Matlab 中使用如下:
我得到了这个回报:
当我在 2012 年 1 月 1 日尝试时,一切正常。有什么建议或者为什么会发生这种情况?
I have tried the functions written by @Amro but the result for certain dates are not correct.
What I tried was:
It seems to have problems with date with 1 Jan 00:00:00 for some years e.g. 2014, 2015. For example,
I got dtmat = 735599.0 from this.
I used in Matlab as follow:
I got this in return:
When I tried 1 Jan 2012 it was OK. Any suggestion or why this happens?
我和@Johan有同样的问题。
问题在于闰年无法正确计算日期
要解决此问题,我更改了将 DateTime 转换为以下内容的代码:
I had the same issue as @Johan.
The problem is in Leap years that not calculate correctly the date
To fix it I change the code that converts the DateTime to the following: