两年前写的一篇文章,先拿来撑下门面。后面可能会出一个基于模型开发相关的系列,欢迎大家关注。

MBD过程中,有时候需要用到Data Store Read/Write模块。

1,什么时候必须用该模块

在simulink建模过程中,不提倡使用Data Store Read/Write 模块,因为它会降低模型可读性,且给后续的模型测试带来问题。但是,有时候为了实现某些策略,又不得不使用该模块,比如:需要在一个模块中实现对同一个全局变量的读取和赋值。举个项目实例:

空调控制器有一条需求,空调关闭前,需要记录当前鼓风机的挡位(比如有0挡,1挡,2挡,3挡),以备下次打开空调时,鼓风机能直接工作在上次关闭前的挡位上。

如果空调鼓风机挡位用一个全局变量BlowerLevel表示,那么为了在simulink中实现上面的的需求,则需要用到DataStoreRead/Write.

再比如,一个芯片供应商提供的一段demo代码:

Fig 1 芯片供应商代码

变量Motor_fault_status是模块A的输出(该变量在A模块中定义),同时该变量是模块B的输入,且上述代码是在模块B中实现的。也就是对于模块B来说,需要读取变量Motor_fault_status,还需要对该变量赋值。这时候使用inport/outport进行建模难以实现,需要用到DataStoreRead/Write协助实现。如下图:

Fig2 Simulink Model for demo code

Fig 2模型生成代码如下:

Fig 3 generated code

顺便提下Data Store Memory模块。Fig 2中模块配置如下:

Fig 4 DataStoreMemory for Motor_fault_status

该模块对变量Motor_fault_status的属性进行定义,如果使用数据字典定义变量Motor_fault_status,则可替换上述模块。

2,该模块和Inport/Outport的可替换性

以前见过某tier1供应商搭建的simulink模型,大大小小几十个模块,模型顶层输入输出端口全是DataStoreRead/Write。以前表示不理解,为什么他们要这么干,是不是要特立独行才能显出自己的水平?后来想想,他们这样做或许有他们的道理,至少目前看来不影响代码的生成。

建模对比:

Fig 5 simulink for Inport/Outport vs DataStoreRead/Write

生成代码对比:

Fig 6 Generated code for Inport/Outport vs DataStoreRead/Write

需要注意:在建立数据字典时,使用DataStoreRead/Write模块必须指明Dimensions ,DataType和Complexity的信息。

3,该模块用作bus 信号

如果模型的输入与输出中存在结构体,和第2部分类似,也可以直接用Data Store Read/Write 来替换Inport/Outport。而且甚至可以直接用一个DataStoreRead/Write去替换整个结构体相关的inport/Outport和Bus Creater/Bus Selector,罗列了所有可能情况,见下图:

Fig 7 Bus Signal by inport/outport/DataStoreRead/DataStoreWrite

从上图,可见DataStoreRead/Write在处理结构体时,是灵活多变的。

Fig7 生成代码如下(代码太长,删掉了代码中的注释):

Fig 8 Generated Code by simulink model in Fig 7

如果输入/输出结构体需要初始化呢?Inport/Outport 是不支持结构体初始化的。

Fig 9 Matlab2018a 不支持基于inport/outport的bus signal 初始化

为什么要提这个呢?这是在项目中真正遇到过的。本来打算利用Inport/Outport处理结构体问题。但是生成代码后,在编译链接时报错,说是放在了不合法的地址段.bss。我们知道,一个全局变量未初始化时会默认放在.bss段,如果初始化则放在.data段。先不论上述报错是否合理,当下最重要的还是需要生成满足要求的代码。于是我遇到了Fig 9 报出的问题。我妥协了,所以我尝试使用DataStoreRead/Write,幸运的是这个问题得到了解决。

Fig 10 Blocks that support bus signal initialization

4,使用该模块的弊端

第一部分已经提到慎用DataStoreRead/Write,这是MathWorks的官方说法。如果你在simulink中使用DataStoreMemory模块开始看起来会有些不习惯,不过还好能看明白,但如果在你stateflow中定义了DataStoreMemory的变量,从stateflow你都看不到它的端口的存在,这给模型测试带来了很多困扰。

下图(这里仅是示意图,不必计较具体逻辑实现)在stateflow中包含DataStoreMemory变量ErrorIndex。该变量并不会显示在外部端口。

Fig 11 DataStoreMemory

如果利用simulink 模型创建testharness,DataStoreRead/Write会被忽略,见下图。

Fig 12 Create TestHarness

5,使用DataStoreRead/Write ,如何做模型测试

方法1:创建subsystem的testharness

创建子系统,将非DataStoreRead/Write模块放在一个子系统中,然后基于该子系统创建testharness。

方法2:利用DataStoreWrite/Read

模型如下:

Fig 13 model

模型生成test harness后如Fig15中的modelreference模块。在其前后添加DataStoreWrite/Read即可。这部分可以想办法写脚本以实现自动化。

Fig 14 harness model

仿真结果如图:

Fig 15 SimulationResult

欢迎大家关注我的公众号 土人很土

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐