开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块

文章目录

前言

S-Fuction Builder

模块配置

编写Update_wrapper()

编写Outputs_wrapper()

Build S-Fuction

仿真验证

生成代码

Tips

分析和应用

总结


前言

        见《开箱报告,Simulink Toolbox库模块使用指南(一)——powergui模块》

        见《开箱报告,Simulink Toolbox库模块使用指南(二)——MATLAB Fuction模块》

        见《开箱报告,Simulink Toolbox库模块使用指南(三)——Simscape 电路仿真模块》

        见《开箱报告,Simulink Toolbox库模块使用指南(四)——S-Fuction模块》

        见《开箱报告,Simulink Toolbox库模块使用指南(五)——S-Fuction模块(C MEX S-Function)》

        见《开箱报告,Simulink Toolbox库模块使用指南(六)——S-Fuction模块(TLC)》

S-Fuction Builder

        S-Fuction Builter模块Mathworks官方Help对该部分内容的说明如下所示。

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第1张图片

        DFT算法的原理讲解和模块开发在前几篇文章中已经完成了,本文介绍如何使用S-Fuction Builter模块一步到位地自动开发DFT算法模块,包括建立C MEX S-Function文件、TLC文件和编译生成等工作。

模块配置

        第一步是模块配置,包括S-Fuction的名字、开发语言、输入输出端口、状态变量和固定参数等,如下图所示:

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第2张图片

编写Update_wrapper()

         第二步是编写Update_wrapper()函数,沿用前期C MEX S-Function的代码,使用自动生成的函数接口,写出的Update_wrapper()函数如下:

void DFT_CMexSfuncBuilder_Update_wrapper(const real_T *u0,
                                        real_T *y0,
                                        real_T *xD,
                                        const real_T *Freq, const int_T p_width0)
{
/* Update_BEGIN */
    static real_T Fs = 10e3;
    static real_T L = 5e3;
        
    real_T Sr_cos;
    real_T Sr_sin;
    real_T T;
            
    if(xD[0]<=L)
    {   
        Sr_cos = cos(2*3.14*xD[4]*xD[1]);
        Sr_sin = sin(2*3.14*xD[4]*xD[1]);
        xD[2] = xD[2] + u0[0]*Sr_cos;
        xD[3] = xD[3] + u0[0]*Sr_sin;
        
        xD[0] = xD[0] + 1;
        T = 1/Fs;
        xD[1] = xD[1] + T;
    }
/* Update_END */
}

编写Outputs_wrapper()

        第三步是编写Outputs_wrapper()函数,沿用前期C MEX S-Function的代码,使用自动生成的函数接口,写出的Outputs_wrapper()函数如下:

void DFT_CMexSfuncBuilder_Outputs_wrapper(const real_T *u0,
                                        real_T *y0,
                                        const real_T *xD,
                                        const real_T *Freq, const int_T p_width0)
{
/* Output_BEGIN */
/* This sample sets the output equal to the input
      y0[0] = u0[0]; 
   For complex signals use: y0[0].re = u0[0].re; 
      y0[0].im = u0[0].im;
      y1[0].re = u1[0].re;
      y1[0].im = u1[0].im;
 */
    static real_T L = 5e3;
    real_T real = 0;
    real_T imag = 0;
    real_T modl = 0;
    
    if(xD[0]==L+1)
    {
        real = xD[2]/L*2;
        imag = xD[3]/L*2;
        modl = sqrt(real*real + imag*imag);
        y0[0] = modl;       
    }
/* Output_END */
}

Build S-Fuction

        上述配置和函数编写完成后,点击Build按钮,可以看到如下是信息:

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第3张图片

        其中,DFT_CMexSfuncBuilder.c文件就是自动生成的C MEX文件,DFT_CMexSfuncBuilder_wrapper.c文件是C MEX文件中调用的wrapper函数,DFT_CMexSfuncBuilder.tlc是自动生成的TLC文件。

        与此同时,工程文件夹里边还会自动生成DFT_CMexSfuncBuilder.mexw64、rtwmakecfg.m和SFB__DFT_CMexSfuncBuilder__SFB.mat,都是S-Fuction的执行文件和代码生成和编译的相关文件。

仿真验证

        将上述编写好的S-Fuction Buider模块,放入Simulink模型中进行验证,如下所示:

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第4张图片

        运行上述模型,得到的电流和电压如上图所示,与前期C MEX S-Function的结果一致。

        至此,可以证明该S-Fuction Buider模块可以较好地实现,手动开发C MEX S-Function相同的功能。

生成代码

        点击代码生成按钮,可以看到如下过程提示:

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第5张图片

        点击打开报告按钮,可以看到如下生成报告:

开箱报告,Simulink Toolbox库模块使用指南(七)——S-Fuction Builder模块_第6张图片

        点击左侧的sfucbuilder.c超链接,可以看到如下生成的代码,其中30行到117行是该模型主要功能的代码,47行到86行是与我们S-Fuction Buider模块直接相关的代码。

File: sfucbuilder.c
1	/*
2	 * sfucbuilder.c
3	 *
4	 * Code generation for model "sfucbuilder".
5	 *
6	 * Model version              : 1.52
7	 * Simulink Coder version : 9.4 (R2020b) 29-Jul-2020
8	 * C source code generated on : Thu Oct  5 22:12:11 2023
9	 *
10	 * Target selection: grt.tlc
11	 * Note: GRT includes extra infrastructure and instrumentation for prototyping
12	 * Embedded hardware selection: Intel->x86-64 (Windows64)
13	 * Code generation objectives: Unspecified
14	 * Validation result: Not run
15	 */
16	
17	#include "sfucbuilder.h"
18	#include "sfucbuilder_private.h"
19	
20	/* Block signals (default storage) */
21	B_sfucbuilder_T sfucbuilder_B;
22	
23	/* Block states (default storage) */
24	DW_sfucbuilder_T sfucbuilder_DW;
25	
26	/* Real-time model */
27	static RT_MODEL_sfucbuilder_T sfucbuilder_M_;
28	RT_MODEL_sfucbuilder_T *const sfucbuilder_M = &sfucbuilder_M_;
29	
30	/* Model step function */
31	void sfucbuilder_step(void)
32	{
33	  /* Selector: '/Selector5' incorporates:
34	   *  Constant: '/Constant6'
35	   *  UnitDelay: '/Output'
36	   */
37	  sfucbuilder_B.Selector5 =
38	    sfucbuilder_ConstP.Constant6_Value[sfucbuilder_DW.Output_DSTATE];
39	
40	  /* Selector: '/Selector4' incorporates:
41	   *  Constant: '/Constant5'
42	   *  UnitDelay: '/Output'
43	   */
44	  sfucbuilder_B.Selector4 =
45	    sfucbuilder_ConstP.Constant5_Value[sfucbuilder_DW.Output_DSTATE];
46	
47	  /* S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder' */
48	  DFT_CMexSfuncBuilder_Outputs_wrapper(&sfucbuilder_B.Selector4,
49	    &sfucbuilder_B.SFunctionBuilder, &sfucbuilder_DW.SFunctionBuilder_DSTATE[0],
50	    &sfucbuilder_ConstP.pooled1, 1);
51	
52	  /* S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder1' */
53	  DFT_CMexSfuncBuilder_Outputs_wrapper(&sfucbuilder_B.Selector5,
54	    &sfucbuilder_B.SFunctionBuilder1, &sfucbuilder_DW.SFunctionBuilder1_DSTATE[0],
55	    &sfucbuilder_ConstP.pooled1, 1);
56	
57	  /* Switch: '/FixPt Switch' incorporates:
58	   *  Constant: '/FixPt Constant'
59	   *  Sum: '/FixPt Sum1'
60	   *  UnitDelay: '/Output'
61	   */
62	  if ((uint16_T)(sfucbuilder_DW.Output_DSTATE + 1U) > 4999) {
63	    /* Update for UnitDelay: '/Output' incorporates:
64	     *  Constant: '/Constant'
65	     */
66	    sfucbuilder_DW.Output_DSTATE = 0U;
67	  } else {
68	    /* Update for UnitDelay: '/Output' */
69	    sfucbuilder_DW.Output_DSTATE++;
70	  }
71	
72	  /* End of Switch: '/FixPt Switch' */
73	
74	  /* Update for S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder' */
75	
76	  /* S-Function "DFT_CMexSfuncBuilder_wrapper" Block: /S-Function Builder */
77	  DFT_CMexSfuncBuilder_Update_wrapper(&sfucbuilder_B.Selector4,
78	    &sfucbuilder_B.SFunctionBuilder, &sfucbuilder_DW.SFunctionBuilder_DSTATE[0],
79	    &sfucbuilder_ConstP.pooled1, 1);
80	
81	  /* Update for S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder1' */
82	
83	  /* S-Function "DFT_CMexSfuncBuilder_wrapper" Block: /S-Function Builder1 */
84	  DFT_CMexSfuncBuilder_Update_wrapper(&sfucbuilder_B.Selector5,
85	    &sfucbuilder_B.SFunctionBuilder1, &sfucbuilder_DW.SFunctionBuilder1_DSTATE[0],
86	    &sfucbuilder_ConstP.pooled1, 1);
87	
88	  /* Matfile logging */
89	  rt_UpdateTXYLogVars(sfucbuilder_M->rtwLogInfo,
90	                      (&sfucbuilder_M->Timing.taskTime0));
91	
92	  /* signal main to stop simulation */
93	  {                                    /* Sample time: [0.001s, 0.0s] */
94	    if ((rtmGetTFinal(sfucbuilder_M)!=-1) &&
95	        !((rtmGetTFinal(sfucbuilder_M)-sfucbuilder_M->Timing.taskTime0) >
96	          sfucbuilder_M->Timing.taskTime0 * (DBL_EPSILON))) {
97	      rtmSetErrorStatus(sfucbuilder_M, "Simulation finished");
98	    }
99	  }
100	
101	  /* Update absolute time for base rate */
102	  /* The "clockTick0" counts the number of times the code of this task has
103	   * been executed. The absolute time is the multiplication of "clockTick0"
104	   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
105	   * overflow during the application lifespan selected.
106	   * Timer of this task consists of two 32 bit unsigned integers.
107	   * The two integers represent the low bits Timing.clockTick0 and the high bits
108	   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
109	   */
110	  if (!(++sfucbuilder_M->Timing.clockTick0)) {
111	    ++sfucbuilder_M->Timing.clockTickH0;
112	  }
113	
114	  sfucbuilder_M->Timing.taskTime0 = sfucbuilder_M->Timing.clockTick0 *
115	    sfucbuilder_M->Timing.stepSize0 + sfucbuilder_M->Timing.clockTickH0 *
116	    sfucbuilder_M->Timing.stepSize0 * 4294967296.0;
117	}
118	
119	/* Model initialize function */
120	void sfucbuilder_initialize(void)
121	{
122	  /* Registration code */
123	
124	  /* initialize non-finites */
125	  rt_InitInfAndNaN(sizeof(real_T));
126	
127	  /* initialize real-time model */
128	  (void) memset((void *)sfucbuilder_M, 0,
129	                sizeof(RT_MODEL_sfucbuilder_T));
130	  rtmSetTFinal(sfucbuilder_M, 10.0);
131	  sfucbuilder_M->Timing.stepSize0 = 0.001;
132	
133	  /* Setup for data logging */
134	  {
135	    static RTWLogInfo rt_DataLoggingInfo;
136	    rt_DataLoggingInfo.loggingInterval = NULL;
137	    sfucbuilder_M->rtwLogInfo = &rt_DataLoggingInfo;
138	  }
139	
140	  /* Setup for data logging */
141	  {
142	    rtliSetLogXSignalInfo(sfucbuilder_M->rtwLogInfo, (NULL));
143	    rtliSetLogXSignalPtrs(sfucbuilder_M->rtwLogInfo, (NULL));
144	    rtliSetLogT(sfucbuilder_M->rtwLogInfo, "tout");
145	    rtliSetLogX(sfucbuilder_M->rtwLogInfo, "");
146	    rtliSetLogXFinal(sfucbuilder_M->rtwLogInfo, "");
147	    rtliSetLogVarNameModifier(sfucbuilder_M->rtwLogInfo, "rt_");
148	    rtliSetLogFormat(sfucbuilder_M->rtwLogInfo, 0);
149	    rtliSetLogMaxRows(sfucbuilder_M->rtwLogInfo, 0);
150	    rtliSetLogDecimation(sfucbuilder_M->rtwLogInfo, 1);
151	    rtliSetLogY(sfucbuilder_M->rtwLogInfo, "");
152	    rtliSetLogYSignalInfo(sfucbuilder_M->rtwLogInfo, (NULL));
153	    rtliSetLogYSignalPtrs(sfucbuilder_M->rtwLogInfo, (NULL));
154	  }
155	
156	  /* block I/O */
157	  (void) memset(((void *) &sfucbuilder_B), 0,
158	                sizeof(B_sfucbuilder_T));
159	
160	  /* states (dwork) */
161	  (void) memset((void *)&sfucbuilder_DW, 0,
162	                sizeof(DW_sfucbuilder_T));
163	
164	  /* Matfile logging */
165	  rt_StartDataLoggingWithStartTime(sfucbuilder_M->rtwLogInfo, 0.0, rtmGetTFinal
166	    (sfucbuilder_M), sfucbuilder_M->Timing.stepSize0, (&rtmGetErrorStatus
167	    (sfucbuilder_M)));
168	
169	  /* InitializeConditions for UnitDelay: '/Output' */
170	  sfucbuilder_DW.Output_DSTATE = 0U;
171	
172	  /* InitializeConditions for S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder' */
173	
174	  /* S-Function Block: /S-Function Builder */
175	  {
176	    real_T initVector[5] = { 1, 0, 0, 0, 50.0 };
177	
178	    {
179	      int_T i1;
180	      real_T *dw_DSTATE = &sfucbuilder_DW.SFunctionBuilder_DSTATE[0];
181	      for (i1=0; i1 < 5; i1++) {
182	        dw_DSTATE[i1] = initVector[i1];
183	      }
184	    }
185	  }
186	
187	  /* InitializeConditions for S-Function (DFT_CMexSfuncBuilder): '/S-Function Builder1' */
188	
189	  /* S-Function Block: /S-Function Builder1 */
190	  {
191	    real_T initVector[5] = { 1, 0, 0, 0, 50.0 };
192	
193	    {
194	      int_T i1;
195	      real_T *dw_DSTATE = &sfucbuilder_DW.SFunctionBuilder1_DSTATE[0];
196	      for (i1=0; i1 < 5; i1++) {
197	        dw_DSTATE[i1] = initVector[i1];
198	      }
199	    }
200	  }
201	}
202	
203	/* Model terminate function */
204	void sfucbuilder_terminate(void)
205	{
206	  /* (no terminate code required) */
207	}
208	

        人工检查上述自动生成的C代码,可以实现该Simulink模型设计的功能。

        至此,可以证明该S-Fuction Buider模块可以较好地实现,手动开发TLC相同的功能。

Tips

        本文沿用的例子--DFT算法S-Fuction开发,涉及到一个参数Freq。按照前期C MEX S-Function开发的经验,是可以通过函数直接引用的Freq = (real_T) *mxGetPr(ssGetSFcnParam(S,0)),但是在S-Fuction Buider里边尝试直接应用参数Freq时,却出现了报错。查阅相关资料后,发现有人是先把参数作为初始值赋给一个状态变量,然后再拿这个状态变量作为参数使用。本文中的第5个状态变量xD[4]就是充当Freq的中转桥,经验证这种方法确实可行。虽然这种方法稍微有点绕弯,但是也不失是一种解决问题的办法。

分析和应用

        前面分析了那么多C MEX S-Function和TLC的特点和应用,本文S-Fuction Buider是集它们特点于一身的存在,并且把C MEX S-Function中复杂的接口函数和TLC中复杂的语法,都变成了Matlab后台自动执行的工作,开发者只需把注意力集中在C算法的移植上即可,大大提升了S-Function开发的工作效率。

总结

        以上就是本人在使用S-Fuction Buider时,一些个人理解和分析的总结,首先介绍了S-Fuction Buider的基本知识,然后展示它的使用方法,最后分析了该模块的特点和适用场景。

        后续还会分享另外几个最近总结的Simulink Toolbox库模块,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。

        另外,上述例程使用的Demo工程,可以到笔者的主页查找和下载。


版权声明,原创文章,转载和引用请注明出处和链接,侵权必究!

你可能感兴趣的:(Matlab/Simulink,汽车电子,嵌入式软件,Matlab/Simulink,DFT算法,SFunctionBuider,自动代码生成,C语言)