S-funtion是干嘛的?
由于准备要学习RT-LAB,而RTLAB是在MATLAB基础上运行的,所以先得熟悉MATLAB,对于电气的学生来说,MATLAB中很重要的一个功能就是Simulink,simulink中直接用于电力系统仿真的是simpowersystem模块,simpowersystem中有很多模型,可以直接拖拽,图形化的仿真界面非常方便。但是,不是所有的模型所有的算法simulink、simpowersystem中都能找到的,比如说MMC(模块化多电平换流器的均压排序模块)就没法直接拖拽,所以S-function应运而生。
S-function在整个系统中的定位 我在simulink中搭建模型,都是先搭simulink中有的东西,然后碰到simulink中没有的才会去建S-function,那么在这个时候,你就很清楚你的S-function具体是干什么的,他应该有什么输出,有什么输入,你心里面很清楚,对于系统来说,S-funtion是一个黑匣子,你给他输入,他给你输出。
如何建立S-function?
清楚了上述两个问题,就可以搭建S-function了。与其说是搭建,不如说是修改,因为simulink已经把模版给你了,你只需要修改就可以。以下分步骤说明:
1、打开模板:直接在simulink元件库中搜索S-funtion Examples,点击进入,会有4种模板(09版中是四种),这4种模板分别是用M文件、C语言、C++、Fortran语言来实现的,由于我只学过C,所以以下说明按C语言模板建立的过程,其他应该都是通用的,双击C语言模板,里面又有很多,直接选择Basic C-MEX Template,进入到C语言编辑界面,没错,这是咱们要修改的东西。
2、修改模板:在修改之前,可以该C语言文件另存为一下, 尽量不要再原模板上改。另存好了以后,就可以看这个文件了,C语言基础好的人,基本上能看懂,基础不好的同学,也别怕,我会直接告诉大家改哪里
#define S_FUNCTION_NAME test//这里把文件名sfuntmpl_basic修改为test,注意这个test要跟你将来的 S-function的名字一样,改成别的都可以,但是一定要统一
#define S_FUNCTION_LEVEL 2 //一般不改
#include "simstruc.h" //程序里面要用到的头文件在这里引用,如“math.h”等。 float global_var; //定义 全局变量
static void mdlInitializeSizes(SimStruct *S) //这个函数用来设置S-FUNTION的输入、输出和参数,非常重 要,也就是说这个函数中定义的那些东西都要调整成自己系 统所需要的
ssSetNumSFcnParams(S, 3); /*设置参数个数,这里设为3,大家根据自己需要设置即可,我这只是举例,下面还有好几处都是举例*/
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; } //默认ssSetNumContStates(S, 0);//设置连续状态的个数,缺省为0; //默认
ssSetNumDiscStates(S, 0);//设置离散状态的个数,缺省为0; //默认
if (!ssSetNumInputPorts(S, 1)) return;//设置输入变量的个数,这里为1
ssSetInputPortWidth(S, 0, 2); //设置输入变量0的维数为2,需要注意的是,S-funtion中输入变量和维数的意思,输入变量可以有多个,即u,v,w等等每个变量可以有多维,即u[0]、u[1]、u[2]等等,我猜测之所以这么搞就是为了方便运算,毕竟MATLAB是为矩阵运算而生的。
ssSetInputPortRequiredContiguous(S, 0, true); //设置input0的访问方式,true就是临近访问,这样指针的增量后就可以直接访问下个input端口了。 这里需要注意,如果你有多个变量的话,那么对于每个变量都得进行这样的设置将中间的0改成1、2、3即可,
ssSetInputPortDirectFeedThrough(S, 0, 1);// 设置输入端口的信号是否mdlOutputs函数中使用,这儿设置为true。 这里也需要注意,对于每个变量都需要设置
iif (!ssSetNumOutputPorts(S, 2)) return;//设置输出变量的个数
ssSetOutputPortWidth(S, 0, 1);//设置输出变量0的维数为1维,跟前面的输入时一个意思
ssSetNumSampleTimes(S, 1); //设置采样时间,此处为1s。//默认
ssSetNumRWork(S, 0);//不管
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0);
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
static void mdlInitializeConditions(SimStruct *S)
{
}
#endif /* MDL_INITIALIZE_CONDITIONS */
#define MDL_START /* Change to #undef to remove function */
#if defined(MDL_START)
static void mdlStart(SimStruct *S)
{
}
#endif /* MDL_START */ //以上未注释部分全部不管
//接下来就到最重要的时候了,就是你要写你的主算法的时候了,
static void mdlOutputs(SimStruct *S, int_T tid)//注意这个不要动,默认原来的
{
const real_T *u = (const real_T*) ssGetInputPortSignal ( S,0 );
const real_T *v = (const real_T*) ssGetInputPortSignal ( S,1 );
const real_T *w = (const real_T*) ssGetInputPortSignal ( S,2 );
real_T *y = ssGetOutputPortSignal ( S,0 );//以上这些变量的定义都是默认按照原来的格式,不要动,只是你需要加变量的话按照人家的格式来加就可以,比如上面,原来只有u,现在我自己加了个v,w,但是格式严格保证
y[0]=v[0];
y[1]=w[0];//这两句就是主算法了,反正自己就按照这个样式做就好,我这里只是举个简单例子
}
模板里下面还有好多东西,全部默认。
点击保存,至此,c语言文件修改完成,进入下一步
3、如何把你的c语言跟你的模型连接起来:上一步进行完以后,在matlab主界面中命令栏输入“mex ***.c”(***为你刚定义的C语言文件名),当然这是要在current folder合适的情况下才能实现的,设置一下当前目录就好,如果你的C没有语法问题,那么这一步就成功通过了,并且会在左侧生成一个mex文件,如果有问题,他会提示在哪一行,自己再对照检查。然后,打开simulink,添加S-function,这个直接搜即可,注意这次不是Example了,添加以后,这只是一个啥都没有的S-funtion,然后双击这个模块,将S-function的name改成你刚才在C语言文件里定义的那个,上面是test。其他不用动,设参数的话,应该调整下第二栏。然后点确认,现在这个S-FUNCTION就是具有你刚写的C语言功能的S-FUNTION了,你会发现,你设置的两个变量他就会在输入出来两个头,然后如果你定义的是多维,那么可以用MUX,DEMUX(直接搜)这两个来实现多维的输入输出。附上一张我的基本S-function的仿真界面设置。大家可参考。
4、仿真,点击仿真开始即可,就可以再scope中看到波形了
以上就是我建立S-Function的整个过程,虽然很基础,但是是自己查资料整合资料慢慢探索出来的, 觉得很珍贵,跟大家分享,大家有问题可以留言讨论。另外附上两个文件,从这两个文件中学到不少。
由于准备要学习RT-LAB,而RTLAB是在MATLAB基础上运行的,所以先得熟悉MATLAB,对于电气的学生来说,MATLAB中很重要的一个功能就是Simulink,simulink中直接用于电力系统仿真的是simpowersystem模块,simpowersystem中有很多模型,可以直接拖拽,图形化的仿真界面非常方便。但是,不是所有的模型所有的算法simulink、simpowersystem中都能找到的,比如说MMC(模块化多电平换流器的均压排序模块)就没法直接拖拽,所以S-function应运而生。
S-function在整个系统中的定位 我在simulink中搭建模型,都是先搭simulink中有的东西,然后碰到simulink中没有的才会去建S-function,那么在这个时候,你就很清楚你的S-function具体是干什么的,他应该有什么输出,有什么输入,你心里面很清楚,对于系统来说,S-funtion是一个黑匣子,你给他输入,他给你输出。
如何建立S-function?
清楚了上述两个问题,就可以搭建S-function了。与其说是搭建,不如说是修改,因为simulink已经把模版给你了,你只需要修改就可以。以下分步骤说明:
1、打开模板:直接在simulink元件库中搜索S-funtion Examples,点击进入,会有4种模板(09版中是四种),这4种模板分别是用M文件、C语言、C++、Fortran语言来实现的,由于我只学过C,所以以下说明按C语言模板建立的过程,其他应该都是通用的,双击C语言模板,里面又有很多,直接选择Basic C-MEX Template,进入到C语言编辑界面,没错,这是咱们要修改的东西。
2、修改模板:在修改之前,可以该C语言文件另存为一下, 尽量不要再原模板上改。另存好了以后,就可以看这个文件了,C语言基础好的人,基本上能看懂,基础不好的同学,也别怕,我会直接告诉大家改哪里
#define S_FUNCTION_NAME test//这里把文件名sfuntmpl_basic修改为test,注意这个test要跟你将来的 S-function的名字一样,改成别的都可以,但是一定要统一
#define S_FUNCTION_LEVEL 2 //一般不改
#include "simstruc.h" //程序里面要用到的头文件在这里引用,如“math.h”等。 float global_var; //定义 全局变量
static void mdlInitializeSizes(SimStruct *S) //这个函数用来设置S-FUNTION的输入、输出和参数,非常重 要,也就是说这个函数中定义的那些东西都要调整成自己系 统所需要的
ssSetNumSFcnParams(S, 3); /*设置参数个数,这里设为3,大家根据自己需要设置即可,我这只是举例,下面还有好几处都是举例*/
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; } //默认ssSetNumContStates(S, 0);//设置连续状态的个数,缺省为0; //默认
ssSetNumDiscStates(S, 0);//设置离散状态的个数,缺省为0; //默认
if (!ssSetNumInputPorts(S, 1)) return;//设置输入变量的个数,这里为1
ssSetInputPortWidth(S, 0, 2); //设置输入变量0的维数为2,需要注意的是,S-funtion中输入变量和维数的意思,输入变量可以有多个,即u,v,w等等每个变量可以有多维,即u[0]、u[1]、u[2]等等,我猜测之所以这么搞就是为了方便运算,毕竟MATLAB是为矩阵运算而生的。
ssSetInputPortRequiredContiguous(S, 0, true); //设置input0的访问方式,true就是临近访问,这样指针的增量后就可以直接访问下个input端口了。 这里需要注意,如果你有多个变量的话,那么对于每个变量都得进行这样的设置将中间的0改成1、2、3即可,
ssSetInputPortDirectFeedThrough(S, 0, 1);// 设置输入端口的信号是否mdlOutputs函数中使用,这儿设置为true。 这里也需要注意,对于每个变量都需要设置
iif (!ssSetNumOutputPorts(S, 2)) return;//设置输出变量的个数
ssSetOutputPortWidth(S, 0, 1);//设置输出变量0的维数为1维,跟前面的输入时一个意思
ssSetNumSampleTimes(S, 1); //设置采样时间,此处为1s。//默认
ssSetNumRWork(S, 0);//不管
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0);
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
static void mdlInitializeConditions(SimStruct *S)
{
}
#endif /* MDL_INITIALIZE_CONDITIONS */
#define MDL_START /* Change to #undef to remove function */
#if defined(MDL_START)
static void mdlStart(SimStruct *S)
{
}
#endif /* MDL_START */ //以上未注释部分全部不管
//接下来就到最重要的时候了,就是你要写你的主算法的时候了,
static void mdlOutputs(SimStruct *S, int_T tid)//注意这个不要动,默认原来的
{
const real_T *u = (const real_T*) ssGetInputPortSignal ( S,0 );
const real_T *v = (const real_T*) ssGetInputPortSignal ( S,1 );
const real_T *w = (const real_T*) ssGetInputPortSignal ( S,2 );
real_T *y = ssGetOutputPortSignal ( S,0 );//以上这些变量的定义都是默认按照原来的格式,不要动,只是你需要加变量的话按照人家的格式来加就可以,比如上面,原来只有u,现在我自己加了个v,w,但是格式严格保证
y[0]=v[0];
y[1]=w[0];//这两句就是主算法了,反正自己就按照这个样式做就好,我这里只是举个简单例子
}
模板里下面还有好多东西,全部默认。
点击保存,至此,c语言文件修改完成,进入下一步
3、如何把你的c语言跟你的模型连接起来:上一步进行完以后,在matlab主界面中命令栏输入“mex ***.c”(***为你刚定义的C语言文件名),当然这是要在current folder合适的情况下才能实现的,设置一下当前目录就好,如果你的C没有语法问题,那么这一步就成功通过了,并且会在左侧生成一个mex文件,如果有问题,他会提示在哪一行,自己再对照检查。然后,打开simulink,添加S-function,这个直接搜即可,注意这次不是Example了,添加以后,这只是一个啥都没有的S-funtion,然后双击这个模块,将S-function的name改成你刚才在C语言文件里定义的那个,上面是test。其他不用动,设参数的话,应该调整下第二栏。然后点确认,现在这个S-FUNCTION就是具有你刚写的C语言功能的S-FUNTION了,你会发现,你设置的两个变量他就会在输入出来两个头,然后如果你定义的是多维,那么可以用MUX,DEMUX(直接搜)这两个来实现多维的输入输出。附上一张我的基本S-function的仿真界面设置。大家可参考。
4、仿真,点击仿真开始即可,就可以再scope中看到波形了
以上就是我建立S-Function的整个过程,虽然很基础,但是是自己查资料整合资料慢慢探索出来的, 觉得很珍贵,跟大家分享,大家有问题可以留言讨论。另外附上两个文件,从这两个文件中学到不少。