Функция двигателя Matlab в C возвращает ноль

Мне было интересно, может ли кто-нибудь помочь мне понять синтаксис механизма Matlab в C. Я новичок в C и пытаюсь вызвать пользовательскую функцию Matlab в C с помощью Matlab Engine. Исследования, которые я провел, включают в себя чтение документации по API Matlab, просмотр видео лекций от Mathworks, исследование переполнения стека, чтение примера eng.c файла в Matlab и Google.

Я придумал этот фрагмент кода, который компилируется, но на выходе возвращается ноль. Входной массив также возвращает не массив, а целое число. Я не могу найти подробное видео о том, как создать сценарий C, который

  1. принимает вектор
  2. передает его в функцию Matlab и
  3. возвращает вывод.

Документы очень четко объясняют создание массива, но я не могу найти информацию, которая подробно описывает чтение массива в Matlab, а затем получение вывода.

Ниже приведен код с комментариями о том, что, как я понимаю, делает каждый раздел кода. Пример функции add_up просто вызывает функцию sum для массива. Любая помощь была бы отличной, так как я застрял в том, почему это возвращает ноль.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#define BUFSIZE 256

int main() {

    //Open call to matlab engine
    Engine *ep;

    //Use this conjunction with define BUFSIZe 256 to create double
    //extData is a variable to read external data
    //Number in brackets refer to size
    //We are using double in this case and create the external data using initialization
    double extData[10]={1.0,4.0,7.0,2.0,5.0,8.0,3.0,6.0,9.0,10.0};

    //Next step is to make a pointer of type mxArray 
    //These are pointers to an array of any size or type
    mxArray *pVarNum;
    double *outp;

    //After we make a matrix for the double data initialized above
    //Initialized to 0
    pVarNum=mxCreateDoubleMatrix(1,10,mxREAL);

    //Our array needs to be assigned a variable name for Matlab
    //Workspace
    //const char *myDouble = "T";

    //Our matlab matrix is initialized to zero. We need to use
    //The C memcpy function to get the data from extData to
    //Get the array data using the pointer to pVarNum
    //Use mxGetPr, a mxGet function
    memcpy((void *)(mxGetPr(pVarNum)), (void *)extData,sizeof(extData));

    //Place the variable T into the Matlab workspace
    engPutVariable(ep,"T",pVarNum);

    //Evalute test function
    engEvalString(ep, "out=T+1");

    //Make a pointer to the matlab variable
    outp=engGetVariable(ep,"out");
    //Now make a pointer to the C variable
    printf("%d\n",outp);

    printf("Done!\n");
    mxDestroyArray(pVarNum);

    engClose(ep);

    return EXIT_SUCCESS;

}

person Lee    schedule 20.07.2018    source источник


Ответы (2)


Функция engGetVariable возвращает mxArray*, а не double*:

double *outp;
/* ... */
outp = engGetVariable(ep, "out");
printf("%d\n", outp);

Это должно быть:

mxArray *out;
double *outp;
int ii;
/* ... */
out = engGetVariable(ep, "out");
outp = mxGetPr(out);
for (ii = 0; ii < 9; ii++) {
   printf("%f, ", outp[ii]);
}
printf("%f\n", outp[9]);

Также обратите внимание, что форматер %d в printf печатает int, вам нужно использовать %f для двойного.

person Cris Luengo    schedule 21.07.2018
comment
Спасибо за ответ, и я ценю информацию. Я изменил код, как было предложено, и теперь он будет печатать 0, если я напишу printf(%f,output). Однако, если я попытаюсь каким-либо образом получить доступ к элементам outp, он скажет, что есть ошибка сегментации, которую я просмотрел, чтобы указать, что есть проблема с доступом к памяти указателя. Я предполагаю, что это каким-то образом означает, что outp не является двойным? Все остальное в вашем ответе на высоте, просто это не вернет мне дубль. - person Lee; 23.07.2018
comment
Интересно... Является ли out указателем NULL или outp указателем NULL? engGetVariable возвращает NULL, если запрос терпит неудачу (что, я думаю, означает, что запрошенная переменная не существует?), а mxGetPr завершится ошибкой, если mxArray не имеет реального компонента или не является числовым. Насколько я могу судить, в этом коде ничего из этого не происходит. - person Cris Luengo; 23.07.2018
comment
Спасибо за быстрый ответ. Я проверил оба входа, pVarNum и out. Вы правы, что есть проблема с out. Он возвращает Null, хотя pVarNum не равен Null. Я пытаюсь найти способ получить доступ к элементам pVarNum, чтобы убедиться, что memcpy работает правильно, даже несмотря на то, что он в точности скопирован из руководства по API. Любые другие советы по отладке также будут оценены. - person Lee; 23.07.2018
comment
pVarNum содержит элементы, находящиеся в extData. Итак, вывод, похоже, заключается в том, что есть проблема с расчетом в Matlab, так что он возвращает Null. Я не уверен, почему это было бы так, поскольку я просто добавляю один к каждому числу массива в примере. - person Lee; 23.07.2018
comment
@Lee: проверьте возвращаемое значение engPutVariable (должно быть возвращено 0 в случае успеха и 1 в случае ошибки). Если engEvalString приводит к ошибке внутри MATLAB, он не сообщит вам об этом (хотя в вашем случае это действительно не должно привести к сбою, пока существует T, который должен существовать, если engPutVariable был успешным). См. здесь для некоторых идей о том, как отлаживать проблемы в этом случае. - person Cris Luengo; 23.07.2018
comment
Спасибо за совет по отладке. Он возвращал 1, что приводило к решению. Хотелось бы, чтобы у меня был лучший ответ о том, почему все в конечном итоге заработало, но ниже, пожалуйста, посмотрите сегмент ответов о том, как все было решено. - person Lee; 24.07.2018

Проблема заключалась в том, что engputVariable возвращал 1, поэтому движок Matlab не принимал массив. В итоге я скопировал и вставил точный верхний сегмент кода из Matlab engdemo.c (до вызова engPutVariable), а затем продолжил свой код. Кодировка была в ASCII для файла рабочего кода. Я думаю, что ключевой частью является начальный вызов для открытия Matlab с нулевой строкой, хотя я поместил именно этот фрагмент кода в нерабочий скрипт, и это не привело к engPutVariable работе.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#define  BUFSIZE 256

int main()

{
    Engine *ep;
    mxArray *T = NULL, *outp = NULL;
    double *out;
    int ii;
    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 };


    if (!(ep = engOpen(""))) {
        fprintf(stderr, "\nCan't start MATLAB engine\n");
        return EXIT_FAILURE;
    }

    T = mxCreateDoubleMatrix(1, 10, mxREAL);
    memcpy((void *)mxGetPr(T), (void *)time, sizeof(time));

    engPutVariable(ep, "T", T);


    //Evalute test function. This is new

    engEvalString(ep, "D=add_up(T);");

    //Make a pointer to the matlab variable
    if((outp=engGetVariable(ep,"D"))==NULL){
        printf("Oops!");
    }
    out= mxGetPr(outp);

    //Now make a pointer to the C variable
    for (ii=0; ii<10; ii++) {
        printf("%f\n", out[ii]);
    }
    printf("%f\n",out[2]);

    printf("Done!\n");
    mxDestroyArray(T);
    mxDestroyArray(outp);
    engClose(ep);

    return EXIT_SUCCESS;

}
person Lee    schedule 23.07.2018