Перенос кода пользователя с TLC

wrapper Обзор руководства

Objective: Узнать архитектуру S-функций оболочки и как создать S-функцию встроенной оболочки с помощью TLC.

<reservedrangesplaceholder1> <reservedrangesplaceholder0> / toolbox/rtw/rtwdemos/tlctutorial/wrapper (открыто)

Wrapper S-функции позволяют использовать существующие функции C, не переписывая их полностью в контексте Simulink® S-функции. Каждая оболочка, которую вы предоставляете, является «оболочкой» S-функции, которая просто вызывает одну или несколько существующих внешних функций. Это руководство объясняет и иллюстрирует обертки следующим образом:

  • Why Wrap User Code? - Причина создания функций обертки TLC

  • Getting Started - настройте упражнение обертки

  • Generate Code Without a Wrapper - Как генератор кода обрабатывает внешние функции по умолчанию

  • Generate Code Using a Wrapper - Обхода накладных расходов API

Зачем переносить код пользователя?

Многие пользователи Simulink хотят создавать модели, включающие алгоритмы, которые они уже закодировали, реализовали и протестировали в высокоуровневый язык. Обычно такой код вносится в Simulink как S-функции. Чтобы сгенерировать внешнее приложение, интегрирующее пользовательский код, можно принять несколько подходов:

  • Можно создать S-функцию из пользовательского кода, которая соединяет ее с типовым API Simulink. Это самый простой подход, но жертвует эффективностью для автономных приложений.

  • Можно встраивать S-функцию, повторно имплементируя ее как файл TLC. Это повышает эффективность, но требует времени и усилий, может ввести ошибки в рабочий код и приводит к двум наборам кода для обслуживания каждого алгоритма, если вы не используете Legacy Code Tool (см. «Импорт вызовов во внешний код» в сгенерированный код с помощью Legacy Code Tool).

  • Можно встроить S-функцию через TLC- wrapper function. При этом необходимо создать только небольшое количество кода TLC, и алгоритм может остаться закодированным в существующем виде.

Следующий рисунок иллюстрирует, как работают оболочки S-функций.

Перенос функции устраняет необходимость ее перекодирования, требуя для ее интеграции лишь немного дополнительного кода TLC. Оболочки также позволяют использовать объект модули или библиотеки в S-функциях. Это может быть единственным способом развертывания функций, для которых исходный код недоступен, а также позволяет пользователям распространять модели среди других, не разглашая детали реализации, которые могут быть собственными.

Например, у вас может быть существующий файл объекта, скомпилированный для процессора, на котором Simulink не запускается. Можно написать фиктивную S-функцию C и использовать TLC-оболочку, которая вызывает внешнюю функцию, несмотря на отсутствие её исходного кода. Вы можете аналогично получить доступ к функциям в библиотеке алгоритмов, оптимизированной для целевого процессора. Для этого требуется внести изменения в файл make-файла шаблона или иным образом предоставить средство для связи с библиотекой.

Примечание

Файлы объектов, которые не имеют исходного кода и создаются с помощью Microsoft® Visual C и Microsoft Visual C++® Компилятор (MSVC) работает только с MSVC.

Единственное ограничение для оболочек S-функций - это количество входов и выходов блоков, совпадающих с количеством входов и выходов обернутой внешней функции. Код обертки может включать расчеты, но обычно они ограничиваются преобразованием значений (для примера, масштабирования или переформатирования), переданных в и из обернутых внешних функций.

Начало

В папке с примером в файле обнаруживается «внешняя функция» my_alg.c. Вам также предоставляется функция C S, вызываемая wrapsfcn.c который интегрирует my_alg.c в Simulink. Настройте упражнение следующим образом:

  1. Делайте tlctutorial/wrapper текущая папка.

  2. В MATLAB®, откройте модель externalcode из рабочей папки. Схема блока выглядит следующим образом:

  3. Активируйте блок Scope, дважды кликнув по нему мышью.

  4. Запустите модель (с вкладки Simulation или введите Ctrl+T). Вы получите ошибку, сообщающую вам, что wrapsfcn не существует. Ты можешь выяснить почему?

  5. Ошибка возникает из-за mex файл не существует для wrapsfcn. Чтобы исправить это, в типе командного окна MATLAB

    mex wrapsfcn.c

    Примечание

    Ошибка может возникнуть, если вы ранее не выполняли mex -setup.

  6. Еще раз запустите симуляцию с присутствующей S-функцией.

Блок S-Function умножает свой вход на два. Глядя на блок Scope, вы видите синусоиду, которая колеблется между -2.0 и 2.0. Переменная yout который создается в рабочем пространстве MATLAB, с помощью этих значений.

В оставшейся части упражнения вы создаете и запускаете автономную версию модели, затем записываете некоторый TLC-код, который позволяет генератору кода создать независимый исполняемый файл, которая вызывает S-функцию my_alg.c непосредственно.

Сгенерируйте код без обертки

Перед созданием оболочки сгенерируйте код, который использует типовой API Simulink. Первым шагом является создание автономной модели.

  1. На вкладке C Code нажмите Build.

    Генератор кода создает автономную программу в рабочей папке и помещает исходные и объектные файлы в папку сборки. Файл будет вызван externalcode.exe в Microsoft Windows® платформы или externalcode в UNIX® платформы.

    Когда он генерирует программу, генератор кода сообщает о своем прогрессе в Командном окне MATLAB. Конечные линии:

    ### Created executable: externalcode.exe  
    ### Successful completion of build procedure 
    for model: externalcode
  2. Запустите автономную программу, чтобы увидеть, что она ведет себя так же, как и версия Simulink. Различий быть не должно.

    !externalcode
     
    ** starting the model ** 
    ** created externalcode.mat ** 
  3. Заметьте эту линию в wrapsfcn.c:

    #include "my_alg.c"

    Это включает внешнюю функцию. Эта функция полностью состоит из

    /*
     * Copyright 1994-2002 The MathWorks, Inc.
     */
    
    double my_alg(double u)
    {
        return(u * 2.0);
    }

    Осмотрите mdlOutputs() функция кода в wrapsfcn.c чтобы увидеть, как вызывается внешняя функция.

    static void mdlOutputs(SimStruct *S, int tid)
    {
        int_T             i;    
        InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
        real_T            *y    = ssGetOutputPortRealSignal(S,0);
        int_T             width = ssGetOutputPortWidth(S,0);
    
        *y = my_alg(*uPtrs[0]);
    }

Совет

Для платформ UNIX запустите исполняемую программу в Командном окне с синтаксисом !./executable_name. При желании запустите исполняемую программу из интерпретатора ОС с синтаксисом ./executable_name. Для получения дополнительной информации см. раздел «Запуск внешних команд, скриптов и программ».

Как правило, функции, которые должны быть обернуты, либо включаются в оболочку, как указано выше, либо, когда модули объектов обернуты, разрешаются во время ссылки.

Сгенерируйте код с помощью обертки

Чтобы создать оболочку для внешней функции my_alg.c, необходимо создать TLC- файла, которая воплощает в себе его функцию вызова, wrapsfcn.c. TLC файла должен сгенерировать Код С, который обеспечивает:

  • Прототип функции для внешней функции, которая возвращает double и передает входной double u.

  • Вызов функции для my_alg() в разделе выходов кода.

Чтобы создать обертку для my_alg(), выполните следующее:

  1. Откройте файл change_wrapsfcn.tlc в вашем редакторе и добавьте строки кода, где комментарии указывают на создание работоспособной оболочки.

  2. Сохраните отредактированный файл следующим wrapsfcn.tlc. Оно должно иметь то же имя что и блок S-function, который использует его, или TLC не вызывается для встроенного кода.

  3. В MATLAB откройте модель externalcode из рабочей папки. Активируйте блок Scope двойным кликом по нему и запустите модель (с вкладки Simulation или введите Ctrl+T). Это дает вам базовый результат.

  4. Сообщите Simulink, что ваш код имеет внешнюю ссылку, которая должна быть разрешена. Чтобы обновить параметры модели, в Командном Окне MATLAB выполните одно из следующих действий:

    • Напечатать

      set_param('externalcode/S-Function','SFunctionModules','my_alg')

    • В диалоговом окне параметров S-Function блоков, в S-function modules , задайте 'my_alg'.

  5. Создайте автономное приложение путем ввода одной из следующих команд в Командном окне:

    slbuild('my_alg','ForceTopModelBuild',true)
    slbuild('my_alg', 'StandaloneCoderTarget','ForceTopModelBuild',true)

    Эти команды заставляют генератор кода перестроить верхнюю модель, которая требуется, когда вы вносите изменения, связанные с внешним или пользовательским кодом.

    Также можно форсировать регенерацию кода верхней модели путем удаления папок в папке генерации кода, таких как slprj или сгенерированная папка кода модели.

    Для получения дополнительной информации смотрите Регенерация управления верхней части модели.

  6. Запустите новое автономное приложение и проверьте, что оно дает те же результаты, что и в окне возможностей.

    !externalcode

Если у вас возникли проблемы с созданием приложения:

  • Найдите сообщения об ошибке и попытайтесь определить, какие файлы находятся в состоянии отказа, обращая внимание на какой шаг (генерация кода, компиляция, связывание) не удалось.

  • Убедитесь, что вы выпустили set_param() команда, как указано выше.

  • Вероятность того, что проблемы можно проследить до вашего файла TLC. Может быть полезно использовать отладчик TLC, чтобы пройти wrapsfcn.tlc.

  • В крайнем случае, посмотрите на wrapsfcn.tlc в solutions/tlc_solution папка, также перечисленная ниже:

    %% File    : wrapsfcn.tlc
    %% Abstract:
    %%      Example tlc file for S-function wrapsfcn.c
    %%
    %% Copyright 1994-2002 The MathWorks, Inc.
    %%
    %% 
    
    %implements "wrapsfcn" "C"
    %% Function: BlockTypeSetup ================================
    %% Abstract:
    %%      Create function prototype in model.h as:
    %%	    "extern double my_alg(double u);" 
    %%
    %function BlockTypeSetup(block, system) void
      %openfile buffer
      %% ASSIGNMENT: PROVIDE A LINE OF CODE AS A FUNCTION PROTOTYPE
      %% FOR "my_alg" AS DESCRIBED IN THE WRAPPER TLC ASSIGNMENT 
      extern double my_alg(double u);
    
      %closefile buffer
      %<LibCacheFunctionPrototype(buffer)>
    %endfunction %% BlockTypeSetup
    %% Function: Outputs =======================================
    %% Abstract:
    %%      y = my_alg( u );
    %%
    %function Outputs(block, system) Output
      /* %<Type> Block: %<Name> */
      %assign u = LibBlockInputSignal(0, "", "", 0)
      %assign y = LibBlockOutputSignal(0, "", "", 0)
      %% PROVIDE THE CALLING STATEMENT FOR "wrapfcn"
      %<y> = my_alg( %<u> );
    %endfunction %% Outputs

    Посмотрите на подсвеченные линии. Вы заявляли my_alg() как extern double? Вы звонили my_alg() с ожидаемыми входом и выходом? Исправьте ошибки и перестроите модель.

Похожие темы