Нулевые пересечения

Нулевые пересечения модели S-функций с помощью режима работают вектор (или вектор DWork, сконфигурированный как вектор режима) и непрерывный вектор пересечения нулем. Использует ли S-функция режим или векторы DWork, концепцией и реализацией является то же самое. Для примера с помощью векторов DWork для образцовых нулевых пересечений см. Вектор Режима DWork в разделе “Using Work Vectors”. Остаток от этого раздела использует векторы режима для образцовых нулевых пересечений.

Элементы вектора режима являются целочисленными значениями. Вы задаете количество элементов вектора режима в mdlInitializeSizes, с помощью ssSetNumModes(S,num). Можно затем получить доступ к вектору режима использование ssGetModeVector. Значения вектора режима определяют, как стандартная программа mdlOutputs действует, когда решатели концентрируются на нулевых пересечениях. Решатели Simulink® отслеживают нулевые пересечения или утверждают события (т.е. разрывы в первых производных) некоторого сигнала, обычно функция входа к вашей S-функции, путем рассмотрения непрерывных нулевых пересечений. Укажите количество непрерывных нулевых пересечений в mdlInitializeSizes, с помощью ssSetNumNonsampledZCs(S, num), затем включайте стандартную программу mdlZeroCrossings, чтобы вычислить непрерывные нулевые пересечения. S-функция sfun_zc_sat.c содержит пример пересечения нулем. Остаток от этого раздела описывает фрагменты этой S-функции, которые принадлежат обнаружению пересечения нулем. Для полного описания этого примера смотрите Обнаружение Пересечения нулем.

Во-первых, mdlInitializeSizes задает размеры для режима и непрерывных векторов пересечения нулем с помощью следующих строк кода.

ssSetNumModes(S, DYNAMICALLY_SIZED);
ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);

Поскольку количество режимов и непрерывных нулевых пересечений динамически измерено, mdlSetWorkWidths должен инициализировать фактический размер этих векторов. В этом примере, показанном ниже, существует один вектор режима для каждого выходного элемента и два непрерывных нулевых пересечения для каждого режима. В целом количество непрерывных нулевых пересечений, необходимых для каждого режима, зависит от количества событий, которые должны быть обнаружены. В этом случае каждый вывод (режим) должен обнаружить, когда это поражает верхнее или нижнюю границу, следовательно два непрерывных нулевых пересечения на режим.

static void mdlSetWorkWidths(SimStruct *S)
{
    int nModes;
    int nNonsampledZCs;

    nModes         = numOutput;
    nNonsampledZCs = 2 * numOutput;
    
    ssSetNumModes(S,nModes);
    ssSetNumNonsampledZCs(S,nNonsampledZCs);
}

Затем, mdlOutputs определяет, в каком режиме симуляция запускается в начале каждого главного временного шага. Метод хранит эту информацию в векторе режима, таким образом, это доступно при вычислении выходных параметров и на главных и на незначительных временных шагах.

/* Get the mode vector */
int_T *mode = ssGetModeVector(S);

    /* Specify three possible mode values.*/
    enum { UpperLimitEquation, NonLimitEquation, LowerLimitEquation };

    /* Update the mode vector at the beginning of a major time step */
    if ( ssIsMajorTimeStep(S) ) {
       for ( iOutput = 0; iOutput < numOutput; iOutput++ ) {
            if ( *uPtrs[uIdx] > *upperLimit ) {
               /* Upper limit is reached. */
               mode[iOutput] = UpperLimitEquation;

            } else if ( *uPtrs[uIdx] < *lowerLimit ) {
               /* Lower limit is reached. */
               mode[iOutput] = LowerLimitEquation;

            } else {
               /* Output is not limited. */
                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 ) {
       /* Output upper limit. */
       *y++ = *upperLimit;

    } else if ( mode[iOutput] == LowerLimitEquation ) {
       /* Output lower limit. */
       *y++ = *lowerLimit;

    } else {
       /* Output is equal to input */
       *y++ = *uPtrs[uIdx];
    }

После того, как выходные параметры вычисляются, механизм Simulink вызывает mdlZeroCrossings, чтобы определить, произошло ли нулевое пересечение. Нулевое пересечение обнаруживается, если какой-либо элемент непрерывного вектора пересечения нулем переключается от отрицательного до положительного, или положительный отрицанию. Если это происходит, симуляция изменяет размер шага и повторно вычисляет выходные параметры, чтобы попытаться определить местоположение точного нулевого пересечения. В данном примере значения для непрерывных векторов пересечения нулем вычисляются как показано ниже.

static void mdlZeroCrossings(SimStruct *S)
{
    int_T             iOutput;
    int_T             numOutput = ssGetOutputPortWidth(S,0);
    real_T            *zcSignals = ssGetNonsampledZCs(S);
    InputRealPtrsType uPtrs      = ssGetInputPortRealSignalPtrs(S,0);

    /* Set index and increment for the input signal, upper limit, and lower 
     * limit parameters so that each gives scalar expansion if needed. */
    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;
    }
}

Смотрите также

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте