openFrameworks e MatLab

Padrão

Esse post visa comentar (e ajudar alguém) o caminho para utilizar a MatLab Engine API, não vou explicar os detalhes de funcionamento - pois constam no link. Mas basicamente ela serve para possibilitar a utilização do motor do MatLab por aplicações externas.

O ambiente utilizado foi:

  1. Windows 7 64 bits instalado numa máquina virtual usando VMWare, é grátis para fins não comerciais.
  2. MatLab Student 2013a Versão 32 bits
  3. Visual Studio 2012 Express.
  4. openFrameworks - http://openframeworks.cc/ - versão 0.8.3 para Windows - Visual Studio

Foram utilizados os seguintes links para ajudar:

Após todas as ferramentas instaladas,

  1. Criar um projeto usando o projectGenerator do openFrameworks.
  2. Entrar no Solution criado pelo projectGenerator
  3. Ajustar IDE.
    1. Dentro do Visual Studio, abra as Propriedades (Properties) da solução criada.
    2. Em Configuration Properties -> Debugging -> Command, adicionar o caminho PATH=$C:Program Files (x86)MATLABR2013abin . Lembrem que instalei a versão 32bits do Matlab.  DICA: Crie uma variável MATLABROOT que direcione para o raiz do MatLab - facilita.
    3. Em Configuration Properties -> C/C++ -> General, adicione os endereços dos diretórios com includes em “Additional Include Directories”:
      1. C:Program Files %28×86%29MATLABR2013aexternincludewin32;
      2. C:Program Files %28×86%29MATLABR2013aexterninclude
    4. Em Configuration Properties -> C/C++ -> Precompiled Headers verifique se Precompiled Headers está em “Not Using Precompiled Headers”
    5. Em Configuration Properties -> Linker -> General, adicione o endereço em “Additional Library Directories”:
      1. C:Program Files %28×86%29MATLABR2013aexternlibwin32microsoft
    6. Em Configuration Properties -> Linker -> Input, adicionar as dependencias em “Additional Dependencies”,
      1. libmx.lib
      2. libmat.lib
      3. libeng.lib
  4. Ajustar SO.
    1. Vá em “Configurações Avançadas de Sistema” -> “Variáveis de Ambiente”, em Variáveis do sistema, encontre a variável PATH, e adicione:
      1. C:Program Files (x86)MATLABR2013aruntimewin32;
      2. C:Program Files (x86)MATLABR2013abin;
      3. C:Program Files (x86)MATLABR2013abinWIN32
    2. Aproveite e crie uma variável de usuário MATLABROOT apontando para:
      1.  C:Program Files (x86)MATLABR2013a

Arquivos exemplos da Engine API encontram-se dentro: C:Program Files (x86)MATLABR2013aexternexampleseng_mat

Para testar o ambiente utilizei o engdemo.cpp, copiado na integra aqui:
Seguindo, no openFrameworks, no arquibo ofApp.h, inclua os cabeçalhos, engine.h e matrix.h e faça a instancia do apontamento para a Engine, o trecho de código do cabeçalho segue abaixo

#pragma once

#include "engine.h"
#include "matrix.h"
#include "ofMain.h"
#define  BUFSIZE 256

class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();

void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);

Engine* pEng;
};

No arquivo ofApp.cpp, para este teste, copie o trecho do exemplo dado pelo MatLab dentro do ofApp::setup();

//--------------------------------------------------------------
void ofApp::setup(){

Engine *ep;
mxArray *T = NULL, *result = NULL;
char buffer[BUFSIZE+1];
double time[10] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };

cout<
/*
* Call engOpen with a NULL string. This starts a MATLAB process
* on the current host using the command "matlab".
*/
if (!(ep = engOpen(""))) {
fprintf(stderr, "nCan't start MATLAB enginen");
exit();
}

cout<    /*
* PART I
*
* For the first half of this demonstration, we will send data
* to MATLAB, analyze the data, and plot the result.
*/

/*
* Create a variable for our data
*/
T = mxCreateDoubleMatrix(1, 10, mxREAL);
memcpy((void *)mxGetPr(T), (void *)time, sizeof(time));
/*
* Place the variable T into the MATLAB workspace
*/
engPutVariable(ep, "T", T);

/*
* Evaluate a function of time, distance = (1/2)g.*t.^2
* (g is the acceleration due to gravity)
*/
engEvalString(ep, "D = .5.*(-9.8).*T.^2;");

/*
* Plot the result
*/
engEvalString(ep, "plot(T,D);");
engEvalString(ep, "title('Position vs. Time for a falling object');");
engEvalString(ep, "xlabel('Time (seconds)');");
engEvalString(ep, "ylabel('Position (meters)');");

/*
* use fgetc() to make sure that we pause long enough to be
* able to see the plot
*/
printf("Hit return to continuenn");
fgetc(stdin);
/*
* We're done for Part I! Free memory, close MATLAB figure.
*/
printf("Done for Part I.n");
mxDestroyArray(T);
//engEvalString(ep, "close;");

/*
* PART II
*
* For the second half of this demonstration, we will request
* a MATLAB string, which should define a variable X.  MATLAB
* will evaluate the string and create the variable.  We
* will then recover the variable, and determine its type.
*/

/*
* Use engOutputBuffer to capture MATLAB output, so we can
* echo it back.  Ensure first that the buffer is always NULL
* terminated.
*/

buffer[BUFSIZE] = '';
engOutputBuffer(ep, buffer, BUFSIZE);
while (result == NULL) {
char str[BUFSIZE+1];
/*
* Get a string input from the user
*/
printf("Enter a MATLAB command to evaluate.  This command shouldn");
printf("create a variable X.  This program will then determinen");
printf("what kind of variable you created.n");
printf("For example: X = 1:5n");
printf(">> ");

fgets(str, BUFSIZE, stdin);

/*
* Evaluate input with engEvalString
*/
engEvalString(ep, str);

/*
* Echo the output from the command.
*/
printf("%s", buffer);

/*
* Get result of computation
*/
printf("nRetrieving X...n");
if ((result = engGetVariable(ep,"X")) == NULL)
printf("Oops! You didn't create a variable X.nn");
else {
printf("X is class %stn", mxGetClassName(result));
}
}

/*
* We're done! Free memory, close MATLAB engine and exit.
*/
printf("Done!n");
mxDestroyArray(result);
engClose(ep);
}

Em tese tem que funcionar tudo. 🙂

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *