C S-функции MEX позволяют вам вызывать существующий код С в своих моделях 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™, с помощью предыдущих трех методов. Образцовый sfcndemo_choosing_sfun
содержит блоки, которые используют эти S-функции. Скопируйте эту модель и файлы doubleIt.c
и doubleIt.h
от папки docroot
/toolbox/simulink/sfg/examples
в вашу рабочую папку, если вы планируете продвинуться через примеры.
S-функция wrapsfcn.c
вызывает устаревший функциональный doubleIt.c
в своем методе mdlOutputs
. Сохраните файл wrapsfcn.c
в свою рабочую папку, если вы планируете скомпилировать S-функцию, чтобы запустить в модели в качестве примера sfcndemo_choosing_sfun
.
Чтобы включить унаследованный код в 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]); }
Чтобы скомпилировать S-функцию wrapsfcn.c
, запустите следующую команду mex
. Убедитесь, что файл doubleIt.c
находится в вашей рабочей папке.
mex wrapsfcn.c doubleIt.c
Чтобы сгенерировать код для S-функции с помощью генератора кода Simulink Coder, необходимо записать файл Компилятора выходного языка (TLC). Следующий файл TLC wrapsfcn.tlc
использует функцию BlockTypeSetup
, чтобы объявить прототипа функции для doubleIt.c
c. Функция Outputs
файла TLC затем говорит генератор кода Simulink Coder, как встроить вызов doubleIt.c
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-функции автоматизирует создание S-функций и файлов TLC, которые включают унаследованный код. Для этого примера, в дополнение к doubleIt.c
, вам нужен заголовочный файл doubleIt.h
, который объявляет формат функции doubleIt.c
, можно следующим образом:
extern real_T doubleIt(real_T in1);
Блок S-Function Builder в sfcndemo_choosing_sfun
показывает, как сконфигурировать блочное диалоговое окно, чтобы вызвать устаревший функциональный doubleIt.c
c. В диалоговом окне блока S-Function Builder:
Поле S-имени-функции в панели Параметров задает имя builder_wrapsfcn
для сгенерированной S-функции.
Панель Свойств данных называет порты ввода и вывода как in1
и out1
, соответственно.
Панель Библиотек предоставляет интерфейс унаследованному коду.
Поле Библиотеки/Объекта/Исходных файлов содержит имя исходного файла doubleIt.c
c.
Поле Includes содержит следующую строку, чтобы включать заголовочный файл, который объявляет устаревшую функцию:
#include <doubleIt.h>
Выходная панель вызывает устаревшую функцию со строками:
/* Call function that multiplies the input by 2 */ *out1 = doubleIt(*in1);
Информационная панель Сборки выбирает обертку Generate опция TLC.
Когда вы нажимаете Build, S-Function Builder генерирует три файла.
FileName | Описание |
---|---|
builder_wrapsfcn.c | Основная S-функция. |
builder_wrapsfcn_wrapper.c | Файл обертки, содержащий отдельные функции для кода, введенного в Выходных параметрах, Непрерывных Производных и Дискретных панелях Обновлений Разработчика S-функции. |
builder_wrapsfcn.tlc | Файл S-функции TLC. |
Файл builder_wrapsfcn.c
следует за стандартным форматом:
Файл начинается с набора операторов #define
, которые включают информацию от Разработчика S-функции. Например, следующие строки задают первый входной порт:
#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
. Этот пример требует только функции обертки для Выходного кода.
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-функции помещает вызов наследия C функция вниз дополнительный уровень через файл обертки builder_wrapsfcn_wrapper.c
c.
Файл TLC builder_wrapsfcn.tlc
, сгенерированный Разработчиком S-функции, подобен предыдущей рукописной версии. Файл объявляет устаревшую функцию в 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
Раздел Integrate C Functions into Simulink Models with Legacy Code Tool в “Записи S-функций в C” показывает, как использовать Legacy Code Tool, чтобы создать S-функцию, которая включает doubleIt.c
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-функция, сгенерированная Legacy Code Tool, отличается от S-функции, сгенерированной Разработчиком S-функции можно следующим образом:
S-функция, сгенерированная Разработчиком S-функции, вызывает устаревший функциональный doubleIt.c
через функцию обертки builder_wrapsfcn_wrapper.c
c. S-функция, сгенерированная Legacy Code Tool непосредственно, вызывает doubleIt.c
из своего метода mdlOutputs
.
Использование Разработчика S-функции имена ввода и вывода ввело в панель Свойств данных, позволив вам настроить эти имена в S-функции. Legacy Code Tool использует имена по умолчанию y
и u
для выходных параметров и входных параметров, соответственно. Вы не можете задать настроенные имена, чтобы использовать в сгенерированной S-функции при использовании Legacy Code Tool.
Разработчик S-функции и Legacy Code Tool оба задают наследованную частоту дискретизации по умолчанию. Однако Разработчик S-функции использует время смещения 0.0
, в то время как Legacy Code Tool указывает, что время смещения установлено в незначительных временных шагах.
Файл TLC legacy_wrapsfcn.tlc
поддерживает выражение, сворачивающееся путем определения функций BlockOutputSignal
и BlockInstanceSetup
. Файл TLC также содержит функцию BlockTypeSetup
, чтобы объявить, что прототип функции для doubleIt.c
и функции Outputs
говорит генератор кода Simulink Coder, как встроить вызов doubleIt.c
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