Matlab: interfaz COM

En un post anterior he hablado sobre el toolbox de redes neuronales que matlab nos ofrece como implementación alternativa de todos los algoritmos y estructuras necesarias para trabajar con este tipo de herramienta. Pues bien, puede ser muy interesante poder interactuar entre un lenguaje convencional (java, c++, c#, etc) y matlab, de manera que podamos embeber dentro de una aplicación de usuario final las funcionalidades que matlab nos puede ofrecer.

Para facilitar esto, matlab ofrece un interfaz externo que nos permite bien directamente con C++ o mediante componentes COM (también podemos hacerlo indirectamente con java, puesto que en el terminal de matlab tenemos acceso directo para ejecutar clases java, pero esto está más pensado para invocar código java desde matlab que a la inversa ) ejecutar comandos en el terminal, intercambiar datos, manipular diferentes propiedades de la sesión etc.

Como lo que yo he utilizado han sido los componentes COM, será lo que pasaré a comentar, si bien las funciones son las mismas, y por supuesto utilizando C++ será mucho más eficiente que utilizando COM.

Haciendo una simple búsqueda en la ayuda de matlab por «automation server», nos encontramos con la documentación que matlab nos ofrece [1] sobre cómo utilizar su interfaz externa con ejemplos en Visual Basic, aquí comentaré los métodos que podemos ejecutar y mostrando ejemplos en C#.

El primer paso que debemos dar en conseguir conectar al «automation server» que nos ofrece matlab, utilizando las facilidades que nos ofrezca el lenguaje de programación seleccionado. En este caso utilizaremos las facilidades que nos ofrece el API de reflesión de .NET, que gracias a las clases Type y Activator podremos enlazar dinámicamente con el componente COM de matlab.

//Obtained COM type from a ProdId. In this

//case matlab’s prodId is matlab.application

Type matlabServerType =

Type.GetTypeFromProgID(«matlab.application»);

//Create a Object with Type information

Object matlabServerObj = Activator.CreateInstance(

matlabServerType);

La clase Type nos ofrece el método GetTypeFromProgID que a partir de un identificador de programa nos devuelve una referencia a la clase Type para después pasárselo al método CreateInstance de la clase Activator para recuperar una referencia de tipo Object que después utilizaremos para invocar todos los métodos disponibles en el componente invocando al método InvokeMember.

Podemos ver la cadena «matlab.application» que se pasa el método GetTypeFromProdID. Esta cadena es el progID (identificador de programa) que todo componente COM registrado en nuestro sistema deberá tener y deberemos conocer para poder utilizarlo con esta técnica. En el caso del servidor COM de matlab el identificador es el que acabamos de utilizar.

Bueno, pues ya está, ahora si ejecutamos el código anterior, crearemos una sesión nueva en matlab, apareciéndosenos una ventana de terminal matlab como la mostrada a continuación.

A partir de este momento podremos comenzar a interactuar con la sesión recién creada, creando matrices, invocando comandos y funciones matlab, cerrar sesión, etc, las cuales repasaremos a continuación.

Cerrar Sessión: Quit

La función «Quit» nos permite cerrar la sesión que acabamos de crear. Para invocarla no necesitamos ningún parámetro y el código C# para utilizarla sería el siguiente:

object result = matlabServerType.InvokeMember(

«Quit»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

new
Object[]{});

La variable matlabServerType y matlabServerObj corresponden a los dos objetos de tipo Type y Object que hemos creado en el código del apartado anterior cuando hemos iniciado la sesión. Como no necesitamos pasar ningún argumento a la función Quit, como cuarto parámetro al método InvokeMember, le pasamos un array vacio «new Object[]{}».

Ejecución de comandos: Execute

Para poder ejecutar cualquier comando de matlab, disponemos de la función Execute, que recibe como parámetro la cadena que representa el comando a ejecutar.

object[] arrayInput = new
object[] {aStringCommand};

Object result

= matlabServerType.InvokeMember(

«Execute»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

arrayInput);

En este caso no le pasamos un array vacio de parámetros, puesto que el array contiene un elemento con la cadena que representa el comando a ejecutar. En este caso como resultado en la variable result, obtenemos la salida el comando, que sería lo mismo que matlab nos visualiza cuando ejecutamos el comando sin terminar con el carácter ‘;‘.

Cadenas: PutCharArray & GetCharArray

Con estas dos funciones podemos crear y recuperar variables de tipo cadena.

object[] arrayInput

= new
object[] {«aVarName»,«global»,«aString»};

Object result =

matlabServerType.InvokeMember(

«PutCharArray»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

arrayInput);

En el vector arrayInput alojamos los parámetros de la función PutCharArray: el nombre de la variable que utilizaremos para almacenar el valor de la variable, el workspace que en este caso será «global» (también pudiera ser «base«), y por último, el valor de la variable creada. Así, en este caso crearemos la variable aVarName con el valor aString.

Para realizar el caso contrario y recuperar el valor de una variable de tipo cadena.

object[] arrayInput

= new
object[] {«aVarName»,«global»};

Object result =

matlabServerType.InvokeMember(

«GetCharArray»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

arrayInput);

Para recuperar el valor de la variable, tan solo le tenemos que pasar como parámetros, el nombre de la variable y el workspace, obteniendo en la variable result el valor de la variable indicada.

Matrices: PutFullMatrix & GetFullMatrix

Nos permiten almacenar una matriz o recuperarla respectivamente en el workspace indicado.

Array aRealArray     = new
Double[3]     {2, 3, 5};

Array aImgArray     = new
Double[3]     {0, 0, 0};

object[] arrayInput = new
object[] {

«aVarName»,

«base»,

aRealArray,

aImgArray

};

object result = matlabServerType.InvokeMember(

«PutFullMatrix»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

arrayInput);

En matlab todos los arrays tiene una parte real y otra imaginaria, por este motivo, a parte del nombre de la variable y el workspace, le debemos pasar a la función PutFullMatrix dos arrays, uno con los valores para la parte real y otra para la parte imaginaria.

Para hacer la función inversa y recuperar el valor de una matriz haremos lo siguiente.

Array realArray = new
double[n];

Array imgArray = new
double[n];

object[] arrayInput = new
object[] {

«aVarName»,

«base»,

realArray,

imgArray

};

ParameterModifier p = new
ParameterModifier(4);

p[0] = false; p[1] = false;

p[2] = true; p[3] = true;

ParameterModifier[] mods = {p};

Object result = this.matlabServerType.InvokeMember(

«GetFullMatrix»,

BindingFlags.InvokeMethod,

null,

this.matlabServerObj,

arrayInput,

mods,

null, null);

Para este caso, tendremos que utilizar una forma diferente de la función InvokeMember, que recibe tres parámetros más adicionales, de los cuales los dos últimos dejaremos a null, pero el siguiente se trata de un objeto de tipo ParameterModifier, que se trata de un array de booleanos que nos sirve para indicar cuales de los parámetros que indicamos en el array arrayInput son de salida, de manera que pondremos las posiciones 2 y 3 a true para indicar que los parámetros realArray e imgArray son de salida.

Manipulación de la ventana: MaximizeCommandWindow & MinimizeCommandWindow

Como utilidades, se nos ofrecen dos funciones que nos permiten maximizar y minimizar la ventana de terminal asociada a la sesión de Matlab que hemos creado al principio.

object result = matlabServerType.InvokeMember(

«MaximizeCommandWindow»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

new
Object[]{});

object result = matlabServerType.InvokeMember(

«MinimizeCommandWindow»,

BindingFlags.InvokeMethod,

null,

matlabServerObj,

new
Object[]{});

Esto es todo, si a alguien le interesa este tema y tiene alguna duda, podéis compartirla en este blog y si coincide que le puedo ayudar lo haré. Como ejemplo de cosillas que se pueden hacer, aquí va una captura de pantalla de una aplicación que en su día hice (utilizando este api y el toolbox de redes neuronales de matlab) para manipular redes neuronales, de manera que los equipos de investigación que se dedicaran a trabajar con redes neuronales pudieran crear sus propios prototipos de redes y probar los resultados.

Referencias

[1] Página oficial de Matlab, donde podemos encontrar toda la documentación necesaria.

http://www.mathworks.com/

[2] Ayuda Msdn sobre el api de reflexión.

http://msdn.microsoft.com/en-us/library/ms173183(VS.80).aspx

[3] Ejemplo de reflexión e invocación dinámica

http://my.execpc.com/~gopalan/dotnet/reflection.html

13 respuestas to “Matlab: interfaz COM”

  1. hola que tal una entrada interesante sin embargo por lo que leo es necesario tener instalado el matlab para ejecutar funciones del matlab … es posible llamar a una funcion en matlab desde una aplicacion c # sin tener instalado el matlab? Saludos

  2. Hola Jaime, como bien dices, es necesario tener instalado el matlab para poder invocar sus funciones. Pero lo que si es cierto que no es necesario tener la versión completa de matlab, si lo que nos interesa es para un proyecto utilizar un toolbox en concreto y poder invocarlo desde C#, podemos simplemente tener una versión mínima de este producto con dicho toolbox.

    Un saludo, y espero haberte resuelto la duda.

  3. hola he estado probando lo que aqui propones y me funciona bien, a excepcion de cuando quiero leer una matriz de matlab para pasarla a c# no me regresa nada en la matriz realArray que crees que podria ser ?

    • Pues no se, así a priori el código que tengo de muestra en el post debería funcionar, por lo menos a mi me recupera correctamente las matrices. Una cosa que sí que me tiene dado problemas es cuando se utilizan estructuras, con campos internos, por ejemplo que intentando recuperar el valor de la variable «nombreestructura.nombrecampomatriz» no conseguía recuperar nada, como si la variable perteneciera a un ámbito en el que desde C# no tuviera visibilidad. La verdad es que este problema no lo he conseguido solucionar del todo, lo que hago a veces es crear una variable temporal de la siguiente manera «vartmp = estructura.campomatriz» y despues invoco la función GetFullMatrix sobre la variable vartmp que tiene el valor deseado y lo recupero sin problemas (lo se, es una chapuza pero no he conseguido hacerlo de otra manera, estaría bien que alguién si sabe como solucionarlo correctamente lo comentara).

  4. hola oye he tenido problemas con la funcion que lee una matriz de matlab -> c# la matriz no se actualiza osea no me lee nada tendras un correo a donde pudiera mandarte mi código; lo estoy usando para manejo de imagenes de antemano muchas gracias

  5. hola oye ya te mande mi código te habra llegado ??? sigo buscando y haciendo pruebas. Nota en vBasic si me las lee bien, el problema ,…. no me gusta vB pero a dados los resultados :S en fin me gustaria mucho más en c# ya que tengo ya muchos metodos en c y asi los aprovecharia directo muchas gracias

  6. Luis Fernando Says:

    Hola, estoy muy interesado en el tema, estoy desarrollando mi proyecto y necesio de mucha ayuda para esto, y veo que esta es la posible solucion a mi problema, yo tengo que hacer varios tipos de regresiones para unos datos que me entregan, entonces tengo entendido que polyfit en matlab lo hace muy facil y adicionalmente grafica, entonces el programa inicial esta en Java y en C# ( en ambas versiones ya que como no me decidia lo hice para las dos) entonces quiero saber como hago para mandar los dos vectores a Matlab, que se encargue de hacer las regresiones correspondientes, me regrese su respectiva grafica y poder mostrar todo desde Java. En serio agradeceria su colaboracion!.

    • Hola Luis, el tema de java lo veo más complicado, ya que Matlab tiene interfaces de acceso muy buenas para C y com componentes COM. Para el caso de java, Matla también ofrece interoperatividad, pero en este aso está más pensada para invocar código java desde Matlab que a la inversa, por ejemplo en la línea de comandos de Matlab se puede crear directamente un objeto String de java. Sí que es cierto que partiendo de aquí hay formas de invocar a Matlab desde java, pero la verdad que nunca he produndizado mucho en el tema, pero puedes comenzar buscando info en cualquier buscado sobre el tema.

      Siento mucho no poder serte de mucha ayuda.

  7. Hola, veo que sigues dando respuesta a este tema apesar del tiempo que paso del primer post…
    Bueno lo que quiero saber yo, es de donde puedo obtener todos los comandos que puedo utilizar sobre matlab… (sobre el nucleo, tipo el «Execute» que tu utilizaste)…
    Tambien veo que al ejecutar el codigo de una grafica matlab la lanza sobre una interfaz propia, quisiera saber si se puede capturar dicha grafica e insertarla en c#…
    pejempplo:
    ejecuto comando xxx y me devuelve el grafico que deberia salir sobre la grafica que lanza matlab….
    Gracias..

    • Hola joliva,
      Eso que comentas de capturar directamente la gráfica del matlab, no me suena, pero dicha gráfica no es más que una representación de los resultados del entrenamiento de la red neuronal, y esos datos sí que los tienes disponibles simplemente, así que podrías hacerte tu propia gráfica a partir de los resultados del entrenamiento. Respecto a la documentación sobre las operaciones de matlab, está todo en la propia documentación de matlab, si buscas por «Automation sever» deberías llegar a la documentación con toda la información de las funciones del interfaz remoto.

      Un saludo,

  8. Hola, de ante mano gracias por el articulo,el proyecto q estoy desarrollando lee señales biologicas ( una parte del oximetro de pulso) , debido a exigencias de mi proyecto necesito realizar filtros digitales que en matlab es muy sencillo a comparacion de realizar uno en c# q es muy dificil, trate de enlazar el Matlab r2008 con el c# 2005 mediante la herramienta deploytool, que te genera una dll , un archivo com , mex y una clase en c# , pero al intentar enlazar me sale «dupplicate version attribute»,tienes alguna idea de por q me sale este mensaje.

  9. Hola, muy bueno el post, actualmente quiero comunicar VS 2005 con matlab 7.06, para consumir una red neuronal implemantada en matlab. Creo que eh logrado entender como pasar parametros de c# a matlab y viceversa. Sin embargo, aun no logro ejecutar una función creada en un .m desde c# y obtener los resultados.

    según tengo entendido:

    código en c#

    MLApp.MLAppClass matlab = new MLApp.MLAppClass(); //crear
    matlab.Visible = 0; //hacer invisible el prompt de matlab
    System.Array pr = new double[1]; //creo una matriz con un valor
    pr.SetValue(11, 0); //lo llamo matriz pero es un int
    //que es la parte real
    System.Array pi = new double[1]; //lo mismo que arriba
    pi.SetValue(0, 0); //parte imaginaria

    matlab.PutFullMatrix(«a», «base», pr, pi); //paso el valor de la
    //variable a = 11 a matlab

    System.Array prresult = new double[1]; //creo variables para
    System.Array piresult = new double[1]; //recojer el resultado

    String s = matlab.Execute(«add»); //ejecutar la función
    matlab.GetFullMatrix(«pf», «base», ref prresult, ref piresult); //recojer
    //resultado
    matlab.Quit(); //cierro la conección con matlab

    Código en add.m

    function pf = add1(a) //a es la variable que quize llenar arriba
    pf= a; //pf es la que quiero recojer después

    debo tener errores en ese código, pq no he podido obtener el resultado de pf, siempre Vs me da el mensaje:

    S =»??? Undefined function or variable ‘add’.\n\n».

    y finalmente cuando llega a matlab.GetFullMatrix(«pf», «base», ref prresult, ref piresult) me dice:

    «No se controló System.Runtime.InteropServices.COMException»

    alguien podria ayudarme a arreglar esto?

Deja un comentario