Você está na página 1de 11

Call MATLAB Function from C# Client

This example shows how to call a user-defined MATLAB function, myfunc, from a C#
application.

Create a MATLAB function, myfunc, in the folder c:\temp\example.


function [x,y] = myfunc(a,b,c)
x = a + b;
y = sprintf('Hello %s',c);

Create the C# application.


using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// Create the MATLAB instance
MLApp.MLApp matlab = new MLApp.MLApp();
// Change to the directory where the function is located
matlab.Execute(@"cd c:\temp\example");
// Define the output
object result = null;
// Call the MATLAB function myfunc
matlab.Feval("myfunc", 2, out result, 3.14, 42.0, "world");
// Display result
object[] res = result as object[];
Console.WriteLine(res[0]);
Console.WriteLine(res[1]);
Console.ReadLine();
}
}
}

In Microsoft Visual Studio , add a reference to your C# project to the MATLAB COM
object. From the Project menu, select Add Reference.

Select the COM tab in the Add Reference dialog box.


Select the MATLAB application.

Pass Complex Data to MATLAB from C#


Client
This example creates data in the client C# program and passes it to MATLAB . The
matrix (containing complex data) is then passed back to the C# program.

The reference to the MATLAB Type Library for C# is:


MLApp.MLApp matlab = new MLApp.MLApp();

From your C# client program, add a reference to your project to the MATLAB COM
object. For example, in Microsoft Visual Studio , open your project. From
the Project menu, select Add Reference. Select the COM tab in the Add Reference
dialog box. Select the MATLAB application.

Here is the complete example:


using System;
namespace ConsoleApplication4
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
MLApp.MLApp matlab = new MLApp.MLApp();

System.Array pr = new double[4];


pr.SetValue(11,0);
pr.SetValue(12,1);
pr.SetValue(13,2);
pr.SetValue(14,3);

System.Array pi = new double[4];


pi.SetValue(1,0);
pi.SetValue(2,1);
pi.SetValue(3,2);
pi.SetValue(4,3);

matlab.PutFullMatrix("a", "base", pr, pi);

System.Array prresult = new double[4];


System.Array piresult = new double[4];

matlab.GetFullMatrix("a", "base", ref prresult, ref piresult);


}
}
}

Using Matlab from a C# application

n.podbielski, 17 May 2013 CPOL

46.9K

17

5.00 (6 votes)
Rate:vote 1vote 2vote 3vote 4vote 5
Using Matlab from a C# application.

Is your email address OK? You are signed up for our newsletters but
your email address is either unconfirmed, or has not been reconfirmed in a long
time. Please click here to have a confirmation email sent so we can confirm your
email address and start sending you newsletters again. Alternatively, you
can update your subscriptions.
During writing application for my Masters degree diploma I wrote simple
application that was using COM Matlab server. I have found hard to using it
mainly to lack of documentation, which is really basic with only few code
examples for C#. I guess writing programs that use Matlab for calculating is not
encouraged by MathWorks, you would became competition that way
.
Nonetheless I accomplished why I have required to do so I decided to share this
with rest of the world.
Important: I was using R2010a version of Matlab. I realize that there is newer
version. But I had only this version at my disposal. Since interface for
communicating with Matlab server is dependent of installed Matlab version and
registry entries it may have been different with yours. But I suspect not to much.
I also tries with 7.1 and (if I remember correctly) it required only to swap
reference in Visual Studio. But again... it was only test so there might be other
problems that I am not aware of.
Let's start with simple console application. Lets call it MatlabTest. First we will add
dll reference with COM interface. Click RMB on project and choose [Add
Reference] option. In new window click COM tab. In search text box write
'Matlab'. Then choose "Matlab Application (Version 7.10) Type Library".
You should get new reference like below:

Great. Now we should test if it is working. In order to use it we should create our
Matlab server from C# application. To that we can add code to our main program:
Hide Copy Code

var activationContext = Type.GetTypeFromProgID("matlab.application.single");


var matlab = (MLApp.MLApp)Activator.CreateInstance(activationContext);
Console.WriteLine(matlab.Execute("1+2"));
Console.ReadKey();

This code will create single Matlab COM server through Activator class. Program
Id "matlab.application.single" means single Matlab COM server for our
application. When it will try to create another Matlab, it will just return reference
to the same object. Contrary to that we could use "matlab.application" which will
create another instance of Matlab any time Activator.CreateIntance method will
be executed. In more complex applications or for web applications or other
programs which run for long time it may creates big memory leaks since 1
instance cost around 220 Mb (on 64 bit Windows 7 and Matlab R2010a).
After creating Matlab program execute simple sum of 2 integers, just for test of
communication we don't need anything more sophisticated. It should return also
simple string in console:

It's really simple and more important it works!


This way we can send and receive string messages with MATLAB only. It's not
much useful. Also there is one way to find out if our statement had errors. It will
have 'error' string in response.
Let's try to run something like this: '1*', which will result in error:

So to check our command had errors we have to check if output string have "???
Error" in it.
To send some parameters along with our command we have to use on of 'Put*'
methods. Best is one calledPutWorkspaceData. It takes three parameters. First is
desired name of our new Matlab variable. Two other are much more tricky. To set
variable correctly (so you could reference it in command) you must use global
workspace. But it is called? This one took much more time then I would want. It is
not mentioned in documentation of this method. If I remember it right I found it
in some code example and it should be only "base". In the end I created in my
application another method that encapsulated PutWorkspaceData and forget
about it
. Third parameter is value of our variable. It should be simple. Let's
change our code to:
Hide Copy Code

matlab.PutWorkspaceData("a", "base", 2);


Console.WriteLine(matlab.Execute("a*a"));

Result will as below:

But it is just int. What about more complicated structures? How about
multiplication of two vectors? Matlab is using .NET type double to send and

receive information with our application. Again I did not find it anywhere in
documentation, but rather reverse engineered this from data returned from
Matlab.So let us try send 2 arrays of doubles. and multiplicate them in Matlab.
First will be named 'a' and second 'b'. Matlab command will be "a'*b".
Transposition will give us nice matrix instead for single number.
Hide Copy Code

matlab.PutWorkspaceData("a", "base", new[]{2d,3d,1d});


matlab.PutWorkspaceData("b", "base", new[]{4d,3d,2d});
Console.WriteLine(matlab.Execute("a'*b"));

And in return we will get:

Next step will be to return this output to our console app. To do that we can
use GetWorkspaceData that works similar to PutWorkspaceData or... we can
use GetVariable method. This one returns dynamic so our application needs to
run on .NET 4. It takes to parameters name of variable we want to return from
Matlab and again name of workspace. You really should save this string as const
somewhere

. Change our code to:


Hide Copy Code

matlab.PutWorkspaceData("a", "base", new[]{2d,3d,1d});


matlab.PutWorkspaceData("b", "base", new[]{4d,3d,2d});
Console.WriteLine(matlab.Execute("c=a'*b"));
var c = matlab.GetVariable("c", "base");

After that in our console app we will have variable c and it will be two
dimensional array of doubles. To show values of this array in console we can just
iterate it with simple foreach loop. But instead that we will iterate two of the
dimensions. This will give us info about values and dimensions of this matrix.
Hide Copy Code

for (var i = 0; i < c.GetLength(0); i++)


{
for (var j = 0; j < c.GetLength(1); j++)
Console.Write(c.GetValue(i, j) + " ");
Console.WriteLine();
}

Ok.That was matrix. How about vectors? Luckily vectors are for Matlab just
special case of matrix so it will spit out two dimensional array also. More complex
is case of empty matrix. No it is not null. It would be to easy. Instead it is special
type Missing. I guess it have some logic behind. Null would indicate that variable
have no value at all or this is not defined. But we have empty matrix so this is
not defined nor this is lack of value. So why not just array with zero values in it?
No idea.
Lets try run code like below to test it:
Hide Copy Code

Console.WriteLine(matlab.Execute("c=a'*b"));
Console.WriteLine(matlab.Execute("d=[]"));
var c = matlab.GetVariable("c", "base");
var d = matlab.GetVariable("d", "base");
for (var i = 0; i < d.GetLength(0); i++)
{
for (var j = 0; j < d.GetLength(1); j++)
Console.Write(d.GetValue(i, j) + " ");
Console.WriteLine();
}

Running those command in Matlab will work just fine. Instead of that error will be
throwed on first for loop:

Not very nice. To prevent this errors application have to check if dynamic type
returned from matlab is in fact empty (Missing). Not very clean it is better to
wrap this in other method that will perform this check for us whenever we want
to get our data from Matlab. In my project I ended up writing few methods for
returning vectors, matrices, numbers, strings etc. Vector one looked like this:
Hide Copy Code

public static Vector GetVector(this MLApp.MLApp matlabComObject, string variabla_name)


{
var dynamicVariable = matlabComObject.GetBaseWorkSpaceVariable(variabla_name);
var dataList = new Vector();
if (TypeChecker.IsVector(dynamicVariable))
{
dataList = Vector.DynamicToVector(dynamicVariable);
}
else if (TypeChecker.IsNumber(dynamicVariable))
{
dataList.Add(dynamicVariable);
}
else if (TypeChecker.IsEmptyMatrix(dynamicVariable))
{
//do nothing empty vector or matrix ([0x0] or [1x0])
}
else throw new Exception(string.Format(
"Type of dynamic variable ({0}) is not supproted!", dynamicVariable.GetType()));
return dataList;
}

TypeCheker checks for type of dynamic. It's pretty straightforward. For our
Missing type it's just one line:
Hide Copy Code

public static bool IsEmptyMatrix(object dynamicVariable)


{ return dynamicVariable.GetType() == typeof(Missing); }

After checking type of dynamic we can just cast it to another type to take
advantage of static properties of language. Why use dynamic at all? First I think
that ref and out method parameters are messy and second: I prefer
Hide Copy Code

var d = matlab.GetVariable("d", "base");

from
Hide Copy Code

object e;
matlab.GetWorkspaceData("d", "base", out e);

It is only 1 line. And since object you have to create first and then cast it also
don't bother and just use dynamic. But I guess it is just what will you like better.

String are much more friendly and there are just string. Or null.
Now we know how to put and get data from Matlab. How to execute commands
and check them for errors.
If you executed any of these example you probably take notice of very simple
Matlab window which have opened during life of your console app. If you
terminate it by disabling debugging or it will close due to error, Matlab window
will remain opened. If not it will close nicely with console window. But still it huge
memory leak risk if no maintained properly. To that I recommend creating some
special class that will create instance or instances of Matlab. It should track or of
created instances and in case anything bad happens (but dynamic variable cast
is probability
) it will close all instances prior of application exit. Tracking
should be employed throughWeakReference class, so whenever Garbage
Collector would want to destroy Matlab instance it should not be stopped by our
tracking class. To destroy COM instance we can use
methodMarshal.FinalReleaseComObject. So with weak reference code for that
will look like this:
Hide Copy Code

public static void Release(WeakReference instance)


{
if (instance.IsAlive)
{
Marshal.FinalReleaseComObject(instance.Target);
}
}

Method Quit of matlab server instance does not close it immediately and code
above will.
If you want to hide that popup Matlab window you can set this in it's instance:
Hide Copy Code

matlab.Visible = 0;

This way it will fade away and run as service.


This most basic info about Matlab in C#, but it will get you started. So happy
coding.

License
This article, along with any associated source code and files, is licensed
under The Code Project Open License (CPOL)

Share

Você também pode gostar