主要内容

生成代码如何存储内部信号、状态和参数数据

为了从输入计算输出,生成的代码存储了一些内部数据在全局内存。一种不连接到根级输入或输出的信号(轮廓尺寸外港块)是内部数据。

内部数据还可以包括:

  • 一种块状态,如块的状态单位延迟块。算法必须在执行周期之间保留状态值,因此生成的代码通常将状态存储在全局内存中(例如,作为全局变量或全局结构变量的字段)。

  • 块参数,例如获得参数的获得块,其值不能在代码生成器中内联。例如,代码生成器不能内联非标量参数的值。

  • 有条件执行的子系统(如已启用的子系统)的状态指示器。

要获得更有效的代码,您可以配置优化,例如配置参数>默认参数的行为配置参数>信号存储复用消除存储内部数据的尝试。但是,优化不能消除某些数据的存储,这些数据会消耗生成代码中的内存。

当您理解生成的代码存储内部数据的默认格式时,您可以:

  • 默认情况下,使信号可访问和参数可调。然后,您可以在执行过程中与代码交互并监视代码。

  • 通过消除内部数据的存储,并根据硬件和构建工具链,控制优化无法消除的数据在内存中的位置,从而生成高效的生产代码。

  • 将内部数据片段提升到模型接口,以便其他组件和系统可以访问该数据。

有关生成的代码如何通过接口与调用环境交换数据的信息,请参见生成的代码如何与环境交换数据

生成代码中的内部数据

这个例子展示了生成的代码如何存储内部数据,比如块状态。

探索模型示例

打开示例模型rtwdemo_卷

open_system (“rtwdemo_roll”

模型包含不连接到根级导入或输出块的内部信号。一些信号有一个名字,比如phiCmd信号。

模型还包含一些维护状态数据的块。例如,在BasicRollMode分系统,一个离散时间积分器块标记积分器保持状态。

在模型中,设置>代码生成>系统目标文件grt.tlc

set_param (“rtwdemo_roll”“SystemTargetFile”“grt.tlc”

检查设置是否正确配置参数>代码生成>接口>代码接口打包.背景那种一次性的功能意味着生成的代码不可重用(可重入)。

对于本例,通过清除生成更简单的代码>代码生成>接口>高级参数> Mat-file日志

set_param (“rtwdemo_roll”“MatFileLogging”“关闭”

生成那种一次性代码

设置以下配置参数:

  • 默认参数的行为可调

  • 清晰的信号存储复用

set_param (“rtwdemo_roll”“DefaultParameterBehavior”可调的...“OptimizeBlockIOStorage”“关闭”

从模型生成代码。

slbuild (“rtwdemo_roll”
rtwdemo_roll的构建过程已经成功完成。模型重建行动的原因  ============================================================================================= rtwdemo_roll代码生成和编译代码生成信息文件不存在。1个模型建立(0个模型已经更新)建立时间:0小时0米10.748秒

该文件rtwdemo_roll.h定义几种表示内部数据的结构类型。例如,块输入和输出结构为模型中的每个内部信号定义了一个字段。每个字段名都来自生成信号的块的名称,或者,如果您为信号指定了名称,则来自信号的名称。

file=fullfile(“rtwdemo_roll_grt_rtw”“rtwdemo_roll.h”);rtwdemodbtype(文件,...'/*块信号(默认存储)*/'“}B_rtwdemo_roll_T;”,1,1)
/*块信号(默认存储)*/ typedef struct {real32_T phiCmd;/* '/ModeSwitch' */ real32_T hdgError;/* '/Sum' */ real32_T分配增益;/* '/ disgain ' */ real32_T Product;/* '/Product' */ real32_T Abs;/* '/Abs' */ real32_T FixPtUnitDelay1;/* '/FixPt Unit Delay1' */ real32_T Xnew;/* '/Enable' */ real32_T TKSwitch;/* '/TKSwitch' */ real32_T RefSwitch;/* '/RefSwitch' */ real32_T Integrator; /* '/Integrator' */ real32_T DispLimit; /* '/DispLimit' */ real32_T Sum; /* '/Sum' */ real32_T DispGain_f; /* '/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' */ 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)
/* Block states (default storage) for system '' */ typedef struct {real32_T FixPtUnitDelay1_DSTATE;/* '/FixPt Unit Delay1' */ real32_T Integrator_DSTATE;/* '/Integrator' */ int8_T integrator_preresetstate;/* '/Integrator' */} DW_rtwdemo_roll_T;

该文件定义了一个结构类型来表示参数数据。模型中的每个可调块参数,例如获得增益块的参数显示为该结构的字段。如果块参数从MATLAB变量或金宝appSimulink.参数对象时,变量或对象显示为字段,而不是块参数。

该文件还定义了一种结构类型,即实时模型数据结构,其单个字段表示在运行时指示生成的代码在执行期间是否遇到错误。

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)
/* 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(文件,'/*块信号(默认存储)*/'...“= &rtwdemo_roll_M_;”,1,1)
/*块信号(默认存储)*/ B_rtwdemo_roll_T rtwdemo_roll_B;/*块状态(默认存储)*/ DW_rtwdemo_roll_T rtwdemo_roll_DW;/*外部输入(root import signals with default storage) */ ExtU_rtwdemo_roll_T rtwdemo_roll_U;/*外部输出(由默认存储的信号提供的根输出)*/ ExtY_rtwdemo_roll_T rtwdemo_roll_Y;/*实时模型*/ static RT_MODEL_rtwdemo_roll_T rtwdemo_roll_M_;RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M = &rtwdemo_roll_M_;

该模型一步函数表示主要模型算法,使用a空白空白接口(没有参数)。

rtwdemodbtype(文件,...'/* Model step函数*/'“空白rtwdemo_roll_step(空白),1,1)
/*模型step函数*/ void rtwdemo_roll_step(void)

在函数定义中,算法通过直接访问全局变量来执行计算,并将中间结果存储在信号和状态结构中。该算法还从相应的全局变量中读取参数数据。例如,在BasicRollMode子系统中生成的代码积分器块从结构读取和写入信号、状态和参数数据。

rtwdemodbtype(文件,'/* disteintegrator: " /Integrator " *'...'/* End of DiscreteIntegrator: " /Integrator " */',1,1)
/*离散集成器:'/Integrator'*/if(rtwdemo_roll_B.NotEngaged_e|124;(rtwdemo_roll_DW.Integrator_prevereststate!=0)){rtwdemo_roll_DW.Integrator_DSTATE=rtwdemo_roll_P.Integrator_IC;}if(rtwdemo_roll_roll(DW DW.Integrator(.Integrator)dtate>=rtwdemo_roll_P.intLim)}(rtwdemo_roll_DW.Integrator_DSTATE<=rtwdemo_roll_P.Integrator_LowerSat){rtwdemo_roll_DW.Integrator_DSTATE=rtwdemo_roll_P.Integrator_LowerSat;}/*离散积分器:'/Integrator'*/rtwdemo\u roll\u B.Integrator=rtwdemo\u roll\u DW.Integrator\u DSTATE;/*饱和:'/distrimit'*/u0=rtwdemo\u roll\u B.phiCmd;u1=rtwdemo\u roll\u P.distrimit\u LowerSat;u2=rtwdemo\u roll\P.distrim;if(u0>u2){/*饱和:'/distrimit'*/rtwdemo\r\u.distrimit\r\r\r\r\r\r\n{/*饱和:'/DispLimit'*/rtwdemo\u roll\u B.DispLimit=u1;}其他{/*饱和:'/DispLimit'*/rtwdemo\u roll\u B.DispLimit=u0;}(s)一个学生::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::u2){/*饱和:'/RateLimit'*/rtwdemo\u roll\u B.rateLim=u2;}如果(u0/RateLimit'*/rtwdemo\u roll\u B.RateLimit=u1;}否则{/*饱和:'/rateLim/*饱和结束:“/RateLimit'*/*总和:”/Sum1“合并:*输入:“/Rate\U FB'*/rtwdemo\U roll\U B.Sum1=rtwdemo\U roll\U B.RateLimit-rtwdemo\U roll\U.Rate FB;/*增益:”/RateGain'*/rtwdemo\U roll\U-B.RateGain=rtwdemo\U roll\U P.RateGain*rtwdemo\U roll\U-Sum\U.Sum:/rtwdemo\r\U+rtwdemo\u roll\u B.RateGain;/*饱和:'/CmdLimit'*/u0=rtwdemo\u roll\u B.Sum2;u1=rtwdemo\u roll\u P.CmdLimit\u LowerSat;u2=rtwdemo\u roll\u P.cmdLim;如果(u0>u2){/*饱和:'/CmdLimit'*/rtwdemo\u roll\u B.CmdLimit=u2;}如果(u0/CmdLimit'*/rtwdemo\u roll\u B.CmdLimit=u0;}/*饱和结束:'/CmdLimit'*/*增益:'/IntGain'*/rtwdemo\u roll\u B.IntGain=rtwdemo\u roll\u P.IntGain*rtwdemo\u roll\u B.Sum1;/*离散积分器的更新:'/Integrator'*/rtwdemo\u roll\u DW.Integrator\d state+=rtwdemo\u roll\u P.Integrator\u gainval*rtwdemo\u roll\u B.IntGain;如果(rtwdemo_roll_DW.Integrator_DSTATE>=rtwdemo_roll_P.intLim){rtwdemo_roll_DW.Integrator_DSTATE=rtwdemo_roll_P.intLim;}否则如果(rtwdemo_roll_DW.Integrator_DSTATE<=rtwdemo_roll_P.Integrator_LowerSat){rtwdemo_roll_P.Integrator_LowerSat){rtwdemo_roll_LowerSat=rtwdemo_roll_P.Integrator_.integratordstate=rtemo_roll_LowerSat=rtemo_roll_P.Integrator_.integrartwdemo_roll_B.NotEngaged_e;/*离散集成器更新结束:'/Integrator'*/*子系统输出结束:'/BasicRollMode'*//*开关:'/EngSwitch'合并:*输入:'/AP_Eng'*/if(rtwdemo_roll_.AP_Eng){/*输出:'/Ail_Cmd'*/rtwdemo_roll_Y.ailcmd=rtwdemo_roll;}{/*输出端口:'/Ail\u Cmd'合并:*常量:'/Zero'*/rtwdemo\u roll\u Y.Ail\u Cmd=rtwdemo\u roll\u P.Zero\u Value\u c;}/*开关结束:'/EngSwitch'*/}/*模型初始化函数*/void rtwdemo\u roll\u初始化(void){/*注册码*//*初始化错误状态*/rtmsetroorstatus(rtwdemo\u roll\u,(NULL))/*块I/O*/(void)memset((void*)和rtwdemo_roll_B),0,sizeof(Brtwdemo_roll_T));/*状态(dwork)*/(void)memset((void*)和rtwdemo_roll_DW,0,sizeof(DWrtwdemo_roll_T));/*外部输入*/(void)memset(&rtwdemo_roll,0,sizeof(ExtU;/*外部输出*/rtwdemo\u roll\u Y.Ail\u Cmd=0.0F;/*原子子系统的系统初始化:'/rollingreference'*/*单元延迟的初始化条件:'/FixPt Unit Delay1'*/rtwdemo\u roll\u DW.fixtunitdelay1\u DSTATE=rtwdemo\u roll\P.LatchPhi\u vinit;/*子系统初始化结束:'/rollingreference'/*系统原子子系统的最小化:'/BasicRollMode'*/*离散集成器的初始化条件:'/Integrator'*/rtwdemo\u roll\u DW.Integrator\u DSTATE=rtwdemo\u roll\u P.Integrator;rtwdemo\u roll\u DW.Integrator\u preverestate=0;/*子系统初始化结束:'/BasicRollMode'*/}/*模型终止函数*/void rtwdemo\u roll\u terminate(void){/*(不需要终止代码)*/}

由于空白空白接口和数据直接访问,函数是不可重入的。如果在应用程序中多次调用该函数,则每次调用都将数据写入全局结构变量,后续调用可以读取该数据,从而导致调用之间的意外干扰。

模型初始化函数rtwdemo_roll_initialize将所有内部数据初始化为零。该函数还通过调用专门的宏函数初始化错误状态。初始化函数直接访问全局变量,这意味着函数是不可重入的。

rtwdemodbtype(文件,/*模型初始化函数*/...”sizeof (DW_rtwdemo_roll_T)),“,1,1)
/*模型初始化函数*/void rtwdemo_roll_initialize(void){/*注册码*/*初始化错误状态*/rtmsetorstatus(rtwdemo_roll_M,(NULL))/*块I/O*/(void)memset((void*)和rtwdemo_roll_B),0,sizeof(B_rtwdemo_roll__T))/*状态(dwork)*/(void)memset(void*)和rtwdemo_roll_DW,0,sizeof(DW rtemo_)roll;

然后,该函数将DWork结构中的块状态初始化为模型中的块参数指定的初始值。模型中的三个状态中有两个具有可调的初始值,因此代码通过从参数结构读取数据来初始化它们。

rtwdemodbtype(文件,.../* SystemInitialize for Atomic SubSystem: " /RollAngleReference " */'...'/*模型终止函数*/',1,0)
/* SystemInitialize for Atomic SubSystem: '/RollAngleReference' */ /* initializeconconditions for UnitDelay: '/FixPt Unit Delay1' */ rtwdemo_roll_DW. log . log . log . log . log . log . log . log . log . log . log . log . log . log。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”“可重用函数”

从模型生成代码。

slbuild (“rtwdemo_roll”
###开始:rtwdemo#u roll##的生成过程成功完成:rtwdemo#u roll生成摘要生成的顶级模型目标:模型操作重建原因=========================================================================================================================================================================================================================================================================================================================================================================================================================================================================(0个型号已更新)生成持续时间:0h 0m 9.203s

现在,在rtwdemo_roll.h,实时模型数据结构包含指向错误指示的指针、内部数据和主输入输出数据的形式ExtUExtY子结构(其字段表示模型根级别的import和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;ExtU_rtwdemo_roll_T *输入;ExtY_rtwdemo_roll_T *输出;DW_rtwdemo_roll_T * dwork;};/*块参数(默认存储)*/ extern P_rtwdemo_roll_T rtwdemo_roll_P;

要在应用程序中多次调用生成的代码,您的代码必须在每次调用时为实时模型数据结构分配内存。该文件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

该模型一步函数接受一个表示实时模型数据结构的参数。

rtwdemodbtype(文件,'/* Model step函数*/'“空白rtwdemo_roll_step”,1,1)
/*模型步长函数*/ void rtwdemo_roll_step(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)

在函数定义中,算法首先从实时模型数据结构中提取每个指针到一个局部变量中。

rtwdemodbtype(文件,‘* rtwdemo_roll_B = '“rtwdemo_roll_M - >输出;”,1,1)
B_rtwdemo_roll_T *rtwdemo_roll_B = rtwdemo_roll_M-> blockkio;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->输入;ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *) rtwdemo_roll_M->输出;

然后,为了访问存储在全局内存中的内部数据,算法与这些局部变量进行交互。

rtwdemodbtype(文件,'/* disteintegrator: " /Integrator " */'...'/* End of DiscreteIntegrator: " /Integrator " */',1,1)
/ *离散仪器:' /集成器'* / if(rtwdemo_roll_b-> notEngaged_e ||(RTWDEMO_ROLL_DW-> Integrator_PrevresetState!= 0)){RTWDEMO_ROLL_DW-> Integrator_Dstate = RTWDEMO_ROLL_P.Integrator_ic;}如果(rtwdemo_roll_dw-> ontorator_dstate> = rtwdemo_roll_p.intlim){RTWDEMO_ROLL_DW-> Integrator_DState = RTWDEMO_ROLL_P.Intlim;}否则if(rtwdemo_roll_dw-> onytator_dstate  Integrator_Dstate = RTWDEMO_ROLL_P.Integrator_Lowersat;} / *离散仪器:' /积分器'* / rtwdemo_roll_b-> Integrator = RTWDEMO_ROLL_DW-> Integrator_Dstate;/ *饱和:' / betplimit'* / u0 = rtwdemo_roll_b-> phicmd;u1 = rtwdemo_roll_p.displimit_lowersat;U2 = RTWDEMO_ROLL_P.DISPLIM;if(u0> u2){/ *饱和:' / stultimit'* / rtwdemo_roll_b-> displimit = u2;}如果(U0  / displimit'* / rtwdemo_roll_b-> displimit = u1;} else {/ *饱和:' / stultimit'* / rtwdemo_roll_b-> displimit = u0; } /* End of Saturate: '/DispLimit' */ /* Sum: '/Sum' incorporates: * Inport: '/Phi' */ rtwdemo_roll_B->Sum = rtwdemo_roll_B->DispLimit - rtwdemo_roll_U->Phi; /* Gain: '/DispGain' */ rtwdemo_roll_B->DispGain_f = rtwdemo_roll_P.dispGain * rtwdemo_roll_B->Sum; /* Saturate: '/RateLimit' */ u0 = rtwdemo_roll_B->DispGain_f; u1 = rtwdemo_roll_P.RateLimit_LowerSat; u2 = rtwdemo_roll_P.rateLim; if (u0 > u2) { /* Saturate: '/RateLimit' */ rtwdemo_roll_B->RateLimit = u2; } else if (u0 < u1) { /* Saturate: '/RateLimit' */ rtwdemo_roll_B->RateLimit = u1; } else { /* Saturate: '/RateLimit' */ rtwdemo_roll_B->RateLimit = u0; } /* End of Saturate: '/RateLimit' */ /* Sum: '/Sum1' incorporates: * Inport: '/Rate_FB' */ rtwdemo_roll_B->Sum1 = rtwdemo_roll_B->RateLimit - rtwdemo_roll_U->Rate_FB; /* Gain: '/RateGain' */ rtwdemo_roll_B->RateGain = rtwdemo_roll_P.rateGain * rtwdemo_roll_B->Sum1; /* Sum: '/Sum2' */ rtwdemo_roll_B->Sum2 = rtwdemo_roll_B->Integrator + rtwdemo_roll_B->RateGain; /* Saturate: '/CmdLimit' */ u0 = rtwdemo_roll_B->Sum2; u1 = rtwdemo_roll_P.CmdLimit_LowerSat; u2 = rtwdemo_roll_P.cmdLim; if (u0 > u2) { /* Saturate: '/CmdLimit' */ rtwdemo_roll_B->CmdLimit = u2; } else if (u0 < u1) { /* Saturate: '/CmdLimit' */ rtwdemo_roll_B->CmdLimit = u1; } else { /* Saturate: '/CmdLimit' */ rtwdemo_roll_B->CmdLimit = u0; } /* End of Saturate: '/CmdLimit' */ /* Gain: '/IntGain' */ rtwdemo_roll_B->IntGain = rtwdemo_roll_P.intGain * rtwdemo_roll_B->Sum1; /* Update for DiscreteIntegrator: '/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: '/Integrator' */ /* End of Outputs for SubSystem: '/BasicRollMode' */ /* Switch: '/EngSwitch' incorporates: * Inport: '/AP_Eng' */ if (rtwdemo_roll_U->AP_Eng) { /* Outport: '/Ail_Cmd' */ rtwdemo_roll_Y->Ail_Cmd = rtwdemo_roll_B->CmdLimit; } else { /* Outport: '/Ail_Cmd' incorporates: * Constant: '/Zero' */ rtwdemo_roll_Y->Ail_Cmd = rtwdemo_roll_P.Zero_Value_c; } /* End of Switch: '/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: '/RollAngleReference' */ /* InitializeConditions for UnitDelay: '/FixPt Unit Delay1' */ rtwdemo_roll_DW->FixPtUnitDelay1_DSTATE = rtwdemo_roll_P.LatchPhi_vinit; /* End of SystemInitialize for SubSystem: '/RollAngleReference' */ /* SystemInitialize for Atomic SubSystem: '/BasicRollMode' */ /* InitializeConditions for DiscreteIntegrator: '/Integrator' */ rtwdemo_roll_DW->Integrator_DSTATE = rtwdemo_roll_P.Integrator_IC; rtwdemo_roll_DW->Integrator_PrevResetState = 0; /* End of SystemInitialize for SubSystem: '/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(文件,.../*模型初始化函数*/“空白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”“那种一次性函数”

从模型生成代码。

slbuild (“rtwdemo_roll”
###启动构建过程为:rtwdemo_roll ###成功完成构建过程为:rtwdemo_roll构建摘要顶级模型目标构建:模型动作重建原因============================================================================ rtwdemo_roll生成和编译的代码生成的代码过时。建造时间:0小时0米8.078秒

现在,rtwdemo_roll.h未定义块输入和输出的结构。对于模型中的所有内部信号,优化要么消除存储,要么创建局部函数变量,而不是全局结构字段。

优化不能消除三种块状态的存储,因此文件继续定义DWork结构类型。

file=fullfile(“rtwdemo_roll_grt_rtw”“rtwdemo_roll.h”);rtwdemodbtype(文件,.../*块状态(默认存储)“}DW_rtwdemo_roll_T;”,1,1)
/* Block states (default storage) for system '' */ 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 " '...'/* Update for DiscreteIntegrator: " /Integrator " */',1,1)
/*离散积分器的更新:“/Integrator”合并:*增益:“/IntGain'*/rtwdemo\u roll\u DW.Integrator\u DSTATE+=0.5F*rtb\u TKSwitch*0.025F;如果(rtwdemo\u roll\u DW.Integrator\u DSTATE>=5.0F){rtwdemo\u roll\u DW.Integrator\u DSTATE=5.0F;}否则如果(rtwdemo\u roll\u DW.Integrator\u DSTATE<-5.0F){rtwdemo_roll_DW.Integrator_DSTATE=-5.0F;}rtwdemo_roll_DW.Integrator_prevrestate=(int8_T)rtb_NotEngaged_f;

优化还消除了模型中块参数的存储。例如,在离散时间积分器块中饱和上限低饱和限制参数设置为intLim-intLimintLim是一个金宝appSimulink.参数存储该值的对象5.在为离散时间积分器生成的代码中,这些块参数和intLim显示为内联的文字数5.0度-5.0度

如果模型包含代码生成器不能直接内联的参数(例如数组参数),则代码将定义表示数据的结构类型。这常数参数结构使用常量存储类型限定符,因此一些构建工具链可以进一步优化汇编代码。

生成代码中的局部变量

当您选择优化时配置参数>启用本地块输出,代码生成器试图通过将内部信号表示为局部变量而不是全局结构的字段来生成更有效的代码。如果本地变量所消耗的内存有超过目标硬件上可用堆栈空间的风险,请考虑通过设置指示最大堆栈大小配置参数>最大堆栈大小(字节).有关更多信息,请参见最大堆栈大小(字节)

生成代码中测试点的外观

一个测试点是存储在唯一存储位置的信号。有关在模型中包含测试点的信息,请参见将信号配置为测试点

为包含测试点的模型生成代码时,生成过程会为每个测试点分配单独的内存缓冲区。默认情况下,测试点存储为标准数据结构的成员,例如模型_B

如果你有嵌入式编码器®

  • 控件的代码生成设置可以控制测试点的默认表示内部数据代码映射编辑器中的数据类别(请参见配置数据的默认代码生成(嵌入式编码)).

  • 属性可以指定构建过程忽略模型中的测试点,从而允许最优的缓冲区分配忽略测试点信号(嵌入式编码)参数。忽略测试点有助于从原型转换到部署,并避免由于工作流工件而意外地降低生成的代码。看到忽略测试点信号(嵌入式编码)

即使与测试点相关联,虚拟总线也不会出现在生成的代码中。若要在生成的代码中显示总线,请使用非虚拟总线或由控件转换为非虚拟总线的虚拟总线信号转换块。

工作区变量在生成的代码中的外观

工作空间变量是用于在模型中指定块参数值的变量。工作空间变量包括数值MATLAB®变量和金宝appSimulink.参数存储在工作区(例如基本工作区)或数据字典中的对象。

当您设置默认参数的行为可调默认情况下,工作区变量在生成的代码中显示为全局参数结构的可调字段。如果使用此类变量指定多个块参数值,则该变量将显示为全局参数结构的单个字段。代码不会创建多个字段来表示块参数。因此,在代码执行期间调整字段值会改变模型的数学行为,就像在仿真期间调整MATLAB变量或参数对象的值一样。

如果您有Embedded Coder,您可以通过在代码映射编辑器中为参数数据类别指定代码生成设置来控制工作空间变量的默认表示(请参阅配置数据的默认代码生成(嵌入式编码)).

  • 模型参数类别应用于存储在模型工作区中的变量。

  • 外部参数类别应用于存储在基本工作空间或数据字典中的变量。

将内部数据升级到接口

默认情况下,代码生成器假设应用程序中的其他系统和组件不需要访问内部数据。例如,内部数据受到优化的影响,可以从生成的代码中消除它们。对于原型和测试目的,您可以通过清除优化或配置测试点和应用存储类来访问内部数据(参见在生成的代码中保留变量).对于优化的生产代码,配置单个数据项,使其作为模型接口的一部分出现在生成的代码中。

你可以推广的数据

取决于生成的代码的可重入性,也就是您选择的设置代码接口包装,您可以将模型中的每个数据项配置为参与接口,方法是在代码中显示为以下实体之一:

  • 一种全局符号,如全局变量或对专门化函数的调用

  • 生成的入口点函数的形式形参(实参)

该表显示了每个类别的数据可以用于参与接口的机制。

类别的数据 作为全球符号出现 作为入口点函数的参数出现
根级轮廓尺寸外港 仅用于不可重入模型。 是的。
连接两个区块的信号 仅用于不可重入模型。

仅用于可重入模型,且仅作为结构的字段。

或者,将信号连接到根级外港块。

阻塞状态 仅用于不可重入模型。 仅用于可重入模型,且仅作为结构的字段。
数据存储,如数据存储内存 是的。 仅用于可重入模型,且仅作为结构的字段。
块参数或参数对象,如金宝appSimulink.参数 是的。 只作为一个领域的结构。

单实例算法

对于单实例算法(您设置代码接口包装那种一次性的功能),通过使用模型数据编辑器或属性检查器将存储类直接应用到单个数据项。对于直接应用的存储类,数据项以全局符号(如全局变量)的形式出现在代码中。存储类还防止优化消除数据项的存储。

您可以将存储类应用于信号、块状态和块参数。(对于块参数,您可以通过参数对象间接应用存储类,例如金宝appSimulink.参数).然而,对于信号,考虑将信号连接到外港块在模型的根级。然后,您可以选择将存储类应用到该块。在框图中外港块表示该信号代表一个系统输出。

有关存储类的更多信息,请参见模型接口元素的C代码生成配置

可重入算法

对于可重入算法(您设置代码接口包装可重用的功能),使用不同的技术配置数据项,使其作为生成的入口点函数的形式参数(实参)出现在代码中。

  • 对于内部信号,直接应用存储类模型的默认(见模型接口元素的C代码生成配置).如果您有Embedded Coder,在代码映射编辑器中内部数据类别,将默认存储类设置为默认的或在嵌入式编码器字典中定义的结构化存储类(参见创建代码定义,以便在代码映射编辑器中使用(嵌入式编码)).或者,将信号配置为一个测试点(参见生成代码中测试点的外观).默认情况下,信号显示为一个标准数据结构的字段(参见生成代码如何存储内部信号、状态和参数数据).如果您不希望信号出现在产品代码中,请使用测试点,以便稍后选择模型配置参数忽略测试点信号

    或者,将信号连接到外港块在模型的根级。将信号连接到根级外港块阻止优化从代码中消除信号。为了帮助在大型模型中进行信号路由,请使用转到块。

  • 对于块参数,创建一个参数对象,例如金宝appSimulink.参数并直接应用存储类汽车的对象。存储类阻止优化在代码中内联参数值。

    使用存储类,参数在模型的实例之间共享,这些实例是对入口点函数的调用。函数以全局符号而不是实参的形式直接访问形参数据。您不能将参数配置为作为参数出现在代码中,因此不能允许模型的每个实例为参数使用不同的值。

    有关应用存储类的信息,请参见模型接口元素的C代码生成配置

控件内部数据的默认表示形式(嵌入式编码器

默认情况下,代码生成器将优化不能消除的内部数据(如大多数状态数据)聚合到标准结构(如DWork结构)中。使用Embedded Coder,您可以控制生成的代码如何存储这些数据。

通过插入杂注来控制内存中数据的放置

使用代码映射编辑器为每类数据(如状态和信号)指定默认内存部分(内部数据).在生成的代码中,您的自定义语或其他修饰围绕着数据定义和声明。

您还可以根据模型中的原子子系统来划分结构,以便为子例程和其他算法子组件的数据指定不同的默认内存部分。

有关更多信息,请参见通过插入语控制数据和函数在内存中的位置(嵌入式编码)

控制标准数据结构的类型、字段和全局变量的名称

您可以控制标准数据结构的一些特征。有关更多信息,请参见生成代码中的控件数据类型名称(嵌入式编码)

对于结构特征的额外控制,例如在生成的代码文件中的位置,可以使用Embedded Coder Dictionary创建您自己的结构化存储类。然后,使用代码映射编辑器将存储类应用于数据类别。存储类从标准结构中删除数据,创建其他可以更好地控制的结构。有关将默认存储类应用于数据类别的更多信息,请参见配置数据的默认代码生成(嵌入式编码).有关创建存储类的详细信息,请参见为软件架构定义存储类、内存段和函数模板(嵌入式编码)

根据子组件将数据组织成结构

  • 在标准数据结构中,要创建包含单实例(不可重入)子例程或子组件数据的子结构,请使用原子子系统来封装相应的块。在子系统参数中,设置函数包装可重用的功能.有关更多信息,请参见为非虚拟子系统生成模块函数代码(嵌入式编码)

    或者,将块封装在模型中并使用模型块。在引用的模型中,设置配置参数>模型参考>每个top模型允许的实例总数倍数.有关更多信息,请参见为模型引用层次结构生成代码

  • 要创建包含多实例(可重入)子例程或子组件数据的独立结构,请在模型中使用原子子系统封装相应的块。在子系统参数中,设置函数包装那种一次性的功能并选择具有独立数据的函数.有关更多信息,请参见为非虚拟子系统生成模块函数代码(嵌入式编码)

    或者,将块封装在模型中并使用模型块。在参考模型中,选择其中一种技术:

组织信号和参数数据到有意义的,自定义结构和子结构

要将任意信号和参数组织成自定义结构和子结构,请创建非虚拟总线信号和参数结构。可选地,为了防止优化从代码中消除数据,将总线信号或参数结构的存储类设置为非汽车(默认设置)。

在向模型添加块时,必须显式地将每个新信号和参数放入总线或结构中。

有关更多信息,请参见在生成的代码中将数据组织到结构中

创建单独的全局变量而不是结构字段

要使内部数据类别作为独立的非结构化全局变量而不是标准数据结构的字段出现在生成的代码中,请使用代码映射编辑器对数据类别应用非结构化存储类。例如,应用存储类ExportedGlobal.但是,如果您通过设置配置参数生成多实例可重入代码代码接口包装而不是那种一次性的功能,您不能将此技术用于某些类别的数据(请参阅存储类和可重入、多实例模型和组件).

若要使用代码映射编辑器将默认存储类应用于数据类别,请参见配置数据的默认代码生成(嵌入式编码).要选择存储类,请参见选择存储类以控制生成代码中的数据表示

相关的话题