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

文章目录

前言

C MEX S-Function

算法原理

原始信号创建

编写S函数

仿真验证

Tips

分析和应用

总结


前言

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

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

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

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

C MEX S-Function

        C MEX S-Function是使用C语言开发的一种S-Fuction,具备前一篇文章中讲解的S-Fuction的全部基本特性。它对应S-Fuction中的Level2类型,支持访问更广泛的 S-Function API 集,并支持代码生成。由于汽车电子工程与C语言密不可分,所以我们必须对C MEX S-Function重点关注。

        Mathworks官方Help对该模块的说明如下所示。

        本文以DFT算法为例,介绍如何利用C MEX S-Function搭建项目需求中高度自定义的信号解耦模块。

算法原理

        傅里叶变换告诉我们,任何周期信号都可以分解为正弦波的叠加。具体的做法是:将被求解的原始信号,与目标频率的信号相乘,然后再积分,就得到了原始信号在该频率上的分量,公式如下:

        原始信号:S;

        目标频率信号:D_cos = cos(2pi*w*t);

        目标频率信号:D_sin = sin(2pi*w*t);

        目标信号实部:D_real = dot(S,D_cos)/N*2;

        目标信号虚部:D_imag = dot(S,D_sin)/N*2;

        目标信号模数:D_modl = sqrt(D_real^2 + D_imag^2);

原始信号创建

        这里沿用前一篇文章中的电路方程模型,见《开箱报告,Simulink Toolbox库模块使用指南(四)——S-Fuction模块》

        创建电压和电流信号如下:

        t(S) = (0 : 4999)*0.0001;

        I(A) = 4.235 + 0.035*sin(2pi * 50t + pi);

        U(A) = 3.529 + 0.071*sin(2pi * 50t);

        在Matlab的命令窗口中运行该动态方程,得到的电流和电压曲线,与前一篇文章一致,如下所示:

编写S函数

        根据官方的Basic C MEX S-Function模板,写出的S函数完整代码如下:

#define S_FUNCTION_NAME  DFT_CMexSfunc    //函数名字,与C文件名一致
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"    //Matlab宏函数库static real_T Fs = 10e3;    //信号采样频率,与信号源一致
static real_T L = 5e3;      //信号采样点个数,两者根据Nyquist定理计算/* Function: mdlInitializeSizes ===============================================* Abstract:*    The sizes information is used by Simulink to determine the S-function*    block's characteristics (number of inputs, outputs, states, etc.).*/
static void mdlInitializeSizes(SimStruct *S)
{//一个算法参数Freq,目标解算频率ssSetNumSFcnParams(S, 1);  /* Number of expected parameters */if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {/* Return if number of expected != number of actual parameters */return;}ssSetNumContStates(S, 0);ssSetNumDiscStates(S, 4);      //离散状态的个数if (!ssSetNumInputPorts(S, 1)) return;ssSetInputPortWidth(S, 0, 1);      //一个信号输入端口,信号维度1ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*//** Set direct feedthrough flag (1=yes, 0=no).* A port has direct feedthrough if the input is used in either* the mdlOutputs or mdlGetTimeOfNextVarHit functions.*/ssSetInputPortDirectFeedThrough(S, 0, 1);if (!ssSetNumOutputPorts(S, 1)) return;ssSetOutputPortWidth(S, 0, 1);      //一个信号输出端口,信号维度1ssSetNumSampleTimes(S, 1);ssSetNumRWork(S, 0);ssSetNumIWork(S, 0);ssSetNumPWork(S, 0);ssSetNumModes(S, 0);ssSetNumNonsampledZCs(S, 0);/* Specify the operating point save/restore compliance to be same as a * built-in block */ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT);ssSetOptions(S, 0);
}/* Function: mdlInitializeSampleTimes =========================================* Abstract:*    This function is used to specify the sample time(s) for your*    S-function. You must register the same number of sample times as*    specified in ssSetNumSampleTimes.*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
//     ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);ssSetSampleTime(S, 0, 0.001);     //算法运行周期0.001s,不同于信号采样频率ssSetOffsetTime(S, 0, 0.0);}#define MDL_INITIALIZE_CONDITIONS   /* Change to #undef to remove function */
#if defined(MDL_INITIALIZE_CONDITIONS)/* Function: mdlInitializeConditions ========================================* Abstract:*    In this function, you should initialize the continuous and discrete*    states for your S-function block.  The initial states are placed*    in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S).*    You can also perform any other initialization activities that your*    S-function may require. Note, this routine will be called at the*    start of simulation and if it is present in an enabled subsystem*    configured to reset states, it will be call when the enabled subsystem*    restarts execution to reset the states.*/static void mdlInitializeConditions(SimStruct *S){//离散状态赋初值real_T Count = 1;real_T t = 0;real_T cos_integ = 0;real_T sin_integ = 0;real_T *x0 = ssGetRealDiscStates(S);*x0++ = Count;*x0++ = t;*x0++ = cos_integ;*x0++ = sin_integ;}
#endif /* MDL_INITIALIZE_CONDITIONS */#define MDL_START  /* Change to #undef to remove function */
#if defined(MDL_START) /* Function: mdlStart =======================================================* Abstract:*    This function is called once at start of model execution. If you*    have states that should be initialized once, this is the place*    to do it.*/static void mdlStart(SimStruct *S){}
#endif /*  MDL_START *//* Function: mdlOutputs =======================================================* Abstract:*    In this function, you compute the outputs of your S-function*    block.*/
static void mdlOutputs(SimStruct *S, int_T tid)
{real_T real = 0;real_T imag = 0;real_T modl = 0;real_T *y = ssGetOutputPortSignal(S,0);real_T *x = ssGetRealDiscStates(S);if(x[0]==L+1){real = x[2]/L*2;imag = x[3]/L*2;modl = sqrt(real*real + imag*imag);y[0] = modl;       //解算结果输出}
}#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)/* Function: mdlUpdate ======================================================* Abstract:*    This function is called once for every major integration time step.*    Discrete states are typically updated here, but this function is useful*    for performing any tasks that should only take place once per*    integration step.*/static void mdlUpdate(SimStruct *S, int_T tid){real_T Sr_cos;real_T Sr_sin;real_T T;real_T Freq = (real_T) *mxGetPr(ssGetSFcnParam(S,0));real_T *x = ssGetRealDiscStates(S);const real_T *u = (const real_T*) ssGetInputPortSignal(S,0);if(x[0]<=L){   Sr_cos = cos(2*3.14 * Freq*x[1]);Sr_sin = sin(2*3.14 * Freq*x[1]);x[2] = x[2] + u[0]*Sr_cos;x[3] = x[3] + u[0]*Sr_sin;x[0] = x[0] + 1;T = 1/Fs;x[1] = x[1] + T;}}
#endif /* MDL_UPDATE *//* Function: mdlTerminate =====================================================* Abstract:*    In this function, you should perform any actions that are necessary*    at the termination of a simulation.  For example, if memory was*    allocated in mdlStart, this is the place to free it.*/
static void mdlTerminate(SimStruct *S)
{
}

        C代码编写好之后,用Matlab指令 'mex DFT_CMexSfunc.c' 进行编译。如果代码没有错误,编译成功后会看到如下提示:

仿真验证

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

        运行上述模型,得到的电流和电压如上图所示,也与前一篇文章一致。

        至此,可以证明该C MEX S-Fuction模块可以较好地求解,耦合信号中的自信号分量。

Tips

        C MEX S-Fuction模块能够让使用者充分自由地开发Simulink模块,一方面是跨语言的程序开发方式,只需要include其他c文件的头文件,即可调用其中已开发和验证好的c函数。另一方面是大量的能够与Simulink引擎交互的的宏函数,使得开发人员有了更大的发挥空间。一些常用的,必须熟练掌握宏函数如下:

1.系统输入宏函数

ssSetNumInputPorts(S, 1)

ssSetInputPortWidth(S, 0, 1)

ssSetInputPortDirectFeedThrough(S, 0, 1)

real_T *u = (real_T*) ssGetInputPortSignal(S,0);

Temp = u[0];

2.系统参数宏函数

ssSetNumSFcnParams(S, 1); 

real_T Pa1 = (real_T) *mxGetPr(ssGetSFcnParam(S,0));

//real_T Pa2 = (real_T) *mxGetPr(ssGetSFcnParam(S,1));

Temp = Pa1;

3.系统周期宏函数

ssSetSampleTime(S, 0, 0.001);

ssSetOffsetTime(S, 0, 0.0);

4.系统状态宏函数

ssSetNumDiscStates(S, 4);

real_T *x = ssGetRealDiscStates(S);

*x++ = a;

*x++ = b;

*x++ = c;

*x++ = d;

x[0] = x[0] + 1;

x[1] = x[1] + 1;

x[2] = x[2] + 1;

x[3] = x[3] + 1;

5.系统输出宏函数

ssSetNumOutputPorts(S, 1)

ssSetOutputPortWidth(S, 0, 1)

real_T *y = ssGetOutputPortSignal(S,0);

y[0] = a;

//y[1] = b;

//y[2] = c;

//y[3] = d;

分析和应用

        C MEX S-Fuction是S-Fuction的一种,他们的相同点一样,不同点在于灵活度和自由度进一步延伸,功能进一步扩展。比如本文举例的DFT求解模块,是在原有DFT算法的基础上进一步裁剪,只求解目标期望频率上的信号分量,并且把原本算法中集中计算的几个向量积分、乘除、开方等运算分解到每一个运算周期中,变成单个变量的运算(需要时还可以灵活调整指定N个周期把算法执行完),以此通过延长运算时间来节省算法对单个周期硬件算力的开销,不仅能够保证整个系统的实时性能,还能大大提高算法求解得数据量,以此提高求解精度。同时本文举例的DFT求解求解算法也是以前开发的,经过验证的模块功能,利用C MEX S-Fuction提供的C函数调用机制,无缝衔接的移植了过来。

总结

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

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

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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/64368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PhpStorm安装篇

PhpStorm安装篇: 下载地址 : 进入官网下PhpStorm: PHP IDE and Code Editor from JetBrains 下载完之后&#xff0c;安装包 安装目录建议不要放C盘&#xff0c;放其他盘&#xff0c;其他直接一直点 next &#xff0c;到结束 安装完&#xff0c;打开编辑器 注册账号并登录后…

Android投屏总结

#android手机投屏 ####导语 至于手机投屏的实现方法可谓五花八门&#xff0c;今天小袁就说下以开发人员的角度来说下当今手机的主流投屏方法。目前这种将终端信号经由WiFi传输到电视、电视盒的技术有三种&#xff1a;DLNA、AirPlay、Miracast、Google Cast。 ##手机投屏智能电…

python 深度学习 解决遇到的报错问题3

目录 一、AttributeError: The vocab attribute was removed from KeyedVector in Gensim 4.0.0. 二、ImportError: cannot import name logsumexp 三、FutureWarning: Passing (type, 1) or 1type as a synonym of type is deprecated; in a future version of numpy, it w…

VBA:对Excel单元格进行合并操作

Sub hb()Dim nn 3For i 3 To 18If Range("b" & i) <> Range("b" & i 1) ThenRange("b" & n & ":b" & i).Mergen i 1End IfNextEnd Sub

记录--前端使用a链接下载内容增加loading效果

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 问题描述&#xff1a;最近工作中出现一个需求&#xff0c;纯前端下载 Excel 数据&#xff0c;并且有的下载内容很多&#xff0c;这时需要给下载增加一个 loading 效果。 代码如下&#xff1a; // util…

Maven入门教程(三):Maven语法

视频教程&#xff1a;Maven保姆级教程 Maven入门教程(一)&#xff1a;安装Maven环境 Maven入门教程(二)&#xff1a;idea/Eclipse使用Maven Maven入门教程(三)&#xff1a;Maven语法 Maven入门教程(四)&#xff1a;Nexus私服 Maven入门教程(五)&#xff1a;自定义脚手架 6.Mav…

Loki日志系统

1、Loki是什么&#xff1f; Loki是一个开源的日志聚合系统&#xff0c;由Grafana Labs开发和维护。它旨在帮助用户收集、存储和查询大规模的日志数据&#xff0c;帮助用户更好地理解和监控他们的应用程序和系统。 Loki的设计灵感来自于Prometheus&#xff0c;它采用了类似的标…

【小沐学Unity3d】3ds Max 骨骼动画制作(蒙皮修改器skin)

文章目录 1、简介2、蒙皮修改器3.1 骨骼对象测试3.2 Biped对象测试 3、动画制作4、FBX导出结语 1、简介 “蒙皮”修改器是一种骨骼变形工具&#xff0c;主要设计用于通过另一个对象对一个对象进行变形来创建角色动画。可使用骨骼、样条线和其他对象变形网格、面片和 NURBS 对象…

python3+requests:接口自动化测试(二)

前言&#xff1a;上篇文章python3requestsunittest&#xff1a;接口自动化测试&#xff08;一&#xff09;&#xff1a;已经介绍了基于unittest框架的实现接口自动化&#xff0c;但是也存在一些问题&#xff0c;比如最明显的测试数据和业务没有区分开&#xff0c;接口用例不便于…

【机器学习】线性回归

Model Representation 1、问题描述2、表示说明3、数据绘图4、模型函数5、预测总结附录 1、问题描述 一套 1000 平方英尺 (sqft) 的房屋售价为300,000美元&#xff0c;一套 2000 平方英尺的房屋售价为500,000美元。这两点将构成我们的数据或训练集。面积单位为 1000 平方英尺&a…

2010-2021年上市公司和讯网社会责任评级CSR数据/和讯网上市公司社会责任数据

2010-2021年上市公司和讯网社会责任评级CSR数据 1、时间&#xff1a;2010-2021年 2、指标&#xff1a;股票名称、股票代码、年份、总得分、等级、股东责任、员工责任、供应商、客户和消费者权益责任、环境责任、社会责任、所属年份 3、样本量&#xff1a;4万 4、来源&#…

数据结构与算法基础-学习-31-交换排序之冒泡排序、快速排序

排序的其他相关知识点和源码分享可以参考之前的博客&#xff1a; 《数据结构与算法基础-学习-30-插入排序之直接插入排序、二分插入排序、希尔排序》 一、交换排序基本思想 两两比较&#xff0c;如果发生逆序则交换位置&#xff0c;直到所有数据记录都排好序为止。 二、冒…

大模型理解之CLIP

前言 2021年2月份&#xff0c;CLIP模型被提出&#xff0c;想法很简单&#xff0c;性能高效&#xff0c;而且具备很好的泛化性。我在这里简单谈论下我对CLIP模型的理解&#xff0c;以及发现的一些问题。 我是在沐神的视频中了解的CLIP, 里面提到CLIP最大的贡献在于打破了固定类…

四轴飞行器的电池研究(MatlabSimulink仿真)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

全球免费编程教育网站:Code.org

全球免费编程教育网站&#xff1a;Code.org 官网地址注册使用 你还在为小朋友的编程教育而发愁吗&#xff1f; 你还在为小朋友放假无聊而头疼吗&#xff1f; 他来了他来了&#xff0c;全球免费编程教育网站来了。 2013年成立的Code.org是一个非营利组织。 它致力于为年轻女子、…

Xilinx UltraScale架构之可配置逻辑块CLB

目录 一、概览 二、UltraScale架构 2.1 UltraScale/UltraScale特点 2.2 与7系列CLB差异 三、 CLB结构 3.1 LUT 3.2 FF 3.3 多路选择器Multiplexers 3.4 进位链Carry Chain 四、应用 4.1 分布式RAM 4.2 移位寄存器 4.3 进位链Carry Chain 五、参考资料 一、概览 二…

专门针对开发人员,攻击者利用Rust获取操作系统信息

近日&#xff0c;研究人员在 Rust 编程语言的 crate 注册表中发现了一些恶意软件包&#xff0c;专门针对开发人员。 Phylum 在上周发布的一份报告中称&#xff0c;这些库是由一个名为 "amaperf "的用户在 2023 年 8 月 14 日至 16 日之间上传的。现已删除的软件包名…

【LeetCode-中等题】114. 二叉树展开为链表

文章目录 题目方法一&#xff1a;前序遍历&#xff08;构造集合&#xff09; 集合&#xff08;构造新树&#xff09;方法二&#xff1a;原地构建方法三&#xff1a;前序遍历--迭代&#xff08;构造集合&#xff09; 集合&#xff08;构造新树&#xff09; 题目 方法一&#x…

el-select 选择一条数据后,把其余数据带过来

1. 案例&#xff1a; ps: 票号是下拉框选择&#xff0c;风险分类、场站名称以及开始时间是选择【票号】后带过来的。 2. 思路: 使用官网上给的方法&#xff0c;选择之后&#xff0c;触发change方法从而给其余字段赋值 3. 代码 <el-form-itemlabel"票号&#xff1a;&…

buildAdmin的使用笔记

安装buildAdmin 下载完整包&#xff0c;解压进入 buildadmin 的文件夹&#xff0c; 输入命令 composer install 启动的时候使用&#xff0c; php think run 就可以了 为什么启动只需要&#xff0c; php think run 这种启动方式&#xff0c; 我是头一回看见 &#xff0c;后来才…