首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐
2025年6月4日 星期三 2:02am

Simulink代码生成: Optimization配置

  • 23-09-22 00:45
  • 4739
  • 6371
blog.csdn.net

本文研究Embedded Coder中的Optimization配置,通过一些模型示例和代码直观地比较配置对代码生成的影响。由于配置选项很多,本文会长期更新。

文章目录

  • 1 Optimization配置
  • 2 Default parameter behavior
    • 2.1 描述
    • 2.2 模型示例
    • 2.3 生成代码
    • 2.4 分析与思考
  • 3 Pass reusable subsystem outputs as
    • 3.1 描述
    • 3.2 模型示例
    • 3.3 生成代码
    • 3.4 分析与思考
  • 4 Remove root level I/O zero initialization
    • 4.1 描述
    • 4.2 模型示例
    • 4.3 生成代码
    • 4.4 分析与思考
  • 5 Remove internal data zero initialization
    • 5.1 描述
    • 5.2 模型示例
    • 5.3 生成代码
    • 5.4 分析与思考
  • 6 Use memcpy for vector assignment
    • 6.1 描述
    • 6.2 模型示例
    • 6.3 生成代码
    • 6.4 分析与思考

1 Optimization配置

Optimization配置中包含了代码生成的优化选项。在Simulink配置窗口的Code Generation下可以找到Optimization配置。
在这里插入图片描述
后文会研究Optimization配置中的一些常用选项。

2 Default parameter behavior

2.1 描述

该配置直译过来是“默认参数行为”,其含义是,生成代码时常量参数的形式。

该配置中包含两个选项:Tunable和Inlined。如果选Tunable,意为可调式,生成的代码就会以StorageClass中的Auto类来表现常数参数。如果选Inlined,意为内联式,会把参数“内联”到代码中,表现为直接的数值。

配置中默认为Inlined。
在这里插入图片描述

2.2 模型示例

打开Simulink,建立一个简单的带有Gain模块的模型。
在这里插入图片描述
将Gain模块的增益系数写为3.观察后续这个系数在代码中的表现方式。
在这里插入图片描述

2.3 生成代码

1)当Default parameter behavior选为Tunable时,生成的代码如下:
在这里插入图片描述
可以看出,输入变量乘以一个系数demo_P.Gain_Gain。这个变量在demo_data.c中定义。
在这里插入图片描述
2)当Default parameter behavior选为Inlined时,生成的代码如下:
在这里插入图片描述
这里可以看出,系数直接写成了3.0F这个浮点数。也就是说,把Gain参数“内联”到代码中了。

2.4 分析与思考

比较两种代码生成的方式,显然是Inlined更好。这是因为将参数生成全局变量会占据芯片的RAM资源。

在企业级项目中,每个模型都可能有数十个这种常量,广泛地存在于Constant,Gain等模块中。如果这些常量占据了大量的RAM资源,就可能会导致链接过程中出现资源溢出。

3 Pass reusable subsystem outputs as

3.1 描述

这个配置项影响了可复用子系统的输出生成的代码。

下拉框包含两个选项。默认的是Individual arguments,指的是输出为局部变量。还有一个选项是Structure reference,他会生成一个全局结构体变量,然后可复用子系统对应的函数会调用这个结构体的指针。
在这里插入图片描述

3.2 模型示例

建立如下图模型,将两个完全相同的子系统配置为原子子系统以及可复用函数。这样模型就符合这个配置项的场景了。

原子子系统内随便什么模型都可以,这里用了个比较简单的Gain模块。
在这里插入图片描述

3.3 生成代码

1)当Pass reusable subsystem outputs as这个配置选为Individual arguments时,代码生成如下:
在这里插入图片描述
可以看出,在只有一个返回值的情况下,子系统所对应的函数直接把计算结果返回。在step函数中直接把结果赋值给Out1或者Out2。

因为模型比较简单,在step函数中把局部变量优化掉了。如果比较复杂的模型会把demo_Subsystem的结果先赋值给一个局部变量,然后参与后续的运算。

2)当Pass reusable subsystem outputs as这个配置选为Structure reference时,代码生成如下:
在这里插入图片描述
可以看出函数复杂了一些。首先是生成了一个结构体的全局变量demo_B,这里面存的是子系统的输出值。然后子系统对应的函数,用了个结构体指针获取返回值。

再看看下图中的Step函数:
在这里插入图片描述
step函数是先用demo_Subsystem这个函数更新了全局变量结构体里的成员,然后再把成员变量的值赋值给Out1或Out2。这样,在这个过程中就没有局部变量了,而是多了全局变量。

3.4 分析与思考

正所谓鱼和熊掌不可兼得,这两种方式就是对局部变量和全局变量的取舍。多生成一些全局变量,就用Structure reference,多生产一些局部变量,就用Individual arguments。

博主根据个人经验认为,汽车ECU软件一般已经用了很多全局变量,包括模型输入输出接口和观测量等都是全局变量。所以全局变量占据的RAM资源是比较稀缺和紧张的,这里按照Simulink默认的Individual arguments配置比较好,也就是多生成些局部变量。

而且,从代码复杂度的角度来说,也是Individual arguments配置更优。

4 Remove root level I/O zero initialization

4.1 描述

这个配置决定了生成的代码在initialize函数中是否有对根路径输入输出的零初始化。
在这里插入图片描述

4.2 模型示例

模型其实很简单,只要根路径下有个输入输出的模块就行。

4.3 生成代码

当不勾选Remove root level I/O zero initialization的时候,会在初始化函数中将输入输出模块的变量初始化为0.
在这里插入图片描述
当勾选Remove root level I/O zero initialization的时候,初始化函数中不会有对输入输出的零初始化。
在这里插入图片描述

4.4 分析与思考

个人认为这一项可以勾选,也就是说不在初始化函数中将输入输出初始化为零。

因为在ECU中,我们生成的函数不断地被OS调度,每个采样周期都会赋给新的数值,而大多数时候不会关注他们的初始值。对于需要定义初始值的信号,一般也会在模型中做好初始化的子系统,以保证某个信号生成代码的时候赋给特定的初值而不是零。

所以没有必要生成零初始化,这样也能减少一些Flash的占用,提高代码生成效率。虽然微不足道。

除了一种特殊的情况,如果控制器因为某种原因,复位后没有将RAM中的数值清零。这时候就需要这部分的初始化函数。

5 Remove internal data zero initialization

5.1 描述

这个配置决定了生成的代码在initialize函数中是否对内部变量进行零初始化。
在这里插入图片描述

5.2 模型示例

内部变量的类型有很多种,这里用一个Unit Delay为例。由于Unit Delay实现的是一个延时效果,所以生成的代码会通过一个全局变量来存储上一个周期的数值。这个全局变量就是一种内部变量。建一个简单的模型如下:
在这里插入图片描述

5.3 生成代码

当不勾选Remove internal data zero initialization的时候,会在初始化函数中将Unit Delay模块内部的全局变量初始化为0。下图中用了一个memset函数。
在这里插入图片描述
当勾选了Remove internal data zero initialization的时候,初始化函数中就不会把Unit Delay模块内部的全局变量初始化为0。
在这里插入图片描述

5.4 分析与思考

同4.4一样,博主也认为这条可以勾选。但是还是要根据实际项目需求来看,因为博主也只是基于自身项目团队的经验所得出的结论。

6 Use memcpy for vector assignment

6.1 描述

该选项控制生成代码时,是否用memcpy函数代替for循环对数组赋值。
在这里插入图片描述

6.2 模型示例

在模型中构建出Vector信号,在生成的代码中就会有数组的赋值操作。搭建如下示例模型:
1)在空白的Simulink中搭建一个Inport模块、一个Selector模块和一个Outport模块。
在这里插入图片描述
2)将Inport模块的Dimension配置为[1X100],Output DataType配置为int32。
在这里插入图片描述
3)将Selector配置如下,表示取出输入信号的前50个元素。
在这里插入图片描述
4)仿真模型后,显示出Vector信号的长度以及数据类型。
在这里插入图片描述

6.3 生成代码

1)当勾选上Use memcpy for vector assignment时,生成的代码如下:
在这里插入图片描述
很容易看出,step函数中用了memcpy函数对输出Out1的数组进行赋值。

2)当取消勾选Use memcpy for vector assignment时,生成的代码如下:
在这里插入图片描述
可以看出,step函数中用了一个for循环对输出Out1逐个赋值。

6.4 分析与思考

通过memcpy对数组赋值会比用for循环的方式执行速度更快,所以勾选这一项比较合理。

注:本文转载自blog.csdn.net的chhttty的文章"https://blog.csdn.net/u013288925/article/details/106695439"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top