Примеры вектора 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;
}

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];
}

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

Следующий пример использует царапину вектор DWork, чтобы сохранить значение статической переменной. mdlInitializeSizes метод конфигурирует ширину и тип данных вектора DWork. ssSetDWorkUsageType макрос затем указывает, что вектор DWork является вектором царапины.

ssSetNumDWork(S, 1);

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

Остаток от S-функции использует царапину вектор DWork точно, когда это было бы любой другой тип вектора DWork. 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-функцию, создайте следующий файл Компилятора выходного языка (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-функция использовала вектор генерала Дуорка вместо царапины, вектор ДУОРКА, генерируя код с тем же файлом TLC привел бы к вектору ДУОРКА, включаемому в структуру данных, можно следующим образом:

sfcndemo_dscratch_DWork.SFunction_DWORK1 = 2000.0;

Вектор работы DState

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

mdlInitializeSizes метод затем конфигурирует вектор DWork как вектор DState с помощью вызова ssSetDWorkUsedAsDState. Это эквивалентно вызову ssSetDWorkUsageType макрос со значением SS_DWORK_USED_AS_DSTATE. 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);
}

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; 
    }
}

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 вместо явного режима работают вектор (см., что Элементарные Векторы работы для получения дополнительной информации о режиме работают векторы). Эта S-функция реализует блок абсолютного значения.

mdlInitializeSizes метод определяет номер векторов DWork и векторов пересечения нулем (см. Нулевые Пересечения) к DYNAMICALLY_SIZED. 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);
    }
}

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]);
    }
}