exponenta event banner

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

wrapper Обзор учебного пособия

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

Папка: matlabroot/toolbox/rtw/rtwdemos/tlctutorial/wrapper (открыто)

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

  • Зачем переносить код пользователя? - Причина создания функций оболочки TLC

  • Начало работы - настройка упражнения обертки

  • Генерировать код без обертки - как генератор кода обрабатывает внешние функции по умолчанию

  • Создание кода с помощью обертки - обход заголовка API

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

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

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

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

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

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

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

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

Примечание

Файлы объектов, в которых отсутствует исходный код и которые создаются с помощью 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. Активируйте блок «Область», дважды щелкнув его.

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

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

    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 должен генерировать код C, который обеспечивает:

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

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

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

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

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

  3. В MATLAB откройте модель. externalcode из рабочей папки. Активируйте блок «Область», дважды щелкнув его, и запустите модель (на вкладке «Моделирование» или введите Ctrl + T). Это дает базовый результат.

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

    • Напечатать

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

    • В диалоговом окне «S-Function block parameters» (Параметры S-функционального блока) в диалоговом окне 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() с ожидаемыми входными и выходными данными? Исправьте ошибки и восстановите модель.

Связанные темы