主要内容

零交叉

S函数使用模式工作向量(或配置为模式向量的Dwork向量)和连续过零向量的零交叉。S函数是否使用模式或DWORK矢量,概念和实现是相同的。有关使用DWORK VECTORS模拟过零点的示例,请参阅DWork模式向量在“使用工作向量”部分。本节的其余部分使用模式向量来模拟过零点。

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

第一的,mdlinitializatize使用以下代码行指定模式和连续过零向量的大小。

sssetnummode(s,dynamically_sized);sssetnumnonsampledzcs(s,动态_sized);

由于模式数和连续的零交叉是动态大小的,mdlSetWorkWidths必须初始化这些向量的实际大小。在该示例下,如下所示,每个输出元件有一个模式向量,每个模式为两个连续过零点。通常,每个模式所需的连续零点的数量取决于需要检测的事件的数量。在这种情况下,每个输出(模式)需要检测它何时击中上限或下限,因此每种模式的两个连续过零点。

静态void mdlsetworkwidths(Simstruct * s){int nmodes;int nnonsampledzcs;nmode = numoutput;nnonsampledzcs = 2 * numoutput;sssetnummode(s,nmodes);sssetnumnonsampledzcs(s,nnonsampledzcs);}

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

/*获取模式向量*/ int_T *mode = ssGetModeVector(S);/*指定三个可能的模式值。*/ enum {UpperLimitEquation, NonLimitEquation, LowerLimitEquation};/* Update mode vector at the beginning of a major time step */ if (sismajortimestep (S)) {for (iOutput = 0;iOutput < numOutput;iOutput++) {if (*uPtrs[uIdx] > *upperLimit){/*达到上限。*/ mode[iOutput] = upperlimiteequation; / /输入输出} else if (*uPtrs[uIdx] < *lowerLimit){/*达到下限。*/ mode[iOutput] = lowerlimiteequation; / /输出} 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++ = *上限;} else if (mode[iOutput] == LowerLimitEquation){/*输出下限。*/ *y++ = *lowerLimit;} else{/*输出等于输入*/ *y++ = *uPtrs[uIdx];}

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

static void mdlzerocrosings (SimStruct *S) {int_T iOutput;int_T numOutput = ssgetoutputporttwidth (S,0);real_T *zcSignals = ssGetNonsampledZCs(S);InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);/*设置输入信号的索引和增量、上限和下限*限制参数,以便每个参数在需要时给出标量展开。*/ int_T uIdx = 0;int_T uInc = (ssgetinputporttwidth (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; } }

也可以看看

相关话题