|
汽车零部件采购、销售通信录 填写你的培训需求,我们帮你找 招募汽车专业培训老师
全文约3000字,你将看到以下内容:
函数(代码)接口封装
模型不可复用函数
模型可复用函数
变量名称的格式控制符
模型函数的复用方法
autoMBD最近发布了《autoMBD原创技术文章合集》
合集包含156页丰富的MBD入门基础和MBDT硬件支持包的使用还包含基于MBD的电机控制算法开源项目——AMBD-MC合集配备了丰富的视频讲解
和大量的模型、文档和软件资源
如何获取请参考@所有读者:autoMBD发布《autoMBD原创技术文章合集》。
在上一期文章中,介绍了如何通过“Configure C Step Function Interface”来修改函数的原型和传参。但是该方法有一些限制,例如:只能修改Step函数的原型;不支持可重用函数;也不支持多任务模型(multitasking model)等。
本篇文章是第8期文章的补充,将介绍另外一种通过控制函数接口封装形式的方法,来实现对函数原型、传参的修改,还能支持模型代码的可复用。
点击以下链接,可以查看MBD的Simulink使用技巧系列的往期文章:
MBD的Simulink使用技巧①:Simulink代码生成的基本概念MBD的Simulink使用技巧②:详解代码生成中的模型与代码MBD的Simulink使用技巧③:虚拟子系统与原子子系统的代码生成MBD的Simulink使用技巧④:详解生成代码的结构与代码的生成流程
MBD的Simulink使用技巧⑤:详解自动代码生成的配置与优化
MBD的Simulink使用技巧⑥:代码生成目标配置工具
MBD的Simulink使用技巧⑦:自动生成代码的集成方法
MBD的Simulink使用技巧⑧:函数原型、传参的控制与修改
特别提示:在本篇文章中使用到的PI控制器模型等文件,可以在autoMBD资源库的“临时资源分享”文件夹中找到(资源序号为tA22、tA30)。资源库链接的获取可以在《autoMBD原创技术文章合集》中找到(见文章开头)。
1 函数(代码)接口封装
函数(代码)接口封装(Code Interface Packaging)配置项可以直接控制生成代码的接口形式,从而改变函数原型和传参。
它位于Code Generation -> Interface配置页面,如下所示:
代码接口封装配置选项 - From autoMBD
该选项对顶层模型起作用,它一共有两个可选项:
Nonreusable function(不可复用函数)
Reusable function(可复用函数)
2 模型不可复用函数
Tips:在《MBD的Simulink使用技巧③:虚拟子系统与原子子系统的代码生成》中我们介绍了子系统模型如何生成不可复用函数和可复用函数,这里的可复用性是针对顶层模型的。
默认情况下函数接口封装选项为“不可复用函数”,此时函数原型、传参由“Configure C Step Function Interface”中的配置决定(详见上一期)。
上一篇文章中,如果读者已经使用tA27模型生成了代码,可以发现其生成的Step函数并不能实现重复使用。原因是模型中包含了一个离散积分器,它具有状态量(States)。
tA27模型生成的代码中,离散积分器的状态量生成了一个全局变量,如下所示:
/* 文件:autoMBD_example_PI_SetArg.c *//* Block states (default storage) */DW_autoMBD_example_PI_SetArg_T autoMBD_example_PI_SetArg_DW;该状态量并没有作为传参传入Step函数,因而每一次调用Step函数都会改变同一个状态量,使得Step函数不可复用。
3 模型可复用函数如果将函数接口封装选项设置为“可复用函数”,函数会生成包含输入传参、输出传参、状态传参的函数形式,函数原型随之发生变化。新增的状态传参使得模型能够实现可重复使用。
将选项设置为“可复用函数”后,页面将会新出现两个配置项,如下所示:
新增的配置项为:
Multi-instance code error diagnostic
Pass root-level I/O as
前者为诊断信息,保持默认即可。后者是影响函数接口形式的关键选项,一共包含三个可选项:
Individual arguments(独立传参)
Structure reference(结构体传参)
Part of model data structure(模型集合传参)
只看名称比较抽象,这里还是以初始的PI控制器模型生成的代码为例,向大家展示这三个选项的区别:
初始PI控制器模型 - From autoMBD
Tips:该模型可以在autoMBD资源库的“临时资源分享”文件夹中找到该模型,资源序号tA22。
作为对比,一共包含四种情况,即:默认配置下(不可复用函数),以及分别设置这三个选项。生成的函数接口分别如下:
/* 文件:autoMBD_example_PI_noSubs.h *//* Model entry point functions */externvoidautoMBD_example_PI_noSubs_initialize(void);externvoidautoMBD_example_PI_noSubs_step(void);externvoidautoMBD_example_PI_noSubs_terminate(void);
Pass root-level I/O as: Individual arguments(可复用函数)
/* 文件:autoMBD_example_PI_noSubs.h *//* Model entry point functions */externvoidautoMBD_example_PI_noSubs_initialize( RT_MODEL_autoMBD_example_PI_n_T *const autoMBD_example_PI_noSubs_M, real_T *autoMBD_example_PI_noSubs_U_Req_Ctrl, real_T *autoMBD_example_PI_noSubs_U_Feedback, real_T *autoMBD_example_PI_noSubs_Y_PI_Ctrl);externvoidautoMBD_example_PI_noSubs_step( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M, real_T autoMBD_example_PI_noSubs_U_Req_Ctrl, real_T autoMBD_example_PI_noSubs_U_Feedback, real_T *autoMBD_example_PI_noSubs_Y_PI_Ctrl);externvoidautoMBD_example_PI_noSubs_terminate( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M);
Pass root-level I/O as: Structure reference(可复用函数)
/* 文件:autoMBD_example_PI_noSubs.h *//* Model entry point functions */extern void autoMBD_example_PI_noSubs_initialize( RT_MODEL_autoMBD_example_PI_n_T *const autoMBD_example_PI_noSubs_M, ExtU_autoMBD_example_PI_noSub_T *autoMBD_example_PI_noSubs_U, ExtY_autoMBD_example_PI_noSub_T *autoMBD_example_PI_noSubs_Y);externvoidautoMBD_example_PI_noSubs_step( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M, ExtU_autoMBD_example_PI_noSub_T *autoMBD_example_PI_noSubs_U, ExtY_autoMBD_example_PI_noSub_T *autoMBD_example_PI_noSubs_Y);externvoidautoMBD_example_PI_noSubs_terminate( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M);
Pass root-level I/O as: Part of model data structure(可复用函数)
/* 文件:autoMBD_example_PI_noSubs.h *//* Model entry point functions */externvoidautoMBD_example_PI_noSubs_initialize( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M);externvoidautoMBD_example_PI_noSubs_step( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M);externvoidautoMBD_example_PI_noSubs_terminate( RT_MODEL_autoMBD_example_PI_n_T * const autoMBD_example_PI_noSubs_M);生成的代码看着比较复杂,实际上只是自动生成的数据类型和变量名太长了而已,本身并不复杂。仔细对比可以发现:开启可复用函数后,函数接口(包括Step函数、初始化函数和终止函数)的传参均不再为空(void),而是包含输入传参、输出传参、状态传参三个部分。这三部分传参在不同的“Pass root-level I/O as”配置选项下表现出不同的形式:
Individual arguments:每个输入、输出变量都是分开独立的;状态变量存放在模型结构体中。
Structure reference:所有的输入变量放在一个结构体中,通过输入结构体指针输入;输出变量亦是如此;状态变量存放在模型结构体中。
Part of model data structure:所有的输入变量、输出变量、状态变量都存放在模型结构体中,通过结构体指针输入。
第三种配置选项和上一篇中介绍的“结构体指针传参”方法有类似的效果,区别是:本篇中的结构体是Simulink自动生成的,除了输入、输出,还包含状态量和模型相关信息;而上篇中的结构体是用户自定义的,用户自由度更高。下面的代码展示了第三种配置选项下,模型结构体是如何存放所有输入变量、输出变量、状态变量的:
/* 文件:autoMBD_example_PI_noSubs.h *//* Block states (default storage) for system '<Root>' */typedefstruct { real_T DiscreteTimeIntegrator_DSTATE;/* '<Root>/Discrete-Time Integrator' */} DW_autoMBD_example_PI_noSubs_T;
/* External inputs (root inport signals with default storage) */typedefstruct { real_T Req_Ctrl; /* '<Root>/Req_Ctrl' */ real_T Feedback; /* '<Root>/Feedback' */} ExtU_autoMBD_example_PI_noSub_T;
/* External outputs (root outports fed by signals with default storage) */typedefstruct { real_T PI_Ctrl; /* '<Root>/PI_Ctrl' */} ExtY_autoMBD_example_PI_noSub_T;
/* Real-time Model Data Structure */structtag_RTM_autoMBD_example_PI_no_T {const char_T * volatile errorStatus; ExtU_autoMBD_example_PI_noSub_T *inputs; ExtY_autoMBD_example_PI_noSub_T *outputs; DW_autoMBD_example_PI_noSubs_T *dwork;};特别提示,当配置为“Individual arguments”时,函数接口封装(Code Interface Packaging)是可以和“Configure C Step Function Interface”同时起作用的,此时传参形式和传参变量名由后者控制,读者可以自行验证体会。而另外两个配置项,不能和“Configure C Step Function Interface”同时使用,会产生错误。
4 变量名称的格式控制符上述介绍的函数接口封装的配置方法也有一些不足,它不能直接控制和修改函数名、传参名。要修改这些名称,需要在其他地方进行配置。修改函数名依然可以在“Code Mappings - C”窗口操作(详见上一期)。如果要修改传参名、变量名,那么只能通过修改Simulink标识符“Identifiers”来实现(Individual arguments除外):
Simulink标识符Identifier - From autoMBD在标识符配置页面中,列出来各种变量和数据类型的格式控制符,其中带“$”符号的是转义字符。通过修改这些格式控制符,可以达到修改传参名、变量名称的目的。
要注意的是,格式控制符对全局生效,相同类型的变量和数据类型都会按照同一个格式控制符生成代码。所以通过它来控制名称并不算太灵活,但总归能实现。
下面是对Simulink转义字符的归纳总结:
$R,顶层模型名$G,存储类名$N,对象名$U,用户定义文本$H,系统层级数$F,子系统方法名$E,文件类型$I,输入或输出$M,名称剪切处(当名称超过约定长度,该转义字符前面的内容会被剪切)
5 模型函数的复用方法
生成可复用的模型函数(包括Step函数、初始化函数和终止函数)后,需要定义实例化参数(Instancing Variables)才能使用这些接口函数,模型函数是通过多个不同的实例化参数实现复用的。
下文以PI控制器配置可复用函数为“Structure reference”时生成的代码来展示实例化参数的方法。
Tips:该模型可以在autoMBD资源库的“临时资源分享”文件夹中找到该模型,资源序号tA30。
首先在model.h中,会生成状态变量、输入变量、输出变量和模型变量的结构体类型定义,如下所示:
/* 文件:autoMBD_example_PI_noSubsReusable.h *//* Block states (default storage) for system '<Root>' */typedefstruct { real_T DiscreteTimeIntegrator_DSTATE;/* '<Root>/Discrete-Time Integrator' */} DW_autoMBD_example_PI_noSubsR_T;
/* External inputs (root inport signals with default storage) */typedefstruct { real_T Req_Ctrl; /* '<Root>/Req_Ctrl' */ real_T Feedback; /* '<Root>/Feedback' */} ExtU_autoMBD_example_PI_noSub_T;
/* External outputs (root outports fed by signals with default storage) */typedefstruct { real_T PI_Ctrl; /* '<Root>/PI_Ctrl' */} ExtY_autoMBD_example_PI_noSub_T;
/* Real-time Model Data Structure */structtag_RTM_autoMBD_example_PI_no_T { DW_autoMBD_example_PI_noSubsR_T *dwork;};模型变量结构体在中model_types.h被定义为数据类型:
/* 文件:autoMBD_example_PI_noSubsReusable_types.h *//* Forward declaration for rtModel */typedefstructtag_RTM_autoMBD_example_PI_no_TRT_MODEL_autoMBD_example_PI_n_T;用以上定义的结构体数据类型,直接定义变量即可,即要对模型、输入、输出和状态分别定义变量,从而得到实例化变量,如下所示:
/* 文件:ert_main.c */static RT_MODEL_autoMBD_example_PI_n_T autoMBD_example_PI_noSubsReu_M_;static RT_MODEL_autoMBD_example_PI_n_T *const autoMBD_example_PI_noSubsR_MPtr = &autoMBD_example_PI_noSubsReu_M_; /* Real-time model */static DW_autoMBD_example_PI_noSubsR_T autoMBD_example_PI_noSubsReu_DW;/* Observable states */static ExtU_autoMBD_example_PI_noSub_T autoMBD_example_PI_noSubsReus_U;/* External inputs */static ExtY_autoMBD_example_PI_noSub_T autoMBD_example_PI_noSubsReus_Y;/* External outputs */上述代码对模型变量还定义了一个指针,所以有五个实例化变量。这五个变量组成一组,便可以使用模型函数进行运算了,如下所示:/* 文件:ert_main.c *//* Step the model */autoMBD_example_PI_noSubsReusable_step(autoMBD_example_PI_noSubsReu_M, &autoMBD_example_PI_noSubsReus_U, &autoMBD_example_PI_noSubsReus_Y);
/* Initialize model */autoMBD_example_PI_noSubsReusable_initialize(autoMBD_example_PI_noSubsReu_M, &autoMBD_example_PI_noSubsReus_U, &autoMBD_example_PI_noSubsReus_Y);
/* Terminate model */autoMBD_example_PI_noSubsReusable_terminate(autoMBD_example_PI_noSubsReu_M);可以根据实际需求,定义任意多的实例化变量(五个一组),每一组都可以独立调用模型函数,并且不会相互影响运算结果。这就是可复用模型函数的使用方法。 |
|