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]); }
Скомпилировать wrapsfcn.c
S-функция, запустите следующий mex
команда. Убедитесь что doubleIt.c
файл находится в вашей рабочей папке.
mex wrapsfcn.c doubleIt.c
Чтобы сгенерировать код для S-функции с помощью генератора кода Simulink Coder, необходимо записать файл Компилятора выходного языка (TLC). Следующий файл TLC wrapsfcn.tlc
использует BlockTypeSetup
функция, чтобы объявить прототипа функции для doubleIt.c
. Outputs
файла TLC функция затем говорит генератор кода 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-функции автоматизирует создание S-функций и файлов TLC, которые включают унаследованный код. В данном примере в дополнение к doubleIt.c
, вам нужен заголовочный файл doubleIt.h
это объявляет doubleIt.c
функциональный формат, можно следующим образом:
extern real_T doubleIt(real_T in1);
Блок S-Function Builder в sfcndemo_choosing_sfun
показывает, как сконфигурировать диалоговое окно блока, чтобы вызвать устаревший функциональный 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 генерирует три файла.
FileName | Описание |
---|---|
builder_wrapsfcn.c | Основная S-функция. |
builder_wrapsfcn_wrapper.c | Файл обертки, содержащий отдельные функции для кода, введенного в Outputs, Continuous Derivatives и панелях Discrete Updates Разработчика 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
файл. Этот пример требует только функции обертки для кода 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
, как задано в панели 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
имеет три части:
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
раздел содержит информацию от поля External reference declarations на панели Libraries. Этот пример не использует этот раздел.
Output functions
раздел объявляет функциональный builder_wrapfcn_Outputs_wrapper
, который содержит код, введенный в диалоговом окне блока S-Function Builder панель Outputs:
/* * 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
.
Файл 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
. Для скрипта, который выполняет шаги в том примере, скопируйте файл 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
. S-функция, сгенерированная Legacy Code Tool непосредственно, вызывает doubleIt.c
от его mdlOutputs
метод.
Использование Разработчика S-функции имена ввода и вывода ввело в панель Data Properties, позволив вам настроить эти имена в S-функции. Legacy Code Tool использует имена по умолчанию y
и u
для выходных параметров и входных параметров, соответственно. Вы не можете задать настроенные имена, чтобы использовать в сгенерированной S-функции при использовании Legacy Code Tool.
Разработчик S-функции и Legacy Code Tool оба задают наследованный шаг расчета по умолчанию. Однако Разработчик S-функции использует время смещения 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