您现在的位置是:首页 >技术交流 >使用S-function实现基于C语言的电力电子控制器网站首页技术交流
使用S-function实现基于C语言的电力电子控制器
自己摸索+参考了一部分ChatGPT的回答,也通过搭建电路验证了控制的有效性。
意义:能直接将CCS工程的控制代码copy到s-function模块,在simulink中只需要搭建好PWM模块和主功率电路即可,好处是能节省时间,且对实际系统的还原度更高,能验证一些复杂的控制策略的效果。
事前准备:需要为MATLAB安装MinGW64 Compiler编译器,配置环境,否则无法编译。参考:
Matlab mex -setup 找不到编译器:为MATLAB安装MinGW64 Compiler编译器_matlab安装mex_booksyhay的博客-CSDN博客
在Library中搜索S-Function Examples,按照以下顺序双击打开:
就能得到一个level-2的S-function模板sfuntmpl_basic.c。(level-1的已经基本不再使用)
将sfuntmpl_basic.c文件复制出来到与仿真文件的同一文件夹下,再进行修改名称,添加头文件,声明变量等。建议将宏定义和内联函数等定义都放在头文件中;因此我的头文件包含(如果你喜欢的话也可以将代码全部放在.c里,这样就只需要引用simstruc.h和mex.h):
#include "simstruc.h"//定义S函数的接口
#include "Gen4PlateSet.h"//C2000相关的一些接口
#include "LoopDef.h"//环路控制相关的宏定义
#include "mex.h"//MATLAB C/C++接口中的一个头文件
将这个.c文件重命名为LoopControl.c,那么它的整体架构是这样的:
/*Part1
头文件、宏定义等。
/*Part2
控制相关代码:Copy来自CCS的控制相关代码。
/*Part3
mdl函数:至少要包含mdlInitializeSizes、mdlInitializeSampleTimes、mdlInitializeConditions、mdlOutputs和mdlTerminate。
对于完成以上配置的S-function,它的生命周期是先在仿真开始时执行mdlInitializeConditions,然后每过一次采样周期,完成采样后就会执行一次mdlOutputs,仿真结束执行mdlTerminate。
因此,我们需要将控制算法放在mdlOutputs中保证其周期性执行,初始化代码放在mdlInitializeConditions中。
mdlInitializeSizes和mdlInitializeSampleTimes主要用于配置输入输出个数、采样时间等。
mdlTerminate里什么都不需要写,但是没有它会编译错误。
对于电力电子控制器相关S-function函数的配置,我配置的模板如下(8个输入,5个输出,采样频率为100kHz):
#define S_FUNCTION_NAME LoopControl
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#include "Gen4PlateSet.h"
#include "LoopDef.h"
#include "mex.h"
#define N_INPUT 8
#define N_OUTPUT 5
#define SAMPLE_TS (0.00001)
static void DataInput(const real_T* adc)
{
InputData.XXX= adc[0];
......
InputData.XXX = adc[7];
}
static void DataOutput(real_T* out)
{
out[0] = OutputData.YYY;
......
out[4] = OutputData.YYY;
}
/**********控制代码Start**********/
包含控制算法LoopCtrl()、初始化函数LoopCtrlInit()
建议将宏定义和内联函数打包放在LoopDef.h中
/**********控制代码end**********/
static void mdlInitializeSizes(SimStruct *S)
{
// 设置输入端口个数
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, N_INPUT);
ssSetInputPortDirectFeedThrough(S, 0, 1);
// 启用直接穿透,也就是输入更新完毕输出会马上更新
ssSetInputPortRequiredContiguous(S, 0, true);
// 设置连续存储,优化性能
// 设置输出端口个数
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, N_OUTPUT);
ssSetNumSampleTimes(S, 1);//采样时间的个数
ssSetNumRWork(S, 0);//设置实数型工作向量的大小为0
ssSetNumIWork(S, 0);//设置整数型工作向量的大小为0
ssSetNumPWork(S, 0);//设置指针型工作向量的大小为0
ssSetNumModes(S, 0);//定义状态向量中模式的数量为0
ssSetNumNonsampledZCs(S, 0);//无非采样零点
ssSetOptions(S, 0);//将选项设置为默认值
}
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, SAMPLE_TS);
ssSetOffsetTime(S, 0, 0);
}
static void mdlInitializeConditions(SimStruct *S)//只在仿真之前初始化一次,初始化代码放这里
{
LoopCtrlInit();
}
static void mdlOutputs(SimStruct *S, int_T tid)//在每个采样周期结束后立即执行的
{
const real_T *u = (const real_T*) ssGetInputPortSignal(S,0);//定义只读的输入指针变量u
real_T *y = ssGetOutputPortSignal(S,0);//定义输出指针变量y
DataInput(u);
LoopCtrl();
DataOutput(y);
}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
说明:
1、InputData和OutputData结构体需要自行配置,LoopCtrl()为你的环路控制函数, LoopCtrlInit()为你的初始化函数,需要你自行配(fu)置(zhi)。
2、注意此处的采样时间的个数应设置为1,如果你设置了ssSetNumSampleTimes(S, 2),那么你就需要配置两个采样时间ts1和ts2,系统就会在m*ts1+n*ts2的时间点进行采样。
3、对于输入、输出而言,我只定义了一个输入端口和输出端口,但是它们的维度分别是8和5,因此你需要在仿真中使用mux和demux。
配置完毕后,还需要执行以下matlab代码来完成C语言的编译,才能在仿真中使用你的控制器:
setenv('MW_MINGW64_LOC', 'C:TDM-GCC-64');
mex -setup C++;
mex LoopControl.c;
如果你的代码缺少什么,编译器会如实地告诉你,你对代码中缺少的部分进行添加。
最后当然是不要忘记设置你的S-Function模块参数: