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帮助手册,这里就不赘述了。

elementplus 表格数据字典翻译_数据

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.slddTestVar.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