生成的代码如何存储内部信号、状态和参数数据
为了计算输入的输出,生成的代码存储一些内部数据在全局内存中。不连接到根级输入或输出的信号(轮廓尺寸或外港块)是内部数据。
内部数据还可以包括:
的状态单位延迟块。算法必须在执行周期之间保留状态值,因此生成的代码通常将状态存储在全局内存中(例如,作为全局变量或全局结构变量的字段)。
块参数,如获得a的参数获得块,代码生成器不能将其值内联到代码中。例如,代码生成器不能内联非标量参数的值。
有条件执行的子系统的状态指示器,例如已启用的子系统。
要获得更高效的代码,可以配置如下优化配置参数>默认参数行为和配置参数>信号存储重用试图消除内部数据的存储。但是,优化不能消除某些数据的存储,这些数据会消耗生成代码中的内存。
当您了解生成的代码存储内部数据的默认格式时,您可以:
默认情况下使信号可访问和参数可调。然后,您可以在执行期间与代码交互并监视代码。
通过消除内部数据的存储,并根据您的硬件和构建工具链,控制优化无法消除的数据在内存中的位置,从而生成高效的产品代码。
将内部数据片段提升到模型接口,以便其他组件和系统可以访问该数据。
有关生成的代码如何通过接口与调用环境交换数据的信息,请参见生成的代码如何与环境交换数据。
生成代码中的内部数据
这个例子展示了生成的代码如何存储内部数据,比如块状态。
探索示例模型
打开示例模型rtwdemo_roll
。
open_system (“rtwdemo_roll”)
该模型包含不连接到根级import或Outport块的内部信号。有些信号有一个名称,比如phiCmd
信号。
该模型还包含一些维护状态数据的块。例如,在BasicRollMode
子系统,一个离散时间积分器块标记积分器
维护状态。
在模型中,设置>代码生成>系统目标文件来grt.tlc
。
set_param (“rtwdemo_roll”,“SystemTargetFile”,“grt.tlc”)
检查以下设置配置参数>代码生成>接口>代码接口封装。设置那种一次性的功能
意味着生成的代码不可重用(可重入)。
对于本例,通过清除生成更简单的代码配置参数>代码生成>接口>高级参数>文件日志。
set_param (“rtwdemo_roll”,“MatFileLogging”,“关闭”)
生成不可重用的代码
设置这些配置参数:
集默认参数行为来
可调
。清晰的信号存储重用。
set_param (“rtwdemo_roll”,“DefaultParameterBehavior”,可调的,…“OptimizeBlockIOStorage”,“关闭”)
从模型生成代码。
rtwbuild (“rtwdemo_roll”)
###启动模型的构建过程:rtwdemo_roll ###成功完成模型的构建过程:rtwdemo_roll
该文件rtwdemo_roll.h
定义几个表示内部数据的结构类型。例如,块输入和输出结构为模型中的每个内部信号定义一个字段。每个字段名来自生成信号的块的名称,或者,如果您为信号指定了一个名称,则来自信号的名称。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.h”);rtwdemodbtype(文件,…'/*阻塞信号(默认存储)*/',“}B_rtwdemo_roll_T;”, 1, 1)
/* Block信号(默认存储)*/ typedef struct {real32_T phiCmd;/* '/ModeSwitch' */ real32_T Abs;/* ' /Abs' */ real32_T FixPtUnitDelay1;/* ' /FixPt单元延迟' */ real32_T Xnew;/* ' /Enable' */ real32_T TKSwitch;/* ' /TKSwitch' */ real32_T RefSwitch;/* ' /RefSwitch' */ real32_T Integrator;/* ' /Integrator' */ real32_T displlimit;/* ' /DispLimit' */ real32_T Sum;/* ' /Sum' */ real32_T disgain; /* ' /DispGain' */ real32_T RateLimit; /* ' /RateLimit' */ real32_T Sum1; /* ' /Sum1' */ real32_T RateGain; /* ' /RateGain' */ real32_T Sum2; /* ' /Sum2' */ real32_T CmdLimit; /* ' /CmdLimit' */ real32_T IntGain; /* ' /IntGain' */ real32_T hdgError; /* ' /Sum' */ real32_T DispGain_a; /* ' /DispGain' */ real32_T Product; /* ' /Product' */ boolean_T NotEngaged; /* ' /NotEngaged' */ boolean_T TKThreshold; /* ' /TKThreshold' */ boolean_T RefThreshold2; /* ' /RefThreshold2' */ boolean_T RefThreshold1; /* ' /RefThreshold1' */ boolean_T Or; /* ' /Or' */ boolean_T NotEngaged_e; /* ' /NotEngaged' */ } B_rtwdemo_roll_T;
该文件定义了一个结构类型,DWork结构,来表示块状态,例如离散时间积分器块的状态。
rtwdemodbtype(文件,…'/*系统的块状态(默认存储)',“}DW_rtwdemo_roll_T;”, 1, 1)
/*块状态(默认存储)系统'' */ typedef struct {real32_T FixPtUnitDelay1_DSTATE;/* ' /FixPt Unit Delay1' */ real32_T Integrator_DSTATE;/* ' /Integrator' */ int8_T integrator_preresetstate;/* ' /Integrator' */} DW_rtwdemo_roll_T;
该文件定义了一个结构类型来表示参数数据。模型中的每个可调块参数,例如获得参数,显示为该结构的字段。如果块参数从MATLAB变量或万博1manbetx仿真软件。参数
对象时,变量或对象显示为字段,而不是块参数。
该文件还定义了一个结构类型实时模型数据结构,其单个字段表示生成的代码在执行期间是否遇到错误的运行时指示。
rtwdemodbtype(文件,'/*实时模型数据结构*/',…'/*阻塞参数(默认存储)*/', 1,0)
/*实时模型数据结构*/ 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(文件,'/* rtModel的正向声明*/',…“RT_MODEL_rtwdemo_roll_T;”, 1, 1)
/ / typepedef struct tag_RTM_rtwdemo_roll_T RT_MODEL_rtwdemo_roll_T;
使用这些结构类型,文件rtwdemo_roll.c
定义(为其分配内存)存储生成算法的内部数据的全局结构变量。该文件还定义了表示实时模型数据结构的变量和指向该结构的指针。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.c”);rtwdemodbtype(文件,'/*阻塞信号(默认存储)*/',…“= &rtwdemo_roll_M_;”, 1, 1)
/*阻塞信号(默认存储)*/ B_rtwdemo_roll_T rtwdemo_roll_B;/*块状态(默认存储)*/ DW_rtwdemo_roll_T rtwdemo_roll_DW;/*外部输入(根输入信号默认存储)*/ ExtU_rtwdemo_roll_T rtwdemo_roll_U;/*外部输出(根输出由默认存储的信号提供)*/ ExtY_rtwdemo_roll_T rtwdemo_roll_Y;/*实时模型*/ RT_MODEL_rtwdemo_roll_T rtwdemo_roll_M_;RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M = &rtwdemo_roll_M_;
该模型一步
函数,它表示主要的模型算法,使用空白空白
接口(不带参数)。
rtwdemodbtype(文件,…'/*模型阶跃函数*/',“空白rtwdemo_roll_step(空白), 1, 1)
/*模型步进函数*/ void rtwdemo_roll_step(void)
在函数定义中,算法通过直接访问全局变量来执行计算并将中间结果存储在信号和状态结构中。该算法还从相应的全局变量中读取参数数据。例如,在BasicRollMode
子系统,生成的代码为积分器
块从结构中读写信号、状态和参数数据。
rtwdemodbtype(文件,'/* DiscreteIntegrator: "/Integrator " *' ,…'/*离散积分器结束:"/积分器" */' , 1, 1)
/*离散集成商:'/集成商' */ if (rtwdemo_roll_B。NotEngaged_e || (rtwdemo_roll_DW。积分器_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; } } rtwdemo_roll_B.Integrator = rtwdemo_roll_DW.Integrator_DSTATE;
由于空白空白
接口和数据直接访问,函数不可重入。如果在应用程序中多次调用该函数,则每次调用都将数据写入全局结构变量,随后的调用可以读取该数据,从而导致调用之间的无意干扰。
模型初始化函数rtwdemo_roll_initialize
将所有内部数据初始化为零。该函数还通过调用专门的宏函数来初始化错误状态。初始化函数直接访问全局变量,这意味着该函数不可重入。
rtwdemodbtype(文件,'/*模型初始化函数*/',…”sizeof (DW_rtwdemo_roll_T)),“, 1, 1)
/*模型初始化函数*/ void rtwdemo_roll_initialize(void){/*注册码*/ /*初始化错误状态*/ 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(文件,…'/* SystemInitialize for Atomic SubSystem: "/ rollanglerreference " */' ,…'/*模型终止函数*/', 1,0)
/* SystemInitialize for Atomic SubSystem: '/RollAngleReference' */ /* initializconditions for UnitDelay: ' /FixPt Unit Delay1' */ rtwdemo_roll_DW。FixPtUnitDelay1_DSTATE = rtwdemo_roll_P.LatchPhi_vinit;/* SystemInitialize for SubSystem: ' /RollAngleReference' */ /* SystemInitialize for Atomic SubSystem: ' /BasicRollMode' */ /* initializconditions for DiscreteIntegrator: ' /Integrator' */ rtwdemo_roll_DW. /Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC;rtwdemo_roll_DW。积分器_PrevResetState = 0; /* End of SystemInitialize for SubSystem: ' /BasicRollMode' */ }
生成可重用代码
您可以将生成的代码配置为可重入的,这意味着您可以在应用程序中多次调用入口点函数。通过这种配置,入口点函数不是直接访问全局变量,而是通过形式形参(指针参数)接受内部数据。使用这些指针参数,每个调用都可以在一组单独的全局变量中维护内部数据,从而防止调用之间的意外交互。
在模型中,设置配置参数>代码生成>接口>代码接口封装来可重用的功能
。
set_param (“rtwdemo_roll”,“CodeInterfacePackaging”,“可重用函数”)
从模型生成代码。
rtwbuild (“rtwdemo_roll”)
###启动模型的构建过程:rtwdemo_roll ###成功完成模型的构建过程:rtwdemo_roll
现在,在rtwdemo_roll.h
,实时模型数据结构包含指向错误指示的指针、内部数据以及以形式表示的主要输入输出数据ExtU
和ExtY
子结构(其字段表示模型根级的Inport和Outport块)。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.h”);rtwdemodbtype(文件,'/*实时模型数据结构*/',…'/*依赖源文件的外部数据声明*/', 1,0)
/*实时模型数据结构*/ struct tag_RTM_rtwdemo_roll_T {const char_T *errorStatus;B_rtwdemo_roll_T * blockIO;P_rtwdemo_roll_T * defaultParam;ExtU_rtwdemo_roll_T *输入;ExtY_rtwdemo_roll_T *输出;boolean_T paramIsMalloced;DW_rtwdemo_roll_T * dwork;};
要在应用程序中多次调用生成的代码,您的代码必须为每次调用分配实时模型数据结构的内存。该文件rtwdemo_roll.c
定义一个专门的函数,该函数为新的实时模型数据结构分配内存并返回指向该结构的指针。该函数还为模型数据结构中的字段所指向的子结构分配内存,比如DWork结构。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.c”);rtwdemodbtype(文件,'/*模型数据分配函数*/',…“RT_MODEL_rtwdemo_roll_T * rtwdemo_roll(空白), 1, 1)
/*模型数据分配函数*/ RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)
该模型一步
函数接受表示实时模型数据结构的参数。
rtwdemodbtype(文件,'/*模型阶跃函数*/',“空白rtwdemo_roll_step”, 1, 1)
/*模型步进函数*/ void rtwdemo_roll_step(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)
在函数定义中,算法首先将实时模型数据结构中的每个指针提取到一个局部变量中。
rtwdemodbtype(文件,‘* rtwdemo_roll_P_e = ',“rtwdemo_roll_M - >输出;”, 1, 1)
P_rtwdemo_roll_T *rtwdemo_roll_P_e = ((P_rtwdemo_roll_T *) rtwdemo_roll_M->defaultParam);B_rtwdemo_roll_T *rtwdemo_roll_B = ((B_rtwdemo_roll_T *) rtwdemo_roll_M->blockIO);DW_rtwdemo_roll_T *rtwdemo_roll_DW = ((DW_rtwdemo_roll_T *) rtwdemo_roll_M->dwork);ExtU_rtwdemo_roll_T *rtwdemo_roll_U = (ExtU_rtwdemo_roll_T *) rtwdemo_roll_M->输入;ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *) rtwdemo_roll_M->输出;
然后,为了访问存储在全局内存中的内部数据,算法与这些局部变量交互。
rtwdemodbtype(文件,'/* DiscreteIntegrator: "/Integrator " */' ,…'/*离散积分器结束:"/积分器" */' , 1, 1)
/* DiscreteIntegrator: '/Integrator' */ if (rtwdemo_roll_B->NotEngaged_e || (rtwdemo_roll_DW-> integrator_preresetstate != 0)) {rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P_e->Integrator_IC;} if (rtwdemo_roll_DW->Integrator_DSTATE >= rtwdemo_roll_DW-> intLim) {rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P_e->intLim;} else {if (rtwdemo_roll_DW->Integrator_DSTATE <= rtwdemo_roll_P_e->Integrator_LowerSat) {rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P_e->Integrator_LowerSat;}} rtwdemo_roll_B->Integrator = rtwdemo_roll_DW->Integrator_DSTATE;
类似地,模型初始化函数接受实时模型数据结构作为参数。
rtwdemodbtype(文件,…'/*模型初始化函数*/',“空白rtwdemo_roll_initialize”, 1, 1)
/*模型初始化函数*/ void rtwdemo_roll_initialize(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)
由于对入口点函数的每次调用都与单独的实时模型数据结构进行交互,因此可以避免调用之间的意外交互。
通过代码生成优化消除内部数据
要获得消耗更少内存的更高效的代码,请选择优化,例如默认参数行为你之前清理过的。
set_param (“rtwdemo_roll”,“DefaultParameterBehavior”,“内联”,…“OptimizeBlockIOStorage”,“上”,…“LocalBlockOutputs”,“上”)
在本例中,对于更简单的代码,设置代码接口封装来那种一次性的功能
。
set_param (“rtwdemo_roll”,“CodeInterfacePackaging”,“那种一次性函数”)
从模型生成代码。
rtwbuild (“rtwdemo_roll”)
###启动模型的构建过程:rtwdemo_roll ###成功完成模型的构建过程:rtwdemo_roll
现在,rtwdemo_roll.h
没有定义块输入和输出的结构。对于模型中的所有内部信号,优化要么消除了存储,要么创建了局部函数变量,而不是全局结构字段。
优化无法消除三种块状态的存储,因此文件继续定义DWork结构类型。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.h”);rtwdemodbtype(文件,…'/*系统的块状态(默认存储)',“}DW_rtwdemo_roll_T;”, 1, 1)
/*块状态(默认存储)系统'' */ typedef struct {real32_T FixPtUnitDelay1_DSTATE;/* ' /FixPt Unit Delay1' */ real32_T Integrator_DSTATE;/* ' /Integrator' */ int8_T integrator_preresetstate;/* ' /Integrator' */} DW_rtwdemo_roll_T;
为离散时间积分器块生成的代码现在只在DWork结构中存储状态和输出数据。
File = fullfile(“rtwdemo_roll_grt_rtw”,“rtwdemo_roll.c”);rtwdemodbtype(文件,'/* Update for DiscreteIntegrator: '/Integrator'' ,…'/*离散集成器更新结束:"/集成器" */' , 1, 1)
/*更新:'/Integrator'合并:*增益:' /IntGain' */ rtwdemo_roll_DW。Integrator_DSTATE += 0.5F * rtb_TKSwitch * 0.025F;如果(rtwdemo_roll_DW。积分器_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
是一个万博1manbetx仿真软件。参数
对象,该对象存储值5
。在为离散时间积分器生成的代码中,这些块参数和intLim
显示为内联文字数字5.0度
和-5.0度
。
如果模型包含代码生成器不能直接内联的参数(例如,数组参数),则代码将定义表示该数据的结构类型。这常数参数结构使用常量
存储类型限定符,因此某些构建工具链可以进一步优化汇编代码。
生成代码中的局部变量
当你选择优化配置参数>启用本地块输出,代码生成器试图通过将内部信号表示为局部变量而不是全局结构的字段来生成更高效的代码。如果本地变量消耗的内存可能超过目标硬件上可用的堆栈空间,请考虑通过设置来指示最大堆栈大小配置参数>最大堆栈大小(字节)。有关更多信息,请参见最大堆栈大小(字节)。
生成代码中测试点的外观
一个测试点是存储在唯一内存位置的信号。有关在模型中包括测试点的信息,请参见测试点(万博1manbetx模型)。
当您为包含测试点的模型生成代码时,构建过程为每个测试点分配一个单独的内存缓冲区。默认情况下,测试点被存储为适当的标准数据结构的成员,例如
。模型
_B
如果你有嵌入式编码器®:
您可以通过指定代码生成设置来控制测试点的默认表示内部数据在“代码映射编辑器”中设置数据的类别(参见为数据配置默认代码生成(嵌入式编码器))。
您可以指定构建过程忽略模型中的测试点,从而允许最佳的缓冲区分配忽略测试点信号参数。忽略测试点有助于从原型到部署的过渡,并避免由于工作流工件而导致的生成代码的意外降级。看到忽略测试点信号。
虚拟总线不会出现在生成的代码中,即使在与测试点相关联时也是如此。若要在生成的代码中显示总线,请使用非虚拟总线或由信号转换块。
生成代码中工作空间变量的外观
工作空间变量是用于在模型中指定块参数值的变量。工作空间变量包括MATLAB数值®变量和万博1manbetx仿真软件。参数
存储在工作空间(如基本工作空间)或数据字典中的对象。
当你设定默认参数行为来可调
默认情况下,工作空间变量作为全局参数结构的可调字段出现在生成的代码中。如果您使用这样的变量来指定多个块参数值,则该变量将显示为全局参数结构的单个字段。代码没有创建多个字段来表示块参数。因此,在代码执行期间调整字段值会改变模型的数学行为,就像在仿真期间调整MATLAB变量或参数对象的值一样。
如果您有嵌入式编码器,您可以通过在代码映射编辑器中为参数数据的类别指定代码生成设置来控制工作空间变量的默认表示(参见为数据配置默认代码生成(嵌入式编码器))。
的本地参数类别适用于您存储在模型工作区中的变量。
的全局参数类别适用于存储在基本工作空间或数据字典中的变量。
将内部数据提升到接口
默认情况下,代码生成器假定应用程序中的其他系统和组件不需要访问内部数据。例如,内部数据需要经过优化才能从生成的代码中消除它们。对于原型和测试目的,您可以通过清除优化或配置测试点和应用存储类来访问内部数据(参见为快速原型配置数据可访问性).对于优化的产品代码,配置单个数据项,使其作为模型接口的一部分出现在生成的代码中。
你可以推广的数据
取决于所生成代码的可重入性,也就是您所选择的设置代码接口封装,您可以配置模型中的每个数据项,通过在代码中显示为以下实体之一来参与接口:
一种全局符号,如全局变量或对专用函数的调用
生成的入口点函数的形式参数(参数)
该表显示了每一类数据可用于参与接口的机制。
数据类别 | 显示为全局符号 | 作为入口点函数的参数出现 |
---|---|---|
根级轮廓尺寸或外港块 | 仅适用于不可重入模型。 | 是的。 |
连接两个模块的信号 | 仅适用于不可重入模型。 | 仅用于可重入模型,并且仅作为结构的字段。 或者,将信号连接到根级外港块。 |
阻塞状态 | 仅适用于不可重入模型。 | 仅用于可重入模型,并且仅作为结构的字段。 |
数据存储,如a数据存储内存块 | 是的。 | 仅用于可重入模型,并且仅作为结构的字段。 |
块参数或参数对象,如万博1manbetx仿真软件。参数 |
是的。 | 只作为一个结构的场。 |
单实例算法
对于单实例算法(您设置代码接口封装来那种一次性的功能
),通过使用模型数据编辑器或属性检查器将存储类直接应用于单个数据项。使用直接应用的存储类,数据项在代码中显示为全局符号,如全局变量。存储类还可以防止优化消除数据项的存储。
您可以将存储类应用于信号、块状态和块参数。(对于块参数,您可以通过参数对象间接应用存储类,例如万博1manbetx仿真软件。参数
).然而,对于一个信号,考虑将信号连接到一个外港块在模型的根级。然后,您可以选择将存储类应用于块。在框图中,外港块表示该信号代表系统输出。
有关存储类的详细信息,请参见将存储类应用于单个信号、状态和参数数据元素。
可重入算法
对于可重入算法(您设置代码接口封装来可重用的功能
),使用不同的技术配置数据项,使其作为生成的入口点函数的形式参数(参数)出现在代码中。
对于内部信号,直接应用存储类
模型的默认
(见将存储类应用于单个信号、状态和参数数据元素).如果你有嵌入式编码器®,在代码映射编辑器中内部数据类别时,将默认存储类设置为默认的
或到您在嵌入式编码器字典中定义的结构化存储类(参见创建用于默认代码生成设置的代码定义(嵌入式编码器))。或者,将信号配置为测试点(参见生成代码中测试点的外观).默认情况下,信号显示为标准数据结构之一的字段(参见生成的代码如何存储内部信号、状态和参数数据).如果您不希望信号出现在产品代码中,请使用一个测试点,以便您以后可以选择模型配置参数忽略测试点信号。或者,将信号连接到一个外港块在模型的根级。将信号连接到根级外港块防止从代码中消除信号的优化。要帮助处理大型模型中的信号路由,请使用转到和从块。
对于块参数,创建一个参数对象,如
万博1manbetx仿真软件。参数
并直接应用存储类以外的汽车
到对象。存储类防止优化在代码中内联参数值。对于存储类,参数在模型的所有实例之间共享,这些实例是对入口点函数的调用。函数直接访问形参数据,作为一个全局符号,而不是参数。您不能将参数配置为作为参数出现在代码中,因此您不能使模型的每个实例使用不同的参数值。
有关应用存储类的信息,请参见将存储类应用于单个信号、状态和参数数据元素。
控件内部数据的默认表示(嵌入式编码器)
默认情况下,代码生成器将无法通过优化消除的内部数据(例如大多数状态数据)聚合到DWork结构等标准结构中。使用嵌入式编码器,您可以控制生成的代码如何存储这些数据。
通过插入pragma来控制数据在内存中的位置
使用代码映射编辑器为每个数据类别(如状态和信号)指定默认内存部分(内部数据).在生成的代码中,您的自定义pragma或其他修饰围绕着数据定义和声明。
您还可以根据模型中的原子子系统对结构进行分区,以便为子例程和其他算法子组件的数据指定不同的默认内存部分。
有关更多信息,请参见通过插入pragma在内存中放置控制数据和函数(嵌入式编码)。
标准数据结构的类型、字段和全局变量的控制名称
您可以控制标准数据结构的一些特征。有关更多信息,请参见数据结构控制特性(嵌入式编码器)。
要对结构特征(例如在生成的代码文件中的位置)进行额外控制,请使用嵌入式编码器字典创建您自己的结构化存储类。然后,使用“代码映射编辑器”将存储类应用于数据类别。存储类从标准结构中删除数据,创建可以更好地控制的其他结构。有关将默认存储类应用于数据类别的详细信息,请参见为数据配置默认代码生成(嵌入式编码)。有关创建存储类的详细信息,请参见为软件架构定义存储类、内存段和函数模板(嵌入式编码)。
根据子组件将数据组织成结构
在标准数据结构中,要创建包含单实例(不可重入)子例程或子组件的数据的子结构,请使用原子子系统封装相应的块。在子系统参数中设置函数包装来
可重用的功能
。有关更多信息,请参见生成模块功能代码(嵌入式编码)。或者,将块封装在模型中并使用模型块。在引用的模型中,设置配置参数>模型参考>每个顶级模型允许的实例总数来
多个
。有关更多信息,请参见引用模型的代码生成。要在模型中创建包含多实例(可重入)子例程或子组件的数据的独立结构,请使用原子子系统封装相应的块。在子系统参数中设置函数包装来
那种一次性的功能
并选择具有单独数据的函数。有关更多信息,请参见生成模块功能代码(嵌入式编码)。或者,将块封装在模型中并使用模型块。在参考模型中,选择以下技术之一:
集配置参数>模型参考>每个顶级模型允许的实例总数来
一个
。有关更多信息,请参见引用模型的代码生成。集每个顶级模型允许的实例总数来
多个
并通过使用嵌入式编码器字典创建结构化存储类。然后,使用“代码映射编辑器”将存储类应用于数据类别。要创建存储类,请参见为软件架构定义存储类、内存段和函数模板(嵌入式编码)。若要将存储类应用于数据类别,请参见为数据配置默认代码生成(嵌入式编码)。
将信号和参数数据组织成有意义的、自定义的结构和子结构
将任意信号和参数组织到自定义结构和子结构中,创建非虚拟总线信号和参数结构。可选地,为了防止优化消除代码中的数据,请将总线信号或参数结构的存储类设置为非汽车
(默认设置)。
在向模型中添加块时,必须显式地将每个新信号和参数放入总线或结构中。
有关更多信息,请参见在生成的代码中将数据组织成结构。
创建单独的全局变量而不是结构字段
若要使内部数据类别在生成的代码中显示为单独的非结构化全局变量,而不是标准数据结构的字段,请使用“代码映射编辑器”将非结构化存储类应用于数据类别。例如,应用存储类ExportedGlobal
。但是,如果通过设置配置参数生成多实例、可重入的代码代码接口封装的值那种一次性的功能
,您不能对某些类别的数据使用此技术(请参阅在可重入、多实例模型和组件中使用存储类).
若要使用代码映射编辑器将默认存储类应用于数据类别,请参见为数据配置默认代码生成(嵌入式编码)。要选择存储类,请参见选择用于在生成的代码中控制数据表示的存储类。