S-функции включают устаревший код С

Обзор

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™, с помощью предыдущих трех методов. Модель в качестве примера содержит блоки, которые используют эти S-функции. Если вы планируете создать модель, скопируйте файлы doubleIt.c и doubleIt.h от папки docroot/toolbox/simulink/examples в вашу рабочую папку.

Используя рукописную S-функцию, чтобы включить унаследованный код

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. 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-функции автоматизирует создание 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 генерирует три файла.

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

Используя Legacy Code Tool, чтобы включить унаследованный код

Раздел 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