Примеры векторов DWork

Общий вектор DWork

S-функция sfun_rtwdwork.c показывает, как сконфигурировать вектор DWork для использования с Simulink® Coder™ продукт. Модель Simulink sfcndemo_sfun_rtwdwork использует эту S-функцию для реализации простого аккумулятора.

Следующий фрагмент mdlInitializeSizes метод инициализирует вектор DWork и все связанные с ним свойства генерации кода.

ssSetNumDWork(S, 1);
ssSetDWorkWidth(S, 0, 1);
ssSetDWorkDataType(S, 0, SS_DOUBLE);

/* Identifier; free any old setting and update */
id = ssGetDWorkRTWIdentifier(S, 0);
if (id != NULL) {
    free(id);
}
id = malloc(80);
mxGetString(ID_PARAM(S), id, 80);
ssSetDWorkRTWIdentifier(S, 0, id);

/* Type Qualifier; free any old setting and update */
tq = ssGetDWorkRTWTypeQualifier(S, 0);
if (tq != NULL) {
    free(tq);
}
tq = malloc(80);
mxGetString(TQ_PARAM(S), tq, 80);
ssSetDWorkRTWTypeQualifier(S, 0, tq);

/* Storage class */
sc = ((int_T) *((real_T*) mxGetPr(SC_PARAM(S)))) - 1;
ssSetDWorkRTWStorageClass(S, 0, sc);

S-функция инициализирует вектор DWork в mdlInitializeConditions.

#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ============================
 * Abstract:
 *    Initialize both continuous states to zero
 */
static void mdlInitializeConditions(SimStruct *S)
{
    real_T *x = (real_T*) ssGetDWork(S,0);

    /* Initialize the dwork to 0 */
    x[0] = 0.0;
}

The mdlOutputs метод присваивает значение вектора DWork выходу S-функции.

/* Function: mdlOutputs ========================================
 * Abstract:
 *      y = x
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    real_T *y = ssGetOutputPortRealSignal(S,0);
    real_T *x = (real_T*) ssGetDWork(S,0);

    /* Return the current state as the output */
    y[0] = x[0];
}

The mdlUpdate метод увеличивает значение DWork на вход.

#define MDL_UPDATE
/* Function: mdlUpdate ============================================
 * Abstract:
 *    This function is called once for every major integration
 *    time step. Discrete states are typically updated here, but
 *    this function is useful for performing any tasks that should 
 *    only take place once per integration step.
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
    real_T *x = (real_T*) ssGetDWork(S,0);
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
        
    /*
     * Increment the state by the input 
     * U is defined as U(element) (*uPtrs[element])
     */
    x[0] += U(0);
}

Вектор царапин DWork

В следующем примере для хранения статического значения переменных используется вектор scratch DWork. The mdlInitializeSizes метод конфигурирует ширину и тип данных вектора DWork. The ssSetDWorkUsageType macro задает вектор DWork как царапин.

ssSetNumDWork(S, 1);

ssSetDWorkWidth(S, 0, 1);
ssSetDWorkDataType(S, 0, SS_DOUBLE);
ssSetDWorkUsageType(S,0, SS_DWORK_USED_AS_SCRATCH);

Остальная часть S-функции использует вектор scratch DWork точно так же, как и любой другой тип вектора DWork. The InitializeConditions метод устанавливает начальное значение и mdlOutputs метод использует значение, сохраненное в векторе DWork.

#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ================================ */
static void mdlInitializeConditions(SimStruct *S)
{
    real_T *x = (real_T*) ssGetDWork(S,0);
    /* Initialize the dwork to 0 */
    x[0] = 0.0;
}
/* Function: mdlOutputs ============================================= */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    real_T *y = ssGetOutputPortRealSignal(S,0);
    real_T *x1 = (real_T*) ssGetDWork(S,1);

    x[0] = 2000;
    y[0] = x[0] * 2;
}

Если у вас есть Simulink Coder, программное обеспечение Simulink Coder обрабатывает DWork по-другому по сравнению с другими векторами DWork при генерации кода для встроенной S-функции. Чтобы встроить S-функцию, создайте следующий файл Target Language Compiler (TLC), чтобы описать mdlOutputs способ.

%implements sfun_dscratch "C"

%% Function: Outputs ==========================================================
%%
/* dscratch Block: %<Name> */
%<LibBlockDWork(DWork[0], "", "", 0)> = 2000.0;
%<LibBlockOutputSignal(0,"","",0)> = %<LibBlockDWork(DWork[0],"","", 0)> * 2;

Когда программное обеспечение Simulink Coder генерирует код для модели, оно вводит S-функцию и объявляет второй вектор DWork как локальный вектор-царапину. Для примера функция выходов модели содержит следующие линии:

/* local scratch DWork variables */
real_T SFunction_DWORK1;
SFunction_DWORK1 = 2000.0;

Если бы S-функция использовала общий вектор DWork вместо царапанного вектора DWork, сгенерирование кода с тем же файлом привело бы к включению вектора DWork в структуру данных следующим образом:

sfcndemo_dscratch_DWork.SFunction_DWORK1 = 2000.0;
Вектор

Работы DState

Этот пример переписывает пример S-функции dsfunc.c использовать вектор DState вместо явного вектора дискретного состояния. The mdlInitializeSizes макрос инициализирует количество дискретных состояний как нуль и вместо этого инициализирует один вектор DWork.

The mdlInitializeSizes затем метод конфигурирует вектор DWork как вектор DState, используя вызов для ssSetDWorkUsedAsDState. Это эквивалентно вызову ssSetDWorkUsageType макрос со значением SS_DWORK_USED_AS_DSTATE. The mdlInitializeSizes метод задает ширину и тип данных вектора DState и задает состояние как имя с помощью ssSetDWorkName.

Примечание

Векторам DWork, сконфигурированным как векторы DState, должно быть присвоено имя для механизма Simulink, чтобы зарегистрировать вектор как дискретные состояния. Функция Simulink .BlockDiagram.getInitialStates (mdl) возвращает назначенное имя в label поле для начальных состояний.

static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Parameter mismatch reported by the Simulink engine */
    }

    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, 2);
    ssSetInputPortDirectFeedThrough(S, 0, 1);

    if (!ssSetNumOutputPorts(S, 1)) return;
    ssSetOutputPortWidth(S, 0, 2);

    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);

    ssSetNumDWork(S, 1);
    ssSetDWorkUsedAsDState(S, 0, SS_DWORK_USED_AS_DSTATE);
    ssSetDWorkWidth(S, 0, 2);
    ssSetDWorkDataType(S, 0, SS_DOUBLE);
    ssSetDWorkName(S, 0, "SfunStates");

    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}

The mdlInitializeConditions метод инициализирует значения векторов DState с помощью указателя, возвращенного ssGetDWork.

#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ===============================
 * Abstract:
 *    Initialize both discrete states to one.
 */
static void mdlInitializeConditions(SimStruct *S)
{
    real_T *x0 = (real_T*) ssGetDWork(S, 0);
    int_T  lp;

    for (lp=0;lp<2;lp++) { 
        *x0++=1.0; 
    }
}

The mdlOutputs затем метод использует значения, сохраненные в векторе DState, чтобы вычислить выход дискретного уравнения пространства состояний.

/* Function: mdlOutputs ========================================
 * Abstract:
 *      y = Cx + Du 
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    real_T            *y    = ssGetOutputPortRealSignal(S,0);
    real_T            *x    = (real_T*) ssGetDWork(S, 0);
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
 
    UNUSED_ARG(tid); /* not used in single tasking mode */

    /* y=Cx+Du */
    y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
    y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}

Наконец, mdlUpdate метод обновляет вектор DState новыми значениями для дискретных состояний.

#define MDL_UPDATE
/* Function: mdlUpdate ============================================
 * Abstract:
 *      xdot = Ax + Bu
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
    real_T            tempX[2] = {0.0, 0.0};
    real_T            *x       = (real_T*) ssGetDWork(S, 0);
    InputRealPtrsType uPtrs    = ssGetInputPortRealSignalPtrs(S,0);

    UNUSED_ARG(tid); /* not used in single tasking mode */

    /* xdot=Ax+Bu */
    tempX[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
    tempX[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
 
    x[0]=tempX[0];
    x[1]=tempX[1];
}

Вектор режима DWork

Этот пример переписывает S-функцию sfun_zc.c использовать вектор режима DWork вместо рабочего вектора явного режима (для получения дополнительной информации о рабочих векторах режима см. Elementary Work Vectors). Эта S-функция реализует блок абсолютных значений.

The mdlInitializeSizes метод устанавливает количество векторов DWork и векторов пересечения нулем (см. Пересечения нуля) равным DYNAMICALLY_SIZED. The DYNAMICALLY_SIZED установка позволяет механизму Simulink отложить задание рабочих размеров вектора до тех пор, пока он не узнает размерности входного сигнала, позволяя S-функции поддерживать вход с произвольной шириной.

static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Parameter mismatch reported by the Simulink engine */
    }

    ssSetNumContStates(    S, 0);
    ssSetNumDiscStates(    S, 0);

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);
    ssSetInputPortDirectFeedThrough(S, 0, 1);

    if (!ssSetNumOutputPorts(S,1)) return;
    ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);

    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumDWork(S, 1);
    ssSetNumModes(S, 0);
    
    /* Initializes the zero-crossing and DWork vectors */
    ssSetDWorkWidth(S,0,DYNAMICALLY_SIZED);
    ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);

    /* Take care when specifying exception free code - see sfuntmpl_doc.c */
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}

Механизм Simulink инициализирует количество векторов пересечения нулем и векторов DWork к количеству элементов в сигнале, поступающем в первый входной порт S-функции. Затем двигатель вызывает mdlSetWorkWidths метод, который использует ssGetNumDWork чтобы определить, сколько векторов DWork было инициализировано, и затем задать свойства для каждого вектора DWork.

#define MDL_SET_WORK_WIDTHS
static void mdlSetWorkWidths(SimStruct *S) {
    int_T numdw = ssGetNumDWork(S);
    int_T i;
    
    for (i = 0; i < numdw; i++) {
        ssSetDWorkUsageType(S, i, SS_DWORK_USED_AS_MODE);
        ssSetDWorkDataType(S, i, SS_BOOLEAN);
        ssSetDWorkComplexSignal(S, i, COMPLEX_NO);
    }
}

The mdlOutputs метод использует значение, сохраненное в векторе режима DWork, чтобы определить, должен ли выходной сигнал равняться входному сигналу или абсолютному значению входного сигнала.

static void mdlOutputs(SimStruct *S, int_T tid)
{
    int_T             i;
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
    real_T            *y    = ssGetOutputPortRealSignal(S,0);
    int_T             width = ssGetOutputPortWidth(S,0);
    boolean_T         *mode = ssGetDWork(S,0);

    UNUSED_ARG(tid); /* not used in single tasking mode */

    if (ssIsMajorTimeStep(S)) {
        for (i = 0; i < width; i++) {
            mode[i] = (boolean_T)(*uPtrs[i] >= 0.0);
        }
    }

    for (i = 0; i < width; i++) {
        y[i] = mode[i]? (*uPtrs[i]): -(*uPtrs[i]);
    }
}