中国汽车工程师之家--聚集了汽车行业80%专业人士 

论坛口号:知无不言,言无不尽!QQ:542334618 

本站手机访问:直接在浏览器中输入本站域名即可 

  • 277查看
  • 0回复

[Simulink] MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化

[复制链接]


该用户从未签到

发表于 2-3-2024 09:33:55 | 显示全部楼层 |阅读模式

汽车零部件采购、销售通信录       填写你的培训需求,我们帮你找      招募汽车专业培训老师


全文约3500字,你将看到以下内容:

    代码生成的配置概述

    代码生成的配置选项
    代码生成的配置方法小结
autoMBD最近发布了《autoMBD原创技术文章合集》
合集包含156页丰富的MBD入门基础和MBDT硬件支持包的使用还包含基于MBD的电机控制算法开源项目——AMBD-MC合集配备了丰富的视频讲解
和大量的模型、文档和软件资源

如何获取请参考@所有读者:autoMBD发布《autoMBD原创技术文章合集》。

经过忙碌的九月、十月,终于可以回到更新文章的状态。本篇文章将介绍如何在Simulink中,对模型生成的代码进行配置和优化。点击以下链接,可以查看往期文章:
    MBD的Simulink使用技巧①:Simulink代码生成的基本概念MBD的Simulink使用技巧②:详解代码生成中的模型与代码MBD的Simulink使用技巧③:虚拟子系统与原子子系统的代码生成
    MBD的Simulink使用技巧④:详解生成代码的结构与代码的生成流程


1  代码生成的配置概述

当我们对模型设置不同的配置选项时,会对模型生成的代码产生不同的影响。评价代码优化情况,有以下几个维度:


    否影响调试性(Debugging)

    否影响可追踪性(Traceability)

    否影响执行效率(Efficiency)
    否影响安全预防(Safety precaution)

调试性指的是调试模型生成代码的编译过程,这里不做深入介绍。

可追踪性指的是模型和代码之间的映射关系是否易于追踪,例如:如果代码优化水平设置的比较高,代码和模型之间可能会没有明显的一一对应关系,这会不利于追踪。

执行效率包括生成的代码所占用的RAM、ROM空间大小,以及处理器执行生成代码的效率,这一般是我们最关心的优化目标。

安全预防指的是代码是否具备防止执行错误的情况发生,例如:除零检查、溢出检查等。

安全预防一般与效率是矛盾的,因为安全检查需要消耗存储空间和执行时间。有些代码优化选项会移除掉这些安全检查,开发者一般根据需求来决定,是模型来保证安全,还是开发者自己来保证安全。

下面的链接可以查看MathWorks官方对全部配置选项和相应的影响的总结。
MathWorks:模型配置参数建议配置总结https://ww2.mathworks.cn/help/ecoder/ref/parameter-reference.html?s_tid=srchtitle_recommended%20settings%20summary_1

Tips:由于自动生成代码的配置选项较多,文章中仅对常用的配置选项进行简单介绍,具体的功能和作用读者自行在实践中练习和体验。

Tips:不同的Simulink版本,配置界面可能会有一些细微区别,本文是基于2020b版本进行展示的。

2  代码生成的配置选项

2.1 静态代码的度量报告

在生成代码时,可以配置生层静态代码的度量报告,报告详细列举了代码量的信息(文件数量、代码行数等)。不同的代码优化配置选项,生成的代码量是不一样的,可以作为代码优化的一个参考指标。

Tips:读者可以通过对比某一优化选项开启和关闭时,代码度量报告的区别,来了解该优化选项的效果。也可以直接对比生成的代码,查看该优化选项的具体作用。

打开静态代码度量报告的方法如下所示:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w1.jpg

打开静态代码的度量报告 - From autoMBD

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w2.jpg

静态代码的度量报告 - From autoMBD

2.2 优化不必要代码

生成的代码中,有时候包括一些不影响功能的不必要代码,可以优化去掉。这些代码包括:
    数据初始化代码(Data initialization)

对于浮点数的零初始化过程,可以配置使用memset()函数,或者直接var=0.0赋值。初始化的数据非常多时,后者会花费更多的存储空间和执行时间。如下图所示:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w3.jpg

配置浮点数零初始化方法 - From autoMBD

还可以选择移除零初始化代码,因为一般变量的内存区域初始值已经为零,不需要再初始化,这种配置是最高效的。如下图所示:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w4.jpg

移除零初始化代码 - From autoMBD
    终止代码(Termination)

如果终止代码中没有必要代码,那么可以移除,如下所示:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w5.jpg

移除不必要的终止代码 - From autoMBD
    整型数据的溢出回环(Integer wrapping)
假设这样一种情况:将浮点数float 80000.0转换为16位无符号整型数据unsigned short。很显然这里发生了数据溢出,因为16位无符号整型数据最大值为65535。在C语言中,溢出的位会被忽略,只保留低16位数据,float 80000.0转换为16位无符号整型数据的结果为unsigned short 14464。如下C语言中示例结果:
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w6.jpg

C语言中的数据回环 - From autoMBD
但在Simulink中,有些配置选项会添加软件处理过程,来保证这个过程的正确性。如下所示的数据转换模型和生成的代码:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w7.jpg

数据转换模型 - From autoMBD
/* Model step function */voidfloat2int_step(void){  real_T tmp;
/* DataTypeConversion: '<Root>/Data Type Conversion' incorporates:   *  Constant: '<Root>/Constant'   */  tmp = fmod(floor(float2int_P.Constant_Value), 65536.0);
/* Outport: '<Root>/y' incorporates:   *  DataTypeConversion: '<Root>/Data Type Conversion'   */  float2int_Y.y = (int16_T)(tmp < 0.0 ? (int32_T)(int16_T)-(int16_T)(uint16_T)    -tmp : (int32_T)(int16_T)(uint16_T)tmp);}一般情况下,这部分的代码也是不必要的,可以去掉(默认是去掉的),将这一过程交给编译器来实现,去掉的方式如下:
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w8.jpg

移除数据回环代码 - From autoMBD

配置移除数据回环代配置选项后,生成的代码如下:

/* Model step function */voidfloat2int_step(void){/* Outport: '<Root>/y' incorporates:   *  Constant: '<Root>/Constant'   *  DataTypeConversion: '<Root>/Data Type Conversion'   */  float2int_Y.y = (int16_T)floor(float2int_P.Constant_Value);}

    代数运算异常保护代码(Arithmetic exceptions)

代数运算异常最常见的就是除零错误,Simulink可以生成相应的代码进行除零检查,但需要消耗额外的执行时间和存储空间,影响代码效率。

如下所示的除法模型和生成的代码:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w9.jpg

除法模型 - From autoMBD
/* Model step function */void divide_step(void){  /* Outport: '<Root>/y' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   *  Product: '<Root>/Divide'   */  divide_Y.y = divid_U.In2 == 0U ? MAX_uint32_T : divide_U.In1 /    divide_U.In2;}可以看到,一个简单的除法操作,被添加了“0判断条件”,这会消耗额外的资源。在保证不会有除零的情况发生的前提下,可以去掉这部分代码,配置选项如下:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w10.jpg

移除代数异常检查代码 - From autoMBD

配置异常代数运算异常检查代码后,除法模型新生成的代码如下:
/* Model step function */void divide_step(void){  /* Outport: '<Root>/y' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   *  Product: '<Root>/Divide'   */  divide_Y.y = divide_U.In1 / divide_U.In2;}

    无效的模块(Unnecessary blocks)


在有些情况下,模型中的有些模块永远也得不到执行,例如下图所示的模型:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w11.jpg

不被执行的无效模块 - From autoMBD

模型中的加法运算永远得不到执行,因为Switch的判断条件(>0)始终是上面乘法的路径是有效的。

我们应当避免搭建这种无效的模型,但也可以通过配置,使无效的模型不生成代码,配置方法如下:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w12.jpg

移除的无效模块 - From autoMBD

配置移除无效模型后,上述模型生成的代码如下:
/* Model step function */void autoMBD_example_defaultConfig_step(void){  /* Outport: '<Root>/Out2' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   *  Product: '<Root>/Product'   *  Trigonometry: '<Root>/Trigonometric Function'   */  autoMBD_example_defaultConfig_Y.Out2 = sin(autoMBD_example_defaultConfig_U.In1    * autoMBD_example_defaultConfig_U.In2);}可以看到生成的代码中,只有乘法的路径,加法的模块没有生成任何代码。

2.3 优化变量的使用形式

Simulink模型支持非常多的数据类型,包括浮点数、复数、变步长信号等,但其中有一部分并不是代码所需要的,可以将其去掉(一般仅保留浮点数即可):

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w13.jpg

移除不必要的数据支持 - From autoMBD

关于生成代码中变量的形式,信号存储复用(Signal store reuse)是比较重要的优化配置选项。如下图所示,默认情况下全部复用功能都是打开的:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w14.jpg

信号存储复用的配置选项 - From autoMBD

在《MBD的Simulink使用技巧②:详解代码生成中的模型与代码》中曾提到:模型中的信号(Signals)有两种:外部信号和内部信号。对于内部信号,具有分叉点的信号线会生成局部变量,变量名为“rtb_信号名”。

实际上内部信号还包括模块信号,接下来将介绍如何配置生成模块信号。

还是以下图的模型为例:



示例模型 - From autoMBD

信号存储复用的配置选项全部打开时(即默认配置),生成的代码如下所示,可以看到生成的代码非常简洁,只有一行就完成了所有操作,并没有任何的中间变量。
/* Model step function */void autoMBD_example_defaultConfig_step(void){  /* Outport: '<Root>/Out2' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   *  Product: '<Root>/Product'   *  Trigonometry: '<Root>/Trigonometric Function'   */  autoMBD_example_defaultConfig_Y.Out2 = sin(autoMBD_example_defaultConfig_U.In1    * autoMBD_example_defaultConfig_U.In2);}
当信号存储复用的选项全部关闭时,那么生成的代码每一行只会执行一个操作,并且每一个操作得到的结果都会存储在一个变量当中或者输出。生成的代码如下:

/* Model step function */voidautoMBD_example_defaultConfig_step(void){/* Product: '<Root>/Product' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   */  autoMBD_example_defaultConfig_B.Product = autoMBD_example_defaultConfig_U.In1 *    autoMBD_example_defaultConfig_U.In2;
/* Switch: '<Root>/Switch' */  autoMBD_example_defaultConfig_B.Switch =    autoMBD_example_defaultConfig_B.Product;
/* Outport: '<Root>/Out2' incorporates:   *  Trigonometry: '<Root>/Trigonometric Function'   */  autoMBD_example_defaultConfig_Y.Out2 = sin    (autoMBD_example_defaultConfig_B.Switch);}可以看到,原本的一行代码被分解成了三个操作:乘法操作、传值操作、sin运算。同时还新增了一个变量:模型名_B。该变量是一个全局变量,被用来存储模块的变量值。这种方式执行效率降低,但执行的逻辑是最清晰的,易于阅读。模型名_B的定义如下,包含Product和Switch两个元素:/* Block signals (default storage) */typedefstruct {  real_T Product;                      /* '<Root>/Product' */  real_T Switch;                       /* '<Root>/Switch' */} B_autoMBD_example_defaultConf_T;
如果把信号存储复用的选项配置为如下:

MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w16.jpg

打开Enable local block output - From autoMBD

此时生成的代码如下:

/* Model step function */voidautoMBD_example_defaultConfig_step(void){  real_T rtb_Product;  real_T rtb_Switch;  real_T rtb_TrigonometricFunction;
/* Product: '<Root>/Product' incorporates:   *  Inport: '<Root>/In1'   *  Inport: '<Root>/In2'   */  rtb_Product = autoMBD_example_defaultConfig_U.In1 *    autoMBD_example_defaultConfig_U.In2;
/* Switch: '<Root>/Switch' */  rtb_Switch = rtb_Product;
/* Trigonometry: '<Root>/Trigonometric Function' */  rtb_TrigonometricFunction = sin(rtb_Switch);
/* Outport: '<Root>/Out2' */  autoMBD_example_defaultConfig_Y.Out2 = rtb_TrigonometricFunction;}可以看到,原来的全局变量“模型名_B”已经不见了,取而代之的是局部变量“rtb_模块名”。所以可以准确控制模块变量是全局变量还是局部变量,不同的需求下,可能会选择不同的变量形式。信号存储复用的选项还有其他的组合方式,这里不再继续展示,读者可以自行测试验证。单看某一个配置项,似乎没有多大影响。但当模型变得复杂时,某一个配置项能对代码产生非常大的影响。总体而言,信号存储复用的各个选项对代码生成有着较大的影响,特别是代码效率,具体怎么来配置需要更加需求来定。在不清楚各个选项的具体用途情况下,稳妥的方法是全部保持默认配置(全打开),执行效率最高,但可读性和可追踪性较差;如果已经清楚了各个选项的具体作用,则可以根据需求来控制特定的变量生成方式。
3  代码生成的配置方法小结到这里,Simulink代码生成过程中,常用的的配置方法和优化方法已经简单介绍完毕。读者可能更关心的是,如何在实际中使用这些配置选项。但很遗憾,并没有一个固定的定式来回答这个问题。大多数情况下,官方默认配置即可满足要求。但也存在一些需要修改配置的才能实现的需求,这就要具体情况具体分析。实际上除了这些配置选项,还有其他的方法和途径来控制代码生成,例如存储类(Store class),这会在后续的文章中进行介绍。读者或许发现还有一些配置选项没有讲到。文章中主要介绍的是常用到的配置选项,未提及的部分,建议保持默认配置即可。读者也可以自行测试和验证其他的配置选项。读者或许也能发现,上文中讲解的代码生成的各个配置选项,分布有点杂乱无序,没有集中在一起。大部分在Optimization标签下面,但其他标签(例如Simulation target和Interface)下面也存在一些对代码生成有影响的配置选项。对于不熟悉的人,配置时还是会感到困惑。
MathWorks官方或许也发现了这个问题,所以他们提供了一个专门的配置工具来追踪不同的配置选项,这个在下一期中进行介绍,欢迎持续关注哦
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w17.jpg




MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w19.jpg

如果你觉得文章对你有帮助,欢迎关注,我会持续更新更多原创文章

与我交流讨论

由于新开通的公众号均不支持留言,欢迎给我发私信,我会及时回复的
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w20.jpg


版权归autoMBD所有,转载请注明作者和来源。
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化w21.jpg

快速发帖

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|Archiver|汽车工程师之家 ( 渝ICP备18012993号-1 )

GMT+8, 26-11-2024 03:05 , Processed in 0.719042 second(s), 31 queries .

Powered by Discuz! X3.5

© 2001-2013 Comsenz Inc.