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

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

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

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

  • A параметров блоков, такой как параметр Gain блока Gain, значение которого генератор кода не может встроить в код. Для примера генератор кода не может входить в значение нескалярного параметра.

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

Для более эффективного кода можно сконфигурировать такие оптимизации, как Configuration Parameters > Default parameter behavior и Configuration Parameters > Signal storage reuse, которые пытаются исключить хранилище для внутренних данных. Однако оптимизация не может устранить хранилище для некоторых данных, которые используют память в сгенерированном коде.

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

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

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

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

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

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

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

Исследуйте модель примера

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

open_system('rtwdemo_roll')

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

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

В модели установите параметры конфигурации > Генерация кода > Системный целевой файл grt.tlc.

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

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

В данном примере сгенерируйте более простой код путем очистки Configuration Parameters > Code Generation > Interface > Advanced parameters > Mat-file logging.

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 задает несколько типов структур, которые представляют внутренние данные. Для примера, блок входа и структуры output задает одно поле для каждого внутреннего сигнала в модели. Каждое имя поля происходит от имени блока, который генерирует сигнал или, если вы задаете имя для сигнала, от имени сигнала.

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;

Файл задает тип структуры, чтобы представлять данные параметра. Каждый настраиваемые параметры блоков в модели, такой как параметр Gain блока Gain, появляются как поле этой структуры. Если параметры блоков получают свое значение от Переменного 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 на 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;

Код, сгенерированный для блока Дискретного времени Integrator, теперь хранит состояние и выходные данные только в структуре 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 определитель типа склада, поэтому некоторые цепочки инструментов сборки могут оптимизировать код сборки далее.

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

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

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

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

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

Если у вас есть Embedded Coder®:

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

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

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

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

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

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

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

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

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

Продвижение внутренних данных к интерфейсу

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

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

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

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

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

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

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

Только для повторяющейся модели и только как поля структуры.

Кроме того, соедините сигнал с блоком Outport корневого уровня.

Состояние блокаТолько для нерецентной модели.Только для повторяющейся модели и только как поля структуры.
Хранилище данных, такое как блок Data Store MemoryДа.Только для повторяющейся модели и только как поля структуры.
Параметры блоков или объекта параметра, такого как Simulink.ParameterДа.Только как поле структуры.

Алгоритм с одним экземпляром

Для алгоритма с одним экземпляром (вы устанавливаете Code interface packaging равным Nonreusable function), применить классы памяти непосредственно к отдельным элементам данных с помощью Model Data Editor или Property Inspector. С непосредственно примененным классом памяти элемент данных появляется в коде как глобальный символ, такой как глобальная переменная. Класс памяти также препятствует тому, чтобы оптимизация исключала устройство хранения данных для элемента данных.

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

Для получения дополнительной информации о классах хранения смотрите Строение Генерации кода C для Элементов Интерфейса Модели.

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

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

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

    Кроме того, соедините сигнал с блоком Outport на корневом уровне модели. Подключение сигнала к блоку Outport корневого уровня препятствует оптимизации удаления сигнала из кода. Чтобы помочь с маршрутизацией сигнала в большой модели, используйте Goto и From блоки.

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

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

    Для получения информации о применении классов памяти смотрите Строение Генерации кода C для Элементов Интерфейса Модели.

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

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

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

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

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

Для получения дополнительной информации смотрите Control Data and Function Placement in Memory by Inserting Pragmas (Embedded Coder).

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

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

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

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

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

    Кроме того, инкапсулируйте блоки в модель и используйте блок Model. В модели-ссылке задайте Configuration Parameters > Model Referencing > Total number of instances allowed per top model Multiple. Для получения дополнительной информации смотрите Сгенерировать код для иерархии Модели-ссылки.

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

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

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

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

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

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

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

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

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

Похожие темы