MBD的Simulink使用技巧⑪:详解数据对象与数据字典(上)
autoMBD最近发布了《autoMBD原创技术文章合集》
《合集》包含156页丰富的MBD入门基础和MBDT硬件支持包的使用,还包含基于MBD的电机控制算法开源项目——AMBD-MC,《合集》配备了丰富的视频讲解和大量的模型、文档和软件资源。获取方式、详情点击下面文章。
本期文章将介绍 数据对象 (Data Objects)和 数据字典 (Data Dictionary)的基本概念和相关的创建方法。
点击以下链接,可以查看MBD的Simulink使用技巧系列的往期文章:
- MBD的Simulink使用技巧①:Simulink代码生成的基本概念
- MBD的Simulink使用技巧②:详解代码生成中的模型与代码
- MBD的Simulink使用技巧③:虚拟子系统与原子子系统的代码生成
- MBD的Simulink使用技巧④:详解生成代码的结构与代码的生成流程
- MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化
- MBD的Simulink使用技巧⑥:代码生成目标配置工具
- MBD的Simulink使用技巧⑦:自动生成代码的集成方法
- MBD的Simulink使用技巧⑧:函数原型、传参的控制与修改
- MBD的Simulink使用技巧⑧(续):函数接口封装的控制和修改
- MBD的Simulink使用技巧⑨:代码数据类型的修改和控制
- MBD的Simulink使用技巧⑩:数据存储类的使用方法
特别提示 :在本篇文章中使用到的.m脚本等文件,可以在autoMBD资源库的“临时资源分享”文件夹中找到(资源序号为 tA34 )。资源库链接的获取可以在《autoMBD原创技术文章合集》中找到(见文章开头)。
1 写在前面
使用Simulink建模开发,有一个非常重要的、进阶的思想: 数据(Data)和模型(Model)分别开发和管理 。
这会带来诸多好处,这里总结主要有以下三点:
- 独立性 :有利于数据和模型分别的迭代开发、管理;
- 通用性 :一份数据供多个模型使用,或一个模型快速变更不同数据;
- 操作性 :可以通过.m脚本实现自动化测试和管理。
上述思想无关乎MBD(代码生成),适用于所有的建模应用。对于初学者来说,他们往往只着眼于模型,而 忽视了数据的开发和管理 。特别是在大模型、复杂模型中,数据的开发和管理显得尤为重要。
具体而言, 在Simulink中数据即数据对象(Data Objects),而管理数据对象的集合被称为数据字典(Data Dictionary) 。
有的读者可能对数据对象还不太熟悉,在介绍数据对象如何控制生成代码之前,会先介绍数据对象和数据字典的一些基本概念和使用方法。
2 数据对象的基本概念和创建
一般而言,我们提及的 数据(Data) ,它是一个集合概念;数据由若干的 数据对象(Data Objects) 构成,即 数据对象是数据的基本元素 。
数据对象通过其 属性(Properties) 来描述和表征,例如名称、值、数据类型等。不同的数据对象可能具有不同的属性。
通常把 一组特定属性的组合称为类(Class) 。一个数据对象只属于一个类,多个数据对象可以属于相同的类,一个数据集合可以有多个不同的类。
更加形象的例子如下图所示:
上图中展示了数据和数据对象的一般关系,图中数据集合包含四个数据对象;不同的颜色表示数据对象具有不同的属性,即图中包含三个类,数据对象 C1 和 C2 属于同一个类。
Tips :后文将通过示例来展示数据对象的创建方法,相关脚本可以在autoMBD资源库的“临时资源分享”文件夹中找到(资源序号为tA34)。
2.1 创建MATLAB数据对象
在MATLAB的命令行中输入如下代码:
a = 1;
初学者会认为,运行得到了一个名为a的 变量 ,它的值为1。
进阶一点, 从数据的角度来理解 ,我们得到一个数据集合,其中 包含一个数据对象 ,该数据对象的名称为a,值为1,数据类型为double(默认),维度为1x1(默认),值域为实数域(默认)。
Tips :理解角度不同,所掌握的信息也就不同。“变量”或“数据对象”是从不同的角度来描述数据。
上述语句a = 1虽然简单,但在MATLAB中,就已经实现了数据对象的创建。
上述得到的数据对象a,属于MATLAB Variable类,该类是MATLAB中 最简单、最通用的类 。MATLAB Variable类具体属性如下:
- 名称
- 值
- 数据类型
- 维度
- 值域
MATLAB Variable类对应的数据对象,如果 数据类型不同 ,其具体创建方式还会有所不同。下面给出一些常见的MATLAB Variable类、不同数据类型属性的数据对象创建方法(.m脚本):
% autoMBD示例脚本
% 展示MATLAB variable class的基本创建方法
% 创建时间2023-02-04
%% 清空数据
clear; clc;
%% 数值类型
a1 = 1; % 普通数值,默认double
a2 = single(1); % 指定数据类型single
a3 = [1 2 3; 4 5 6]; % 数组数值
a4 = 1 + 2i; % 复数数值
%% 字符串类型
b1 = 'I am a string!'; % 字符数组,注意为单引号
b2 = "I am a strings!";% 字符串数组,注意为双引号
%% 结构体类型
c1.elm1 = 1; % 通过索引符"."定义结构体
c1.elm2 = 2; % 通过索引符"."定义结构体
c2 = struct('elm1', 1, 'elm2', 2); % 通过struct()函数定义结构体
%% 元胞数组类型
d = {a1, a1, b1, b2}; % 定义元胞数组
%% 时序类型
ts = timeseries(); % 定义时序数据对象
%% 在Model Explorer显示结果
sfexplr;
Tips :这里只展示了常见数据的创建,还有一些其他的数据类型,以及不同的创建方法,读者可以在MATLAB的Help文件中收索关键词“数据类型”,自行学习。
在工作空间中,MATLAB Variable类的不同数据类型,会显示 不同的图标 ,如下图所示:
在Model Explorer中(通过语句sfexplr打开),可以更加方便地 管理数据对象 、 查看数据对象的属性 ,如下图所示:
注意 ,在Model Explorer中,MATLAB Variable数据对象除了Value属性,其他属性都只是可读 ,不可编辑。
2.2 创建Simulink数据对象
上文介绍的MATLAB Variables类数据对象是最基本的数据对象, 在MATLAB和Simulink中都是通用的。
针对Simulink数据对象,有其特有的 Simulink类 ,常用的有以下几个类:
- Simulink.Parameter
- Simulink.Signal
- Simulink.AliasType
- Simulink.NumericType
- Simulink.Bus
Simulink类不能像MATLAB类那样,通过直接赋值来创建数据对象,需要 通过类的相关函数来创建 。
Tips :类的相关函数,在MATLAB中也被称为“方法”,不过我还是习惯称为“函数”。
例如,要创建一个Simulink.Parameter类的数据对象,创建方法如下:
paramObj = Simulink.Parameter;
这里的Simulink.Parameter是一个返回对应数据对象的函数,如此这样就创建好了一个名为paramObj的Simulink.Parameter数据对象。
Simulink.Parameter类的属性包括:
- CoderInfo
- Complexity
- DataType
- Description
- Dimension
- Max
- Min
- Unit
- Value
可以看到,它的属性比基础的MATLAB Variable类多,特别是 包含了CoderInfo属性 ,可以控制代码的生成。
要注意的是,刚刚创建的数据对象仅为一个 空对象 ,它的部分属性要进行适当设置后才能使用。
下面给一个对Simulink.Parameter数据对象进行设置的例子:
% 设置属性参数
paramObj.Value = 1;
paramObj.DataType = 'uint16';
paramObj.Max = 10000;
paramObj.CoderInfo.StorageClass = 'ExportedGlobal';
上述脚本中,对Simulink.Parameter数据对象的部分属性进行了设置,包括前面文章介绍的极为强大的 存储类 。
要注意,属性的设置要满足该属性的要求,例如paramObj.DataType就只能设置为'uint16', 'double', 'singl', ...等Simulink支持的数据类型。
不熟悉类的人可能会比较困惑: 怎么知道一个类有哪些属性可以设置?怎么知道特定属性的设置要求是什么?
这就要借助强大的MATLAB Help文档了。对于一个不熟悉的类,直接在Help工具中检索该类的名称,找到该类的详细页面,如下所示:
在类的详细介绍页面,找到 属性相关内容 ,该标题下详细列举了该类的所有属性,以及每个属性的作用、设置要求等。
有的详情页中还包括Example示例,可供参考学习。如下所示:
下面给出一些Simulink类和数据对象的常用方法,供读者参考:
% autoMBD示例脚本
% 展示Simukink class的基本创建方法
% 创建时间2023-02-04
%% 清空数据
clear; clc;
%% Simulink.Parameter类
paramObj = Simulink.Parameter;
% 设置属性参数
paramObj.Value = 1;
paramObj.DataType = 'uint16';
paramObj.Max = 10000;
paramObj.CoderInfo.StorageClass = 'ExportedGlobal';
%% Simulink.Signal类
signalObj = Simulink.Signal;
% 设置属性参数
signalObj.SampleTime = 0.001;
signalObj.DataType = 'double';
signalObj.Max = 10000;
signalObj.CoderInfo.StorageClass = 'ImportedExtern';
%% Simulink.NumericType类
typeObj = Simulink.NumericType;
% 设置属性参数
typeObj.DataTypeMode = 'Boolean';
%% Simulink.AliasType类
aliasObj_float = Simulink.AliasType;
% 设置属性参数
aliasObj_float.BaseType = 'single';
%% Simulink.Bus类
busObj = Simulink.Bus;
% 创建子类
elm1 = Simulink.BusElement;
elm1.Name = 'BusElm1';
elm1.DataType = 'single';
elm2 = Simulink.BusElement;
elm2.Name = 'BusElm2';
% 设置属性参数
busObj.Elements = [elm1 elm2];
%% 在Model Explorer显示结果
sfexplr;
上述的脚本中,一共创建了五个不同的数据对象,并对部分属性进行了设置。
Simulink类和MATLAB类除了属性的不同,其 操作性也不同 。在Model Explorer中,可以对Simulink类数据对象进行更多的操作。
例如,可以通过Model Explorer的属性窗口对Simulink类数据对象进行修改和控制,如下所示:
除了通过脚本创建数据对象,也可以在Model Explorer的工具栏中, 通过“Add”菜单创建数据对象 。由“Add”菜单创建的数据对象和脚本创建的是一样的。
特别注意 ,通过“Add”菜单创建的数据对象,一定要 保存 下来(保存为.mat格式),不然关闭MATLAB/Simulink后,创建的数据对象就会丢失。
Tips :少量数据对象是可以用“Add”菜单来创建,但大量数据对象还是推荐脚本的方法来创建。
“Add”菜单如下所示:
“Add”菜单不仅仅可以创建MATLAB Variable和Simulink数据对象,还可以创建Configuration对象,甚至自定义对象。感兴趣的读者可以自行研究这部分功能。
3 数据字典的基本概念和创建
上述的示例中,运行脚本后创建的数据对象,被放置在 Base Workspace 中。一般情况下,Simulink模型可以直接使用Base Workspace中的数据对象。
但是当数据对象很多、模型也很多的时候,不同模型使用的数据对象也不一样,这时把所有数据对象都放在Base Workspace中,明显不是一个好的方法。
数据字典(Data Dictionary)这时候就可以派上用场了,数据字典的作用就是用来 存储和管理创建的数据对象 。
3.1 数据字典的基本概念
数据字典本质上也 是一个对象(Object) ,只不过不是普通的数据对象,它的类为:
- Simulink.data.Dictionary
它还包含 三个重要的子类 :
- Simulink.data.dictionary.Section
- Simulink.data.dictionary.Entry
- Simulink.data.dictionary.EnumTypeDefinition
数据字典的 Section是用来保存“对象”的区域 ,不仅仅是数据对象,也包括其他对象(例如Configuration、Embedded Coder Dictionary等)。不同的对象被放置在不同的区域,数据字典包含如下四个区域:
- Design Data
- Configurations
- Embedded Coder Dictionary
- Other Data
我们常常用到的 数据对象被保存在“Design Data”区域 当中,可以就把它理解为一个 单独的Workspace ,可供某一个模型单独使用。
在数据字典中, “对象”被称为Entry(可以翻译为“项”) 。所以Section中的每一个对象就是一个Entry。
第三个重要的子类是枚举类型(Enum Type)的定义。在Simulink中,枚举类型是一个非常特殊的类型。
但是,在生成代码中 不建议使用Simulink枚举类型,建议使用系统枚举类型 。
系统枚举类型的创建方法会在后续的文章中进行介绍。关于数据字典的基本信息就介绍到这里,更多关于数据字典的内容,读者可以查看官方Help文档进行学习。
Tips :数据字典相关内容非常丰富,上述只是非常基础的介绍。读者要想熟练使用数据字典,需要在实践中多多练习,勤查Help文档。
3.2 创建和管理数据字典
下面给出一个简单的示例脚本,展示如何创建和修改数据字典,实现对数据对象的管理:
% autoMBD示例脚本
% 展示Data Dictionary的基本创建方法
% 创建时间2023-02-04
%% 清空数据
clear; clc;
%% 创建数据字典
if (exist('myDictionary.sldd', 'file'))
ddObj = Simulink.data.dictionary.open('myDictionary.sldd');
ddObj = Simulink.data.dictionary.create('myDictionary.sldd');
%% 新建一个数据对象paramObj,属Simulink.Parameter类
paramObj = Simulink.Parameter;
% 设置属性参数
paramObj.Value = 1;
paramObj.DataType = 'uint16';
paramObj.Max = 10000;
paramObj.CoderInfo.StorageClass = 'ExportedGlobal';
%% 将创建的数据对象添加到数据字典中
% 获取数据字典的'Design Data'区域
listEntry(ddObj);
sectionObj = getSection(ddObj, 'Design Data');
if (exist(sectionObj, 'paramObj'))
paramObjEntry = getEntry(sectionObj, 'paramObj');
paramObjEntry = addEntry(sectionObj, 'paramObj', paramObj);