LICENCE: 本文根据《JMAAB V4.01》部分章节进行翻译和整理,文中只是针对MBD开发方式描述了模型架构的纲要和观念。由于Simulink提供了多种可以满足需求的模块及建模方法,所以很难进行详尽的描述说明,翻译和整理由Tomato一人完成,欢迎来知乎探讨。
所有的系统都可以使用Simulink或Stateflow进行建模。
如果使用Stateflow进行建模,Simulink仅仅作为信号的输入输出和仿真,在Stateflow中可以使用多种公式和方法来替代simulink进行处理。如果只用Simulink,可以通过使用Switch-Case块的方法来替代Stateflow实现复杂的状态变量。
因此,使用Simulink或Stateflow对于特定部分的建模,是主观依据开发人员对于哪种表达方法更为理解。应该根据整体的团队水平来实现如上选择和建模。
在大多数情况下,Stateflow的RAM效率要比Simulink差。因此,Simulink在使用简单公式的计算中具有优势。除此之外,Simulink在使用简单的触发和切换系统中,对于状态变量的使用也更具有优势。当使用Stateflow所建的模型可以用Simulink进行替代建模时,需要考虑如下因素进而做出决定:
确保静态RAM足够大,以保证Stateflow 的输入输出以及内部变量的正确运行。
当使用内部通用计算公式时,要设计防溢出的保护。
当外部计算完成时,需要对整体进行分块,以降低这个模块的理解难度。
在一些情况下,Stateflow能够比Simulink进行更接近于C语言的表达方法,但是这样的模型没有很好的外观状态,并不是很容易理解。在这些情况下,使用S-Function会更有利。
Stateflow 可以计算特定的状态安排,或进行for-loop的计算,在这些层面上要比Simulink更有效率,但是近些年来,使用Matlab语言进行如上计算,也变得更有效率一些。
当使用Simulink进行建模时,如果处理如下所述的状态,则可通过使用Stateflow来改善可读性。
同一个输入有不同的输出值
多个状态存在 (例如3个及更多)
对于定义的一个状态的意义,不是无限的值而是一个离散的数值。
在状态内部,要求初始化(首次执行)和后面的 执行状态期间有所不同。
除了状态变量,输入和输出变量是可以被可视化的信号.
举个例子,在触发器电路中,不同的输出对应于同一个输入。而且,状态变量的值被限定在0和1。然而,在输入输出都为0或1的情况下,仍可以有无限多的状态分类。此外,在状态进入和执行两个动作间没有区别。换句话说,上诉几条中仅仅符合第一条,所以这时候应该使用Simulink进行建模。
关于采用Simulink还是Stateflow进行建模可以和几个人进行沟通协商,并最终取决于需要解决的实际问题。Stateflow中是采用状态转换还是 流程图函数也需要进行考虑和决定,例如需要 定夺 使用 状态的转换和条件分支来 替代 使用状态的流程图函数。真值表也被分类为使用条件分支当中的方法。
此外,当使用Stateflow进行如上设计时,需要依据经典的模型样式进行设计,以便于能够更好的生成嵌入式代码。
Stateflow支持生成HDL代码。在实现HDL编码器时,应使用Mealy和Moore模式。此外,当需要对内部泄漏进行保护时, Moore 模式更适合。
需要注意,本指南不是针对HDL代码生成。
如下示例了模型分层中分割和布局的观念,可作为开发中的参考。这并不是一个明确的规则,但这是一个建模的基础方法。
搭建层的方法
如果主要目的为调整一层的空间排布,则应尽量避免打包到子系统
如下为层次的概念,子系统需要依据此描述进行分层
不要使用多余的层
一层模型中,允许复合层的建模概念
层概念
名称 |层概念 | 层目的
-------|-----------|------------
顶层 |功能层 |大块功能部分
|调度层 |执行时间的表达(采样、顺序)
底层 |子功能层 |功能的细节表达部分
|控制流层 |根据处理和执行顺序划分(input → judgment → output,等)
|选择层 | (select output with Merge block) 切换相应被激活的子系统并且执行
|数据流层 |用于不可分离计算的层
对于顶层划分,主要有如下三个方法
简单控制模型
表现为功能层和调度层在同一层中,在这样的模型里,功能 = 执行单元。
例子:控制模型只有一个采样周期,并且各功能模块都按照执行顺序进行排列。
复杂控制模型 α
调度层放在最顶层
这样会使手写代码更容易集成,但是功能模块被分割,导致模型可读性降低。
复杂控制模型 β
功能层放在最顶层,并且调度层在各功能模块下进行构建。
根据功能划分子系统,每个子系统代表“一个独立功能”
对于执行单元,“一个独立功能”的子系统是不必要的。因此,各子系统不一定全都设为原子子系统。
(对于如上列出的 type β, 将功能层子系统设为虚拟子系统更合适一些。如果将他们设为原子子系统,则可能会出现代数环。)
使用注释,功能概述必须在图层上描述或包含在子系统概述中,并显示为注释。
如果模型里有几个大的功能模块,则需要考虑使用模型引用。
需要设置周期间隔和优先级及顺序。
设置多个周期间隔需要注意
在不同周期的连接系统中,有可能发生信号变量会在快周期任务中被调用,此时在慢周期中该信号还没有被计算出来。当不同周期进行连接时,需要一块固定的RAM区。因此,需要在顶层为每个不同周期的任务进行进行时间分割,保证底层中没有不同周期的模块进行连接。
设置优先级
在设计多个不同功能的系统时,优先级设定十分重要。建议尽量根据连接的顺序来使系统自动确定运行顺序。
对于顺序优先级,如下项需要进行设定:不同周期的优先级,和同周期的优先级。
周期间隔和优先级的设定方法:
如下描述的方法可大体上分为2种类型。
子系统或模块的执行周期时间和优先级设置。
使用条件子系统,用户设置独立的排列顺序来匹配任务调度。
几个条件下存在的模式,例如配置单速率或多速率,原子子系统设置,是否使用模型引用等。这其中启用哪个功能都会直接影响到生成的C代码,所以需要根据项目的不同情况进行综合考量。
受影响的典型因素如下:
模型方面上
是否存在不同的采样时间?
模型是否需要实现几个独立的功能?
使用模型引用
模型数量 (Simulink是否会生成多个源代码)
源代码方面上
是否使用实时操作系统
实际采样周期和理论计算周期的一致性
适用范围 (应用层或基础软件)
源代码类型:是否符合/支持 AUTOSAR .
RAM, ROM 特别是RAM剩余百分比
进行如上考量后,将会对使用的样式进行调整。
控制层是用于表示所有输入处理、中间处理、和输出处理的层。模块和子系统的排列十分重要。将多个混合的小功能分组,最后排列成3个大组,包括:输入处理,中间过程处理,输出处理。这三个大组构成了控制层的概念基础。与数据流层相似的排列方法是,都使用水平线代表模块运行顺序和方向,与其不同的是控制流层大多是由复合模块和子系统构成的。
在控制流程,同一水平线上的根据箭头所指方向进行顺序处理,同一垂直方向的代表有相同的优先级。
可以使用Area工具进行框选并标注几个模块的部分
控制层可以和具有功能的模块共存。
这些模块放置在子功能层和数据流层之间的区域。
当模块的数量特别多,且都在数据流层进行使用,这时可以使用功能单元打包的方式进行控制层的整合。这样会使模型更容易理解,同时提高了模型的可维护性。
即使仅由模块构成,不存在子系统和模块的混合体,如果模型的水平方向结构能够划分成 输入/中间过程/输出 处理,这样也可以称作为控制层。
选择层可以垂直或水平方向构建。(There is no significance to which orientation is chosen)
选择层是和控制层进行混合而成。
下图红色框内,根据条件只有一个子系统能够运行,所以这被称作为选择层。这层模型虽然能够被划分成 initial processing/intermediate processing (conditional control flow)/output processing这三个处理模块组,但是称为控制层并不恰当,因为在控制层,水平方向代表不同的处理,并且具有相同优先级的并行处理在垂直方向上进行排列。而在选择层,垂直方向上的并不一定是并行处理,而是每次仅选择其中一个进行运行。
例子:
Switching of coupled functions between running upwards or downwards, changing in chronological order.
Switching to setting where the computation switches after the first time (immediately after reset) and second time.
Switching between destination A and destination B.
数据流层是在选择层/控制层之下的一层。
当仅表现为一个功能,并作为输入/中间过程/输出处理的具体实现,且不能再进行划分,则这样的一层被称作为数据流层。举个例子,一个持续计算不能被分割的系统。除一些特殊情况下,数据流层不允许出现子系统。
特殊情况:如下情况允许在数据流层出现子系统。
子系统被设为重用子系统。
Simulink 标准库里存在的子系统。
用户自定义库中存在的子系统。
简单数据流层 例子
复杂数据流层 例子
当遇到输入处理和中间过程处理不能够清晰进行划分的时候,就如上面的例子所示,展开为数据流层。
当同时计算一个信号的前端反馈和后端反馈时,数据流层会变得复杂。甚至此种情况会有很多模块在同一层, 但是为了清晰的表达计算,仍旧不能在数据流层进行子系统的创建。当能够通过划分模型进行整合的时候,应该被打包成控制层而不是数据流层。
在真实的嵌入式系统中运行,需要Simulink模型生成嵌入式C代码。这有很大一部分受到Simulink配置项的影响,根据Simulink针对相关功能进行何种程度的建模,以及如何嵌入和真实系统的时间设定。
如果嵌入式系统里使用的任务与Simulink模型里调度的任务不同,这将产生很严重的影响。
本文中,并不对AUTOSAR标准进行解释,而会说明AUTOSAR的概念。用户不必完全符合AUTOSAR标准,但必须了解它,并作为建模中的参考。
当设计一个控制模型的时候,必须要遵循AUTOSAR 软件平台的概念,并要审查所设计的模型是归类到应用软件还是基础软件。
如果模型混合了应用和基础软件,需要在设计阶段就进行划分。
AUTOSAR 软件平台概念
高容量,低速,常规的处理在应用软件层
高速,非常规驱动的处理在基础软件层
AUTOSAR软件平台如下图所示
举个例子,设计引擎控制模型的时候,不建立以中断执行任务方式的模型,而是在应用软件层计算所有气缸共享的变量。例如,计算当前排放状态或目标力矩。当不规则中断从基础软件区发生,通过RTE传递到应用层时,计算结果能够被调用,实际的驱动器也能够被激活。AUTOSTAR的概念使得基础软件区的通用计算能够尽可能简单的放到应用层。
当Simulink模型全部构建好之后, 建议在中断服务区添加尽量简单的计算。中断服务程序的简单可以减少其所占时间,这样能保证系统调用任务时间间隔的准确性。如果可以,中断中不要包含标准的PID计算,推荐放置仅执行设定动作的函数。当然,不能缺少必要的计算。举个例子,对于错误诊断,即使是复杂计算,在该执行的时刻还是必须要诊断出结果的。
对于那些比中断服务程序慢的部分,和接收指令要比执行速度快的部分,不应该给出直接执行的代码,而是要让目标值或阶段值在下一个命令到来之前,通过线性插值的方法传递出去。
使用RCP等设备建模类似于AUTOSAR中软件更新的概念。当然,生成的代码不符合AUTOSAR规范。例如,RCP的I/O软件允许供应商提供的S函数进行链接,并且允许用户设置应用程序区域。应用程序中用户自定义函数和S函数能够在Simulink中直接连接,不需要考虑对RAM等因素的影响。
生成的C代码在实时操作系统上运行,Simulink 里I/O相关会生成在不同的源代码文件中,实时操作部分和作为中断处理的部分会自然分离。用户不必考虑那些平台;厂商创建的 I/O S-function会在需要的时候运行,并且对于 应用程序建模,不用考虑I/O处理的内容和时间。
具有这种软件结构的真实的控制模型/软件,会有更多的优势。由于RCP能够集中精力开发应用程序,而不必考虑软件结构,他们会自然的选择AUTOSAR 平台。换言之,如果你的产品不满足AUTOSAR 标准,并且在RCP上使用AUTOSAR的概念进行开发,你必须自定义生成的代码,并且从MBD开发成果的共享中分离出来。
嵌入式软件调度器设计中,有单任务和多任务的概念。
对于单任务,假定基础周期为2ms,当2ms、8ms、10ms在系统中存在时,这些时间片都是基于2ms的计时器进行创建的。每2ms的执行顺序为:8ms的任务下每4个2ms任务后执行一次,10ms就是每5个2ms。需要注意的是,要使用低频率的任务片来处理复杂的运算,并且2ms、8ms、10ms都是由相同的2ms进行周期计算。因为所有的运算都要在2ms内完成,以便保证嵌入式软件的实时性,在这种情况下8ms和10ms的任务被分割成了几段,以保证所有2ms的计算量基本持平。在这种方法下,可以通过分区来减少每个周期的计算量,并且使得CPU负载平均分配。
基于如上原因,10ms的任务片被分成如下几个部分。
|Fundamental frequency |Offset |
|---------------------- |-------|
|10ms |0ms |
|10ms |2ms |
|10ms |4ms |
|10ms |6ms |
|10ms |8ms |
同理可知,8ms的任务片被分割成了4部分。
当然,绝对的平均分配是不现实的,某些运算功能不能够被分配到所有周期,但重要的是报保证CPU的平均一致的负载率
如何设置任务的运行频率
设置Tasking mode for periodic sample times 为 Single Tasking
然后在子系统的“Sample Time”中输入 “sampling period, offset” 的值。可以指定运行周期的子系统为 原子子系统。
多任务为使用实时操作系统的情况下,系统支持多任务周期设定。如之前介绍单任务中所述,在单任务系统中,平衡CPU负载率不是自动的,需要进行巧妙的设定。而在多任务系统中,CPU会根据当前状态进行自动计算,并且不需要进行特殊的任务分配和设定。系统会从优先级高的任务开始计算并给出结果,任务的优先级由开发人员进行设定。大多数情况下,需要快速执行的任务被分配高的优先级。
在周期内完成计算是十分重要的,包括慢任务,和当高优先级任务执行计算且CPU 释放时,执行下一个优先级任务的计算。高优先级任务会打断低优先级任务,并会先执行完高优先级的计算。
如果子系统B有20ms的运行周期,使用了10ms运行周期的子系统A的输出,当B还在进行计算的时候A可能会有不同的输出。如果在运算过程中发生了值得改变,子系统B可能会运算出一个错误的结果。举个例子,在B中如果存在首次计算值与A的输出比较的运算,且最终输出依据比较的结果,此时有可能发生在B计算过程中A的值发生改变,导致最终输出不正确的情况。为了避免此种情况发生,如果任务主体发生改变,从A得到的输出值需要在被B使用之前进行固定。换言之,即便在B运算过程中A的输出值发生改变,因为调用了不同的RAM区,最终的计算结果也不受影响。
当在Simulink中创建模型并且在Simulink中连接了具有不同运行周期的子系统时,Simulink会自动保留所需的RAM。
当然,如果不同运行周期的输入值获得是通过 手写代码集成的方式,则相应嵌入式软件工程师需要进行相应RAM区保留的设置。在AUTOSAR中的RTW层,就是在接收和发送出口方面都定义了了不同的RAM。
单任务
2ms循环内信号值相同,但是需要注意不同的2ms运算值和上一个2ms的值可能不同。如果2-1 、 2-2 使用了F 1中的信号A,则 2-1 、 2-2 会使用不同2ms任务计算出的值,此处要进行影响识别。
多任务
对于多任务,不能够指定使用计算结果的时间点。在多任务系统中,无论是否为不同运行周期,总是需要给信号变量和传递变量分配不同的RAM。
在执行任务的新计算之前,所有的值都会一次性复制一遍。
版权声明:本文为知乎「Tomato」的原创文章,已获作者发表许可。
推荐阅读
谈谈Bootloader自更新
谈谈对两家AUTOSAR工具看法
奥迪首款800V车型技术总览
CAN设计与应用指南
汽车软件需求是如何变成用户功能?
电子电气架构设计需要考虑哪些方面?
汽车E/E架构的网络安全分析
电子电气架构设计需要考虑哪些方面?
分享不易,恳请点个【👍】和【在看】