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, чтобы сохранить значение статической переменной. 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;
Этот пример переписывает пример 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]; }
Этот пример переписывает 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]); } }