Проверяйте S-функции Используя S-функцию API анализатора

Используйте S-функцию API анализатора, чтобы запустить проверки качества на C-MEX S-функции в модели или библиотеке. Эти проверки идентифицируют потенциальные проблемы и улучшения и предлагают решения. В этом примере вы видите как к:

  • Найдите S-функции в модели

  • Укажите информацию сборки для S-функций

  • Задайте опции и запустите S-функцию анализатор

  • Смотрите и интерпретируйте результаты

Необходимые условия

Чтобы завершить пример, вам нужны следующие продукты:

  • MATLAB®

  • Simulink®

  • (Дополнительный) Polyspace®

  • Компилятор C – Для большинства платформ, компилятор C по умолчанию предоставляется установкой MATLAB. Для списка поддерживаемых компиляторов см. Компилятор Значения по умолчанию Изменения. Можно также изменить компилятор по умолчанию с помощью mex -setup команда.

Setup рабочая среда

  1. Создайте локальную рабочую папку, например, C:\sfa.

  2. Превратитесь в docroot\toolbox\simulink\examples папка. В командной строке MATLAB, введите:

    cd(fullfile(docroot, 'toolbox', 'simulink', 'examples'))

  3. Скопируйте перечисленные файлы в свою локальную рабочую папку:

    • ex_slexSfunctionCheckExample.slx

    • external.c

    • external.h

    • sfcnModifyMinorStepDiscState.c

    • sfcnModifyMinorStepDiscState_wrapper.c

    • sfcnUpdateModifyContinuous.c

    • sfcnUpdateModifyContinuous_wrapper.c

    • sfcnUseExternalSrc.c

    • slexBadSFcn.c

    • slexBadSFcn_wrapper.c

Осуществите проверки S-функции

Откройте новый скрипт от редактора MATLAB и сохраните его как ex_slexSfunctionCheckScript.m. Чтобы видеть модель в качестве примера, дважды кликните ex_slexSfunctionCheckExample.slx в Current Folder или типе ex_slexSfunctionCheckExample в командной строке MATLAB.

Задайте модель

model = 'ex_slexSfunctionCheckExample'

Найдите S-функции в модели (Необязательно)

Используйте 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-функциях.

  1. Эта проблема имеет код описания 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;
           } 
        }

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

  3. Код описания 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);
        }
    }

  4. Код описания 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);

  5. Код описания 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);
    }

  6. Код описания 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

Можно проверять на использование недокументированных API в исходном коде S-функции, чтобы избежать любых несовместимостей в будущих релизах. Включить эту проверку, в Simulink.sfunction.analyzer. Объект Options, набор EnableUsePublishedOnly к 1. В качестве альтернативы при создании файлов MEX, используйте -DUSE_PUBLISHED_ONLY опция. Например, попытайтесь создать sfcnModifyMinorStepDiscState.c с этим использованием опции:

mex sfcnModifyMinorStepDiscState.c -DUSE_PUBLISHED_ONLY

Включите проверки Polyspace

S-функция анализатор дает вам опцию, чтобы осуществить проверки Polyspace Code Prover вашего кода. Включить проверку, в Simulink.sfunction.analyzer. Объект Options, набор EnablePolyspace к 1. Polyspace Code Prover делится, зарегистрировался в красных, зеленых, оранжевых, и серых проверках. Для получения дополнительной информации о типах проверок смотрите Цвета Результата и Исходного кода Программы автоматического доказательства Кода (Polyspace Code Prover).

В S-функции анализатор самый важный код ошибки является красным. Если выполнение сбоев исходного кода S-функции во всех путях, Polyspace Code Prover дает красную ошибку проверки. Для получения дополнительной информации смотрите, Интерпретируют Результаты Программы автоматического доказательства Кода в Пользовательском интерфейсе Рабочего стола Polyspace (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;
    }

Смотрите также

| | |

Похожие темы

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте