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); }
В следующем примере для хранения статического значения переменных используется вектор 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;
Этот пример переписывает пример 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]; }
Этот пример переписывает 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]); } }