文档

零交叉

s函数使用模式功矢量(或配置为模式矢量的DWork矢量)和连续过零矢量来模拟过零。无论s函数使用模态向量还是DWork向量,其概念和实现都是相同的。有关使用DWork向量对零点交叉建模的示例,请参见DWork模式向量在“使用功向量”部分。本节的其余部分使用模式向量来模拟零交叉。

模式向量的元素是整数值。中模式向量元素的个数mdlInitializeSizes,使用ssSetNumModes(年代,num).然后,您可以使用ssGetModeVector.模式向量值决定如何mdlOutputs例程在解算器指向零交叉点时运行。的仿真软金宝app件®求解器跟踪一些信号的零交叉或状态事件(即一阶导数中的不连续),通常是s函数输入的函数,通过查看连续的零交叉。登记连续过零的次数mdlInitializeSizes,使用ssSetNumNonsampledZCs(年代,num),然后包括mdlZeroCrossings例程来计算连续的过零。的功能sfun_zc_sat.c包含一个过零示例。本节的其余部分将描述这个s函数中与过零检测有关的部分。有关此示例的完整描述,请参见讨论二阶导数过零检测

首先,mdlInitializeSizes使用以下代码行指定模式向量和连续过零向量的大小。

ssSetNumModes(年代,DYNAMICALLY_SIZED);ssSetNumNonsampledZCs(年代,DYNAMICALLY_SIZED);

由于模式和连续过零的数量是动态大小的,mdlSetWorkWidths必须初始化这些向量的实际大小。在下面的示例中,每个输出元素都有一个模式向量,每个模式有两个连续的过零点。一般来说,每个模式所需的连续过零次数取决于需要检测的事件数量。在这种情况下,每个输出(模式)需要检测它何时到达上界或下界,因此每个模式需要连续两次过零。

static void mdlSetWorkWidths(SimStruct *S) {int nModes;int nNonsampledZCs;nModes = numOutput;nNonsampledZCs = 2 * numOutput;ssSetNumModes(年代,nModes);ssSetNumNonsampledZCs(年代,nNonsampledZCs);}

接下来,mdlOutputs确定在每个主要时间步骤开始时运行的模拟模式。该方法将此信息存储在模式向量中,以便在计算主要和次要时间步长的输出时可用。

/*获取模式向量*/ int_T *mode = ssGetModeVector(S);/*指定三个可能的模式值。*/ enum {UpperLimitEquation, NonLimitEquation, LowerLimitEquation};*/ if (ssIsMajorTimeStep(S)) {for (iOutput = 0;iOutput < numOutput;ioutput++) {if (*uPtrs[uIdx] > *upperLimit){/*达到上限。*/ mode[iOutput] =上限方程;} else if (*uPtrs[uIdx] < *lowerLimit){/*达到下限。*/ mode[iOutput] = LowerLimitEquation;} else{/*输出不受限制。 */ mode[iOutput] = NonLimitEquation; } /* Adjust indices to give scalar expansion. */ uIdx += uInc; upperLimit += upperLimitInc; lowerLimit += lowerLimitInc; } /* Reset index to input and limits. */ uIdx = 0; upperLimit = mxGetPr( P_PAR_UPPER_LIMIT ); lowerLimit = mxGetPr( P_PAR_LOWER_LIMIT ); } /* end IsMajorTimeStep */

输出计算mdlOutputs是基于模式向量中存储的值完成的。

for (iOutput = 0;iOutput < numOutput;iOutput++) {if (mode[iOutput] == UpperLimitEquation){/*输出上限。*/ *y++ = *upperLimit;} else if (mode[iOutput] == LowerLimitEquation){/*输出下限。*/ *y++ = *lowerLimit;} else{/*输出等于输入*/ *y++ = *uPtrs[uIdx];}

计算输出之后,Simulink引擎调用金宝appmdlZeroCrossings来确定是否发生了零交叉。如果连续过零矢量的任何元素从负变为正,或从正变为负,则检测到过零。如果发生这种情况,模拟将修改步长并重新计算输出,以尝试定位精确的过零点。对于本例,连续过零向量的值计算如下所示。

static void mdlZeroCrossings(SimStruct *S) {int_T iOutput;int_T numOutput = ssGetOutputPortWidth(S,0);real_T *zcSignals = ssGetNonsampledZCs(S);InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);/*设置输入信号的索引和增量、上限和下限参数,以便每个参数在需要时给出标量展开。*/ int_T uIdx = 0;int_T uInc = (ssGetInputPortWidth(S,0) > 1);const real_T *upperLimit = mxGetPr(P_PAR_UPPER_LIMIT);int_T upperLimitInc = (mxGetNumberOfElements(P_PAR_UPPER_LIMIT) > 1);const real_T *lowerLimit = mxGetPr(P_PAR_LOWER_LIMIT); int_T lowerLimitInc = ( mxGetNumberOfElements( P_PAR_LOWER_LIMIT ) > 1 ); /*Check if the input has crossed an upper or lower limit */ for ( iOutput = 0; iOutput < numOutput; iOutput++ ) { zcSignals[2*iOutput] = *uPtrs[uIdx] - *upperLimit; zcSignals[2*iOutput+1] = *uPtrs[uIdx] - *lowerLimit; /* Adjust indices to give scalar expansion if needed */ uIdx += uInc; upperLimit += upperLimitInc; lowerLimit += lowerLimitInc; } }

另请参阅

相关的话题