C MEX S-функции позволяют вызывать существующий код C в моделях Simulink ®. Например, рассмотрим простую функцию CdoubleIt.c , которая выводит значение, в два раза превышающее значение ввода функции.
double doubleIt(double u)
{
return(u * 2.0);
}Можно создать S-функцию, вызывающую doubleIt.c либо:
Запись обертки S-функции. С помощью этого метода можно вручную записать новую C S-функцию и связанный файл TLC. Этот метод требует наибольших знаний о структуре C S-функции.
Использование блока S-Function Builder. Этот метод позволяет ввести признаки S-функции в диалоговое окно блока. Этот метод не требует каких-либо знаний о написании S-функций. Однако базовое понимание структуры S-функции может упростить использование диалогового окна S-Function Builder.
Использование инструмента «Унаследованный код». Этот метод командной строки позволяет определить признаки S-функции в структуре данных в рабочей области MATLAB ®. Этот метод требует наименьшего объема знаний о S-функциях.
Можно также вызвать внешний код C из модели Simulink с помощью функционального блока MATLAB. Дополнительные сведения см. в разделе Интеграция кода C с помощью функционального блока MATLAB.
В следующих разделах описывается создание S-функций для использования при моделировании Simulink и создании кода Simulink Coder™ с использованием трех предыдущих методов. Пример модели содержит блоки, использующие эти S-функции. Если планируется создать модель, скопируйте файлы. doubleIt.c и doubleIt.h из папки docroot/toolbox/simulink/examples в рабочую папку.

S-функция wrapsfcn.c вызывает унаследованную функцию doubleIt.c в своем mdlOutputs способ. Сохранить wrapsfcn.c файл в рабочей папке, если планируется создать пример модели.
Для включения унаследованного кода в S-функцию wrapsfcn.c начинается с объявления doubleIt.c со следующей строкой:
extern real_T doubleIt(real_T u);
После объявления S-функция может использовать doubleIt.c в своем mdlOutputs способ. Например:
/* Function: mdlOutputs =======================================
* Abstract:
* Calls the doubleIt.c function to multiple the input by 2.
*/
static void mdlOutputs(SimStruct *S, int tid){
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
*y = doubleIt(*uPtrs[0]);
}Для компиляции wrapsfcn.c S-функция, выполните следующее mex команда. Убедитесь, что doubleIt.c находится в рабочей папке.
mex wrapsfcn.c doubleIt.c
Чтобы создать код для S-функции с помощью генератора кода Simulink Coder, необходимо записать файл компилятора целевого языка (TLC). Следующий файл TLC wrapsfcn.tlc использует BlockTypeSetup функция для объявления прототипа функции для doubleIt.c. Файл TLC Outputs затем функция сообщает генератору кода Simulink Coder, как встроить вызов в doubleIt.c. Например:
%implements "wrapsfcn" "C" %% File : wrapsfcn.tlc %% Abstract: %% Example tlc file for S-function wrapsfcn.c %% %% Function: BlockTypeSetup ================================ %% Abstract: %% Create function prototype in model.h as: %% "extern double doubleIt(double u);" %% %function BlockTypeSetup(block, system) void %openfile buffer %% PROVIDE ONE LINE OF CODE AS A FUNCTION PROTOTYPE extern double doubleIt(double u); %closefile buffer %<LibCacheFunctionPrototype(buffer)> %%endfunction %% BlockTypeSetup %% Function: Outputs ======================================= %% Abstract: %% CALL LEGACY FUNCTION: y = doubleIt( u ); %% %function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %assign u = LibBlockInputSignal(0, "", "", 0) %assign y = LibBlockOutputSignal(0, "", "", 0) %% PROVIDE THE CALLING STATEMENT FOR "doubleIt" %<y> = doubleIt( %<u> ); %endfunction %% Outputs
Дополнительные сведения о TLC см. в разделе Основы компилятора целевого языка (Simulink Coder).
S-Function Builder автоматизирует создание S-функций и файлов TLC, содержащих устаревший код. Для этого примера, в дополнение к doubleIt.c, вам нужен файл заголовка doubleIt.h которая объявляет doubleIt.c формат функции, следующий:
extern real_T doubleIt(real_T in1);
Блок S-Function Builder используется для настройки диалогового окна блока для вызова устаревшей функции doubleIt.c. В диалоговом окне «S-Function Builder» выполните следующие действия.
Поле «Имя S-функции» на панели «Параметры» определяет имя builder_wrapsfcn для сгенерированной S-функции.
На панели «Свойства данных» входные и выходные порты называются in1 и out1соответственно.
Панель «Библиотеки» обеспечивает интерфейс с унаследованным кодом.
Поле Library/Object/Source files содержит имя исходного файла. doubleIt.c.
Поле Includes содержит следующую строку для включения файла заголовка, который объявляет устаревшую функцию:
#include <doubleIt.h>
Панель «Выходы» вызывает унаследованную функцию со строками:
/* Call function that multiplies the input by 2 */
*out1 = doubleIt(*in1);На панели Сведения о построении (Build Info) выбирается параметр Создать оболочку TLC (Generate wrapper TLC).
При нажатии кнопки Построить (Build) S-Function Builder генерирует три файла.
| Имя файла | Описание |
|---|---|
builder_wrapsfcn.c | Основная S-функция. |
builder_wrapsfcn_wrapper.c | Файл-оболочка, содержащий отдельные функции для кода, введенного в области «Выходы», «Непрерывные производные» и «Дискретные обновления» конструктора S-функций. |
builder_wrapsfcn.tlc | Файл TLC S-функции. |
builder_wrapsfcn.c файл имеет стандартный формат:
Файл начинается с набора #define операторы, включающие информацию из S-Function Builder. Например, первый входной порт определяется следующими строками:
#define NUM_INPUTS 1 /* Input Port 0 */ #define IN_PORT_0_NAME in1 #define INPUT_0_WIDTH 1 #define INPUT_DIMS_0_COL 1 #define INPUT_0_DTYPE real_T #define INPUT_0_COMPLEX COMPLEX_NO #define IN_0_FRAME_BASED FRAME_NO #define IN_0_DIMS 1-D #define INPUT_0_FEEDTHROUGH 1
Далее файл объявляет все функции оболочки, найденные в builder_wrapsfcn_wrapper.c файл. В этом примере для кода Outputs требуется только функция-оболочка.
extern void builder_wrapsfcn_Outputs_wrapper(const real_T *in1,
real_T *out1);Следуя этим определениям и объявлениям, файл содержит методы S-функций, такие как mdlInitializeSizes, которые инициализируют входные порты, выходные порты и параметры S-функции. Список методов, вызываемых во время фазы инициализации S-функции, см. в ракурсе процесса.
mdlOutputs метод файла вызывает builder_wrapsfcn_wrapper.c функция. Метод использует входные и выходные имена in1 и out1, как определено на панели «Свойства данных», при вызове функции-оболочки. Например:
/* Function: mdlOutputs =============================================
*
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
const real_T *in1 = (const real_T*) ssGetInputPortSignal(S,0);
real_T *out1 = (real_T *)ssGetOutputPortRealSignal(S,0);
builder_wrapsfcn_Outputs_wrapper(in1, out1);
}Файл builder_wrapsfcn.c завершается требуемым mdlTerminate способ.
Функция обертки builder_wrapsfcn_wrapper.c имеет три части:
Include Files раздел включает в себя doubleIt.h вместе со стандартными файлами заголовков S-функций:
/* * Include Files * */ #if defined(MATLAB_MEX_FILE) #include "tmwtypes.h" #include "simstruc_types.h" #else #include "rtwtypes.h" #endif /* %%%-SFUNWIZ_wrapper_includes_Changes_BEGIN --- EDIT HERE TO _END */ #include <math.h> #include <doubleIt.h> /* %%%-SFUNWIZ_wrapper_includes_Changes_END --- EDIT HERE TO _BEGIN */
External References содержит информацию из поля Объявления внешних ссылок на панели Библиотеки. В этом примере этот раздел не используется.
Output functions раздел объявляет функцию builder_wrapfcn_Outputs_wrapper, который содержит код, введенный в диалоговом окне «Выходные данные» блока S-Function Builder:
/*
* Output functions
*
*/
void builder_wrapfcn_Outputs_wrapper(const real_T *in1,
real_T *out1)
{
/* %%%-SFUNWIZ_wrapper_Outputs_Changes_BEGIN --- EDIT HERE TO _END */
/* Call function that multiplies the input by 2 */
*out1 = doubleIt(*in1);
/* %%%-SFUNWIZ_wrapper_Outputs_Changes_END --- EDIT HERE TO _BEGIN */
}Примечание
По сравнению с рукописной S-функцией, S-Function Builder помещает вызов устаревшей C-функции на дополнительный уровень через файл оболочки. builder_wrapsfcn_wrapper.c.
Файл TLC builder_wrapsfcn.tlc созданное S-Function Builder аналогично предыдущей рукописной версии. Файл объявляет устаревшую функцию в BlockTypeSetup и вызывает его в Outputs способ.
%implements builder_wrapsfcn "C"
%% Function: BlockTypeSetup ====================================
%%
%% Purpose:
%% Set up external references for wrapper functions in the
%% generated code.
%%
%function BlockTypeSetup(block, system) Output
%openfile externs
extern void builder_wrapsfcn_Outputs_wrapper(const real_T *in1,
real_T *out1);
%closefile externs
%<LibCacheExtern(externs)>
%%
%endfunction
%% Function: Outputs ===========================================
%%
%% Purpose:
%% Code generation rules for mdlOutputs function.
%%
%function Outputs(block, system) Output
/* S-Function "builder_wrapsfcn_wrapper" Block: %<Name> */
%assign pu0 = LibBlockInputSignalAddr(0, "", "", 0)
%assign py0 = LibBlockOutputSignalAddr(0, "", "", 0)
%assign py_width = LibBlockOutputSignalWidth(0)
%assign pu_width = LibBlockInputSignalWidth(0)
builder_wrapsfcn_Outputs_wrapper(%<pu0>, %<py0> );
%%
%endfunctionВ разделе Интеграция функций C в модели Simulink с устаревшим инструментом кода в разделе «Запись S-функций в C» показано, как использовать устаревший инструмент кода для создания S-функции, включающей doubleIt.c. Для сценария, выполняющего шаги в этом примере, скопируйте файл lct_wrapsfcn.m в рабочую папку. Убедитесь, что doubleIt.c и doubleIt.h файлы находятся в рабочей папке, а затем запускают сценарий, вводя lct_wrapsfcn в командной строке MATLAB. Сценарий создает и компилирует S-функцию legacy_wrapsfcn.c и создает файл TLC legacy_wrapsfcn.tlc с помощью следующих команд.
% Create the data structure
def = legacy_code('initialize');
% Populate the data struture
def.SourceFiles = {'doubleIt.c'};
def.HeaderFiles = {'doubleIt.h'};
def.SFunctionName = 'legacy_wrapsfcn';
def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
def.SampleTime = [-1,0];
% Generate the S-function
legacy_code('sfcn_cmex_generate', def);
% Compile the MEX-file
legacy_code('compile', def);
% Generate a TLC-file
legacy_code('sfcn_tlc_generate', def);S-функция legacy_wrapsfcn.c генерируемый инструментом кода Legacy Code Tool начинается с включения doubleIt.h файл заголовка. mdlOutputs затем непосредственно вызывает doubleIt.c , следующим образом:
static void mdlOutputs(SimStruct *S, int_T tid)
{
/*
* Get access to Parameter/Input/Output/DWork/size information
*/
real_T *u1 = (real_T *) ssGetInputPortSignal(S, 0);
real_T *y1 = (real_T *) ssGetOutputPortSignal(S, 0);
/*
* Call the legacy code function
*/
*y1 = doubleIt( *u1);
}S-функция, генерируемая инструментом кода предыдущей версии, отличается от S-функции, генерируемой построителем S-функций, следующим образом:
S-функция, генерируемая построителем S-функций, вызывает унаследованную функцию. doubleIt.c через функцию обертки builder_wrapsfcn_wrapper.c. S-функция, генерируемая унаследованным инструментом кода, вызывает непосредственно doubleIt.c из его mdlOutputs способ.
Построитель S-функций использует входные и выходные имена, введенные на панели Свойства данных (Data Properties), что позволяет настраивать эти имена в S-функции. Инструмент кода предыдущей версии использует имена по умолчанию y и u для выходов и входов соответственно. Нельзя указать настраиваемые имена, которые будут использоваться в сгенерированной S-функции при использовании инструмента кода прежней версии.
S-Function Builder и Legacy Code Tool по умолчанию определяют наследуемое время выборки. Однако построитель S-функций использует время смещения, равное 0.0 в то время как инструмент «Унаследованный код» указывает, что время смещения фиксируется во второстепенных временных шагах.
Файл TLC legacy_wrapsfcn.tlc поддерживает сворачивание выражений путем определения BlockInstanceSetup и BlockOutputSignal функции. Файл TLC также содержит BlockTypeSetup функция для объявления прототипа функции для doubleIt.c и Outputs функция, указывающая генератору кода кодера Simulink, как встроить вызов в doubleIt.c.:
%% Function: BlockTypeSetup ===============================================
%%
%function BlockTypeSetup(block, system) void
%%
%% The Target Language must be C
%if ::GenCPP==1
%<LibReportFatalError("This S-Function generated by the Legacy Code Tool
must be only used with the C Target Language")>
%endif
%<LibAddToCommonIncludes("doubleIt.h")>
%<LibAddToModelSources("doubleIt")>
%%
%endfunction
%% Function: BlockInstanceSetup ===========================================
%%
%function BlockInstanceSetup(block, system) void
%%
%<LibBlockSetIsExpressionCompliant(block)>
%%
%endfunction
%% Function: Outputs ======================================================
%%
%function Outputs(block, system) Output
%%
%if !LibBlockOutputSignalIsExpr(0)
%assign u1_val = LibBlockInputSignal(0, "", "", 0)
%assign y1_val = LibBlockOutputSignal(0, "", "", 0)
%%
%<y1_val = doubleIt( %<u1_val>);
%endif
%%
%endfunction
%% Function: BlockOutputSignal ============================================
%%
%function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void
%%
%assign u1_val = LibBlockInputSignal(0, "", "", 0)
%assign y1_val = LibBlockOutputSignal(0, "", "", 0)
%%
%switch retType
%case "Signal"
%if portIdx == 0
%return "doubleIt( %<u1_val>)"
%else
%assign errTxt = "Block output port index not supported: %<portIdx>"
%endif
%default
%assign errTxt = "Unsupported return type: %<retType>"
%<LibBlockReportError(block,errTxt)>
%endswitch
%%
%endfunction