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


    文章目录

    前言

    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对该部分内容的说明如下所示。

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

    模块配置

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

    编写Update_wrapper()

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

    1. void DFT_CMexSfuncBuilder_Update_wrapper(const real_T *u0,
    2. real_T *y0,
    3. real_T *xD,
    4. const real_T *Freq, const int_T p_width0)
    5. {
    6. /* Update_BEGIN */
    7. static real_T Fs = 10e3;
    8. static real_T L = 5e3;
    9. real_T Sr_cos;
    10. real_T Sr_sin;
    11. real_T T;
    12. if(xD[0]<=L)
    13. {
    14. Sr_cos = cos(2*3.14*xD[4]*xD[1]);
    15. Sr_sin = sin(2*3.14*xD[4]*xD[1]);
    16. xD[2] = xD[2] + u0[0]*Sr_cos;
    17. xD[3] = xD[3] + u0[0]*Sr_sin;
    18. xD[0] = xD[0] + 1;
    19. T = 1/Fs;
    20. xD[1] = xD[1] + T;
    21. }
    22. /* Update_END */
    23. }

    编写Outputs_wrapper()

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

    1. void DFT_CMexSfuncBuilder_Outputs_wrapper(const real_T *u0,
    2. real_T *y0,
    3. const real_T *xD,
    4. const real_T *Freq, const int_T p_width0)
    5. {
    6. /* Output_BEGIN */
    7. /* This sample sets the output equal to the input
    8. y0[0] = u0[0];
    9. For complex signals use: y0[0].re = u0[0].re;
    10. y0[0].im = u0[0].im;
    11. y1[0].re = u1[0].re;
    12. y1[0].im = u1[0].im;
    13. */
    14. static real_T L = 5e3;
    15. real_T real = 0;
    16. real_T imag = 0;
    17. real_T modl = 0;
    18. if(xD[0]==L+1)
    19. {
    20. real = xD[2]/L*2;
    21. imag = xD[3]/L*2;
    22. modl = sqrt(real*real + imag*imag);
    23. y0[0] = modl;
    24. }
    25. /* Output_END */
    26. }

    Build S-Fuction

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

            其中,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模型中进行验证,如下所示:

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

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

    生成代码

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

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

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

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


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

  • 相关阅读:
    后端接口错误总结
    基于随机森林、svm、CNN机器学习的风控欺诈识别模型
    Python量化接口源码分享
    web站点的欢迎页面
    数学建模与MatheMatica
    你对Spring Security使用场景以及底层原理有了解吗?
    Docker安装MySql教程步骤
    visual studio 2022 opencv 4.6.0 创建测试工程
    spring中注解来创建bean
    29 | 在 centos中部署 openssl
  • 原文地址:https://blog.csdn.net/CSSUST/article/details/133564049