Используйте API анализатора S-функций, чтобы запустить проверки качества на C-MEX
S-функции в модели или библиотеке. Эти проверки выявляют потенциальные проблемы и улучшения и предлагают решения. В этом руководстве вы видите, как:
Найдите S-функции в модели
Укажите информацию о сборке для S-функций
Задайте опции и запустите анализатор S-функций
Смотрите и интерпретируйте результаты
Чтобы завершить руководство, вам нужны следующие продукты:
MATLAB®
Simulink®
Polyspace® (необязательно)
Компилятор C - Для большинства платформ компилятор C по умолчанию поставляется с установкой MATLAB. Список поддерживаемых компиляторов см. в разделе Изменение компилятора по умолчанию. Можно также изменить компилятор по умолчанию с помощью mex -setup
команда.
Создайте локальную рабочую папку, например C:\sfa
.
Измените на docroot\toolbox\simulink\examples
папка. В командной строке MATLAB введите:
cd(fullfile(docroot, 'toolbox', 'simulink', 'examples'))
Скопируйте перечисленные файлы в локальную рабочую папку:
ex_slexSfunctionCheckExample.slx
external.c
external.h
sfcnModifyMinorStepDiscState.c
sfcnModifyMinorStepDiscState_wrapper.c
sfcnUpdateModifyContinuous.c
sfcnUpdateModifyContinuous_wrapper.c
sfcnUseExternalSrc.c
slexBadSFcn.c
slexBadSFcn_wrapper.c
Откройте новый скрипт из РЕДАКТОРА MATLAB и сохраните его как ex_slexSfunctionCheckScript.m
. Чтобы увидеть модель примера, дважды кликните ex_slexSfunctionCheckExample.slx
в Current Folder или типах ex_slexSfunctionCheckExample
в командной строке MATLAB.
model = 'ex_slexSfunctionCheckExample'
Использование Simulink.sfunction.analyzer.findSfunctions
метод, чтобы увидеть все S-функции, которые будут анализироваться в модели. Этот метод не находит S-функции в ссылочной модели.
sfunctions = Simulink.sfunction.analyzer.findSfunctions(model)
Чтобы задать сведения о сборке, такие как исходный код S-функции, внешние библиотеки и заголовочные файлы, можно использовать Simulink.sfunction.analyzer.BuildInfo
. В этом руководстве, поскольку у нас есть четыре S-функции в модели, существует четыре различных BuildInfo
объекты. Для получения дополнительной информации смотрите Simulink.sfunction.Analyzer
и Simulink.sfunction.analyzer.BuildInfo
.
bdInfo1= Simulink.sfunction.analyzer.BuildInfo('sfcnUseExternalSrc.c',... 'ExtraSrcFileList',{'external.c'},... 'SrcPaths',{pwd},'IncPaths',{pwd}); bdInfo2= Simulink.sfunction.analyzer.BuildInfo('sfcnModifyMinorStepDiscState.c',... 'ExtraSrcFileList',{'sfcnModifyMinorStepDiscState_wrapper.c'},... 'SrcPaths',{pwd}); bdInfo3= Simulink.sfunction.analyzer.BuildInfo('sfcnUpdateModifyContinuous.c',... 'ExtraSrcFileList',{'sfcnUpdateModifyContinuous_wrapper.c'},... 'SrcPaths',{pwd}); bdInfo4= Simulink.sfunction.analyzer.BuildInfo('slexBadSFcn.c',... 'ExtraSrcFileList',{'slexBadSFcn_wrapper.c'},... 'SrcPaths',{pwd});
Можно сконфигурировать опции для выполнения анализатора S-функций с помощью Simulink.sfunction.analyzer.Options
класс. Можно включить проверку Polyspace Code Prover™ и проверку робастности параметра, задать максимальное время симуляции модели и задать путь отчета. Если вы не используете класс для задания любой из опций, опции по умолчанию применяются к анализу. См. Simulink.sfunction.analyzer.Options
для получения дополнительной информации.
Примечание
Выполнение проверок робастности Polyspace Code Prover и параметров занимает некоторое время.
Для выполнения проверок Polyspace Code Prover требуется лицензия Polyspace. Для получения дополнительной информации об использовании проверок Polyspace в анализаторе S-функций, смотрите Включить проверки Polyspace. Для этого руководства включаются проверки робастности параметров.
opts = Simulink.sfunction.analyzer.Options(); opts.EnableRobustness = 1;
Запустите проверку анализатора S-функций с помощью Simulink.sfunction.Analyzer.run
. Затем используйте Simulink.sfunction.Analyzer.generateReport
чтобы увидеть проблемы в вашей модели или коде.
sfunAnalyzer = Simulink.sfunction.Analyzer(model,'BuildInfo',{bdInfo1,bdInfo2,bdInfo3,bdInfo4},'Options',opts); analysisResult=sfunAnalyzer.run(); sfunAnalyzer.generateReport()
generateReport
метод создает struct
и HTML о результатах проверок анализатора S-функций. analysisResult = struct with fields: TimeGenerated: '13-Jul-2017 13:22:37' Platform: 'win64' Release: '(R2017b)' SimulinkVersion: '9.0' ExemptedBlocks: {} MexConfiguration: [1×1 mex.CompilerConfiguration] Data: [4×4 struct]
Пример модели имеет два предупреждения в Source Code Checks
и четыре выпуска по вопросам S-function MEX-file checks
. В целом предупреждения не так значительны, как сбои, но они являются хорошими источниками для получения дополнительной информации о ваших S-функциях.
У этой проблемы есть код описания MinorStepModifyDiscreteStates
. Это описание ошибки указывает, что дискретные состояния блока изменяются в мелкий шаг в mdlOutputs
. Чтобы исправить эту проблему, дискретные состояния должны быть изменены только на основном шаге, охраняемом ssIsMajorTimeStep
.
Оригинальный код | Модифицированный код |
---|---|
MinorStepDiscState_Outputs_wrapper(u0, y0, xC);
if (ssGetT(S)>0.5) {
xD[0] = xD[0]+1;
xD[1] = xD[0]+xD[1]*2.0;
} |
if (ssGetT(S)>0.5) { if (ssIsMajorTimeStep(S)) { xD[0] = xD[0]+1; xD[1] = xD[0]+xD[1]*2.0; } } |
The MEX Compile Check
код описания указывает, что в линии, указанной в отчете, есть неиспользуемая переменная. Это предупреждение устраняется путем удаления линии 208 и повторного запуска кода.
Оригинальный код | Модифицированный код |
---|---|
static void mdlOutputs(SimStruct *S, int_T tid) { const real_T *u0 = (const real_T*) ssGetInputPortSignal(S,0); real_T *y0 = (real_T *)ssGetOutputPortRealSignal(S,0); real_T *xC = ssGetContStates(S); *y0 = *xC; } |
static void mdlOutputs(SimStruct *S, int_T tid) { // const real_T *u0 = (const real_T*) ssGetInputPortSignal(S,0); real_T *y0 = (real_T *)ssGetOutputPortRealSignal(S,0); real_T *xC = ssGetContStates(S); *y0 = *xC; } |
Код описания MdlUpdateModifyContinuousStates
указывает, что в исходном коде S-функции (в данном случае в исходном коде блока S-Function1
), непрерывные состояния изменяются в его mdlUpdate
способ. Можно изменять состояния блока только в основной временной шаг, используя ssSetSolverNeedsReset
макрос.
Оригинальный код | Модифицированный код |
---|---|
#define MDL_UPDATE static void mdlUpdate(SimStruct *S, int_T tid) { real_T *xC = ssGetContStates(S); *xC = *xC + 1.0; } |
#define MDL_UPDATE static void mdlUpdate(SimStruct *S, int_T tid) { real_T *xC = ssGetContStates(S); // Modify continuous states if (ssIsMajorTimeStep(S)) { *xC = *xC + 1.0; ssSetSolverNeedsReset(S); } } |
Код описания MEX Compile Check
указывает, что переменные outputDimsInfo
и inputDimsInfo
не используются в исходном коде. Вы можете исправить это, комментируя или удаляя линии, которые содержат эти переменные.
Оригинальный код | Модифицированный код |
---|---|
static void mdlInitializeSizes(SimStruct *S) { DECL_AND_INIT_DIMSINFO(inputDimsInfo); DECL_AND_INIT_DIMSINFO(outputDimsInfo); ssSetNumSFcnParams(S, NPARAMS); |
static void mdlInitializeSizes(SimStruct *S) { // DECL_AND_INIT_DIMSINFO(inputDimsInfo); // DECL_AND_INIT_DIMSINFO(outputDimsInfo); ssSetNumSFcnParams(S, NPARAMS); |
Код описания CombinedMdlOutputsMdlUpdateWithDiscreteState
указывает, что S-функция имеет дискретные состояния, и вам нужно использовать MdlUpdate
и MdlOutputs
методы в коде отдельно. Как решение для этого кода описания, задайте отдельное mdlUpdate
для изменения состояний в S-функции.
#define MDL_UPDATE static void mdlUpdate(SimStruct *S, int_T tid) { /* update the discrete states here! */ real_T *xD = ssGetDiscStates(S); }
Код описания DeclareCanBeConditionalExecWithState
указывает, что у вас есть данные, подобные состоянию, или если вы используете несколько шагов расчета в модели, вы не можете использовать SS_OPTION_CAN_BE_CALLED_CONDITIONALLY
опция в исходном коде S-функции.
Чтобы исправить проблему в этом конкретном примере, удалите ssSetOptions
функция.
Оригинальный код | Модифицированный код |
---|---|
static void mdlInitializeSizes(SimStruct *S) { DECL_AND_INIT_DIMSINFO(inputDimsInfo); DECL_AND_INIT_DIMSINFO(outputDimsInfo); ssSetNumSFcnParams(S, NPARAMS); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } ssSetNumContStates(S, NUM_CONT_STATES); ssSetNumDiscStates(S, NUM_DISC_STATES); if (!ssSetNumInputPorts(S, NUM_INPUTS)) return; ssSetInputPortWidth(S, 0, INPUT_0_WIDTH); ssSetInputPortDataType(S, 0, SS_DOUBLE); ssSetInputPortComplexSignal(S, 0, INPUT_0_COMPLEX); ssSetInputPortDirectFeedThrough(S, 0, INPUT_0_FEEDTHROUGH); ssSetInputPortRequiredContiguous(S, 0, 1); /*direct input signal access*/ if (!ssSetNumOutputPorts(S, NUM_OUTPUTS)) return; ssSetOutputPortWidth(S, 0, OUTPUT_0_WIDTH); ssSetOutputPortDataType(S, 0, SS_DOUBLE); ssSetOutputPortComplexSignal(S, 0, OUTPUT_0_COMPLEX); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, SS_OPTION_CAN_BE_CALLED_CONDITIONALLY); } |
static void mdlInitializeSizes(SimStruct *S) { DECL_AND_INIT_DIMSINFO(inputDimsInfo); DECL_AND_INIT_DIMSINFO(outputDimsInfo); ssSetNumSFcnParams(S, NPARAMS); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } ssSetNumContStates(S, NUM_CONT_STATES); ssSetNumDiscStates(S, NUM_DISC_STATES); if (!ssSetNumInputPorts(S, NUM_INPUTS)) return; ssSetInputPortWidth(S, 0, INPUT_0_WIDTH); ssSetInputPortDataType(S, 0, SS_DOUBLE); ssSetInputPortComplexSignal(S, 0, INPUT_0_COMPLEX); ssSetInputPortDirectFeedThrough(S, 0, INPUT_0_FEEDTHROUGH); ssSetInputPortRequiredContiguous(S, 0, 1); /*direct input signal access*/ if (!ssSetNumOutputPorts(S, NUM_OUTPUTS)) return; ssSetOutputPortWidth(S, 0, OUTPUT_0_WIDTH); ssSetOutputPortDataType(S, 0, SS_DOUBLE); ssSetOutputPortComplexSignal(S, 0, OUTPUT_0_COMPLEX); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); } |
Когда вы исправляете все проблемы в модели, в отчете показываются зеленые метки для каждой группы проверок.
Можно проверить использование недокументированных API в исходном коде S-функции, чтобы избежать любых несовместимостей в будущих релизах. Чтобы включить эту проверку, в объекте Опции задайте EnableUsePublishedOnly
по 1. Кроме того, при построении файлов MEX используйте -DUSE_PUBLISHED_ONLY
опция. Например, попробуйте создать sfcnModifyMinorStepDiscState.c
при помощи этой опции:
mex sfcnModifyMinorStepDiscState.c -DUSE_PUBLISHED_ONLY
Анализатор S-функций дает вам опцию запускать проверки Polyspace Code Prover на вашем коде. Чтобы включить проверку, в объекте Опции задайте EnablePolyspace
по 1. Polyspace Code Prover делит проверки на проверки красного, зеленого, оранжевого и серого цветов. Для получения дополнительной информации о типах проверок смотрите Результаты Code Prover и Цвета исходного кода (Polyspace Code Prover).
В анализаторе S-функций самый главный код ошибки - красный. Если исходный код S-функции не справляется с выполнением во всех путях, Polyspace Code Prover выдает красную ошибку проверки. Для получения дополнительной информации смотрите Результаты интерпретации Code Prover в Пользовательском интерфейсе Polyspace Desktop (Polyspace Code Prover). Вот пример, как устранить ошибку красной проверки.
Красная проверка Polyspace Code Prover указывает, что в исходном коде вашей S-функции есть проблема. Чтобы выяснить проблему с помощью Polyspace, щелкните гиперссылку в отчете. Эта ссылка автоматически открывает Polyspace Project окно. На панели «Список результатов» разверните Red Check и выберите ошибку. В окне Source откроется исходный файл. Из этого окна можно исправить и сохранить код так же, как и в РЕДАКТОРА MATLAB.
Код ошибки Polyspace Code Prover указывает на проблему с указателем. Указатель на *p
выходит за пределы, поскольку используется в более раннем цикле. Исправьте ошибку, заменив этот указатель на переменную по вашему выбору или удалив *p
из этой строки кода.
Оригинальный код | Модифицированный код |
---|---|
if (return_val < 3)
{
tmp = *p+5; /* Out of bounds */
tmp++;
return_val = 10;
} |
if (return_val < 3)
{
tmp = 5;
tmp++;
return_val = 10;
} |
findSfunctions
| Simulink.sfunction.Analyzer
| Simulink.sfunction.analyzer.BuildInfo
| Simulink.sfunction.analyzer.Options