Интеграция функций C с помощью Legacy Code Tool

Обзор

Можно интегрировать существующие функции C (или C++), такие как драйверы устройств, интерполяционные таблицы и общие функции и интерфейсы, в Simulink® моделирует при помощи Legacy Code Tool. Использование спецификаций, которые вы поставляете как MATLAB® код, инструмент преобразует существующие функции в S-функции C MEX, которые можно включить в модели Simulink. Если вы используете Simulink Coder™ для генерации кода, Legacy Code Tool может вставить соответствующий вызов вашей функции C в сгенерированный код. Для получения дополнительной информации смотрите Импорт вызовов во внешний код в сгенерированный код с помощью Legacy Code Tool (Simulink Coder).

По сравнению с использованием S-Function Builder или записью S-функции, Legacy Code Tool проще в использовании и генерирует оптимизированный код (не генерирует код оболочки), часто требуемый встраиваемыми системами. Однако рассмотрим альтернативные подходы для гибридной системы, такой как система, которая включает в себя объект и контроллер, или системный компонент, написанный на языке, отличном от C или C++. Альтернативные подходы более гибки в том, что они поддерживают больше функций и языков программирования.

Для взаимодействия с Legacy Code Tool, вы

  • Используйте структуру данных Legacy Code Tool, чтобы задать

    • Имя для S-функции

    • Спецификации для существующих функций C

    • Файлы и пути, необходимые для компиляции

    • Опции для сгенерированной S-функции

  • Используйте legacy_code функции в

    • Инициализируйте структуру данных Legacy Code Tool для заданной функции C

    • Сгенерируйте S-функцию для использования во время симуляции

    • Скомпилируйте и соедините сгенерированную S-функцию в динамически загружаемый исполняемый файл

    • Сгенерируйте маскированный Блок s-function для вызова сгенерированной S-функции

    • Сгенерируйте файл блока TLC и, при необходимости, sFunction_makecfg.m или rtwmakecfg.m файл для генерации кода (требуется лицензия продукта Simulink Coder)

Примечание

Прежде чем вы сможете использовать legacy_codeубедитесь, что для установки MATLAB настроен компилятор C.

Следующая схема иллюстрирует общую процедуру использования Legacy Code Tool. Интеграция функций C с моделями Simulink с помощью Legacy Code Tool приводит пример, который использует Legacy Code Tool для преобразования существующей функции C в S-функцию C MEX.

Если у вас есть лицензия продукта Simulink Coder, смотрите Импорт вызовов во внешний код в сгенерированный код с помощью Legacy Code Tool (Simulink Coder) для получения информации об использовании Legacy Code Tool для генерации кода.

Интеграция функций C с моделями Simulink с помощью Legacy Code Tool

Этот пример демонстрирует, как интегрировать существующую функцию C в модель Simulink с помощью Legacy Code Tool.

Предположим, что у вас есть функция C, которая выводит значение ее входного сигнала с плавающей точкой, умноженное на два. Функция определяется в исходном файле с именем doubleIt.c, и его объявление существует в заголовочном файле с именем doubleIt.h.

  1. Инициализируйте struct MATLAB def с полями, которые представляют свойства Legacy Code Tool, используя legacy_code функция.

    def = legacy_code('initialize')

    Структура данных Legacy Code Tool с именем def отображает его поля в командном окне MATLAB, как показано здесь:

    def = 
    
                  SFunctionName: ''
    InitializeConditionsFcnSpec: ''
                  OutputFcnSpec: ''
                   StartFcnSpec: ''
               TerminateFcnSpec: ''
                    HeaderFiles: {}
                    SourceFiles: {}
                   HostLibFiles: {}
                 TargetLibFiles: {}
                       IncPaths: {}
                       SrcPaths: {}
                       LibPaths: {}
                     SampleTime: 'inherited'
                        Options: [1x1 struct]
  2. Задайте соответствующие значения для полей в структуре данных Legacy Code Tool, чтобы идентифицировать свойства существующей функции C. Например, укажите источник функций C и имена файлов заголовков путем ввода следующих команд в командной строке MATLAB:

    def.SourceFiles = {'doubleIt.c'};
    def.HeaderFiles = {'doubleIt.h'};

    Необходимо также указать информацию о S-функции, которую Legacy Code Tool создает из кода С Для примера задайте имя для S-функции и ее объявления выходной функции путем ввода:

    def.SFunctionName = 'ex_sfun_doubleit';
    def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';

    Для получения информации о различных полях структуры данных см. legacy_code страница с описанием.

  3. Сгенерируйте исходный файл S-функции из существующей функции C при помощи legacy_code функция. В командной строке MATLAB введите:

    legacy_code('sfcn_cmex_generate', def);

    Legacy Code Tool использует информацию, указанную в def для создания исходного файла S-функции с именем ex_sfun_doubleit.c в текущей папке MATLAB.

  4. Скомпилируйте и соедините исходный файл S-функции в динамически загружаемый исполняемый файл для Simulink, используяlegacy_code функция. В командной строке MATLAB введите:

    legacy_code('compile', def);

    В командном окне MATLAB появляются следующие сообщения:

    ### Start Compiling ex_sfun_doubleit
        mex('ex_sfun_doubleit.c', 'd:\work\lct_demos\doubleIt.c', 
           '-Id:\work\lct\lct_demos')
    ### Finish Compiling ex_sfun_doubleit
    ### Exit

    На 32-разрядной версии Microsoft® Windows® система, получившийся исполняемый файл S-функции назван ex_sfun_doubleit.mexw32.

  5. Вставьте маскированный S-Function блок в модель Simulink.

    legacy_code('slblock_generate', def);

    Legacy Code Tool конфигурирует блок, чтобы использовать S-функцию C MEX, созданную на предыдущем шаге. Кроме того, инструмент маскирует блок таким образом, чтобы он отображал значение своего OutputFcnSpec свойство (см. описание legacy_code функция).

  6. Добавьте блок амплитуды 1 Sine Wave к входу блока S-функции C-MEX и блок Scope к выходу.

    Запустите симуляцию. Блок C-MEX S-Function возвращает значение своего входа с плавающей точкой, умноженное на два. Он ведет себя как функция C doubleIt.

Интегрирование функции C, аргументы которой являются указателями на структуры

В этом примере показано, как использовать Legacy Code Tool для интеграции функции C, аргументы которой являются указателями на структуры.

В Simulink ® создайте Simulink.Bus объект, представляющий тип структуры. Используйте сигналы шины в модели, чтобы представлять структурированные сигналы и состояния. Создайте структуры MATLAB в рабочей области или в диалоговом окне параметров блоков, чтобы представлять структуры параметров.

Для получения основной информации о сигналах шины смотрите Virtual Bus. Для получения основной информации о структурах параметров смотрите Organize Related Block Parameter Definitions in Structures. Для создания объектов шины см. раздел «Создание и определение объектов Simulink .Bus».

Исследуйте внешний код

Скопируйте этот пользовательский исходный код в файл с именем ex_mySrc_LCT.c в текущей папке.

#include "ex_myTypes_LCT.h"

void myFcn(sigStructType *in, paramStructType *params, sigStructType *out)
{
    out->sig1 = in->sig1 * params->param1;
    out->sig2 = in->sig2 * params->param2 + params->param3;
}

Аргументы функции myFcn - указатели на структуры. Функция принимает аргумент входного сигнала, аргумент параметра и аргумент выходного сигнала.

Скопируйте этот пользовательский код заголовка в файл с именем ex_myTypes_LCT.h в текущей папке.

#ifndef _MY_TYPES_H_
#define _MY_TYPES_H_

typedef struct {
  double sig1;
  double sig2;
} sigStructType;

typedef struct {
  double param1;
  double param2;
  double param3;
} paramStructType;

void myFcn(sigStructType *in, paramStructType *params, sigStructType *out);

#endif

Файл определяет типы структур сигналов и параметров, которые myFcn использует.

Создайте объекты шины, чтобы представлять типы структур в Simulink

В командной строке используйте функцию Simulink.importExternalCTypes чтобы сгенерировать объекты шины в базовом рабочем пространстве.

Simulink.importExternalCTypes('ex_myTypes_LCT.h');

Объекты шины соответствуют struct типы, которые ex_myTypes_LCT.h задает.

Создайте блок для выполнения внешнего кода

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

def = legacy_code('initialize');

Установите имя S-функции равным sfun_ex_mySrc_LCT.

def.SFunctionName = 'sfun_ex_mySrc_LCT';

Идентифицируйте внешний исходный код и заголовочные файлы по их именам.

def.SourceFiles = {'ex_mySrc_LCT.c'};
def.HeaderFiles = {'ex_myTypes_LCT.h'};

Задайте прототип выходной функции, которую модель вызывает каждый шаг симуляции, путем копирования прототипа внешней функции myFcn. Установите имена аргументов равными u1, p1, и y1 для представления входного параметра, аргумента параметра и выходного аргумента. Используйте синтаксис [1] чтобы указать, что каждый аргумент является указателем.

def.OutputFcnSpec = ['void myFcn(sigStructType u1[1], ',...
    'paramStructType p1[1], sigStructType y1[1])'];

Используйте функцию legacy_code чтобы создать S-функцию и соответствующий исполняемый файл C MEX из спецификации, def. Задайте опцию 'generate_for_sim' для подготовки S-функции к нормальным и ускоренным симуляциям.

legacy_code('generate_for_sim',def);
### Start Compiling sfun_ex_mySrc_LCT
    mex('-I/tmp/BR2021ad_1584584_202060/publish_examples13/tp1adb5b81/ex12763634', '-c', '-outdir', '/tmp/BR2021ad_1584584_202060/publish_examples13/tp6c5c5b35_65b0_40a1_bf2b_a8cd7d349cb4', '/tmp/BR2021ad_1584584_202060/publish_examples13/tp1adb5b81/ex12763634/ex_mySrc_LCT.c')
Building with 'gcc'.
MEX completed successfully.
    mex('sfun_ex_mySrc_LCT.c', '-I/tmp/BR2021ad_1584584_202060/publish_examples13/tp1adb5b81/ex12763634', '/tmp/BR2021ad_1584584_202060/publish_examples13/tp6c5c5b35_65b0_40a1_bf2b_a8cd7d349cb4/ex_mySrc_LCT.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling sfun_ex_mySrc_LCT
### Exit

Создайте маскированный блок S-Function, который вызывает S-функцию во время симуляции.

legacy_code('slblock_generate', def);

Блок появляется в новой модели.

Чтобы использовать блок S-Function в вашей модели, создайте сигнал шины типа sigStructType для использования в качестве блока входных параметров. Блок выводит также сигнал шины. Маска блока принимает параметр, P1. Чтобы задать значение параметра, используйте структуру MATLAB, поля которой совпадают с полями типа структуры paramStructType.

Проверьте выполнение внешнего кода

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

Для примера просмотрите модель ex_lct_struct.

open_system('ex_lct_struct')

В диалоговое окно блока Constant параметр Constant значения устанавливается на структуру, поля которой совпадают с полями типа структуры sigStructType. На вкладке Signal Attributes Выхода тип данных устанавливается на объект шины sigStructType.

Блок S-Function вызывает S-функцию sfun_ex_mySrc_LCT который вы создали. Выход блока входит в блок Bus Selector, который извлекает сигнальные элементы sig1 и sig2.

Блок S-Function принимает параметр через диалоговое окно маски. Создайте структуру MATLAB structParam для использования в качестве значения параметра.

structParam = struct;
structParam.param1 = 15;
structParam.param2 = 20;
structParam.param3 = 5;

Опционально используйте Simulink.Parameter объект, содержащий структуру. Если вы используете объект параметра, можно задать тип данных структуры при помощи объекта шины paramStructType.

structParam = Simulink.Parameter(structParam);
structParam.DataType = 'Bus: paramStructType';

В диалоговом окне «Маска» установите P1 равным structParam.

set_param('ex_lct_struct/sfun_ex_mySrc_LCT','SParameter1','structParam')

Симулируйте модель. Блоки Возможностей показывают, что блок S-Function вызывает внешнюю функцию myFcn.

open_system('ex_lct_struct/Scope')
open_system('ex_lct_struct/Scope1')
sim('ex_lct_struct')
%

Регистрация Legacy Code Tool структур данных

Первым шагом к использованию Legacy Code Tool является регистрация одной или нескольких структур MATLAB с полями, которые представляют свойства существующего кода С и генерируемой S-функции. Процесс регистрации является гибким. Вы можете принять решение настроить ресурсы и инициировать регистрацию различными способами, включая

  • Размещение всех необходимых заголовков и исходных файлов в текущей рабочей папке или в иерархической структуре папки

  • Генерация и размещение одной или нескольких S-функций в текущей рабочей папке

  • Наличие одного или нескольких файлов регистрации в одной папке

Чтобы зарегистрировать структуру данных Legacy Code Tool:

  1. Используйте legacy_code функция, установка 'initialize' как первый аргумент.

    lct_spec = legacy_code('initialize')

    Структура данных Legacy Code Tool с именем lct_spec отображает его поля в командном окне MATLAB, как показано ниже:

    lct_spec = 
    
                  SFunctionName: ''
    InitializeConditionsFcnSpec: ''
                  OutputFcnSpec: ''
                   StartFcnSpec: ''
               TerminateFcnSpec: ''
                    HeaderFiles: {}
                    SourceFiles: {}
                   HostLibFiles: {}
                 TargetLibFiles: {}
                       IncPaths: {}
                       SrcPaths: {}
                       LibPaths: {}
                     SampleTime: 'inherited'
                        Options: [1x1 struct]
  2. Задайте значения для полей структуры данных (свойств), которые применяются к существующей функции C и S-функции, которую вы намереваетесь сгенерировать. Минимально, вы должны задать

    • Исходные файлы и заголовки для существующей функции C (SourceFiles и HeaderFiles)

    • Имя для S-функции (SFunctionName)

    • По крайней мере, одна спецификация функции для S-функции (InitializeConditionsFcnSpec, OutputFcnSpec, StartFcnSpec, TerminateFcnSpec)

    Полный список и описание полей в структуре см. в разделе legacy_code страница с описанием функции.

Если вы задаете поля, которые задают ресурсы компиляции и задаете относительные пути, Legacy Code Tool ищет ресурсы относительно следующих директорий в следующем порядке:

  1. Текущая рабочая папка

  2. Папка S-функции C-MEX, если отличается от текущей рабочей папки

  3. Директории, которые вы задаете

    • IncPaths для заголовочных файлов

    • SrcPaths для исходных файлов

    • LibPaths для целевых и хост-библиотек

  4. Директории в пути поиска файлов MATLAB, исключая директории тулбокса

Объявление спецификаций функций Legacy Code Tool

The InitializeConditionsFcnSpec, OutputFcnSpec, StartFcnSpec, и TerminateFcnSpec поля, определенные в структуре данных Legacy Code Tool (см. описание legacy_code функция) требуют значений векторов символов, которые соответствуют определенному синтаксическому формату. Необходимый синтаксический формат позволяет Legacy Code Tool сопоставить возврату значение и аргументы существующей функции C с возвратом значением, входами, выходами, параметрами и рабочими векторами S-функции, которую генерирует инструмент.

Общий синтаксис

return-spec = function-name(argument-spec)

Например, следующий вектор символов задает функцию с именем doubleIt со спецификацией возврата double y1 и спецификация входного параметра double u1.

def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';

Для получения дополнительной информации об объявлении спецификаций функций см.

Спецификация возврата

Спецификация возврата определяет тип данных и имя переменной для возвращаемого значения существующей функции C.

return-type return-variable
return-typeТип данных, перечисленный в Поддерживаемые типы данных.
return-variableЛексема формы y1, y2, ..., yn, где n - общее количество выходных аргументов.

Если функция не возвращает значение, можно опустить спецификацию возврата или указать ее как void.

В следующей таблице показан действительный синтаксис спецификации функции для целочисленного возвращаемого значения. Используйте таблицу, чтобы идентифицировать синтаксис, который вы должны использовать для прототипа функции C.

Тип возвратаПрототип функции CСпецификация функции Legacy Code Tool
Нет возвращаемого значенияvoid myfunction(...)void myfunction(...)
Скалярное значениеint = myfunction(...)int16 y1 = myfunction(...)

Имя функции

Заданное имя функции должно совпадать с именем существующей функции C.

Например, рассмотрите следующий прототип функции C:

float doubleIt(float inVal);

В этом случае имя функции в спецификации функции Legacy Code Tool должно быть doubleIt.

Имя макроса C задавать не следует. Если необходимо, установите поле Options.isMacro на true в выражение случая.

Спецификация аргументов

Спецификация аргумента задает один или несколько типов данных и пар маркеров, которые представляют входу, вывод, параметр и аргументы рабочего вектора существующей функции C. Входные параметры функции и выходные аргументы сопоставляются с входом и выходными портами и параметрами блоков, а также с параметрами рабочей области.

argument-type argument-token
argument-typeТип данных, перечисленный в Поддерживаемые типы данных.
argument-tokenЛексема одной из следующих форм:
  • Вход - u1, u2, ..., un, где n - общее количество входных параметров

  • Выход - y1, y2, ..., yn, где n - общее количество выходных аргументов

  • Параметр - p1, p2, ..., pn, где n - общее количество аргументов параметра

  • Векторы работы (постоянная память) - work1, work2, ..., workn, где n - общее количество аргументов в виде рабочих векторов

Если функция не имеет аргументов, можно опустить спецификацию аргумента или указать ее как void.

Примите во внимание следующий прототип функции C:

float powerIt(float inVal, int exponent);

Чтобы сгенерировать S-функцию, которая вызывает предыдущую функцию в каждом временном шаге, установите поле структуры данных Legacy Code Tool OutputFcnSpec к следующему:

'single y1 = powerIt(single u1, int16 p1)'

Используя эту спецификацию функции, Legacy Code Tool сопоставляет следующую информацию.

Возвращаемое значение или аргументтипа CК лексеметипа данных
Возвращаемое значениеfloaty1single
inValfloatu1single
exponentintp1int16

Если вашей функции требуется блок S-функции Simulink с несколькими входными и выходными портами, сопоставьте аргументы функции с входными портами с помощью уникально пронумерованного u лексема. Для выходных портов используйте уникально пронумерованную y лексема. Эти лексемы описаны в предыдущей таблице спецификаций аргументов. Например, рассмотрите следующий прототип функции C:

void myfunc(double *y2, double u2, double u3, double u1, double *y1);

Система координат OutputFcnSpec вектор символов, сопоставляющий аргументы с входными и выходными портами, выглядит аналогично следующему:

'void myfunc(double y2[1], double u2, double u3, double u1, double y1[1])'

Получившийся блок s-function включает три входных порта и два выходных порта. Первый вход преобразуется в аргумент функции u1, второй вход для u2, и третий вход для u3. Для портов выхода аргумент функции y1[1] преобразуется в первый выход, и аргумент y2[1] преобразуется во второй выход. Для другого примера отображения прототипа функции с несколькими входными и выходными портами смотрите Использование шин с устаревшими функциями, имеющими аргументы структуры.

В следующей таблице показан действительный синтаксис спецификации функции для аргументов с целым числом типов. Используйте таблицу, чтобы идентифицировать и затем адаптировать синтаксис, который вы должны использовать для прототипа функции C.

Тип аргументаПрототип функции CСпецификация функции Legacy Code Tool
Входные параметры
Аргументов нетfunction(void)function(void)
Скалярный проход по значениюfunction(int in1)function(int16 u1)
Скалярный проход мимо указателяfunction(int *in1)function(int16 u1[1])
Фиксированный векторfunction(int in1[10]) или
function(int *in1)
function(int16 u1[10])
Вектор с переменнойfunction(int in1[]) или
function(int *in1)
function(int16 u1[])
Фиксированная матрицаfunction(int in1[15]) или
function(int in1[]) или
function(int *in1)
function(int16 u1[3][5])
Матрица переменныхfunction(int in1[]) или
function(int *in1)
function(int16 u1[][])
Выходные аргументы
Скалярный указательfunction(int *y1)function(int16 y1[1])
Фиксированный векторfunction(int y1[10]) или
function(int *y1)
function(int16 y1[10])
Фиксированная матрицаfunction(int y1[15]) или
function(int y1[]) или
function(int *y1)
function(int16 y1[3][5])
Аргументы параметра
Скалярный проход по значениюfunction(int p1)function(int16 p1)
Скалярный проход мимо указателяfunction(int *p1)function(int16 p1[1])
Фиксированный векторfunction(int p1[10]) или
function(int *p1)
function(int16 p1[10])
Вектор с переменнойfunction(int p1[]) или
function(int *p1)
function(int16 p1[])
Фиксированная матрицаfunction(int p1[15]) или
function(int p1[]) или
function(int *p1)
function(int16 p1[3][5])
Матрица переменныхfunction(int p1[]) или
function(int *p1)
function(int16 p1[][])
Работа векторные аргументы
Скаляр, переданный значениемfunction(int work1)function(int16 work1)
Скалярный указательfunction(int *work1)
function(void *work1)
function(void **work1)
function(int16 work1[1])
void function(void *work1)
void function(void **work1)
Фиксированный векторfunction(int work1[10]) или
function(int *work1)
function(int16 work1[10])
Фиксированная матрицаfunction(int work1[15]) или
function(int work1[]) или
function(int *work1)
function(int16 work1[3][5])

Поддерживаемые типы данных

Тип данныхПоддерживается для входа и выхода?Поддерживается для параметров?Поддерживается для рабочих векторов?
Типы данных, поддерживаемые Simulink (за исключением string)ДаДаДа
Simulink.Bus1ДаДаДа
Массив Simulink.Bus2ДаНетДа
Simulink.NumericType3ДаДаДа
Simulink.AliasType1ДаДаДа
enum1ДаДаДа
Фиксированная точка4ДаДаДа
Объекты FiН/ДДаН/Д
Комплексные числа5ДаДаДа
1-D массивДаДаДа
2-D массив6ДаДаДа
n-D массив7ДаДаДа
void *НетНетДа
void * *НетНетДа
  1. Вы должны предоставить заголовочный файл, который определяет структуру шины, задает enum type или определяет тип данных с таким же именем, как и псевдоним. Структура шины, объявленная в заголовочном файле, должна совпадать со структурой объекта шины (для примера, количество и порядок элементов, типы данных и ширины элементов и так далее). Для получения примера смотрите Использование шин с устаревшими функциями, имеющими аргументы структуры.

    Чтобы сгенерировать объекты типа данных и классы перечисления, которые соответствуют пользовательским типам данных, заданным вашим кодом С, используйте Simulink.importExternalCTypes функция.

  2. Элемент шины может быть комплексным, но только со встроенными типами данных Simulink. Также поддерживается вложение массивов на любой уровень.

  3. Вы должны предоставить заголовочный файл, который определяет тип данных, только если тип числовых данных также является псевдонимом.

  4. Вы должны объявить данные как Simulink.NumericType объект (не заданный масштабирование не поддерживается). Для примеров смотрите Сигналы Фиксированной Точки в Устаревших Функциях и Параметры Фиксированной Точки в Устаревших Функциях.

  5. Ограничено использованием со встроенными типами данных Simulink. Чтобы задать сложный тип данных, заключайте встроенный тип данных в угловые скобки (< >) и подготовьте слово complex (например, complex<double>). Для получения примера смотрите Комплексные Сигналы в Устаревшей Функции.

  6. Продукты MATLAB, Simulink и Simulink Coder хранят многомерные массивы в основном формате в качестве вектора. Если код внешней функции записан для данных основной строки, используйте convertNDArrayToRowMajor Опция S-функции в legacy_code.

  7. Для многомерного сигнала можно использовать size функция для определения количества элементов в сигнале. Для примеров смотрите Интерполяционные таблицы, реализованные в устаревших функциях и многомерных сигналах в устаревших функциях.

Для получения дополнительной информации см. «Типы данных, поддерживаемые Simulink».

Правила спецификации функций Legacy Code Tool

Спецификации для legacy_code должны соответствовать следующим правилам:

  • Если аргумент не скаляром, необходимо передать аргумент по ссылке.

  • Нумерация токенов входных, выходных, параметрических и векторных аргументов должна начинаться с 1 и увеличиваться монотонно.

  • Для заданной структуры данных Legacy Code Tool тип данных и размер входа, выхода, параметра и аргументов рабочего вектора должны быть одинаковыми для спецификаций функций StartFcnSpec, InitializeConditionsFcnSpec, OutputFcnSpec, и TerminateFcnSpec.

  • Можно задать размерности аргументов с выражениями, которые используют следующие:

    • Функции: numel , size

    • Значения параметров

    • Операторы: +, -, *, и /

    • Целое число и литералы с плавающей точкой

    • Круглые скобки для группировки подвыражений

    Для примера:

    def.OutputFcnSpec=
    foo4(int8 p1[], int8 u1[], double y1[numel(u1)+2][numel(u1)+3], ...
    int32 (numel(p1)+numel(u1))*2+size(y1,2))';

Правила наследования функций C

Чтобы интегрировать функцию C с помощью Legacy Code Tool, функция должна соответствовать следующим правилам:

  • Функция не должна изменять значение входных параметров. Если входной сигнал является переданным по ссылке аргументом функции, функция не должна изменять данные, на которые указывает аргумент.

  • Возвращаемое значение функции не может быть указателем.

  • Спецификации функций, которые вы определяете для StartFcnSpec, InitializeConditionsFcnSpec, или TerminateFcnSpec не удается получить доступ к входным или выходным аргументам. Для StartFcnSpec и InitializeConditionsFcnSpec, вы можете получить доступ к выходным портам, если опция S-Function outputsConditionallyWritten установлено в true. С помощью этой настройки опции сгенерированная S-функция задает, что память, связанная с каждым выходам портом, не может быть перезаписана и является глобальной (SS_NOT_REUSABLE_AND_GLOBAL).

Генерация и компиляция S-функций

После регистрации структуры данных Legacy Code Tool для существующей функции C используйте legacy_code функция, как объяснено ниже, чтобы сгенерировать, скомпилировать и связать S-функцию.

  1. Сгенерируйте S-функцию MEX на основе информации, определенной в структуре. Звонить legacy_code с 'sfcn_cmex_generate' как первый аргумент и имя структуры данных как второй аргумент.

    legacy_code('sfcn_cmex_generate', lct_spec);
  2. Скомпилируйте и соедините S-функцию. Этот шаг предполагает, что для установки MATLAB настроен компилятор C. Звонить legacy_code с 'compile' как первый аргумент и имя структуры данных как второй аргумент.

    legacy_code('compile', lct_spec);
    

    В командном окне MATLAB появляются информационные сообщения, подобные нижеследующим, и динамически загружаемые исполняемые результаты. В 32-разрядной системе Windows программное обеспечение Simulink называет файл ex_sfun_doubleit.mexw32.

    ### Start Compiling ex_sfun_doubleit
    mex  ex_sfun_doubleit.c -Id:\work\lct\lct_demos
    ### Finish Compiling ex_sfun_doubleit
    ### Exit

Для удобства можно сгенерировать, скомпилировать и связать S-функцию за один шаг вызовом legacy_code с вектором символов 'generate_for_sim'. Функция также генерирует файл TLC для ускоренных симуляций, если Options.useTlcWithAccel для поля структуры данных Legacy Code Tool задано значение 1.

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

Генерация маскированного блока s-function для вызова сгенерированной S-функции

У вас есть опция использовать Legacy Code Tool, чтобы сгенерировать блок s-function (графическое представление), который сконфигурирован для вызова сгенерированной S-функции C MEX. Чтобы сгенерировать такой блок, вызовите legacy_code с 'slblock_generate' как первый аргумент и имя структуры данных Legacy Code Tool в качестве второго аргумента.

legacy_code('slblock_generate', lct_spec);

Инструмент маскирует блок таким образом, чтобы в нем отображалось значение OutputFcnSpec поле. Затем можно добавить блок в модель вручную.

Если вы предпочитаете, чтобы Legacy Code Tool автоматически добавлял блок в модель, укажите имя модели в качестве третьего аргумента. Для примера:

legacy_code('slblock_generate', lct_spec, 'myModel');

Если заданная модель (для примера, myModel) существует, legacy_code открывает модель и добавляет маскированный блок s-function, описанный структурой данных Legacy Code Tool. Если модель не существует, функция создает новую модель с заданным именем и добавляет маскированные Блоки s-function.

Принудительный режим Accelerator для использования кода Inlining S-Function TLC

Если вы используете режим Accelerator™ Simulink, можно сгенерировать и принудительно использовать инлайнинговый код TLC для S-функции, сгенерированной Legacy Code Tool. Для этого:

  1. Сгенерируйте файл блока TLC для S-функции путем вызова legacy_code функция со 'sfcn_tlc_generate' как первый аргумент и имя структуры данных Legacy Code Tool в качестве второго аргумента.

    legacy_code('sfcn_tlc_generate', lct_spec);

    Рассмотрим пример в Интегрировать функции C в модели Simulink с помощью Legacy Code Tool. Чтобы сгенерировать файл TLC для модели, показанной в конце этого примера, введите следующую команду:

    legacy_code('sfcn_tlc_generate', def);
  2. Заставьте Режим Accelerator использовать TLC-файл при помощи ssSetOptions SimStruct функция для установки опции S-функции SS_OPTION_USE_TLC_WITH_ACCELERATOR.

Вызов функций наследования C++

Чтобы вызвать устаревшую функцию C++ после инициализации структуры данных Legacy Code Tool, присвойте значение 'C++' Options.language поле. Для примера,

def = legacy_code('initialize');
def.Options.language = 'C++';

Чтобы проверить новую настройку, введите

def.Options.language

Примечание

Legacy Code Tool может взаимодействовать с функциями C++, но не с объектами C++. Для получения дополнительной информации см. раздел «Ограничения Legacy Code Tool» в документации Simulink.

Обработка нескольких файлов регистрации

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

Рассмотрим следующий пример, где lct_register_1, lct_register_2, и lct_register_3 каждый из них создает и инициализирует поля структуры Legacy Code Tool.

defs1 = lct_register_1;
defs2 = lct_register_2;
defs3 = lct_register_3;
defs = [defs1(:);defs2(:);defs3(:)];

Затем можно использовать следующую последовательность вызовов legacy_code в порядок для генерации файлов на основе трех файлов регистрации:

legacy_code('sfcn_cmex_generate', defs);
legacy_code('compile', defs);
legacy_code('sfcn_tlc_generate', defs);

Кроме того, каждый файл регистрации можно обрабатывать отдельно. Для примера:

defs1 = lct_register1;
legacy_code('sfcn_cmex_generate', defs1);
legacy_code('compile', defs1);
legacy_code('sfcn_tlc_generate', defs1);
.
.
.
defs2 = lct_register2;
legacy_code('sfcn_cmex_generate', defs2);
legacy_code('compile', defs2);
legacy_code('sfcn_tlc_generate', defs2);
.
.
.
defs3 = lct_register3;
legacy_code('sfcn_cmex_generate', defs3);
legacy_code('compile', defs3);
legacy_code('sfcn_tlc_generate', defs3);

Развертывание сгенерированных S-функций

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

Примеры Legacy Code Tool

Для примеров Legacy Code Tool, смотрите Реализуйте Алгоритмы Используя Legacy Code Tool.

Ограничения, накладываемые на Legacy Code Tool

Legacy Code Tool

  • Генерирует S-функции на C MEX для существующих функций, написанных на C или C++. Инструмент не поддерживает преобразование функций MATLAB или Фортран.

  • Может взаимодействовать с функциями C++, но не с объектами C++. Один из способов преодоления этого ограничения - использовать S-Function Builder, чтобы сгенерировать интерпретатор S-функции, а затем вызвать устаревший код С++ из S-функции mdlOutputs функцию обратного вызова.

  • Не поддерживает симуляцию непрерывных или дискретных состояний. Это препятствует использованию mdlUpdate и mdlDerivatives функции обратного вызова. Если вашему приложению требуется эта поддержка, см. Раздел «Использование S-Function Builder для включения унаследованного кода».

  • Всегда устанавливает флаг S-функций для прямого сквозного соединения (sizes.DirFeedthrough) к true. Из-за этой настройки и предыдущего ограничения сгенерированная S-функция не может сломать алгебраические циклы.

  • Поддерживает только непрерывный, но фиксированный в незначительном временном шаге, шаге расчета и опции смещения.

  • Поддерживает комплексные числа, но только со встроенными типами данных Simulink.

  • Не поддерживает использование указателей на функцию в качестве выхода вызываемой устаревшей функции.

  • Не поддерживает следующие функции S-функции:

    • Рабочие векторы, кроме общих векторов DWork

    • Основанные на кадрах входные и выходные сигналы

    • Основанные на порте шаги расчета

    • Несколько шагов расчета на основе блоков

  • Не поддерживает использование оператора scope (::) для доступа к данным и методам класса C++. Для статических методов можно написать простые макросы препроцессора, похожие на следующие, чтобы работать вокруг этого:

    #define CCommon_computeVectorDotProduct CCommon::computeVectorDotProduct

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