嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > Simulink模型生成代码的优化方法

Simulink模型生成代码的优化方法

3. 模型的代码优化方法

文章目录:

  • 3.1 代码优化概述

  • 3.2 代码优化度量标准

  • 3.3 代码优化方法设置

    • 3.3.1 数据初始化

    • 3.3.2 终止代码

    • 3.3.3 整型数据的溢出回环

    • 3.3.4  代数运算异常保护代码

    • 3.3.5 无效的模块

    • 3.3.6 优化变量的使用形式

3.1 代码优化概述

  • 在生成代码时,对模型设置不同的配置选项,会对模型生成的代码产生不同的影响,评价代码优化情况,需要基于以下几个维度思考:

    • 调试性(Debugging)
    • 可追踪性(Traceability)
    • 执行效率(Efficiency)
    • 安全预防(Safety precaution)
  • 调试性指的是调试模型生成代码的编译过程

  • 可追踪性指的是模型和代码之间的映射关系是否易于追踪

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

  • 安全预防指的是代码是否具备防止执行错误的情况发生,例如:除零检查、溢出检查等。安全预防一般与效率是矛盾的,因为安全检查需要消耗存储空间和执行时间

3.2 代码优化度量标准

  • 在生成代码时,可以配置生层静态代码的度量报告:static code metric,报告详细列举了代码量的信息,例如:文件数量代码行数全局变量入口函数等信息
  • 选择不同的代码优化配置选项,生成的代码量是不一样的,通过对比某一优化选项开启和关闭时,代码度量报告的区别,即可了解该优化选项的效果;当然也可以直接对比生成的代码,查看该优化选项的具体作用
  • 打开静态代码度量报告的方法如下所示:
  • 选择 static code metric选项后,生成代码的报告会有个统计页,可以查看生成代码的相关信息

3.3 代码优化方法设置

3.3.1 数据初始化

  • 对于浮点数的零初始化过程,可以配置使用memset()函数,或者直接var=0.0赋值,初始化的数据非常多时,前者会花费更多的存储空间和执行时间
  • 初始化还可以通过:remove initialization code  选择移除零初始化代码,因为一般变量的内存区域初始值已经为零,不需要再初始化,这种配置是最高效的

3.3.2 终止代码

  • 如果终止代码中没有必要代码,通过设置:removing termination code,用来把变量的中止赋值等代码优化掉

3.3.3 整型数据的溢出回环

  • 在数值类型转换计算时,会存在数据溢出情况

例如:将浮点数float 80000.0转换为16位无符号整型数据unsigned short,很显然这里发生了数据溢出,因为16位无符号整型数据最大值为65535;在C语言中,溢出的位会被忽略,只保留低16位数据,float 80000.0转换为16位无符号整型数据的结果为unsigned short 14464

  • 在Simulink中,常会使用数据转换模型来实现数值转换,有些配置选项会添加软件处理过程,来保证这个过程的正确性
/* Model step function */
void float2int_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);
}
  • 一个简单的数据类型转换,被生成了多个操作,这部分的代码是不必要的,去掉的方式如下
  • 配置移除数据回环代配置选项后,生成的代码如下:
/* Model step function */
void float2int_step(void)
{
  /* Outport: '<Root>/y' incorporates:
   *  Constant: '<Root>/Constant'
   *  DataTypeConversion: '<Root>/Data Type Conversion'
   */

  float2int_Y.y = (int16_T)floor(float2int_P.Constant_Value);
}