当前位置: 首页 > news >正文

开箱报告,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工程,可以到笔者的主页查找和下载。


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

相关文章:

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

文章目录 前言 C MEX S-Function 算法原理 原始信号创建 编写S函数 仿真验证 Tips 分析和应用 总结 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;一&#xff09;——powergui模块》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用…...

摄像头的调用和视频识别

CV_tutorial3 摄像头调用实时播放保存视频 运动目标识别帧差法背景减除法 摄像头调用 创建视频捕捉对象&#xff1a;cv2.VideoCapture() 参数为视频设备的索引号&#xff0c;就一个摄像投的话写0默认&#xff1b; 或者是指定要读取视频的路径。 实时播放 import cv2 import …...

多通道分离与合并

目录 1.多通道分离split() 2.多通道合并merge() 3.Android JNI demo 1.多通道分离split() void cv::split ( InputArray m, OutputArrayOfArrays mv &#xff09; m:待分离的多通道图像。 mv:分离后的单通道图像&#xff0c;为向量vector形式。 2.多通道合并merge…...

JOJO的奇妙冒险

JOJO,我不想再做人了。 推荐一部动漫 JOJO的奇妙冒险 荒木飞吕彦创作的漫画 《JOJO的奇妙冒险》是由日本漫画家荒木飞吕彦所著漫画。漫画于1987年至2004年在集英社的少年漫画杂志少年JUMP上连载&#xff08;1987年12号刊-2004年47号刊&#xff09;&#xff0c;2005年后在集英…...

LeetCode56.合并区间

这道题我想了一会儿&#xff0c;实在想不到比较好的算法&#xff0c;只能硬着头皮写了&#xff0c;然后不断的debug&#xff0c;经过我不懈的努力&#xff0c;最后还是AC&#xff0c;不过效率确实低。 我就是按照最直接的方法来&#xff0c;先把intervals数组按照第一个数star…...

【内推码:NTAMW6c】 MAXIEYE智驾科技2024校招启动啦

MAXIEYE智驾科技2024校招启动啦【内推码&#xff1a;NTAMW6c】 【招聘岗位超多&#xff01;&#xff01;公司食堂好吃&#xff01;&#xff01;】 算法类&#xff1a;感知算法工程师、SLAM算法工程师、规划控制算法工程师、目标及控制算法工程师、后处理算法工程师 软件类&a…...

Python框架【模板继承 、继承模板实战、类视图 、类视图的好处 、类视图使用场景、基于调度方法的类视图】(四)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…...

对于前端模块化的理解与总结(很全乎)

目录 模块化的好处 模块化的commonJS导入导出 暴露(导出)模块&#xff1a;module.exports value或exports.xxx value 导入模块——使用 es6模块化 方法一逐个导出 方法二默认导出 方法三 方法四 方法五 export 和import 同时存在 多个文件导出到一个文件后在相关文件…...

NewStarCTF 2022 web方向题解 wp

----------WEEK1---------- BUU NewStarCTF 公开赛赛道 WEEK1 [NotPHP] 先看题目&#xff0c;要传参加绕过。 分析一下代码&#xff1a;首先get一个datadata://test/plain,Wel…。然后key1和2用数组可以绕过。num2077a可以绕过弱类型。eval()中的php语句被#注释了&#xff0c…...

WebGL矩阵变换库

目录 矩阵变换库&#xff1a; Matrix4对象所支持的方法和属性如表所示&#xff1a; 方法属性规范&#xff1a; 虽然平移、旋转、缩放等变换操作都可以用一个44的矩阵表示&#xff0c;但是在写WebGL程序的时候&#xff0c;手动计算每个矩阵很耗费时间。为了简化编程&#xf…...

block层:8. deadline调度器

deadline 源码基于5.10 0. 私有数据 struct deadline_data {/** run time data*//** requests (deadline_rq s) are present on both sort_list and fifo_list*/struct rb_root sort_list[2];struct list_head fifo_list[2];/** next in sort order. read, write or both ar…...

DTO,VO,PO的意义与他们之间的转换

DTO&#xff08;Data Transfer Object&#xff09;&#xff1a;数据传输对象&#xff0c;这个概念来源于J2EE的设计模式&#xff0c;原来的目的是为了EJB的分布式应用提供粗粒度的数据实体&#xff0c;以减少分布式调用的次数&#xff0c;从而提高分布式调用的性能和降低网络负…...

Java 集合框架2

一、关于set接口的常用类 1.HashSet类 用来处理无序的单列数据&#xff0c;没有重复的元素,重复的元素算一个 i.构造方法 //HashSet类是set接口的子类&#xff0c;是无序的单列数据&#xff0c;没有重复的元素&#xff0c;重复的元素算一个 //HashSet的构造方法 //HashSet() …...

2024王道408数据结构P144 T16

2024王道408数据结构P144 T16 思考过程 首先看题目&#xff0c;要求我们把二叉树的叶子结点求出来并且用链表的方式存储&#xff0c;链接时用叶结点的右指针来存放单链表指针。我们很清楚可以看出来能用中序遍历递归的方式实现&#xff0c;因为第一个叶子结点在整棵树的最左下…...

【ARM Coresight 系列文章 22 -- linux frace 与 trace-cmd】

文章目录 ftrace 介绍trace-cmd 介绍trace-cmd 常用跟踪事件ftrace 与 trace-cmd 关系ftrace 编译依赖 ftrace 介绍 ftrace 是 Linux 内核中的一个跟踪工具&#xff0c;主要用于帮助开发者分析和调试内核的行为。ftrace 的名字来源于 “function tracer”&#xff0c;它最初是…...

MyBatis的一级缓存和二级缓存是怎么样的?

目录 1. 一级缓存 2. 一级缓存失效的几种情况 3. 二级缓存 4.二级缓存失效的情况 5. 二级缓存的相关配置 6. 缓存的查询顺序 MyBatis 的缓存共分为一级缓存和二级缓存。 1. 一级缓存 一级缓存是 SqlSession 级别的&#xff0c;通过同一个 SqlSession 查询到的数据会被缓…...

下载的文件被Windows 11 安全中心自动删除

今天从CSDN上下载了自己曾经上传的文件&#xff0c;但是浏览器下载完之后文件被Windows安全中心自动删除&#xff0c;说是带病毒。实际是没有病毒的&#xff0c;再说了即便有病毒也不应该直接删除啊&#xff0c;至少给用户一个保留或删除的选项。 研究了一番&#xff0c;可以暂…...

【Java List与数组】List<T>数组和数组List<T>的区别(124)

List数组&#xff1a;存储List的数组&#xff0c;即&#xff1a;数组中的元素是&#xff1a;List&#xff1b; 数组List&#xff1a;存储数组的List&#xff0c;即&#xff1a;List中的数据是类型的数组&#xff1b; 测试案例&#xff1a; import java.util.ArrayList; impor…...

Nuxt 菜鸟入门学习笔记四:静态资源

文章目录 public 目录assets 目录全局样式导入 Nuxt 官网地址&#xff1a; https://nuxt.com/ Nuxt 使用以下两个目录来处理 CSS、fonts 和图片等静态资源&#xff1a; public 目录 public 目录用作静态资产的公共服务器&#xff0c;可通过应用程序定义的 URL 公开获取。 换…...

C语言 - 结构体、结构体数组、结构体指针和结构体嵌套

结构体的意义 问题&#xff1a;学籍管理需要每个学生的下列数据&#xff1a;学号、姓名、性别、年龄、分数&#xff0c;请用 C 语言程序存储并处理一组学生的学籍。 单个学生学籍的数据结构&#xff1a; 学号&#xff08;num&#xff09;&#xff1a; int 型姓名&#xff08;…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...