Simulink中从Excel自动生成数据字典
- 1. Excel文件定义
- 2. 源码分析
- 2.1 概述
- 2.2 确定Excel和m文件名
- 2.2 读取excel文件
- 2.3 逐行提取excel数据
- 2.4 将提取到的数据写入m文件
- 2.5 生成数据字典
- 3. 功能优化
- 3.1 使用waitbar显示运行进度
- 4. 如何使用
- 源码
本文介绍如何使用matlab脚本语言实现从Excel自动生成数据字典(Sldd);
1. Excel文件定义
SignalName | DataType | Dimensions | Initia Value | StorageClass | CustomStorageClass | HeaderFile | Description |
信号名字 | 数据类型 | 维度 | 默认值 | 存储类别 | 定制存储类别 | 头文件 | 描述 |
TestSignal | uint8 | 10 | Custom | GetSet | inc.h | 测试信号 |
如上表,在自动生成数据字典之前,需要创建一个包含上述类型的excel sheet用来导入数据字典,sheet名需要定义为“Signal”。
维度,默认值,头文件,描述为可选内容,如果不需要可以为空;
其中StorageClass和CustomStorageClass有多重组合方式,具体可以参阅matlab帮助手册,这里就不赘述了。
2. 源码分析
2.1 概述
从excel自动生成数据字典,本文描述的方法是先将excel文件内容写到一个新的m文件中,然后使用import函数,将m文件中的内容导入到数据字典里。
2.2 确定Excel和m文件名
Excel_name = 'Test'; %获取表格名称
disp(Excel_name);
mfile_name = strcat(Excel_name,'Var.m'); %生成的m文件名
DictName = strcat(Excel_name,'.sldd');
fid = fopen(mfile_name,'w');
fprintf(fid,'\n\n\n');
Excel_name 为获取到的excel名字,不含后缀;
disp 显示变量的值;
strcat 水平串联字符串;
fopen 打开文件或获得有关打开文件的信息。参数’w’为放弃现有内容(如果有);
fprintf 将数据写入文本文件
fid 文件标识符
生成的m文件名为:TestVar.m
生成的数据字典文件名为:Test.sldd
注意:这里仅演示从Excel自动生成数据字典功能,excel名字为已确定的名字,如果需要做成一个通用的函数还需要依据不同的场景获取当前Excel的名字;
例如:excel名与当前打开的模型名字一致,可以使用下面代码自动获取模型名字,并使用为excel名字;
ModelName = get_param(bdroot,'Name'); %获取模型名
Excel_name = ModelName ; %excel名与模型名一致
get_param 获取参数名称和值
bdroot 当前系统的顶层模型
2.2 读取excel文件
[~,Signal_Cell] = xlsread(Excel_name,'Signal'); %导入Signal工作表为单元数组 数据要转换为char类型
xlsread 读取 Microsoft Excel 电子表格文件;
注意:使用这种方式读取到的值,在写入m文件时,需要先转化为char类型;
使用isempty函数可以确定当前单元格是否为空;
if isempty(char(Signal_Cell(x,y)))
end
isempty 确定数组是否为空;
char 字符数组;
2.3 逐行提取excel数据
SignalNum = 0;
for row = 2:size(Signal_Cell) %从第2行开始循环处理每一行内容
% 提取Excel数据
OrgName = char(Signal_Cell(row,1)); %SignalName
DataType = char(Signal_Cell(row,2)); %DataType
Dimensions = char(Signal_Cell(row,3)); %Dimensions
InitialValue = char(Signal_Cell(row,4)); %InitiaValue
StorageClass = char(Signal_Cell(row,5)); %StorageClass
if isequal(StorageClass,'Custom')
CustomStorageClass = char(Signal_Cell(row,6)); %CustomStorageClass
end
HeaderFile = char(Signal_Cell(row,7)); %HeaderFile
Description = char(Signal_Cell(row,8)); %Description
size 数组大小
isequal 确定数组相等性
逐行提取excel中的数据,并存放在指定变量内;
其中仅有StorageClass配置为Custom时,CustomStorageClass中的数据才有意义,否则CustomStorageClass中的数据无意义;
2.4 将提取到的数据写入m文件
if ~isempty(OrgName)
SignalNum = SignalNum+1;
SignalName = OrgName;
str_tmp = strcat(SignalName,' =',32,'mpt.Signal',';','\n'); %mpt Simulink
fprintf(fid, str_tmp);
str_tmp = strcat(SignalName,'.CoderInfo.StorageClass = ''',StorageClass,''';','\n');
fprintf(fid, str_tmp);
if contains(DataType ,'Enum')
rDataType = strcat('Enum:',32,DataType);
str_tmp = strcat(SignalName,'.DataType = ''',rDataType,''';','\n');
else
str_tmp = strcat(SignalName,'.DataType = ''',DataType,''';','\n');
end
fprintf(fid, str_tmp);
if ~isempty(Dimensions)
str_tmp = strcat(SignalName,'.Dimensions = ',Dimensions,';','\n');
fprintf(fid, str_tmp);
end
if ~isempty(Description)
str_tmp = strcat(SignalName,'.Description = ''',Description,''';','\n');
fprintf(fid, str_tmp);
end
if ~isempty(InitialValue)
str_tmp = strcat(SignalName,'.InitialValue = ''',InitialValue,''';','\n');
fprintf(fid, str_tmp);
end
if isequal(StorageClass,'Custom')
str_tmp = strcat(SignalName,'.CoderInfo.CustomStorageClass = ''',CustomStorageClass,''';','\n');
fprintf(fid, str_tmp);
if isequal(CustomStorageClass,'GetSet')
if ~isempty(HeaderFile)
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.HeaderFile = ''',HeaderFile,''';','\n');
fprintf(fid, str_tmp);
end
if isequal(DataType,'boolean')
rDataType = 'bool';
else
rDataType = DataType;
end
GetFunction = strcat('Get_',rDataType,'_',OrgName);
SetFunction = strcat('Set_',rDataType,'_',OrgName);
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.GetFunction = ''',GetFunction,''';','\n');
fprintf(fid, str_tmp);
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.SetFunction = ''',SetFunction,''';','\n');
fprintf(fid, str_tmp);
end
end
fprintf(fid,'\n');
end
本段代码确认了之前提取到的数据是否正常,若正常则将相应的内容写入m文件,否则跳过该属性或信号;
2.5 生成数据字典
exist_flag = exist(DictName,'file'); %判断数据字典是否已经建立
if exist_flag == 0
DictObj = Simulink.data.dictionary.create(DictName);
Result = '数据字典已生成!!!';
else
DictObj = Simulink.data.dictionary.open(DictName);
Result = '数据字典已更新!!!';
end
SectObj = getSection(DictObj,'Design Data');
importFromFile(SectObj,mfile_name,'existingVarsAction','overwrite');
saveChanges(DictObj);
exist 检查变量、脚本、函数、文件夹或类的存在情况
Simulink.data.dictionary.create 创建新的数据字典并创建 Simulink.data.Dictionary 对象
Simulink.data.dictionary.open 打开数据字典进行编辑
getSection 选择数据字典的相关节数据
importFromFile 从文件导入数据
existingVarsAction 对现有数据字典采取的操作
overwrite 导入所有目标变量并覆盖现有数据字典中已经存在的变量
saveChanges 保存更改到数据字典
3. 功能优化
上述源码已经实现了从Excel自动生成数据字典的功能,但是在运行时间没有任何体现,并且读取excel时间是比较久的,为避免误操作,加入读取文件进度提示;
3.1 使用waitbar显示运行进度
waitbarName = strcat('正在打开Excel文件:',Excel_name,'.xlsx...');
f = waitbar(0,waitbarName);
waitbar(row/(length(Signal_Cell)),f,'正在获取Singnal...'); %更新waitbar进度
delete(f);%删除waitbar
waitbar 创建或更新等待条对话框
4. 如何使用
使用该脚本时,要确保当前工作路径存在一个符合条件的excel文件,直接运行该脚本;
会自动生成TestVar.m,和TestVar.sldd,TestVar.m为中间文件,TestVar.sldd是需要的数据字典;
源码
%% 自定义CreateSldd
% 2021.05.04
% Author: LL
%% 自定义CreateSldd
function CreateSldd(~)
clc;clear;
%% 定义Excel各列内容
%% step1:选择Excel文件
Excel_name = 'Test'; %获取表格名称
disp(Excel_name);
mfile_name = strcat(Excel_name,'Var.m'); %生成的m文件名
DictName = strcat(Excel_name,'.sldd');
fid = fopen(mfile_name,'w');
fprintf(fid,'\n\n\n');
%% step2:导入Simulink/mpt.Signal
waitbarName = strcat('正在打开Excel文件:',Excel_name,'.xlsx...');
f = waitbar(0,waitbarName);
[~,Signal_Cell] = xlsread(Excel_name,'Signal'); %导入Signal工作表为单元数组 数据要转换为char类型
SignalNum = 0;
for row = 2:size(Signal_Cell) %从第2行开始循环处理每一行内容
% 提取Excel数据
OrgName = char(Signal_Cell(row,1)); %SignalName
DataType = char(Signal_Cell(row,2)); %DataType
Dimensions = char(Signal_Cell(row,3)); %Dimensions
InitialValue = char(Signal_Cell(row,4)); %InitiaValue
StorageClass = char(Signal_Cell(row,5)); %StorageClass
if isequal(StorageClass,'Custom')
CustomStorageClass = char(Signal_Cell(row,6)); %CustomStorageClass
end
HeaderFile = char(Signal_Cell(row,7)); %HeaderFile
Description = char(Signal_Cell(row,8)); %Description
if ~isempty(OrgName)
SignalNum = SignalNum+1;
SignalName = OrgName;
str_tmp = strcat(SignalName,' =',32,'mpt.Signal',';','\n'); %mpt Simulink
fprintf(fid, str_tmp);
str_tmp = strcat(SignalName,'.CoderInfo.StorageClass = ''',StorageClass,''';','\n');
fprintf(fid, str_tmp);
if contains(DataType ,'Enum')
rDataType = strcat('Enum:',32,DataType);
str_tmp = strcat(SignalName,'.DataType = ''',rDataType,''';','\n');
else
str_tmp = strcat(SignalName,'.DataType = ''',DataType,''';','\n');
end
fprintf(fid, str_tmp);
if ~isempty(Dimensions)
str_tmp = strcat(SignalName,'.Dimensions = ',Dimensions,';','\n');
fprintf(fid, str_tmp);
end
if ~isempty(Description)
str_tmp = strcat(SignalName,'.Description = ''',Description,''';','\n');
fprintf(fid, str_tmp);
end
if ~isempty(InitialValue)
str_tmp = strcat(SignalName,'.InitialValue = ''',InitialValue,''';','\n');
fprintf(fid, str_tmp);
end
if isequal(StorageClass,'Custom')
str_tmp = strcat(SignalName,'.CoderInfo.CustomStorageClass = ''',CustomStorageClass,''';','\n');
fprintf(fid, str_tmp);
if isequal(CustomStorageClass,'GetSet')
if ~isempty(HeaderFile)
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.HeaderFile = ''',HeaderFile,''';','\n');
fprintf(fid, str_tmp);
end
if isequal(DataType,'boolean')
rDataType = 'bool';
else
rDataType = DataType;
end
GetFunction = strcat('Get_',rDataType,'_',OrgName);
SetFunction = strcat('Set_',rDataType,'_',OrgName);
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.GetFunction = ''',GetFunction,''';','\n');
fprintf(fid, str_tmp);
str_tmp = strcat(SignalName,'.CoderInfo.CustomAttributes.SetFunction = ''',SetFunction,''';','\n');
fprintf(fid, str_tmp);
end
end
fprintf(fid,'\n');
end
waitbar(row/(length(Signal_Cell)),f,'正在获取Singnal...'); %更新waitbar进度
end
%% step3:生成数据字典
fclose(fid);
waitbar(0,f,'正在生成数据字典...'); %更新waitbar进度
exist_flag = exist(DictName,'file'); %判断数据字典是否已经建立
if exist_flag == 0
DictObj = Simulink.data.dictionary.create(DictName);
Result = '数据字典已生成!!!';
else
DictObj = Simulink.data.dictionary.open(DictName);
Result = '数据字典已更新!!!';
end
SectObj = getSection(DictObj,'Design Data');
importFromFile(SectObj,mfile_name,'existingVarsAction','overwrite');
saveChanges(DictObj);
waitbar(1,f,'正在生成数据字典...'); %更新waitbar进度
delete(f);
clear;
end