该图片显示了一个具有多个分层子级的复杂Stateflow模型。
图片:具有多个分层子级的复杂Stateflow模型

如何通过建模规范轻松掌控Stateflow开发

在基于模型的开发(MBD)中,Stateflow是一款功能强大的工具,尤其是在汽车等对状态机和复杂逻辑的精确控制要求极高的行业中。然而,要高效应用Stateflow,必须克服一些常见的挑战,例如语法问题以及性能优化方面的考量。

在本文中,我们将探讨来自MES模赛思调查报告中的关键洞察,并提供可操作的优化建议,助您优化Stateflow模型的性能、可靠性和可维护性。

行业专业人士如何使用Stateflow:调查报告

该图片显示了受访者在其模型中使用Stateflow比例的调查结果。
图片:受访者在模型中使用Stateflow的比例

Stateflow在基于模型的开发(MBD)中的应用程度

为持续了解行业实践,我们于2022年联合来自梅赛德斯-奔驰集团博世集团大陆集团等企业的30位专家开展了聚焦Stateflow的专项调研。

我们首先询问这些从事基于模型的开发(MBD)工作的专业人士是否使用Stateflow。

如下方柱状图所示,大多数用户在其20%到50%的模型中使用了Stateflow。

该图片显示了在调查参与者中主要使用C语言或MATLAB语言作为动作语言的比例。
图片:受访者使用哪种动作语言(Action Language)?

Stateflow首选动作语言

我们提出的第二个问题是关于用户使用的动作语言(Action Language)。

如下方饼图所示,多数用户更倾向于使用MATLAB而非C语言进行动作脚本编写。

这一结果反映出MATLAB的简洁性,并且能够更好地实现与Simulink生态系统的集成。

该图片显示了受访者在使用Stateflow时最常遇到的困难。
图片:受访者在使用Stateflow时遇到的困难

使用Stateflow时遇到的常见障碍

第三,我们询问了受访者在使用Stateflow时遇到的挑战。

最常见的障碍是缺乏相关知识(Lacking knowledge),值得注意的是,相当一部分用户表示完全没有遇到困难(None)。功能缺失(Missing features)是最少被提及的问题,这表明:通过加强培训和完善文档,可以帮助用户更好地克服在使用Stateflow时遇到的困难。

此图片显示了受访者在Stateflow中执行算术运算的情况。
图片:受访者在Stateflow中使用算术运算的情况

使用Stateflow进行算术运算

第四个问题涉及是否使用Stateflow进行算术运算。

调查结果显示,56%的受访者对此表示肯定。这凸显了Stateflow的多功能性,表明其能够处理汽车系统中常见的复杂运算。

该图片显示了受访者最多使用的元素和模式。
图片:Stateflow元素和模式的使用情况

最常用的Stateflow元素/模式

最后,我们调查了受访者最常用的Stateflow元素和模式。

调查结果显示,各类元素的使用分布整体较为均衡。其中,状态图(Statecharts)和条件动作(Condition actions)的使用率略高,而框(Boxes)的使用率最低。

这表明受访者更倾向于采用结构化、基于条件的建模方式,特别是在系统中实现决策逻辑时。

关键发现

我们的调研再次证实,Stateflow已成为基于模型的开发(MBD)专业人员工具链中的重要组成部分。然而,调查结果也揭示了用户在使用Stateflow的过程中面临的若干挑战。

基于这些反馈,MES模赛思团队梳理出了常见痛点与改进方向。接下来,本文将深入剖析这些挑战,并提供最佳实践方案,助力提升Stateflow建模的效率与可靠性。

在使用Stateflow进行基于模型的开发(MBD)时面临哪些挑战?

使用Stateflow进行基于模型的开发(MBD)虽功能强大,但同时也存在影响可维护性和开发效率的挑战。主要困难包括:

  • 复杂性增加:随着状态转移数量的增长,管理它们变得更加困难。
  • 可扩展性问题:状态机可能会迅速扩展,使模型变得更难阅读和维护。
  • 语法限制:为了确保一致性并防止错误,必须遵循严格的语法规则。
  • 设计要求高:必须采用结构化的方法,并以规范化的方式使用Stateflow,以避免出现意外行为并提升模型的清晰度。
该图片显示了一个正确的转移标签语法示例。
图片:转移标签的正确语法示例

掌握Stateflow的十大策略

1. 确保转移标签语法正确

在Stateflow中使用正确的转移标签语法,既能提升模型的可读性、可维护性和可预测性,又有助于在TargetLink等工具中生成准确的代码。结构化的方法有助于创建清晰、可靠且易于维护的模型。

首先,让我们对转移标签各部分的含义进行分解和解释:

  • 事件(Event):指定触发状态转移的事件。
  • 条件(Condition):指定一个布尔表达式,当其为true时,允许执行该转移。
  • 条件动作(Condition Action):当条件被评估为true时立即执行的动作。
  • 转移动作(Transition Action):在条件满足且转移目标被判定为有效后执行。

如下展示了一种可能的语法。

其格式为:trigger [condition] {condition_action} /transition_action

需要注意的是,并不一定需要使用以上所有。通常建议避免使用事件(Event),而优先使用条件(Condition),因为这种方式更为标准。此外,应在条件动作(Condition Action)或转移动作(Transition Action)间做出选择。

该图片显示了可能导致错误的历史结点,该处标有 “H ”符号。
图片:可能导致错误的历史结点

2. 遵循安全建模语言子集

基于建模规范:mes_slsf_3110 | misra_slsf_047_ab | misra_slsf_046_a

应避免使用历史结点,因为它们可能导致:

  • 导致模型解释错误。
  • 验证流程复杂化。
  • 隐藏功能,使系统更难理解和维护。

下图展示了以H符号标识的历史结点,这可能引发上述问题。

还应避免使用事件(Events),因为它们可能:

  • 导致递归问题。
  • 造成非预期功能。
  • 隐藏功能,导致模型难以理解和维护。


哪些Stateflow动作规范是安全的?

建议选择一种动作类型(条件动作、转移动作或状态动作),并在整个模型中保持一致。

该图片显示了在条件或转移动作过程中修改变量,可能出现非预期行为。
图片:在条件或转移动作中修改变量可能导致错误

3. 正确使用条件动作和转移动作

基于建模规范:misra_slsf_045_e | misra_slsf_045_f | misra_slsf_045_g

避免在条件动作和转移动作中写入变量:在条件动作或转移动作中修改变量可能导致非预期行为,并增加调试难度。

该图片显示了在后续转移中读取之前转移动作中被修改的变量,可能导致执行不一致。
图片:在转移动作中读取被修改的变量可能导致执行不一致的情况

避免在后续转移中读取由转移动作写入的变量:在转移动作中被修改的变量不应在后续的转移中被读取,否则可能导致执行顺序不一致。

该图片显示了为保持可预测的行为,一个变量在状态之间转移时应仅由单个转移动作进行修改。
图片:为保持可预测的行为,一个变量在状态之间转移时应仅由单个转移动作进行修改

单一转移动作写入:为保持可预测的行为,一个变量在状态之间转移时应仅由单个转移动作进行修改。

该图片显示了跨越并行状态边界的转移的例子。
图片:跨越并行状态边界的转移

4. 避免在Stateflow中出现交叉转移

基于建模规范:mes_slsf_3109

为了保持清晰性并防止图形重叠,应避免在Stateflow图中使用跨越状态边界的转移。交叉的转移会使图表难以阅读,从而增加误解和错误的风险。

此外,布局杂乱会使调试和维护变得更加复杂,使得跟踪执行流程更加困难。通过对转移进行合理组织并保持路径清晰,可以提高模型的可读性、可维护性以及整体可靠性。

在下图中,可以看到明显的跨越并行状态边界的转移。避免这类交叉非常重要,因为它们可能导致混淆和潜在的建模错误。

5. 避免在浮点数中使用相等运算符

基于建模规范:jc_0481 | mes_sltl_002

应避免使用以下相等比较运算符比较浮点数:

  • ==
  • !=
  • ~=
  • <>

由于浮点数采用二进制表示,通常会产生微小的舍入误差,因此精确比较不可靠。这可能导致错误的结果,因为两个在数学上相等的值在内存中可能存在微小差异。因此,对于浮点数来说,不建议使用硬等值比较(严格逐位比较)。

该图片显示了一个Stateflow中回溯导致问题的示例。
图片:Stateflow中回溯导致问题的示例

6. 避免在Stateflow中出现回溯

基于建模规范:mes_sf_002 | misra_slsf_043_h

Stateflow不支持回溯。这说明所有已执行的动作均保持有效,无论转移路径是否达到预期的最终状态。如果某个转移路径未能到达有效的结束状态,可能会导致非预期的行为。

为了避免这样的问题,应确保每一个转移路径包括一个无条件的默认路径。此外,应仅在转移的最后一段使用条件动作,或改用转移动作。

(如第三节所述,选择使用转移动作是有充分理由的。)

请见以下回溯问题示例:

该图片显示了添加Event1如何改变转移顺序,以及为什么建议手动控制。
图片:添加Event1会改变转移顺序,因此建议手动控制

7. 遵循设置执行顺序的最佳实践

基于建模规范:mes_is_0002

在Stateflow中,执行顺序通常按照顺时针方向定义,尤其是在并行状态中。即使是对图形布局的细微调整,或新增一个元素,都可能导致执行顺序发生变化。

下图展示了在Stateflow图中引入一个新的事件(Event1)后,转移的执行顺序如何发生变化,强调了手动指定执行顺序的重要性。

该图片显示了推荐的Simulink设置,以保持Stateflow函数的局部性并避免全局导出,从而简化追踪和数据流。
图片:避免选择“允许Simulink调用导出函数”选项

8. 避免使用全局Stateflow函数

基于建模规范:mes_slsf_3106

将Stateflow函数在各自的图中本地定义是保持模块化并防止产生非预期交互的推荐方法。

使用“导出图表级函数(设为全局)”功能可以使图形函数在模型的任何图中被全局访问。然而,这些函数难以追踪(仅能通过搜索函数名称查找),并且会导致行为不透明。

此外,启用“允许Simulink调用导出函数”(自R2014b起可用)会增加函数管理和数据流方面的复杂性,因此不建议启用该选项。

该图片显示了Stateflow中的递归循环,函数func1与func2相互调用,导致无限递归。
图片: Stateflow中的递归循环,函数func1与func2相互调用,导致无限递归

9. 避免递归循环

基于建模规范:jc_0804

确保Stateflow中的图形函数既不以递归方式定义,也不调用其他图形函数,对于防止非预期行为并保持模型的完整性至关重要。递归调用可能导致无限循环、栈溢出,并增加调试和维护的复杂性。

下图展示了Stateflow图形函数中的递归循环问题。当执行func1(x)时,它会调用func2(x),而func2(x)又调用func1(x),从而形成无限递归。为避免此问题,建议在Stateflow图形函数中避免直接或间接的递归函数调用。

该图片显示了dSPACE的TargetLink Property Manager界面。
图片:dSPACE的TargetLink Property Manager

10. 明确定义输入变量以实现无缝集成

在使用TargetLink、Simulink以及Stateflow时,明确定义输入变量对于维持接口的一致性和良好的结构十分重要。来自dSPACE的TargetLink Property Manager(如下图所示)能够帮助管理这些变量定义,确保模型与最终实现之间的一致性。

总结:通过建模规范管理Stateflow的复杂性

Stateflow为用户提供了强大的建模功能,但如果使用不当,也可能带来风险。

为了更好地管理复杂性,请遵循以下最佳实践:

  • 保持简单!避免在转移和状态逻辑中引入不必要的复杂性。
  • 在Simulink中执行算术运算:否则,图表可能会变得过于庞大而难以控制。
  • 遵循既定的建模规范,以避免出现非预期行为和容易出错的模式。
  • 保持布局清晰且结构化,提高模型的可读性和可维护性。
  • 使用MES Model Examiner® (MXAM)等工具,自动化检查模型是否符合建模规范。

通过遵循这些最佳实践,可以构建稳健、高效且易于维护的Stateflow模型,并实现与Simulink和TargetLink的无缝集成。

如果您希望获取更多关于基于模型的开发(MBD)的文章、网络研讨会、研究项目等资源,欢迎您访问MES模赛思博客。随时获取最新信息,提升专业能力,轻松实现优质建模!

联系我们

本图片是Elena Bley的肖像照。
Elena Bley
Senior Manager (Webinars & Training)

*必须填写

Please add 9 and 6.