C MEX S-функции позволяют вам вызывать существующие Коды С в Simulink® модели. Для примера рассмотрим простую функцию C doubleIt.c
это выводит значение в два раза больше значения входного параметра функции.
double doubleIt(double u) { return(u * 2.0); }
Можно создать S-функцию, которая вызывает doubleIt.c
по одному из следующих:
Написание оболочки S-функции. Используя этот метод, вы вручную записываете новую S-функцию C и связанный с ней файл TLC. Этот метод требует наибольших знаний о структуре S-функции C.
Использование блока S-Function Builder. Используя этот метод, вы вводите характеристики S-функции в диалоговое окно блока. Этот метод не требует никаких знаний о записи S-функций. Однако базовое понимание структуры S-функции может сделать диалоговое окно S-Function Builder более простым в использовании.
Использование Legacy Code Tool. Используя этот метод командной строки, вы определяете характеристики вашей S-функции в структуре данных в MATLAB® рабочей области. Этот метод требует наименьшего объема знаний о S-функциях.
Можно также вызвать внешний код С из модели Simulink с помощью блока MATLAB Function. Для получения дополнительной информации смотрите Интегрировать код С Используя Блок MATLAB function.
В следующих разделах описывается, как создать 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, необходимо написать файл Target Language Compiler (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-function name на панели Parameters задает имя builder_wrapsfcn
для сгенерированной S-функции.
Панель Data Properties называет порты входа и выхода следующими in1
и out1
, соответственно.
Панель Libraries предоставляет интерфейс для унаследованного кода.
Поле Library/Object/Source files содержит имя исходного файла doubleIt.c
.
Поле Includes содержит следующую линию для включения файла заголовка, который объявляет унаследованную функцию:
#include <doubleIt.h>
Панель Outputs вызывает устаревшую функцию со линиями:
/* Call function that multiplies the input by 2 */ *out1 = doubleIt(*in1);
Панель Build Info выбирает опцию Generate wrapper TLC.
Когда вы нажимаете Build, S-Function Builder генерирует три файла.
Имя файла | Описание |
---|---|
builder_wrapsfcn.c | Основная S-функция. |
builder_wrapsfcn_wrapper.c | Файл, содержащий отдельные функции для кода, введенные в Outputs, Continuous Derivatives и Discrete Updates панелях S-Function Builder. |
builder_wrapsfcn.tlc | Файл TLC S-функции. |
The 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-функции.
The mdlOutputs
метод файла вызывает builder_wrapsfcn_wrapper.c
функция. Метод использует входные и выходные имена in1
и out1
, как определено на панели Data Properties, при вызове функции обертки. Для примера:
/* 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
имеет три части:
The 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 */
The External References
раздел содержит информацию из поля External reference declarations на панели Libraries. Этот пример не использует этот раздел.
The Output functions
раздел объявляет функцию builder_wrapfcn_Outputs_wrapper
, который содержит код, введенный в Outputs панели диалогового окна 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 с помощью Legacy Code Tool в «Написание S-функций в C» показано, как использовать Legacy Code Tool для создания 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
заголовочный файл. The 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-функция, сгенерированная Legacy Code Tool, отличается от S-функции, сгенерированной S-Function Builder следующим образом:
S-функция, сгенерированная S-Function Builder, вызывает устаревшую функцию doubleIt.c
через функцию обертки builder_wrapsfcn_wrapper.c
. S-функция, сгенерированная Legacy Code Tool, непосредственно вызывает doubleIt.c
от его mdlOutputs
способ.
S-Function Builder использует входные и выходные имена, введенные в панель Data Properties, что позволяет настраивать эти имена в S-функции. Legacy Code Tool использует имена по умолчанию y
и u
для выходов и входов, соответственно. Вы не можете задать настраиваемые имена для использования в сгенерированной S-функции при использовании Legacy Code Tool.
S-Function Builder и Legacy Code Tool по умолчанию задают унаследованный шаг расчета. Однако S-Function Builder использует время смещения 0.0
в то время как Legacy Code Tool задает, что время смещения фиксировано в незначительных временных шагах.
Файл TLC legacy_wrapsfcn.tlc
поддерживает складывание выражений путем определения BlockInstanceSetup
и BlockOutputSignal
функций. TLC- файла также содержит BlockTypeSetup
функция для объявления прототипа функции для doubleIt.c
и Outputs
функция, чтобы сообщить генератору кода Simulink Coder, как вписать вызов в 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