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

Вектор генерала Дуорка

sfun_rtwdwork.c S-функции показывает, как сконфигурировать вектор DWork для использования с продуктом Simulink® Coder™. Образцовый sfcndemo_sfun_rtwdwork Simulink использует эту 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]);
    }
}
Была ли эта тема полезной?