在之前的文章中大概提到过,使用基于模型的嵌入式开发注意的基本要素,总得概况来说在使用时要注意三点内容:
1、模型的层次结构
2、数据接口
3、配置
这三个方面对生成代码和能否调试成功直接的影响。
这个星期一直在调试一个很大的模型,总体模型是由很多个子模型拼接形成的,使用了ModelReference的形式,调试的过程中遇到了一些大大小小的问题,记录下来给自己留用也给大家分享一下。
1、什么时候用ModelReference?有那些好处?
一般来说,一个系统有很多个相对独立的功能,比如说一个混合动力车辆控制系统中,要实现驾驶员意图判别,力矩仲裁,故障处理等等相对独立的功能,这个时候把这些功能模块拆分为单独的模型来搭建,每个模型实现较为单一的功能,这个时候用ModelReference的方式比较好。
第一、功能实现拆分,降低搭建模型的难度。
第二、可以多个工程师同步进行模型搭建,不同的工程师搭建自己熟悉的部分。
第三、子模型可以单独进行调试修改和测试,比起较早的版本使用library方便很多。
2、如何使用ModelReference?
在主模型中添加模块Model,这个模块可以在Simulink Library Explorer中 Simulink -> Ports & Subsystem 中找到,将其拖放到主模型中。
双击后会弹出如下对话框:
![ModelReference使用随手记 ModelReference使用随手记](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
其中Model Name选择你要引用的模型,点击Browser手动选取。这里要注意的是如果选择的模型不在当前工作路径,应用之后应该会弹出一个对话框问你是否要把该模型的路径添加到工作路径中,选择是然后相应的调用才可成功,不然主模型是找不到相应调用的模块的。
但是,即使选择了是,在下次打开主模型时,如果相应的子模型路径没有被添加到工作路径中,主模型仍会找不到相应的子模型,所以最好在使用模型之前,把所用模型涉及到的模型的路径都添加到工作路径中。
在使用较多的模型引用时,建议大家把各个模型分类保存在不同的文件夹内,然后在主模型的回调函数PreLoadFcn中添加相应的代码,把各个子模块的路径添加工作路径,寻址方式可以使用对主模型相对寻址的办法。
这里给出一个例子:
![ModelReference使用随手记 ModelReference使用随手记](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
这段代码添加了主模型保存位置的一个subsystem文件夹下面的所有文件夹为工作路径。这里不进行代码细讲,大家可以自己研究。
Model argument:模型参数,这个可以在各个子模型中定义,有点类似与如果把整个子模型看作是函数,这个就有点类似与的形参。一般用的不多,在model variants时会用到。
Model argument values:模型参数值,在主模型中定义赋值,有点类似与函数的实参。可以是workspace中的变量,但是要与子模型中的模型参数类型对应,而且必须是有效值。
Simulink mode:有四种方式,简单解释如下——
Normal:将整个被引用模型当作原子子系统载入主模型或发起引用的模型中,进行运算。
Accelerate:将整个被引用模型编译为S-fuction供发起引用的模型调用。
SIL需要Embedded Coder将被引用模型生成产品级代码然后编译仿真。
PIL需要相应的目标板将被引用模型的代码下载到目标处理器中进行仿真。
一般前期的算法验证阶段使用前两种即可,默认为Accelerate模型。
在Model的配置窗口中还有一个Enable variants的按钮,点击之后可以一个模块根据不同的条件引用多个模型,这个有点类似与C语言中的函数重载的概念(只是类似,使用的效果可以完全不同)。具体的使用在后面的文章中会介绍。
其实完成了模型的Model name的定义就可以在发起引用的模型中使用了。和模型中的子系统一样,在被引用的模型中定义的input和output接口,会在model模块上显示为输入输出接口。
3、使用Model Reference的一些注意事项。
主要是在使用过程中注意避免一些数据冲突,建议的做法如下:
第一、被引用的模型的输入输出接口要显式的定义出数据类型,最好不要采用继承选项,特别是在多人合作的项目中,有利于模型的组合调试。
第二、被引用模型的仿真采样时间要显示的定义出,不可以采用集成选项,原因同上。
第三、如果模型大量使用了workspace中的变量建议,Normal仿真模式下,在子模型的参数配置中 Optimization -> Simulaiton and code generation中选择Inlined Parameters 能够顺利的实现调用仿真。(这一点在进行代码生成时的部署可能会不一样,因为这样的方式直接使用数字代替模型中的参数,可以节省内存,但是某些嵌入式系统需要使用在线调参的功能,这里要小心配置。)
第四、如果被引用模型中有 To Workspace 以及 Scope 模块那么,在被引用模型的参数设置中,Model Referencing -> Options for referencing this model 中 Total number of instance allowed per top model中应该对应选择One。
这里解释下对应的几个选项,默认为Multiply,意思是可以在另外某个一个模型中多次引用该模型;如果选择One是只能引用一次;Zero表示该模型禁止被引用。
因为 To Workspace 以及 Scope 模块都会向工作空间内写数据,调用多个模型,那么会有多个模型都可以对工作空间中相同名字的变量进行写操作,所以为了避免数据混乱,这里应该选择One。
第五、这一点和第一点有些相同,不过是个特例,简单说下:有时候我们在子模型中会保留一些输出端口,作为以后备用,会使用一个Groud模块连接到一个输出上,但是在模型引用时,会出现问题,主要是由于Groud的输出是个未定义的类型(虽然我们知道是0)。
解决办法有两个:(1)在模型的参数配置中 Optimization -> Simulaiton and code generation 选择 Block reduction 即在实际编译过程中将Groud的连接的未使用的接口优化掉,当然这不一定符合我们的预期。(2)在Groud和对应的Output端口之间添加一个convert模块明确的输出的0是那个数据类型。
目前调试工作中遇到的问题就这么多,以后发现了继续补充吧。
欢迎读到文章的同学一起讨论和指正。