使用C语言编写S函数实例

引言

最近有接触到用C语言编写S函数,因此对这方面做了一些尝试,直接上代码。两个.c代码实现同样的功能。一个是C语言版,一个是Matlab版本。代码在我的机器上能够调试使用。如果有其他的问题,欢迎在评论区留言。

VScode能够运行的C程序:

#include<stdio.h>
#include<string.h>

typedef struct{
	char Status[100];
	float Value[2]; //value为结构体包含两个值。
} DS_65;

typedef struct{
	float EU_at_100;
	float EU_at_0;
	char Units_index[20];
	short int Decimal_Point;
} DS_68;

typedef struct{
	char Target[20];
	char Actual[20];
	char Permitted[20];
	char Normal[20];
} DS_69;

typedef struct{
	unsigned short int Simulate_Status;
	float Simulate_Value;
	unsigned short int Transducer_Status;
	float Transducer_Value;
	unsigned short int Simulate_EnorDisable;
} DS_82;

typedef struct{
	short int Propagate_Fault_Forward;
	float Uncertain_if_Limited;
	float BAD_if_Limited;
	short int Uncertain_if_Man_mode;
} STATUS_OPTS;

typedef struct{
	short int Increase_to_Close;
	int Fault_State_to_value;

} IO_OPTS;


DS_65 fun(DS_65 SP,IO_OPTS IO_OPT,DS_69 MODE_BLK,float FSTATE_VAL[],\
STATUS_OPTS STATUS_OPT,float INPUTVALUE[],float SP_HI_LIM,float SP_LO_LIM,\
float SP_RATE_UP,float SP_RATE_DN,DS_68 PV_SCALE,DS_68 XD_SCALE,DS_65 SP_INPUT)
{
	DS_65 OUT;
	float SP_rate_auto;
	float SP_rate_cas;
	int target_mode;
	int i;
	target_mode = (strcmp(MODE_BLK.Target,"O/S")==0)*1+(strcmp(MODE_BLK.Target,"IMAN")==0)*2\
					+(strcmp(MODE_BLK.Target,"LO")==0)*3+(strcmp(MODE_BLK.Target,"MAN")==0)*4+\
					(strcmp(MODE_BLK.Target,"CAS")==0)*5+(strcmp(MODE_BLK.Target,"RCAS")==0)*6;
	// printf("%d\n",target_mode);
	switch (target_mode){
		case 1:
			strcpy(OUT.Status,"Bad");
			for(i=0;i<2;i++){
					OUT.Value[i] = SP.Value[i];
			}
			break;
		case 2:
			strcpy(OUT.Status,"GoodNC");
			for(i=0;i<2;i++){
					OUT.Value[i] = SP.Value[i];
			}
			break;
		case 3:
			if(IO_OPT.Fault_State_to_value == 1){
				strcpy(OUT.Status,"Fault State to value");
				OUT.Value[0] = FSTATE_VAL[0];
				OUT.Value[1] = FSTATE_VAL[1];
				}
			// IO_OPTS 的另外一个值:"Target to Man if Fault State activated"
			else{
				strcpy(OUT.Status,"Target to Man if Fault State activated");
				for(i=0;i<2;i++){
					OUT.Value[i] = SP.Value[i];
				}}
			break;
		case 4:
			if(STATUS_OPT.Uncertain_if_Man_mode == 1){
				strcpy(OUT.Status,"Uncertain if Man mode");
				for(i=0;i<2;i++){
					OUT.Value[i] = INPUTVALUE[i];
				}}
			else {
				strcpy(OUT.Status,"GoodNC"); 
				for(i=0;i<2;i++){
					OUT.Value[i] = INPUTVALUE[i];
				}}
			break;
		case 5:
			if(SP.Value[0] > SP_RATE_UP){
				SP.Value[0] = SP_RATE_UP;
			}
			else if(SP.Value[0] < SP_RATE_DN){
				SP.Value[0] = SP_RATE_DN;
			}
			else if(SP.Value[1] > SP_HI_LIM){
				SP.Value[1] = SP_HI_LIM;
			}
			else if(SP.Value[1] < SP_LO_LIM){
				SP.Value[1] = SP_LO_LIM;
			}
			else{
				SP_rate_cas = (SP.Value[1] - PV_SCALE.EU_at_0)*100/(PV_SCALE.EU_at_100 - \
				PV_SCALE.EU_at_0); //PV_SCALE
				OUT.Value[1] = SP_rate_cas*(XD_SCALE.EU_at_100-XD_SCALE.EU_at_0) + \
				XD_SCALE.EU_at_0; //XD_SCALE
				OUT.Value[0] = SP.Value[0];
				strcpy(OUT.Status, SP.Status);
				}
			break;
		case 6:
			if(SP.Value[0] > SP_RATE_UP){
				SP.Value[0] = SP_RATE_UP;
			}
			else if(SP.Value[0] < SP_RATE_DN){
				SP.Value[0] = SP_RATE_DN;
			}
			else if(SP.Value[1] > SP_HI_LIM){
				SP.Value[1] = SP_HI_LIM;
			}
			else if(SP.Value[1] < SP_LO_LIM){
				SP.Value[1] = SP_LO_LIM;
			}
			else{
				SP_rate_cas = (SP.Value[1] - PV_SCALE.EU_at_0)*100/(PV_SCALE.EU_at_100 - \
				PV_SCALE.EU_at_0); //PV_SCALE
				OUT.Value[1] = SP_rate_cas*(XD_SCALE.EU_at_100-XD_SCALE.EU_at_0) + \
				XD_SCALE.EU_at_0; //XD_SCALE
				OUT.Value[0] = SP.Value[0];
				strcpy(OUT.Status, SP.Status);
			}
			break;
		default: // 如果MODE_BLK.Actual不设定值或者设定的值不等于上面的几种情况,则运行该块代码。为“AUTO”模式。
			if(SP_INPUT.Value[0] > SP_RATE_UP){
				SP_INPUT.Value[0] = SP_RATE_UP;
			}
			else if(SP_INPUT.Value[0] < SP_RATE_DN){
				SP_INPUT.Value[0] = SP_RATE_DN;
			}
			else if(SP_INPUT.Value[1] > SP_HI_LIM){
				SP_INPUT.Value[1] = SP_HI_LIM;
			}
			else if(SP_INPUT.Value[1] < SP_LO_LIM){
				SP_INPUT.Value[1] = SP_LO_LIM;
			}
			else{
				SP_rate_auto = (SP_INPUT.Value[1] - PV_SCALE.EU_at_0)*100/(PV_SCALE.EU_at_100 - \
				PV_SCALE.EU_at_0); //PV_SCALE
				OUT.Value[1] = SP_rate_auto*(XD_SCALE.EU_at_100-XD_SCALE.EU_at_0) + \
				XD_SCALE.EU_at_0; //XD_SCALE
				OUT.Value[0] = SP_INPUT.Value[0];
				strcpy(OUT.Status, SP_INPUT.Status);
			}}
	return OUT;
}

void main()
{
	DS_65 sp = {"test_the_fun.",{0.2, 15}};
	IO_OPTS io_opt = {1, 1};
	DS_69 mode_blk = {"CAS","AUTO",'p','n'};
	float fstate_val[] = {0.1,5.0};
	STATUS_OPTS status_opts = {0, 0.4, 0.5, 1};
	float input_value[] = {0.3, 30.0};
	float sp_hi_lim = 100; // 默认值为100%。
	float sp_lo_lim = 0; // 默认值为0。
	float sp_rate_up = 2; // 默认值为-inf。
	float sp_rate_dn = 0; // 默认值为+inf。
	DS_68 pv_scale = {20, 4, "mA", 2};
	DS_68 xd_scale = {100, 20, "kPa", 2};
	DS_65 sp_input = {"man input.",{0.3,30}}; //操作员输入的SP。
	DS_65 out;
	out = fun(sp,io_opt,mode_blk,fstate_val,status_opts,input_value,sp_hi_lim,\
	sp_lo_lim,sp_rate_up,sp_rate_dn,pv_scale,xd_scale,sp_input);
	printf("%s %.2f %.2f", out.Status, out.Value[0], out.Value[1]);
}

Matlab能够运行的C程序:

在matlab中编译使用如下命令:

mex -g AO_MATLAB.c %AO_MATLAB.c为c代码文件名。

#define S_FUNCTION_NAME  AO_MATLAB//这里把文件名sfuntmpl_basic修改为test
#define S_FUNCTION_LEVEL 2
#include<stdio.h>
#include<string.h>
#include<simstruc.h>

//程序里面要用到的头文件在这里引用,如“math.h”等。



static void mdlInitializeSizes(SimStruct *S)
{
 //这个函数用来设置输入、输出和参数的。
    ssSetNumSFcnParams(S, 33);  /*设置参数个数,这里为3 */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return;
    }
    ssSetNumContStates(S, 0);//设置连续状态的个数,缺省为0;
    ssSetNumDiscStates(S, 0);//设置离散状态的个数,缺省为0;
    if (!ssSetNumInputPorts(S, 3)) return;//设置输入变量的个数,这里为1
    ssSetInputPortWidth(S, 0, 1); //设置输入变量0的维数为1
    ssSetInputPortWidth(S, 1, 1); //设置输入变量0的维数为1
    ssSetInputPortWidth(S, 2, 1); //设置输入变量0的维数为1
    ssSetInputPortRequiredContiguous(S, 0, true); //设置input0的访问方式,true就是临近访问,这样指针的增量后就可以直接访问下个input端口了。
    ssSetInputPortDirectFeedThrough(S, 0, 1);// 设置输入端口的信号是否mdlOutputs函数中使用,这儿设置为true。
    if (!ssSetNumOutputPorts(S, 3)) return;//设置输出变量的个数
    ssSetOutputPortWidth(S, 0, 1);//设置输出变量0的维数为1维
    ssSetOutputPortWidth(S, 1, 1);//设置输出变量1的维数为1维
    ssSetOutputPortWidth(S, 2, 1);//设置输出变量2的维数为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);
 
}
#define MDL_INITIALIZE_CONDITIONS   /* Change to #undef to remove function */
#if defined(MDL_INITIALIZE_CONDITIONS)
 
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)//这里填入相关的运算、算法等
{
int i;
real_T *IO_OPT_Fault_State_to_value = mxGetPr(ssGetSFcnParam(S,0)); //1
real_T *CONSTANT_0 = mxGetPr(ssGetSFcnParam(S,1)); //1
real_T *FSTATE_VAL_rate = mxGetPr(ssGetSFcnParam(S,2)); //0.1
real_T *STATUS_OPT_Uncertain_if_Man_mode = mxGetPr(ssGetSFcnParam(S,3)); //1
real_T *INPUTVALUE_rate = mxGetPr(ssGetSFcnParam(S,4)); // 定的是0.3,可改
real_T *SP_HI_LIM = mxGetPr(ssGetSFcnParam(S,5)); //100
real_T *SP_LO_LIM = mxGetPr(ssGetSFcnParam(S,6)); //0
real_T *SP_RATE_DN = mxGetPr(ssGetSFcnParam(S,7)); //0
real_T *SP_RATE_UP = mxGetPr(ssGetSFcnParam(S,8)); //2
real_T *PV_SCALE_EU_at_100 = mxGetPr(ssGetSFcnParam(S,9)); //20
real_T *PV_SCALE_EU_at_0 = mxGetPr(ssGetSFcnParam(S,10)); //4
real_T *XD_SCALE_EU_at_100 = mxGetPr(ssGetSFcnParam(S,11));//100
real_T *XD_SCALE_EU_at_0 = mxGetPr(ssGetSFcnParam(S,12)); //20
real_T *SP_INPUT_Value_rate = mxGetPr(ssGetSFcnParam(S,13)); //0.3
real_T *MODECONSTANT_0 = mxGetPr(ssGetSFcnParam(S,14)); //"O/S"
real_T *RESULTCONSTANT_0 = mxGetPr(ssGetSFcnParam(S,15)); //"Bad"
real_T *MODE_BLK_Target = mxGetPr(ssGetSFcnParam(S,16)); //"CAS"
real_T *SP_INPUT_Status = mxGetPr(ssGetSFcnParam(S,17)); //"man input."
real_T *SP_INPUT_Value_hl = mxGetPr(ssGetSFcnParam(S,18)); //30
real_T *CONSTANT_3 = mxGetPr(ssGetSFcnParam(S,19)); //设定为100.
real_T *RESULTCONSTANT_1 = mxGetPr(ssGetSFcnParam(S,20)); //"GoodNC"
real_T *RESULTCONSTANT_2 = mxGetPr(ssGetSFcnParam(S,21)); //"Fault State to value"
real_T *RESULTCONSTANT_3 = mxGetPr(ssGetSFcnParam(S,22)); //"Target to Man if Fault State activated"
real_T *RESULTCONSTANT_4 = mxGetPr(ssGetSFcnParam(S,23)); //"Uncertain if Man mode"
real_T *RESULTCONSTANT_5 = mxGetPr(ssGetSFcnParam(S,24)); //"GoodNC"
real_T *INPUTVALUE_hl = mxGetPr(ssGetSFcnParam(S,25)); //30.0
real_T *CONSTANT_1 = mxGetPr(ssGetSFcnParam(S,26)); //1
real_T *FSTATE_VAL_hl = mxGetPr(ssGetSFcnParam(S,27)); //5.0
real_T *MODECONSTANT_1 = mxGetPr(ssGetSFcnParam(S,28)); //"IMAN"
real_T *MODECONSTANT_2 = mxGetPr(ssGetSFcnParam(S,29)); //"LO"
real_T *MODECONSTANT_3 = mxGetPr(ssGetSFcnParam(S,30)); //"MAN"
real_T *MODECONSTANT_4 = mxGetPr(ssGetSFcnParam(S,31)); //"CAS"
real_T *MODECONSTANT_5 = mxGetPr(ssGetSFcnParam(S,32)); //"RCAS"

real_T *SP_Value_rate = (real_T*) ssGetInputPortSignal(S,0);
real_T *SP_Value_hl = (real_T*) ssGetInputPortSignal(S,1);
real_T *SP_Status = (real_T*) ssGetInputPortSignal(S,2);
real_T *OUT_Value_rate = ssGetOutputPortSignal(S,0);
real_T *OUT_Value_hl = ssGetOutputPortSignal(S,1);
real_T *OUT_Status = ssGetOutputPortSignal(S,2);

switch ((MODE_BLK_Target[0]==MODECONSTANT_0[0])*1+(MODE_BLK_Target[0]==MODECONSTANT_1[0])*2\
					+(MODE_BLK_Target[0]==MODECONSTANT_2[0])*3+(MODE_BLK_Target[0]==MODECONSTANT_3[0])*4+\
					(MODE_BLK_Target[0]==MODECONSTANT_4[0])*5+(MODE_BLK_Target[0]==MODECONSTANT_5[0])*6){
  case 1:
    OUT_Status[0]=RESULTCONSTANT_0[0];
    OUT_Value_rate[0] = SP_Value_rate[0];
    OUT_Value_hl[0] = SP_Value_hl[0];
    break;
  case 2:
    OUT_Status[0]=RESULTCONSTANT_1[0];
    OUT_Value_rate[0] = SP_Value_rate[0];
    OUT_Value_hl[0] = SP_Value_hl[0];
    break;
  case 3:
    if(IO_OPT_Fault_State_to_value[0] == CONSTANT_1[0]){
      OUT_Status[0]=RESULTCONSTANT_2[0];
      OUT_Value_rate[0] = FSTATE_VAL_rate[0];
      OUT_Value_hl[0] = FSTATE_VAL_hl[0];
      }
    // IO_OPTS 的另外一个值:"Target to Man if Fault State activated"
    else{
      OUT_Status[0]=RESULTCONSTANT_3[0];
      OUT_Value_rate[0] = SP_Value_rate[0];
      OUT_Value_hl[0] = SP_Value_hl[0];
      }
    break;
  case 4:
    if(STATUS_OPT_Uncertain_if_Man_mode[0] == CONSTANT_0[0]){
      OUT_Status[0] = RESULTCONSTANT_4[0];
      OUT_Value_rate[0] = INPUTVALUE_rate[0];
      OUT_Value_hl[0] = INPUTVALUE_hl[0];
      }
    else {
      OUT_Status[0]=RESULTCONSTANT_5[0]; 
      OUT_Value_rate[0] = INPUTVALUE_rate[0];
      OUT_Value_hl[0] = INPUTVALUE_hl[0];
      }
    break;
  case 5:
    if(SP_Value_rate[0] > SP_RATE_DN[0]){
      SP_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_Value_rate[0] < SP_RATE_DN[0]){
      SP_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_Value_hl[0] > SP_HI_LIM[0]){
      SP_Value_hl[0] = SP_HI_LIM[0];
    }
    else if(SP_Value_hl[0] < SP_LO_LIM[0]){
      SP_Value_hl[0] = SP_LO_LIM[0];
    }
    else{
     OUT_Value_hl[0] = (SP_Value_hl[0]- PV_SCALE_EU_at_0[0])*CONSTANT_3[0]/(PV_SCALE_EU_at_100[0] - PV_SCALE_EU_at_0[0])\
      *((XD_SCALE_EU_at_100[0]-XD_SCALE_EU_at_0[0]) + XD_SCALE_EU_at_0[0]); 
      OUT_Value_rate[0] = SP_Value_rate[0];
      OUT_Status[0] = SP_Status[0];
      }
    break;
  case 6:
    if(SP_Value_rate[0] > SP_RATE_DN[0]){
      SP_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_Value_rate[0] < SP_RATE_DN[0]){
      SP_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_Value_hl[0] > SP_HI_LIM[0]){
      SP_Value_hl[0] = SP_HI_LIM[0];
    }
    else if(SP_Value_hl[0] < SP_LO_LIM[0]){
      SP_Value_hl[0] = SP_LO_LIM[0];
    }
    else{
     OUT_Value_hl[0] = (SP_Value_hl[0]- PV_SCALE_EU_at_0[0])*CONSTANT_3[0]/(PV_SCALE_EU_at_100[0] - PV_SCALE_EU_at_0[0])\
      *((XD_SCALE_EU_at_100[0]-XD_SCALE_EU_at_0[0]) + XD_SCALE_EU_at_0[0]);  
      OUT_Value_rate[0] = SP_Value_rate[0];
      OUT_Status[0] = SP_Status[0];
    }
    break;
  default: // 如果MODE_BLK.Actual不设定值或者设定的值不等于上面的几种情况,则运行该块代码。为“AUTO”模式。
    if(SP_INPUT_Value_rate[0] > SP_RATE_DN[0]){
      SP_INPUT_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_INPUT_Value_rate[0] < SP_RATE_DN[0]){
      SP_INPUT_Value_rate[0] = SP_RATE_DN[0];
    }
    else if(SP_INPUT_Value_rate[0] > SP_HI_LIM[0]){
      SP_INPUT_Value_rate[0] = SP_HI_LIM[0];
    }
    else if(SP_INPUT_Value_rate[0] < SP_LO_LIM[0]){
      SP_INPUT_Value_rate[0] = SP_LO_LIM[0];
    }
    else{
      OUT_Value_hl[0] = (SP_INPUT_Value_hl[0]- PV_SCALE_EU_at_0[0])*CONSTANT_3[0]/(PV_SCALE_EU_at_100[0] - PV_SCALE_EU_at_0[0])\
      *((XD_SCALE_EU_at_100[0]-XD_SCALE_EU_at_0[0]) + XD_SCALE_EU_at_0[0]); 
      OUT_Value_rate[0] = SP_INPUT_Value_rate[0];
      OUT_Status[0] = SP_INPUT_Status[0];
    }}
}
#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)
 
  static void mdlUpdate(SimStruct *S, int_T tid)
  {
  }
#endif /* MDL_UPDATE */
#define MDL_DERIVATIVES  /* Change to #undef to remove function */
#if defined(MDL_DERIVATIVES)
  static void mdlDerivatives(SimStruct *S)
  {
  }
#endif /* MDL_DERIVATIVES */
static void mdlTerminate(SimStruct *S)//这里需要把global变量全部初始化,否则下次运行程序时,全局变量还是之前的值。
{
}
 
#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. MATLAB中调用MEX文件相关的介绍;
  2. MATLAB中的S-Function的用法(C语言)
  3. mex -setup 未找到支持的编译器或 SDK。您可以安装免费提供的 MinGW-w64 C/C++ 编译器;请参阅安装 MinGW-w64 编译器。有关更多选项,请访问

后记:

C语言指针和数组在使用时很繁琐,以上代码在调试的过程中出现的问题,也主要是指针和数组的问题。欢迎在评论区留言交流。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值