本文研究如何将Excel表格中的数据字典导入到Matlab工作空间中,并在建模时使用。
1 数据字典的概念及管理方式
在博主的另一篇博客《Simulink代码生成:数据字典的建立、关联模型》中已经详细地解释了Simulink数据字典地概念以及三种管理方式。其中,第3.2章节介绍了通过Excel表格&m脚本地管理方案。
博主工作中虽然已经不再采用这种方案,但有博友私信问我关于从表格导入数据对象的方法,所以可见这种方案还是倍广泛使用的。仔细思考了一下,这种方案还是具有一定的优势,因为用表格文档比较符合工程师的管理习惯,并且也非常方便沟通和交流。
本文会通过一个简单的Excel案例,和对应的Matlab脚本,来演示这种管理数据字典的方案。
2 Excel表格模板建立
首先需要把Simulink仿真中用到的数据对象按照一定的规律填写到Excel表格中。该表格就是整个项目团队达成共识的模板。模板根据自己的习惯创建。
譬如如下博主用的表格模板,包含了三个工作表:‘Signal’,‘AliasType’,‘Bus’,里面分别存放着Simulink中的三种数据对象。
打开每个工作表,都包含了该类数据对象的各种属性信息。这些属性信息都是在UI界面可以看到的,Matlab中提供了相应的接口可以创建或者修改。
这里有一点要注意的地方,对于数值型的数据,譬如InitialValue或者Dimensions中时数值的i情况,需要在数值前加上单引号,再填入单元格内。这样,Matlab解析出来就是字符串了。
3 脚本导入数据字典
3.1 导入方法
- 脚本中需要用到xlsread函数来获取表格内容,生成一个单元数组;
- 通过解析单元数组的内容,获取各个属性信息;
- 最后通过evalin函数把属性信息写到工作空间中;
3.2 m脚本内容
这一节把整个脚本贴出来,后面再解释一些注意点。
function Import_DD()
%% 表格名称
Excel_Name = 'demo_DD'; %表格名称
evalin('base','clear'); %清空工作空间
%% 导入Simulink.Signal
[~,~,Signal_Cell] = xlsread(Excel_Name,'Signal'); %导入Signal工作表为单元数组
for row = 2:size(Signal_Cell,1) %从第2行开始循环处理每一行内容
% 提取信号名,数据类型,初始值,存储类型
SignalName = Signal_Cell{row,1};
DataType = Signal_Cell{row,2};
InitialValue = Signal_Cell{row,3};
StorageClass = Signal_Cell{row,4};
% 在工作空间中建立该对象并配置其属性
evalin('base',[SignalName,' = Simulink.Signal;']);
evalin('base',[SignalName,'.DataType = ''',DataType,''';']);
evalin('base',[SignalName,'.InitialValue = ''',InitialValue,''';']);
evalin('base',[SignalName,'.CoderInfo.StorageClass = ''',StorageClass,''';']);
end
%% 导入Simulink.AliasType
[~,~,AliasType_Cell] = xlsread(Excel_Name,'AliasType'); %导入AliasType工作表为单元数组
for row = 2:size(AliasType_Cell,1) %从第2行开始循环处理每一行内容
% 提取别名、基础类型
AliasName = AliasType_Cell{row,1};
BaseType = AliasType_Cell{row,2};
% 在工作空间中建立该对象并配置其属性
evalin('base',[AliasName,' = Simulink.AliasType;']);
evalin('base',[AliasName,'.BaseType = ''',BaseType,''';']);
end
%% 导入Simulink.Bus
[~,~,Bus_Cell] = xlsread(Excel_Name,'Bus'); %导入Bus工作表为单元数组
for row = 2:size(Bus_Cell,1) %从第2行开始循环处理每一行内容
%更新Bus名称
if ~isnan(Bus_Cell{row,1})
BusName = Bus_Cell{row,1};
i = 1;
evalin('base',[BusName,' = Simulink.Bus;']);
end
% 提取元素名称、尺寸、类型
BusElementName = Bus_Cell{row,2};
Dimensions = Bus_Cell{row,3};
DataType = Bus_Cell{row,4};
% 建立元素并加入Bus中
evalin('base',[BusName,'.Elements(',num2str(i),').Name = ''',BusElementName,''';']);
evalin('base',[BusName,'.Elements(',num2str(i),').Dimensions = ',Dimensions,';']);
evalin('base',[BusName,'.Elements(',num2str(i),').DataType = ''',DataType,''';']);
% Bus元素索引+1
i = i + 1;
end
end
3.3 m脚本简单解释
1)脚本其实很好读懂,比较关键的一个点在于evalin函数。该函数帮助我们跨范围执行语句。
因为脚本是在自己的空间内,所以建立数据字典信息也是在脚本自己的范围。用evalin函数,并将其第一个参数设为’base’,就可以在Matlab命令行中执行语句。这样的话,创建对象的操作就是在外面的工作区完成了。
2)关于Bus信号对象的建立,会比Signal对象稍微复杂了一点。
Bus信号包括整个的Bus定义和Bus中的元素的定义,将这两方面区分开来完成即可。
4 验证与总结
将该脚本和demo_DD.xlsx表格放进一个路径下,然后运行该脚本。脚本会清空工作区的所有其他对象,然后重新定义表格中的数据对象。
打开某个对象可以看到,对应的属性已经按照表格中的定义修改了。
总结一下,本文只是通过一个简单的例子演示了从表格导入数据字典到工作空间的过程。实际工作中,对象的数量不会这么少,种类也不止这三种。但是整个工作流程和思路还是差不多的。如果遇到了更多的问题,再见招拆招即可。