打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
MBD建模中关于调度(Scheduler)方式的讨论
自我简介
姜辛,身高不足180,体重超过180的胖子;自工作至今一直在沿着基于模型的开发路线行进,基于Simulink开发过纯电动控制、混合动力控制策略,EMS发动机管理系统,BMS电池管理系统。对Simulink建模方法,代码生成相关的技术一直很有兴趣。目前在与几位兄弟一起创立的公司(澳特卡新能源)里做新能源汽车三电控制系统开发。欢迎从事基于模型的电控开发同道一起交流。


首先感谢老董给机会邀我写篇关于Simulink模型化开发的分享小文,非常荣幸。

基于Simulink的模型化 自动代码生成的开发方式,在汽车电子行业正在逐渐演变成开发的标准配置。采用模型化的方式来描述控制算法,无论是可读性、可维护性、可移植性、测试验证的便利性等方面,相比于从前手工C代码都有长足的进步。说Simulink Coder是推动人类进步的又一重要阶梯应不为过。

Simulink本质上也是门编程语言,只是用可视化的框图和连线方式替代了原来的程序语句,降低了编程门槛。即使没什么C代码经验的新手工程师,用不了几天也能上手。不过虽然是图形化建模,但最终还是要到生成代码的层级,手工代码时的架构和技巧在这里并未消失,只是换了个面貌存在,一般的编程概念和技巧在模型化开发中仍然非常有用。对于一些之前没写过代码,上手开发就是Simulink的工程师朋友来说,在这方面有时会有所欠缺。我自己在做基于模型的开发之前就没有积累足够的手工代码经验,好在Simulink Coder工具足够鲁棒并且易用,基本上能解决大部分问题。不过要把模型建得更有效率,更优化,还需要一些更深入的考量。这里想就一个大的控制算法模型中,各种不同的任务调度方法这个话题量个人能力讨论一二,抛砖引玉,有不足的还请大牛指正。

嵌入式系统中,从应用层的视角总体来看,任务(Task)分很多类,比如说:

  • 周期性任务:这是最常见的,按固定频率周期性执行的任务。根据需要可能有多个不同频率的,比如一个系统中分别有 1ms, 5ms, 10ms, 20ms, 50ms, 100ms, 1000ms任务

  • 一次性任务:比如控制器的上电初始化任务,下电After Run任务

  • 中断任务:实时性要求特别高的,受中断调度的任务,比如电机矢量控制

  • 事件型任务:比如收到某帧CAN消息,再比如发动机控制中跟随曲轴转角位置触发的任务(虽然可能也是中断机制实现,但我觉得算是事件型的)

然后从系统层级的角度来看,任务可以按触发源头分级:

  • 硬件触发,例如硬件中断

  • 底层嵌入式操作系统(OS)触发

  • 应用层自身的任务调用,这个后面细聊

回到Simulink本身,如果不加任何调度,生成的嵌入式代码后,实质上就是个单/多周期的周期性任务(代码中会生成一个每个步长调用的函数 rtOneStep,其中执行整个模型代码)。

以上扯了这么多,谈到的任务的其实都是比较“根源”的任务。无论是采用<A:应用层模型 底层手工代码集成>的方式,还是<B:底层Simulink化封装的完全模型化开发>的方式,应用层的算法反正都要以某种形式的接口,塞到上述某个任务里。A方式一般是底层软件包给定一个函数接口,比如 void function_10ms(),然后把应用层生成的代码填在里面。B方式对A做了个封装,利用S-Function tlc在模型层面自动填进去,如下图所示,这里借用一张自家公司(澳特卡 eCartronic)的图片,其它类似封装工具包有国外的MotoHawk, OpenECU等。

然后,在这一个根任务之下,还会有细分的功能模块,这不同的功能模块也在时间上、顺序上变化出各种各样复杂的调度需求来。不加调度情况下,就是靠信号流驱动,Simulink根据信号先后依赖关系自行判断执行顺序。但是,不加调度有可能会导致低效的模型,比如说,

  • 很多更新频率要求不高的信号,比如100ms甚至1s计算更新一次就足够的功能模块,不加区分放在一个比较快的5ms 10ms任务里去跑

  • 一些只在特定工况或者模式下需要计算的功能模块,不加调度变成每个步长都在算,偏偏这个算法里又是查表、又是各种数组计算的,白白浪费很多CPU资源

最后,都会导致整个控制器CPU负载率过高。各大主机厂对于各种ECU规范里,都会规定一个CPU最高负载率的限制。那么CPU负载率不达标怎么办,换更高计算能力的芯片,这可都是血淋淋的成本啊。如果在各个功能单元的调度都能仔细考虑一下,软件优化妥妥的。

下面列列我认为常见的几种基本调度方法,主要针对应用层,根据实际需要几种方法组合和嵌套,可以实现比较复杂的调度要求。

时间周期分频:

周期性任务是最常见的,基本上,按照触发源层级分,硬件中断触发的周期最精确,说10ms就是准的10ms;底层操作系统触发的,可能准也可能不准,取决于操作系统的调度机制、任务本身的优先级,以及CPU的负载率;而到了应用层再分频的,本质上就是一个任务里的条件语句分支而已,即所谓的“软分频”,一旦源任务没了所有分频任务就都没了。

总而言之,在执行周期的精确性上,依次递减;在建模实现的方便性上来说,逐步递增。

应用层的周期软分频方法,例如可以利用Stateflow把一个基频分成其它不同的周期:

执行顺序调度:

简单的一个执行顺序调度,用Simulink和Stateflow分别实现:

1分N调度:

把执行顺序的调度稍加变化,就是1分N的调度,用Simulink和Stateflow分别实现(Stateflow还顺便加了一个小技巧,可以控制每个子功能调度的开关):

N合1调度:

N合1的调度比较简单,就是把几个Function Call用Mux合起来。

交互式/多次迭代调度:

这种调度形式实际上我不太能给出一个合适的命名,在MATLAB Help中经常出现,同时在建模规范中进行调度和计算分离的推荐用法。这种形式算是终级大杀器了,因为可以在Stateflow里可以自由地搭各种复杂的逻辑,包括在一个步长多次迭代同一计算过程的算法等。只要Stateflow玩得转,基本想怎么调度都可以。

有谬误之处,请不吝指出。


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Simulink中任务调度实现方法浅谈
Simulink模型架构指导
MATLAB Simulink和Stateflow的控制算法建模指南-MAB 5.0 1-100页(MAAB)
基于模型的嵌入式C代码的实现与验证 测控论文 自动化论文 测控技术文库
怎样生成我想要的C代码系列 | MATLAB Function实现数学运算
怎样生成我想要的 C 代码系列(8)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服