全文约4000字,你将看到以下内容:
数据对象关联到模型
通过数据对象控制代码生成
数据对象和数据字典总结
获取《autoMBD原创技术文章合集》
点击上面链接免费获取156页文章合集
本期是数据对象(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使用技巧⑩:数据存储类的使用方法
MBD的Simulink使用技巧?:详解数据对象与数据字典(上)
MBD的Simulink使用技巧?:详解数据对象与数据字典(中)
特别提示:在本篇文章中使用到的模型、.m脚本等文件,可以在autoMBD资源库的“临时资源分享”文件夹中找到(资源序号为tA22、tA36)。资源库链接的获取可以在《autoMBD原创技术文章合集》中找到(见文章开头)。
在前面两期文章中,介绍了基本的数据对象和数据字典创建方法,以及Bus(总线)和枚举数据类型等特殊数据对象。本期文章将介绍它们的具体关联方法,以及通过数据字典对代码生成的控制方法。
1 数据对象关联到模型
为了便于理解,数据对象的关联方法依然基于PI控制器模型展开。初始的PI控制模型在前面的文章中已多次使用,如下所示:
初始的PI控制器模型 -
From autoMBD
Tips:该模型可以在临时资源分享中找到,资源序号tA22。
经过修改和关联后的最终模型如下所示:
使用数据字典的PI控制器模型 -
From autoMBD
Tips:该模型可以在临时资源分享中找到,资源序号tA36。
该模型是基础版PI控制器模型(资源序号tA22)的修改版本,两者的模型配置参数完全一样。但由于tA36的代码生成过程由数据对象来控制,使得最后生成的代码完全不同。
模型管理数据对象主要使用到Model Data Editor和Model Explorer这两个工具,如下所示:
数据对象的控制窗口 -
From autoMBD
模型关联数据对象的方法并不唯一,相反是很灵活的。下面给出一种简单的关联步骤,供读者参考(示例始于tA22,最终模型为tA36)。
1.1 创建数据字典
打开初始PI控制模型后,另存为一个合适的文件名。对于一个创建好的模型,开始关联数据对象之前,建议先创建数据字典。
Tips:数据对象可以不依赖数据字典,而直接保存在Base Workspace中使用。但为了更好地管理数据对象,建议使用数据字典。
创建数据字典可以通过脚本实现:
% autoMBD示例脚本% 用于autoMBD_example_PI_ObjectiveDD.slx的数据对象管理、执行脚本% 创建时间2023-05-01% 更新时间2023-05-01
%% 清空数据clear; clc;
%% 创建数据字典if (exist('PI_ObjectiveDD.sldd', 'file')) ddObj = Simulink.data.dictionary.open('PI_ObjectiveDD.sldd');else ddObj = Simulink.data.dictionary.create('PI_ObjectiveDD.sldd');end
%% 打开Model Explorer% 在Model Explorer中显示数据字典show(ddObj);也可以通过Model Explorer创建:
创建数据字典 -
From autoMBD
创建好数据字典后,通过Model Settings -> Model Properties -> External Data将模型关联到数据字典,如下所示:
打开Model Properties -
From autoMBD
在External Data中关联数据字典 -
From autoMBD
这里可以不勾选Enable model access to base workspace,这样模型就仅受数据字典的控制。这里勾选与否不影响数据字典的功能。
1.2 创建Data Type数据对象
在众多不同的数据对象中,Data Type相关的数据对象是应该最先创建的,因为它是供其他数据对象使用的。
常见的Data Type相关数据对象有:
别名数据类型(Alias Type)
总线数据类型(Bus)
枚举数据类型(Emumerated Type)
1.2.1 通过Model Explorer创建
通过Model Explorer创建数据对象的创建方法详见《详解数据对象与数据字典(上)》和《详解数据对象与数据字典(中)》,这里不再赘述。
在本次例程中,创建了一个单精度浮点数的类型别名
Float32,以及一个Bus总线数据类型
InputBus,如下所示:
单精度别名数据类型 -
From autoMBD
Bus总线数据类型 -
From autoMBD
InputBus总线包含了两个输入数据Req_Ctrl和Feedback,并且它们的数据类型设置为了刚刚创建的别名数据类型
Float32。
1.2.2 通过Excel和.m脚本创建
实际项目中,数据类型可能非常多,特别是Bus总线数据会变得非常复杂。
Bus总线的数据类型,往往很多都是重复的;并且不同的数据对象,它们的属性条目往往也是相同的。
基于这样的特点,大量数据类型的处理很适合通过表格工具实现。实践中,大量数据类型的创建基本上都是通过Excel工具结合.m脚本实现的。
这个过程的基本原理是:按照数据对象的属性条目,在Excel中创建全部的数据类型,然后通过.m脚本解析和处理Excel文件,批量生成数据对象,再导入到数据字典当中。(如果使用的是Base Workspace,也可以不导入到数据字典中)
这个过程并不算太复杂,.m脚本创建数据对象的方法在前面的文章中也已经详细介绍过了。读者需要额外注意的是.m脚本处理Excel文件的相关函数的使用方法。
Tips:这部分内容不是本期文章的重点,将会在后续的文章中再做补充介绍。
1.3 创建/修改模型
由于Simulink Signal数据对象的关联是通过信号线名称匹配来关联的,建议先把所有需要关联的信号命合适、有意义的名称。
Tips:建模时保持良好的建模习惯,对信号、模块、子系统等在建模伊始就命名。
tA22模型的信号线已经命名,不过为了展示Bus总线数据和Data Store数据的使用,这里还是对tA22做了部分修改。
将输入数据修改为总线数据类型(上一步中创建的Bus总线),并在模型中添加一个Data Store Memory模块,用于保存积分过程的中间数据。如下所示:
模型修改:Bus总线和Data store Memory -
From autoMBD
模型修改:输入端口设置为Bus总线 -
From autoMBD
请留意上图模型中的信号名,部分信号名在数据对象创建时用得到。
特别提示,离散模块的状态和数据存储的变量,也应该和信号线一样命名,因为它们也是关联的Simulink Signl数据对象。
离散状态 -
From autoMBD
数据存储模块 -
From autoMBD
1.4 创建信号、参数等数据对象
非数据类型的相关数据对象,较为常用有两个:
信号(Simulink Signal)
参数(Simulink Parameter)
本示例过程中,一共创建了6个Simulink Signal数据对象和两个Simulink Parameter数据对象,如下所示:
创建信号、参数等数据对象 -
From autoMBD
可以发现,这里创建的Simulink Signal数据对象和将要关联的信号是同名的。这样在关联信号的时候数据对象才能被解析到。
Tips:这里的信号应当包括信号线、离散状态、输入输出端口和数据存储变量。
Simulink Parameter数据对象没有这样的问题,因为它本身就是作为参数输入到模块中的。
当然,创建数据对象的过程也可以通过脚本实现,往期文章中已做过介绍,这里不再赘述。
1.5 关联数据对象
Simulink Signal和Parameter数据对象可以关联模型中所有的数据形式,具体有:
输入输出端口(Inports/Outports)
信号(Signals)
数据存储(Data Stores)
状态(States)
参数(Parameters)
上述前面的四种数据形式可以关联Simulink Signal数据对象;参数可以关联Simulink Parameter数据对象。Tips:特别注意,Simulink Signal数据对象可以关联的不仅仅是信号线,还包括输入输出端口、状态和数据存储。而所有数据对象自身的Data Type则可以关联Bus总线、Alias或者枚举等数据对象。1.5.1 关联信号数据对象
关联Simulink Signal数据对象需要用到Model Data Editor工具。
关联的方法也很简单,只需要在Model Data Editor窗口中,将被关联信号(包括信号线、状态、输入输出端口和数据存储变量)的Resolve勾选上,再点击
即可。
以Signals的关联为例,如下所示:
关联信号数据对象 -
From autoMBD
Simulink会根据信号名进行解析,自动检索相同名称的数据对象进行关联。上图中可以看到,信号关联成功后,关联成功的信号数据对象会会出现在Model Data Editor窗口中。
实际上,此时的数据对象和原本的信号共同控制着模型的行为。当某信号已经关联数据对象,建议只在数据对象上进行修改和控制,尽量不要去动原始的信号实体,部分属性设置为auto即可。
状态、输入输出端口和数据存储变量的关联在不同标签页面下操作的,但关联过程是相同的,这里不再赘述。
这时候,观察模型可以发现,被关联了数据对象的信号线,会出现一个小叉子的小标记,表示该信号线被关联了数据对象,如下所示:
信号线出现叉子标记 -
From autoMBD
Tips:输入端口与其连接的信号线是同一个实体;而输出端口与连接的信号线不是同一个实体。所以上图中的输出有两个信号关联标记。
1.5.2 关联参数数据对象
关联参数数据对象比较简单,只需要在参数框填写对应的数据对象名即可,如下所示:
关联参数数据对象 -
From autoMBD
至此,模型中的信号、状态、输入输出端口、数据存储变量和参数都关联到对应的数据对象。接下来,通过设置数据对象的相关属性即可完成对代码生成的控制。
2 通过数据对象控制代码生成
当一个模型中大部分的数据形式都关联到了对应的数据对象后,就不再需要对数据的实体进行设置和控制了。
由于数据对象集中存储在数据字典中(或Base Workspace),和模型是独立的,管理起来非常方便。
数据字典具有可继承、易于拓展的特点,也更加适合需求设计和迭代开发。
通过数据对象控制代码生成,主要是通过数据对象的两个方面属性设置实现的:
基本属性(Design)
代码生成属性(Code Generation)
数据对象的基础属性和代码生成属性 -
From autoMBD
Tips:在《详解数据对象与数据字典(上)》中,也通过类的角度介绍了这两方面属性。
信号和参数数据对象的这两部分基本上是一样的,下面一并进行介绍。
2.1 数据对象的基础属性
数据对象的基础属性中,对代码生成有影响且比较常用到的是:
基础属性中大多根据实际要求设计即可。其中数据类型可以选择已创建的其他数据类型数据对象,如下所示输入信号选择的是Bus总线数据类型:
数据对象设置Bus类型数据对象 -
From autoMBD
2.2 数据对象的代码生成属性
数据对象的代码生成属性,可以最大限度地控制代码生成的形式,其主要是通过存储类来实现的。
Tips:关于存储类的介绍,可以参考《MBD的Simulink使用技巧⑩:数据存储类的使用方法》,这篇文章里有详细介绍。
代码生成属性中,可以选择系统内置的存储类,也可以自定义存储类。
选择不同的数据存储类后,有不同的Custom attributes选项,可以设置头文件、源文件、标识符等。合理设置这些属性可以提高生成代码的可读性、执行效率和集成效率。
以GetSet存储类为例,如下所示:
设置输出端口的存储类:GetSet -
From autoMBD本示例模型中,对参数、信号、离散状态、数据存储变量和输入输出端口的数据对象,都进行代码生成属性的设置和修改,具体修改内容可以打开tA36模型和相应的数据字典查看。
数据对象的属性设计完成后,即可生成代码了,最终生成的代码如下:
#include "autoMBD_example_PI_ObjectiveDD.h"#include"autoMBD_example_PI_ObjectiveDD_private.h"#include"myOutput.h"
/* Exported block signals */Float32 g_Err; /* '<Root>/Sum2' */Float32 g_PI_Ctrl; /* '<Root>/Sum1' */
/* Exported data definition */
/* Definition for custom storage class: Localizable */static Float32 DiscIntegState; /* '<Root>/Discrete-Time Integrator' */static Float32 InternalStoreMemory; /* '<Root>/Data Store Memory' */
/* Definition for custom storage class: Struct */myInputStuct_type myInputStuct;
/* Real-time model */static RT_MODEL_autoMBD_example_PI_ObjectiveDD_T autoMBD_example_PI_ObjectiveDD_M_;RT_MODEL_autoMBD_example_PI_ObjectiveDD_T *const autoMBD_example_PI_ObjectiveDD_M = &autoMBD_example_PI_ObjectiveDD_M_;
/* Model step function */voidautoMBD_example_PI_ObjectiveDD_step(void){/* Sum: '<Root>/Sum2' incorporates: * Inport: '<Root>/InSig' */ g_Err = myInputStuct.myInput.Req_Ctrl - myInputStuct.myInput.Feedback;
/* Gain: '<Root>/Ki' incorporates: * DataStoreWrite: '<Root>/Data Store Write' */ InternalStoreMemory = myParam_Ki * g_Err;
/* DiscreteIntegrator: '<Root>/Discrete-Time Integrator' incorporates: * DataStoreWrite: '<Root>/Data Store Write' */ DiscIntegState = 0.001F * InternalStoreMemory + DiscIntegState;
/* Sum: '<Root>/Sum1' incorporates: * Gain: '<Root>/Kp' */ g_PI_Ctrl = myParam_Kp * g_Err + DiscIntegState;
/* Outport: '<Root>/PI_Ctrl' */ set_myOutput(g_PI_Ctrl);}如果阅读一下上面的代码,可以发现代码的可读性大大提高了。更多其他生成的代码,读者可以自行运行tA36模型查看。
3 数据对象和数据字典总结数据对象和数据字典的介绍,到本篇算是告一段落了。由于数据对象和数据字典的内容在实际应用中比较常用,所以花了较多笔墨。希望读者能有所收获。理解数据对象和数据字典,最重要的是理解数据与模型之间的关系。笔者认为包括以下三点:
独立性:有利于数据和模型分别的迭代开发、管理;
通用性:一份数据供多个模型使用,或一个模型快速变更不同数据;
操作性:可以通过.m脚本实现自动化测试和管理。
然后就是数据对象对代码生成的控制,主要是通过代码生成属性来实现的,数据存储类起了非常重要的作用。
更多的内容,欢迎在文章中寻找和探索,也欢迎与我私信交流。
如果你觉得文章对你有帮助,欢迎关注,我会持续更新更多原创文章
与我交流讨论
由于新开通的公众号均不支持留言,欢迎给我发私信,我会及时回复的
。
版权归autoMBD所有,转载请注明作者和来源。