exponenta event banner

Как сгенерированный код хранит внутренний сигнал, состояние и данные параметров

Для вычисления выходных данных по входам сгенерированный код сохраняет некоторые внутренние данные в глобальной памяти. Сигнал, не подключенный к входу или выходу корневого уровня (блок Inport или Outport), представляет собой внутренние данные.

Внутренние данные также могут включать:

  • Состояние блока, например состояние блока единичной задержки. Алгоритм должен сохранять значение состояния между циклами выполнения, поэтому сгенерированный код обычно хранит состояния в глобальной памяти (например, в виде глобальной переменной или поля глобальной структурной переменной).

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

  • Индикатор состояния условно выполняемой подсистемы, например, включенной подсистемы.

Для повышения эффективности кода можно настроить такие оптимизации, как «Параметры конфигурации» > «Поведение параметров по умолчанию» и «Параметры конфигурации» > «Повторное использование хранилища сигналов», которые пытаются исключить хранение внутренних данных. Однако оптимизация не может исключить хранение некоторых данных, которые потребляют память в сгенерированном коде.

При понимании формата по умолчанию, в котором созданный код хранит внутренние данные, можно:

  • Сделать сигналы доступными и параметры настраиваемыми по умолчанию. Затем можно взаимодействовать с кодом и контролировать его во время выполнения.

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

  • Передача частей внутренних данных в интерфейс модели, чтобы другие компоненты и системы могли получить доступ к этим данным.

Сведения о том, как сгенерированный код обменивается данными с вызывающей средой через интерфейсы, см. в разделе Как сгенерированный код обменивается данными с средой.

Внутренние данные в сгенерированном коде

В этом примере показано, как созданный код хранит внутренние данные, такие как состояния блоков.

Изучение примера модели

Открыть пример модели rtwdemo_roll.

open_system('rtwdemo_roll')

Модель содержит внутренние сигналы, которые не подключаются к блокам корневого уровня Inport или Outport. Некоторые из сигналов имеют имя, например, phiCmd сигнал.

Модель также содержит некоторые блоки, поддерживающие данные о состоянии. Например, в BasicRollMode подсистема, блок интегратора дискретного времени с меткой Integrator поддерживает состояние.

В модели установите Параметры конфигурации > Создание кода > Целевой файл системы в значение grt.tlc.

set_param('rtwdemo_roll','SystemTargetFile','grt.tlc')

Проверьте настройки параметров конфигурации > Создание кода > Интерфейс > Упаковка интерфейса кода. Настройка Nonreusable function означает, что созданный код не является повторно используемым (повторно вводимым).

В этом примере создайте более простой код, очистив меню Параметры конфигурации > Создание кода > Интерфейс > Дополнительные параметры > Ведение журнала файла.

set_param('rtwdemo_roll','MatFileLogging','off')

Создание неиспользуемого кода

Установите следующие параметры конфигурации:

  • Задать поведение параметра по умолчанию как Tunable.

  • Очистить Повторное использование хранилища сигналов.

set_param('rtwdemo_roll','DefaultParameterBehavior','Tunable',...
    'OptimizeBlockIOStorage','off')

Создайте код из модели.

slbuild('rtwdemo_roll')
### Starting build procedure for: rtwdemo_roll
### Successful completion of build procedure for: rtwdemo_roll

Build Summary

Top model targets built:

Model         Action                       Rebuild Reason                                    
=============================================================================================
rtwdemo_roll  Code generated and compiled  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 10.748s

Файл rtwdemo_roll.h определяет несколько типов структуры, представляющих внутренние данные. Например, блочная структура ввода и вывода определяет одно поле для каждого внутреннего сигнала в модели. Каждое имя поля выводится из имени блока, который генерирует сигнал, или, если вы указываете имя для сигнала, из имени сигнала.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,...
    '/* Block signals (default storage) */','} B_rtwdemo_roll_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real32_T phiCmd;                     /* '<Root>/ModeSwitch' */
  real32_T hdgError;                   /* '<S2>/Sum' */
  real32_T DispGain;                   /* '<S2>/DispGain' */
  real32_T Product;                    /* '<S2>/Product' */
  real32_T Abs;                        /* '<S3>/Abs' */
  real32_T FixPtUnitDelay1;            /* '<S4>/FixPt Unit Delay1' */
  real32_T Xnew;                       /* '<S4>/Enable' */
  real32_T TKSwitch;                   /* '<S3>/TKSwitch' */
  real32_T RefSwitch;                  /* '<S3>/RefSwitch' */
  real32_T Integrator;                 /* '<S1>/Integrator' */
  real32_T DispLimit;                  /* '<S1>/DispLimit' */
  real32_T Sum;                        /* '<S1>/Sum' */
  real32_T DispGain_f;                 /* '<S1>/DispGain' */
  real32_T RateLimit;                  /* '<S1>/RateLimit' */
  real32_T Sum1;                       /* '<S1>/Sum1' */
  real32_T RateGain;                   /* '<S1>/RateGain' */
  real32_T Sum2;                       /* '<S1>/Sum2' */
  real32_T CmdLimit;                   /* '<S1>/CmdLimit' */
  real32_T IntGain;                    /* '<S1>/IntGain' */
  boolean_T NotEngaged;                /* '<S3>/NotEngaged' */
  boolean_T TKThreshold;               /* '<S3>/TKThreshold' */
  boolean_T RefThreshold2;             /* '<S3>/RefThreshold2' */
  boolean_T RefThreshold1;             /* '<S3>/RefThreshold1' */
  boolean_T Or;                        /* '<S3>/Or' */
  boolean_T NotEngaged_e;              /* '<S1>/NotEngaged' */
} B_rtwdemo_roll_T;

Файл определяет тип структуры, структуру DWork, для представления состояний блока, таких как состояние блока интегратора дискретного времени.

rtwdemodbtype(file,...
    '/* Block states (default storage) for system','} DW_rtwdemo_roll_T;',1,1)
/* Block states (default storage) for system '<Root>' */
typedef struct {
  real32_T FixPtUnitDelay1_DSTATE;     /* '<S4>/FixPt Unit Delay1' */
  real32_T Integrator_DSTATE;          /* '<S1>/Integrator' */
  int8_T Integrator_PrevResetState;    /* '<S1>/Integrator' */
} DW_rtwdemo_roll_T;

Файл определяет тип структуры для представления данных параметров. Каждый настраиваемый параметр блока в модели, например параметр усиления блока усиления, отображается как поле этой структуры. Если параметр блока получает свое значение от переменной MATLAB или Simulink.Parameter объект, переменная или объект отображаются как поле, а не как параметр блока.

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

rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
    '/* Block parameters (default storage) */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_rtwdemo_roll_T {
  const char_T *errorStatus;
};

Для типа структуры, представляющей структуру данных модели в реальном времени, файл rtwdemo_roll_types.h создает псевдоним, который впоследствии будет использоваться сгенерированным кодом для выделения памяти структуре.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll_types.h');
rtwdemodbtype(file,'/* Forward declaration for rtModel */',...
    'RT_MODEL_rtwdemo_roll_T;',1,1)
/* Forward declaration for rtModel */
typedef struct tag_RTM_rtwdemo_roll_T RT_MODEL_rtwdemo_roll_T;

Используя эти типы структуры, файл rtwdemo_roll.c определяет (выделяет память для) глобальные структурные переменные, которые хранят внутренние данные для сгенерированного алгоритма. Файл также определяет переменные, которые представляют структуру данных модели в реальном времени и указатель на структуру.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Block signals (default storage) */',...
    '= &rtwdemo_roll_M_;',1,1)
/* Block signals (default storage) */
B_rtwdemo_roll_T rtwdemo_roll_B;

/* Block states (default storage) */
DW_rtwdemo_roll_T rtwdemo_roll_DW;

/* External inputs (root inport signals with default storage) */
ExtU_rtwdemo_roll_T rtwdemo_roll_U;

/* External outputs (root outports fed by signals with default storage) */
ExtY_rtwdemo_roll_T rtwdemo_roll_Y;

/* Real-time model */
static RT_MODEL_rtwdemo_roll_T rtwdemo_roll_M_;
RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M = &rtwdemo_roll_M_;

Модель step функция, представляющая алгоритм первичной модели, использует void void интерфейс (без аргументов).

rtwdemodbtype(file,...
    '/* Model step function */','void rtwdemo_roll_step(void)',1,1)
/* Model step function */
void rtwdemo_roll_step(void)

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

rtwdemodbtype(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' *',...
    '/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* DiscreteIntegrator: '<S1>/Integrator' */
  if (rtwdemo_roll_B.NotEngaged_e || (rtwdemo_roll_DW.Integrator_PrevResetState
       != 0)) {
    rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;
  }

  if (rtwdemo_roll_DW.Integrator_DSTATE >= rtwdemo_roll_P.intLim) {
    rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.intLim;
  } else if (rtwdemo_roll_DW.Integrator_DSTATE <=
             rtwdemo_roll_P.Integrator_LowerSat) {
    rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.Integrator_LowerSat;
  }

  /* DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_B.Integrator = rtwdemo_roll_DW.Integrator_DSTATE;

  /* Saturate: '<S1>/DispLimit' */
  u0 = rtwdemo_roll_B.phiCmd;
  u1 = rtwdemo_roll_P.DispLimit_LowerSat;
  u2 = rtwdemo_roll_P.dispLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B.DispLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B.DispLimit = u1;
  } else {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B.DispLimit = u0;
  }

  /* End of Saturate: '<S1>/DispLimit' */

  /* Sum: '<S1>/Sum' incorporates:
   *  Inport: '<Root>/Phi'
   */
  rtwdemo_roll_B.Sum = rtwdemo_roll_B.DispLimit - rtwdemo_roll_U.Phi;

  /* Gain: '<S1>/DispGain' */
  rtwdemo_roll_B.DispGain_f = rtwdemo_roll_P.dispGain * rtwdemo_roll_B.Sum;

  /* Saturate: '<S1>/RateLimit' */
  u0 = rtwdemo_roll_B.DispGain_f;
  u1 = rtwdemo_roll_P.RateLimit_LowerSat;
  u2 = rtwdemo_roll_P.rateLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B.RateLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B.RateLimit = u1;
  } else {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B.RateLimit = u0;
  }

  /* End of Saturate: '<S1>/RateLimit' */

  /* Sum: '<S1>/Sum1' incorporates:
   *  Inport: '<Root>/Rate_FB'
   */
  rtwdemo_roll_B.Sum1 = rtwdemo_roll_B.RateLimit - rtwdemo_roll_U.Rate_FB;

  /* Gain: '<S1>/RateGain' */
  rtwdemo_roll_B.RateGain = rtwdemo_roll_P.rateGain * rtwdemo_roll_B.Sum1;

  /* Sum: '<S1>/Sum2' */
  rtwdemo_roll_B.Sum2 = rtwdemo_roll_B.Integrator + rtwdemo_roll_B.RateGain;

  /* Saturate: '<S1>/CmdLimit' */
  u0 = rtwdemo_roll_B.Sum2;
  u1 = rtwdemo_roll_P.CmdLimit_LowerSat;
  u2 = rtwdemo_roll_P.cmdLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B.CmdLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B.CmdLimit = u1;
  } else {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B.CmdLimit = u0;
  }

  /* End of Saturate: '<S1>/CmdLimit' */

  /* Gain: '<S1>/IntGain' */
  rtwdemo_roll_B.IntGain = rtwdemo_roll_P.intGain * rtwdemo_roll_B.Sum1;

  /* Update for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW.Integrator_DSTATE += rtwdemo_roll_P.Integrator_gainval *
    rtwdemo_roll_B.IntGain;
  if (rtwdemo_roll_DW.Integrator_DSTATE >= rtwdemo_roll_P.intLim) {
    rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.intLim;
  } else if (rtwdemo_roll_DW.Integrator_DSTATE <=
             rtwdemo_roll_P.Integrator_LowerSat) {
    rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.Integrator_LowerSat;
  }

  rtwdemo_roll_DW.Integrator_PrevResetState = (int8_T)
    rtwdemo_roll_B.NotEngaged_e;

  /* End of Update for DiscreteIntegrator: '<S1>/Integrator' */
  /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */

  /* Switch: '<Root>/EngSwitch' incorporates:
   *  Inport: '<Root>/AP_Eng'
   */
  if (rtwdemo_roll_U.AP_Eng) {
    /* Outport: '<Root>/Ail_Cmd' */
    rtwdemo_roll_Y.Ail_Cmd = rtwdemo_roll_B.CmdLimit;
  } else {
    /* Outport: '<Root>/Ail_Cmd' incorporates:
     *  Constant: '<Root>/Zero'
     */
    rtwdemo_roll_Y.Ail_Cmd = rtwdemo_roll_P.Zero_Value_c;
  }

  /* End of Switch: '<Root>/EngSwitch' */
}

/* Model initialize function */
void rtwdemo_roll_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(rtwdemo_roll_M, (NULL));

  /* block I/O */
  (void) memset(((void *) &rtwdemo_roll_B), 0,
                sizeof(B_rtwdemo_roll_T));

  /* states (dwork) */
  (void) memset((void *)&rtwdemo_roll_DW, 0,
                sizeof(DW_rtwdemo_roll_T));

  /* external inputs */
  (void)memset(&rtwdemo_roll_U, 0, sizeof(ExtU_rtwdemo_roll_T));

  /* external outputs */
  rtwdemo_roll_Y.Ail_Cmd = 0.0F;

  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  rtwdemo_roll_DW.FixPtUnitDelay1_DSTATE = rtwdemo_roll_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;
  rtwdemo_roll_DW.Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

/* Model terminate function */
void rtwdemo_roll_terminate(void)
{
  /* (no terminate code required) */
}

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

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

rtwdemodbtype(file,'/* Model initialize function */',...
    'sizeof(DW_rtwdemo_roll_T));',1,1)
/* Model initialize function */
void rtwdemo_roll_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(rtwdemo_roll_M, (NULL));

  /* block I/O */
  (void) memset(((void *) &rtwdemo_roll_B), 0,
                sizeof(B_rtwdemo_roll_T));

  /* states (dwork) */
  (void) memset((void *)&rtwdemo_roll_DW, 0,
                sizeof(DW_rtwdemo_roll_T));

Затем функция инициализирует состояния блока в структуре DWork до начальных значений, заданных параметрами блока в модели. Два из трех состояний в модели имеют настраиваемые начальные значения, поэтому код инициализирует их, считывая данные из структуры параметров.

rtwdemodbtype(file,...
    '/* SystemInitialize for Atomic SubSystem: ''<Root>/RollAngleReference'' */',...
    '/* Model terminate function */',1,0)
  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  rtwdemo_roll_DW.FixPtUnitDelay1_DSTATE = rtwdemo_roll_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW.Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;
  rtwdemo_roll_DW.Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

Создать повторно используемый код

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

В модели установите Параметры конфигурации > Создание кода > Интерфейс > Упаковка интерфейса кода в значение Reusable function.

set_param('rtwdemo_roll','CodeInterfacePackaging','Reusable function')

Создайте код из модели.

slbuild('rtwdemo_roll')
### Starting build procedure for: rtwdemo_roll
### Successful completion of build procedure for: rtwdemo_roll

Build Summary

Top model targets built:

Model         Action                       Rebuild Reason                   
============================================================================
rtwdemo_roll  Code generated and compiled  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 9.203s

Теперь, в rtwdemo_roll.hструктура данных модели в реальном времени содержит указатели на индикацию ошибки, внутренние данные и первичные входные и выходные данные в виде ExtU и ExtY подструктуры (поля которых представляют блоки Inport и Outport на корневом уровне модели).

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
    '/* External data declarations for dependent source files */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_rtwdemo_roll_T {
  const char_T *errorStatus;
  B_rtwdemo_roll_T *blockIO;
  ExtU_rtwdemo_roll_T *inputs;
  ExtY_rtwdemo_roll_T *outputs;
  DW_rtwdemo_roll_T *dwork;
};

/* Block parameters (default storage) */
extern P_rtwdemo_roll_T rtwdemo_roll_P;

Для многократного вызова сгенерированного кода в приложении код должен выделять память для структуры данных модели в реальном времени для каждого вызова. Файл rtwdemo_roll.c определяет специализированную функцию, которая выделяет память для новой структуры данных модели в реальном времени и возвращает указатель на структуру. Функция также распределяет память для подструктур, на которые указывают поля в структуре данных модели, таких как структура DWork.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Model data allocation function */',...
    'RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)',1,1)
/* Model data allocation function */
RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)

Модель step функция принимает аргумент, представляющий структуру данных модели в реальном времени.

rtwdemodbtype(file,'/* Model step function */','void rtwdemo_roll_step',1,1)
/* Model step function */
void rtwdemo_roll_step(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)

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

rtwdemodbtype(file,'*rtwdemo_roll_B =','rtwdemo_roll_M->outputs;',1,1)
  B_rtwdemo_roll_T *rtwdemo_roll_B = rtwdemo_roll_M->blockIO;
  DW_rtwdemo_roll_T *rtwdemo_roll_DW = rtwdemo_roll_M->dwork;
  ExtU_rtwdemo_roll_T *rtwdemo_roll_U = (ExtU_rtwdemo_roll_T *)
    rtwdemo_roll_M->inputs;
  ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *)
    rtwdemo_roll_M->outputs;

Затем для доступа к внутренним данным, хранящимся в глобальной памяти, алгоритм взаимодействует с этими локальными переменными.

rtwdemodbtype(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' */',...
    '/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* DiscreteIntegrator: '<S1>/Integrator' */
  if (rtwdemo_roll_B->NotEngaged_e ||
      (rtwdemo_roll_DW->Integrator_PrevResetState != 0)) {
    rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;
  }

  if (rtwdemo_roll_DW->Integrator_DSTATE >= rtwdemo_roll_P.intLim) {
    rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.intLim;
  } else if (rtwdemo_roll_DW->Integrator_DSTATE <=
             rtwdemo_roll_P.Integrator_LowerSat) {
    rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.Integrator_LowerSat;
  }

  /* DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_B->Integrator = rtwdemo_roll_DW->Integrator_DSTATE;

  /* Saturate: '<S1>/DispLimit' */
  u0 = rtwdemo_roll_B->phiCmd;
  u1 = rtwdemo_roll_P.DispLimit_LowerSat;
  u2 = rtwdemo_roll_P.dispLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B->DispLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B->DispLimit = u1;
  } else {
    /* Saturate: '<S1>/DispLimit' */
    rtwdemo_roll_B->DispLimit = u0;
  }

  /* End of Saturate: '<S1>/DispLimit' */

  /* Sum: '<S1>/Sum' incorporates:
   *  Inport: '<Root>/Phi'
   */
  rtwdemo_roll_B->Sum = rtwdemo_roll_B->DispLimit - rtwdemo_roll_U->Phi;

  /* Gain: '<S1>/DispGain' */
  rtwdemo_roll_B->DispGain_f = rtwdemo_roll_P.dispGain * rtwdemo_roll_B->Sum;

  /* Saturate: '<S1>/RateLimit' */
  u0 = rtwdemo_roll_B->DispGain_f;
  u1 = rtwdemo_roll_P.RateLimit_LowerSat;
  u2 = rtwdemo_roll_P.rateLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B->RateLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B->RateLimit = u1;
  } else {
    /* Saturate: '<S1>/RateLimit' */
    rtwdemo_roll_B->RateLimit = u0;
  }

  /* End of Saturate: '<S1>/RateLimit' */

  /* Sum: '<S1>/Sum1' incorporates:
   *  Inport: '<Root>/Rate_FB'
   */
  rtwdemo_roll_B->Sum1 = rtwdemo_roll_B->RateLimit - rtwdemo_roll_U->Rate_FB;

  /* Gain: '<S1>/RateGain' */
  rtwdemo_roll_B->RateGain = rtwdemo_roll_P.rateGain * rtwdemo_roll_B->Sum1;

  /* Sum: '<S1>/Sum2' */
  rtwdemo_roll_B->Sum2 = rtwdemo_roll_B->Integrator + rtwdemo_roll_B->RateGain;

  /* Saturate: '<S1>/CmdLimit' */
  u0 = rtwdemo_roll_B->Sum2;
  u1 = rtwdemo_roll_P.CmdLimit_LowerSat;
  u2 = rtwdemo_roll_P.cmdLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B->CmdLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B->CmdLimit = u1;
  } else {
    /* Saturate: '<S1>/CmdLimit' */
    rtwdemo_roll_B->CmdLimit = u0;
  }

  /* End of Saturate: '<S1>/CmdLimit' */

  /* Gain: '<S1>/IntGain' */
  rtwdemo_roll_B->IntGain = rtwdemo_roll_P.intGain * rtwdemo_roll_B->Sum1;

  /* Update for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW->Integrator_DSTATE += rtwdemo_roll_P.Integrator_gainval *
    rtwdemo_roll_B->IntGain;
  if (rtwdemo_roll_DW->Integrator_DSTATE >= rtwdemo_roll_P.intLim) {
    rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.intLim;
  } else if (rtwdemo_roll_DW->Integrator_DSTATE <=
             rtwdemo_roll_P.Integrator_LowerSat) {
    rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.Integrator_LowerSat;
  }

  rtwdemo_roll_DW->Integrator_PrevResetState = (int8_T)
    rtwdemo_roll_B->NotEngaged_e;

  /* End of Update for DiscreteIntegrator: '<S1>/Integrator' */
  /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */

  /* Switch: '<Root>/EngSwitch' incorporates:
   *  Inport: '<Root>/AP_Eng'
   */
  if (rtwdemo_roll_U->AP_Eng) {
    /* Outport: '<Root>/Ail_Cmd' */
    rtwdemo_roll_Y->Ail_Cmd = rtwdemo_roll_B->CmdLimit;
  } else {
    /* Outport: '<Root>/Ail_Cmd' incorporates:
     *  Constant: '<Root>/Zero'
     */
    rtwdemo_roll_Y->Ail_Cmd = rtwdemo_roll_P.Zero_Value_c;
  }

  /* End of Switch: '<Root>/EngSwitch' */
}

/* Model initialize function */
void rtwdemo_roll_initialize(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)
{
  DW_rtwdemo_roll_T *rtwdemo_roll_DW = rtwdemo_roll_M->dwork;

  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  rtwdemo_roll_DW->FixPtUnitDelay1_DSTATE = rtwdemo_roll_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;
  rtwdemo_roll_DW->Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

/* Model terminate function */
void rtwdemo_roll_terminate(RT_MODEL_rtwdemo_roll_T * rtwdemo_roll_M)
{
  /* model code */
  rt_FREE(rtwdemo_roll_M->blockIO);
  rt_FREE(rtwdemo_roll_M->inputs);
  rt_FREE(rtwdemo_roll_M->outputs);
  rt_FREE(rtwdemo_roll_M->dwork);
  rt_FREE(rtwdemo_roll_M);
}

/* Model data allocation function */
RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)
{
  RT_MODEL_rtwdemo_roll_T *rtwdemo_roll_M;
  rtwdemo_roll_M = (RT_MODEL_rtwdemo_roll_T *) malloc(sizeof
    (RT_MODEL_rtwdemo_roll_T));
  if (rtwdemo_roll_M == NULL) {
    return NULL;
  }

  (void) memset((char *)rtwdemo_roll_M, 0,
                sizeof(RT_MODEL_rtwdemo_roll_T));

  /* block I/O */
  {
    B_rtwdemo_roll_T *b = (B_rtwdemo_roll_T *) malloc(sizeof(B_rtwdemo_roll_T));
    rt_VALIDATE_MEMORY(rtwdemo_roll_M,b);
    rtwdemo_roll_M->blockIO = (b);
  }

  /* states (dwork) */
  {
    DW_rtwdemo_roll_T *dwork = (DW_rtwdemo_roll_T *) malloc(sizeof
      (DW_rtwdemo_roll_T));
    rt_VALIDATE_MEMORY(rtwdemo_roll_M,dwork);
    rtwdemo_roll_M->dwork = (dwork);
  }

  /* external inputs */
  {
    ExtU_rtwdemo_roll_T *rtwdemo_roll_U = (ExtU_rtwdemo_roll_T *) malloc(sizeof
      (ExtU_rtwdemo_roll_T));
    rt_VALIDATE_MEMORY(rtwdemo_roll_M,rtwdemo_roll_U);
    rtwdemo_roll_M->inputs = (((ExtU_rtwdemo_roll_T *) rtwdemo_roll_U));
  }

  /* external outputs */
  {
    ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *) malloc(sizeof
      (ExtY_rtwdemo_roll_T));
    rt_VALIDATE_MEMORY(rtwdemo_roll_M,rtwdemo_roll_Y);
    rtwdemo_roll_M->outputs = (rtwdemo_roll_Y);
  }

  {
    B_rtwdemo_roll_T *rtwdemo_roll_B = rtwdemo_roll_M->blockIO;
    DW_rtwdemo_roll_T *rtwdemo_roll_DW = rtwdemo_roll_M->dwork;
    ExtU_rtwdemo_roll_T *rtwdemo_roll_U = (ExtU_rtwdemo_roll_T *)
      rtwdemo_roll_M->inputs;
    ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *)
      rtwdemo_roll_M->outputs;

    /* block I/O */
    (void) memset(((void *) rtwdemo_roll_B), 0,
                  sizeof(B_rtwdemo_roll_T));

    /* states (dwork) */
    (void) memset((void *)rtwdemo_roll_DW, 0,
                  sizeof(DW_rtwdemo_roll_T));

    /* external inputs */
    (void)memset(rtwdemo_roll_U, 0, sizeof(ExtU_rtwdemo_roll_T));

    /* external outputs */
    rtwdemo_roll_Y->Ail_Cmd = 0.0F;
  }

  return rtwdemo_roll_M;
}

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

rtwdemodbtype(file,...
    '/* Model initialize function */','void rtwdemo_roll_initialize',1,1)
/* Model initialize function */
void rtwdemo_roll_initialize(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)

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

Устранение внутренних данных с помощью оптимизации генерации кода

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

set_param('rtwdemo_roll','DefaultParameterBehavior','Inlined',...
    'OptimizeBlockIOStorage','on',...
    'LocalBlockOutputs','on')

В этом примере для более простого кода задайте для параметра Code interface packaging значение Nonreusable function.

set_param('rtwdemo_roll','CodeInterfacePackaging','Nonreusable function')

Создайте код из модели.

slbuild('rtwdemo_roll')
### Starting build procedure for: rtwdemo_roll
### Successful completion of build procedure for: rtwdemo_roll

Build Summary

Top model targets built:

Model         Action                       Rebuild Reason                   
============================================================================
rtwdemo_roll  Code generated and compiled  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 8.078s

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

Оптимизации не удалось устранить хранилище для трех состояний блока, поэтому файл продолжает определять тип структуры DWork.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,...
    '/* Block states (default storage) for system','} DW_rtwdemo_roll_T;',1,1)
/* Block states (default storage) for system '<Root>' */
typedef struct {
  real32_T FixPtUnitDelay1_DSTATE;     /* '<S4>/FixPt Unit Delay1' */
  real32_T Integrator_DSTATE;          /* '<S1>/Integrator' */
  int8_T Integrator_PrevResetState;    /* '<S1>/Integrator' */
} DW_rtwdemo_roll_T;

Код, генерируемый для блока интегратора дискретного времени, теперь сохраняет данные о состоянии и выходные данные только в структуре DWork.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Update for DiscreteIntegrator: ''<S1>/Integrator''',...
    '/* End of Update for DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* Update for DiscreteIntegrator: '<S1>/Integrator' incorporates:
   *  Gain: '<S1>/IntGain'
   */
  rtwdemo_roll_DW.Integrator_DSTATE += 0.5F * rtb_TKSwitch * 0.025F;
  if (rtwdemo_roll_DW.Integrator_DSTATE >= 5.0F) {
    rtwdemo_roll_DW.Integrator_DSTATE = 5.0F;
  } else if (rtwdemo_roll_DW.Integrator_DSTATE <= -5.0F) {
    rtwdemo_roll_DW.Integrator_DSTATE = -5.0F;
  }

  rtwdemo_roll_DW.Integrator_PrevResetState = (int8_T)rtb_NotEngaged_f;

Оптимизации также исключили хранение параметров блока в модели. Например, в блоке интегратора дискретного времени верхний предел насыщения и нижний предел насыщения задаются равными intLim и -intLim. intLim является Simulink.Parameter объект, хранящий значение 5. В коде, сгенерированном для интегратора дискретного времени, эти параметры блока и intLim отображаются в виде встроенных буквенных чисел 5.0F и -5.0F.

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

Локальные переменные в сгенерированном коде

При выборе опции Оптимизация (Optimization) Параметры конфигурации (Configuration Parameters) > Включить вывод локального блока (Enable local block) генератор кода пытается создать более эффективный код, представляя внутренние сигналы как локальные переменные, а не поля глобальной структуры. Если память, потребляемая локальными переменными, рискует превысить пространство стека, доступное на целевом оборудовании, попробуйте указать максимальный размер стека, выбрав Параметры конфигурации > Максимальный размер стека (байт). Дополнительные сведения см. в разделе Максимальный размер стека (байт).

Появление контрольных точек в сгенерированном коде

Контрольная точка - это сигнал, который хранится в уникальной ячейке памяти. Сведения о включении тестовых точек в модель см. в разделе Настройка сигналов как тестовых точек.

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

Если у вас есть встроенный кодер ®:

  • Можно управлять представлением контрольных точек по умолчанию, задав параметры генерации кода для категории внутренних данных данных в редакторе сопоставления кодов (см. Настройка генерации кода по умолчанию для данных (встроенный кодер)).

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

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

Внешний вид переменных рабочей области в сгенерированном коде

Переменные рабочей области - это переменные, которые используются для задания значений параметров блока в модели. Переменные рабочей области включают числовые переменные MATLAB ® иSimulink.Parameter объекты, хранящиеся в рабочей области, например в базовой рабочей области, или в словаре данных.

Если для параметра Поведение по умолчанию (Default parameter behavior Tunableпо умолчанию переменные рабочей области отображаются в сгенерированном коде как настраиваемые поля структуры глобальных параметров. Если такая переменная используется для задания нескольких значений параметров блока, переменная отображается как одно поле структуры глобальных параметров. Код не создает несколько полей для представления параметров блока. Поэтому настройка значения поля во время выполнения кода изменяет математическое поведение модели так же, как настройка значения переменной MATLAB или объекта параметра во время моделирования.

При наличии встроенного кодера можно управлять представлением переменных рабочей области по умолчанию путем задания параметров генерации кода для категорий данных параметров в редакторе сопоставления кода (см. раздел Настройка генерации кода по умолчанию для данных (встроенный кодер)).

  • Категория Параметры модели (Model parameters) применяется к переменным, которые хранятся в рабочем пространстве модели.

  • Категория Внешние параметры применяется к переменным, которые хранятся в базовой рабочей области или словаре данных.

Передача внутренних данных в интерфейс

По умолчанию генератор кода предполагает, что другие системы и компоненты приложения не нуждаются в доступе к внутренним данным. Например, внутренние данные подвергаются оптимизации, которая может исключить их из сгенерированного кода. Для создания прототипов и тестирования можно получить доступ к внутренним данным, очистив их или настроив контрольные точки и применив классы хранения (см. раздел Сохранение переменных в сгенерированном коде). Для оптимизированного производственного кода настройте отдельные элементы данных для отображения в создаваемом коде как части интерфейса модели.

Данные, которые можно продвигать

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

  • Глобальный символ, например, глобальная переменная или вызов специализированной функции

  • Формальный параметр (аргумент) созданных функций точки входа

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

Категория данныхПоказать как глобальный символОтображение в качестве аргумента функции точки входа
Блок ввода или вывода корневого уровняТолько для неназначенной модели.Да.
Сигнал, соединяющий два блокаТолько для неназначенной модели.

Только для исходной модели и только как поле структуры.

Либо подключите сигнал к выходному блоку корневого уровня.

Состояние блокаТолько для неназначенной модели.Только для исходной модели и только как поле структуры.
Хранилище данных, например блок памяти хранилища данныхДа.Только для исходной модели и только как поле структуры.
Параметр блока или объект параметра, например Simulink.ParameterДа.Только как поле структуры.

Одинарный алгоритм

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

Классы хранения можно применять к сигналам, состояниям блоков и параметрам блоков. (Для параметров блоков классы хранения применяются косвенно через такие объекты параметров, как Simulink.Parameter). Однако для сигнала рассмотрите возможность подключения сигнала к блоку Outport на корневом уровне модели. Затем, при необходимости, можно применить класс хранения к блоку. На блок-схеме блок Outport показывает, что сигнал представляет собой выходной сигнал системы.

Дополнительные сведения о классах хранения см. в разделе Конфигурация генерации кода C для элементов интерфейса модели.

Алгоритм повторного ввода

Для алгоритма повторного ввода (для пакета интерфейса кода устанавливается значение Reusable function), используйте различные методы для настройки элементов данных для отображения в коде в качестве формальных параметров (аргументов) сгенерированных функций точки входа.

  • Для внутреннего сигнала непосредственно примените класс хранения Model default (см. Конфигурация генерации кода C для элементов интерфейса модели). Если установлен встроенный кодер, в редакторе сопоставления кодов для категории «Внутренние данные» задайте класс хранения по умолчанию Default или к классу структурированного хранилища, который определяется в словаре встроенного кодера (см. раздел Создание определений кода для использования в редакторе сопоставлений кода (Embedded Coder)). Либо сконфигурируйте сигнал как тестовую точку (см. Внешний вид тестовых точек в сгенерированном коде). По умолчанию сигнал отображается как поле одной из стандартных структур данных (см. раздел Как сгенерированный код хранит внутренний сигнал, состояние и данные параметров). Если вы не хотите, чтобы сигнал отображался в производственном коде, используйте тестовую точку, чтобы впоследствии можно было выбрать параметр конфигурации модели Ignore test point signals.

    Либо подключите сигнал к блоку Outport на корневом уровне модели. Подключение сигнала к корневому блоку Outport предотвращает исключение сигнала из кода при оптимизации. Для упрощения маршрутизации сигналов в большой модели используйте блоки Перейти к (Goto) и Из (From).

  • Для параметра блока создайте объект параметра, например Simulink.Parameter и непосредственно применять класс хранения, отличный от Auto к объекту. Класс хранения не позволяет оптимизациям встроить значение параметра в код.

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

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

Управление представлением внутренних данных по умолчанию (встроенный кодер)

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

Управление размещением данных в памяти путем вставки прагматиков

Используйте редактор отображения кода, чтобы указать раздел памяти по умолчанию для каждой категории данных, таких как состояния и сигналы (внутренние данные). В созданном коде пользовательские прагматики или другие украшения окружают определения и объявления данных.

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

Дополнительные сведения см. в разделе Управление данными и размещением функций в памяти путем вставки прагматиков (встроенный кодер).

Управляющие имена типов, полей и глобальных переменных для стандартных структур данных

Можно управлять некоторыми признаками стандартных структур данных. Дополнительные сведения см. в разделе Имена типов управляющих данных в сгенерированном коде (встроенный кодер).

Для дополнительного управления характеристиками структуры, такими как размещение в созданных файлах кода, создайте собственный структурированный класс хранения с помощью словаря Embedded Coder. Затем примените класс хранения к категориям данных с помощью редактора сопоставления кодов. Класс хранения удаляет данные из стандартных структур, создавая другие структуры, которые можно более точно контролировать. Дополнительные сведения о применении классов хранения по умолчанию к категориям данных см. в разделе Настройка генерации кода по умолчанию для данных (встроенный кодер). Дополнительные сведения о создании класса хранения см. в разделе Определение классов хранения, разделов памяти и шаблонов функций для архитектуры программного обеспечения (Embedded Coder).

Организация данных в структуры в соответствии с подкомпонентами

  • В стандартных структурах данных для создания подструктур, содержащих данные для одинарной (непереходной) подпрограммы или подкомпонента, используйте атомарную подсистему для инкапсуляции соответствующих блоков. В параметрах подсистемы установите для параметра Function packaging значение Reusable function. Дополнительные сведения см. в разделе Создание кода модульной функции для невиртуальных подсистем (встроенный кодер).

    Можно также инкапсулировать блоки в модель и использовать блок модели. В ссылочной модели задайте для параметра «Параметры конфигурации» > «Ссылка на модель» > «Общее число экземпляров, разрешенных для каждой модели верхнего уровня» значение Multiple. Дополнительные сведения см. в разделе Создание кода для иерархии ссылок на модель.

  • Для создания в модели отдельных автономных структур, содержащих данные для многоинстанционной (реэнтрантной) подпрограммы или подкомпонента, используйте атомарную подсистему для инкапсуляции соответствующих блоков. В параметрах подсистемы установите для параметра Function packaging значение Nonreusable function и выберите Function с отдельными данными. Дополнительные сведения см. в разделе Создание кода модульной функции для невиртуальных подсистем (встроенный кодер).

    Можно также инкапсулировать блоки в модель и использовать блок модели. В ссылочной модели выберите один из следующих методов:

Упорядочить данные сигналов и параметров по значимым, пользовательским структурам и подструктурам

Для организации произвольных сигналов и параметров в пользовательские структуры и подструктуры создайте невиртуальные сигналы шины и структуры параметров. Дополнительно, чтобы предотвратить исключение данных из кода при оптимизации, задайте для класса хранения сигнала шины или структуры параметров значение, отличное от Auto (настройка по умолчанию).

При добавлении блоков в модель необходимо явно поместить каждый новый сигнал и параметр в шину или структуру.

Дополнительные сведения см. в разделе Организация данных в структуры в сгенерированном коде.

Создание отдельных глобальных переменных вместо полей структуры

Чтобы категория внутренних данных отображалась в созданном коде как отдельные неструктурированные глобальные переменные вместо полей стандартной структуры данных, примените класс неструктурированного хранения к категории данных с помощью редактора сопоставления кодов. Например, примените класс хранения ExportedGlobal. Однако при создании многоэкземплярного кода повторно введите код, установив для параметра конфигурации Code interface packaging значение, отличное от Nonreusable function, этот метод нельзя использовать для некоторых категорий данных (см. Классы хранения и повторный ввод, многоэкземплярные модели и компоненты).

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

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