Обмен данными между несколькими s-функциями c mex

Я реализую несколько с-функций. Они должны полагаться на одни и те же указатели и переменные, не зависящие от текущей s-функции.

По сути, я хочу создать все переменные и указатели в одной s-функции "setup" (внутри mdlInitialize), а затем иметь возможность использовать эти переменные указатели в различных s-функциях в их функции mdlOutputs. Каждая s-функция будет написана на c.

Я не смог найти ни одной полезной подсказки в справке по математике. Есть ли у вас какие-либо идеи? Благодарю.

1 ответ

Решение

Это можно сделать несколькими способами, хотя ни один из них не является лучшим подходом.

Один из подходов состоит в том, чтобы определить все в dll и загрузить его каждой из S-функций. Это обрисовано в общих чертах в вопросе, как разделить структуру C среди функций C S?,

Другой (и мой предпочтительный) подход заключается в создании пользовательского типа данных, который представляет собой C-структуру, содержащую все общие данные, и которая передается как сигнал между S-функциями в модели. Это изложено в разделе Using Opaque Data Types in C S-Functions документа Настроить пользовательские типы данных.

Документ показывает различные (относительно простые) вещи, которые необходимо выполнить в S-функции, которая создает пользовательскую структуру. В этой S-функции MdlOutputs метод, пользовательская структура будет тогда просто сделать вывод блока обычным способом. Например, если пользовательская структура, содержащая ваши данные, определяется как,

typedef struct{
    real_T sig0;
    real_T sig1;
}myStruct;

Затем в mdlInitializeSizes тебе нужно что-то вроде

myStruct tmp;

/* Register the user-defined data types */
id = ssRegisterDataType(S, "customDataType");
if(id == INVALID_DTYPE_ID) return;

/* Set the size of the user-defined data type */
status = ssSetDataTypeSize(S, id, sizeof(tmp));
if(status == 0) return;

/* Set the zero representation */
tmp.sig0 = 0;
tmp.sig1 = 0;
status = ssSetDataTypeZero(S, id, &tmp);

И вывести это как сигнал, в mdlOutputs метод у вас будет что-то вроде

myStruct *pY0 = (myStruct *)ssGetOutputPortSignal(S, 0);

pY0[0].sig0 = 'value of this param';
pY0[0].sig1 = 'value of this param';

Тогда в mdlInitializeSizes любой S-функции, которая должна использовать этот сигнал вам нужно

DTypeId  id;
id = ssRegisterDataType(S, "customDataType");
if(id == INVALID_DTYPE_ID) return;

который затем дает вам доступ к пользовательской структуре в любом из других методов, используя,

myStruct **uPtrs = (myStruct **) ssGetInputPortSignalPtrs(S,0);

Затем к элементам структуры получают доступ обычным способом,

firstVar = uPtrs[0]->sig0;
secondVar = uPtrs[0]->sig1;

Основным недостатком этого подхода является то, что модель не может быть использована при генерации кода (с использованием Simulink Coder).

Самый простой способ обмена данными между S-функциями в сгенерированном коде - просто передать их через глобальные переменные, если ваши S-функции не встроены.

Поскольку вы получаете ошибку с уже определенными переменными, я полагаю, вы компилируете сгенерированный код на целевой платформе. В данном случае это вызвано дублированием определений - глобальные переменные должны быть определены только в S-функции "setup" и объявлены с ключевым словом extern во всех других S-функциях (это просто C в целевой).

Когда S-функция компилируется с mex в среде Simulink, она не может быть статически связана с другими S-функциями. Хотя можно связать несколько S-функций с одним и тем же внешним исходным файлом C, в Simulink, вероятно, будет несколько экземпляров одних и тех же данных, созданных независимо для каждой S-функции. Поскольку S-функции компилируются и связываются независимо в среде Simulink, определение общих глобальных переменных в каждой S-функции не имеет смысла - вы не можете извлекать их, поскольку они не были бы определены для компоновщика (вызываемого mex).

Очевидный недостаток связывания глобальных объектов с целью состоит в том, что вы не можете использовать среду Simulink для отладки функциональности, которая зависит от общих данных. Но если это не основная функциональность (например, некоторая дополнительная регистрация), ее можно условно включить с флагом RT внутри ваших S-функций, чтобы он появлялся только в сгенерированном коде, позволяя проверить основную функциональность в Simulink.

Другие вопросы по тегам