Run Quality Checks on S-Functions Using S-Function Analyzer
This topic shows how to use the S-function analyzer programmatic interfaces to run
quality checks on C-MEX
S-functions in a model or library. These
checks identify potential problems and improvements and suggest solutions. In this
topic, you see how to:
Find the S-functions in a model
Specify the build information for S-functions
Specify the options and run the S-function analyzer
See and interpret the results
Prerequisites
To complete the tutorial, you need the following products:
MATLAB®
Simulink®
Polyspace® (optional)
C compiler – For most platforms, a default C compiler is supplied with the MATLAB installation. For a list of supported compilers, see Change Default Compiler. You can also change the default compiler using
mex -setup
command.
Setup the Working Environment to Check S-Function Using S-Function Analyzer
This example opens up a directory containing the files required for this topic.
Create a local working folder, for example C:\sfa
. Open this example to access the following files.
ex_slexSfunctionCheckExample.slx
external.c
external.h
sfcnModifyMinorStepDiscState.c
sfcnModifyMinorStepDiscState_wrapper.c
sfcnUpdateModifyContinuous.c
sfcnUpdateModifyContinuous_wrapper.c
sfcnUseExternalSrc.c
slexBadSFcn.c
slexBadSFcn_wrapper.c
Run the S-Function Checks
Open a new script from the MATLAB Editor, and save it as
ex_slexSfunctionCheckScript.m
. To see the example model,
double-click ex_slexSfunctionCheckExample.slx
in
Current Folder or type
ex_slexSfunctionCheckExample
at the MATLAB command line.
Specify the Model
model = 'ex_slexSfunctionCheckExample'
Find S-Functions in the Model (Optional)
Use Simulink.sfunction.analyzer.findSfunctions
method to
see all the S-functions to be analyzed in the model. This method does not find
S-functions in a referenced
model.
sfunctions = Simulink.sfunction.analyzer.findSfunctions(model)
Specify Build Information (Optional)
To specify the build information, such as S-function source code, external
libraries, and header files, you can use
Simulink.sfunction.analyzer.BuildInfo
. In this tutorial,
because we have four S-functions in the model, there are four different
BuildInfo
objects. For more information, see Simulink.sfunction.Analyzer
and 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});
Specify Options (Optional)
You can configure the options for executing the S-function analyzer using
Simulink.sfunction.analyzer.Options
class. You can enable
Polyspace
Code Prover™ check and parameter robustness check, set the maximum model
simulation time, and set the report path. If you do not use the class to specify
any of the options, the default options are applied to the analysis. See
Simulink.sfunction.analyzer.Options
for more details.
Note
Running Polyspace Code Prover and parameter robustness checks take some time.
Performing Polyspace Code Prover checks requires a Polyspace license. For more information on using Polyspace checks in the S-function analyzer, see Enable Polyspace Checks. For this tutorial, parameter robustness checks are turned on.
opts = Simulink.sfunction.analyzer.Options(); opts.EnableRobustness = 1;
Run Checks and See Results
Run the S-function analyzer checks using
Simulink.sfunction.Analyzer.run
. Then use the
Simulink.sfunction.Analyzer.generateReport
to see the
issues in your model or
code.
sfunAnalyzer = Simulink.sfunction.Analyzer(model,'BuildInfo',{bdInfo1,bdInfo2,bdInfo3,bdInfo4},'Options',opts); analysisResult=sfunAnalyzer.run(); sfunAnalyzer.generateReport()
generateReport
method produces a
struct
and an HTML report of the result of S-function
analyzer checks. 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]
Explore and Fix Problems
The example model has two warnings in Source Code Checks
and
four issues on S-function MEX-file checks
. In general, warnings
are not as significant as fails, but they are good sources to obtain further
information about your S-functions.
This issue has the description code
MinorStepModifyDiscreteStates
. This error description indicates that block's discrete states is modified at a minor step inmdlOutputs
. To fix this issue, discrete states should only be modified at a major step guarded byssIsMajorTimeStep
.Original Code Modified Code 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
description code indicates that there is an unused variable in the line indicated on the report. This warning is eliminated by deleting the line 208 and rerunning the code.Original Code Modified Code 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; }
The description code
MdlUpdateModifyContinuousStates
indicates that in the S-function source code (in this case, in the source code of blockS-Function1
), the continuous states are modified in itsmdlUpdate
method. You can only change the states of a block at a major time step usingssSetSolverNeedsReset
macro.Original Code Modified Code #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); } }
The description code
MEX Compile Check
indicates that variablesoutputDimsInfo
andinputDimsInfo
are not used in the source code. You can fix this by commenting or deleting the lines that contain these variables.Original Code Modified Code 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);
The description code
CombinedMdlOutputsMdlUpdateWithDiscreteState
indicates that the S-function has discrete states, and you need to useMdlUpdate
andMdlOutputs
methods in your code separately. As a solution for this description code, define a separatemdlUpdate
to change states in your S-function.#define MDL_UPDATE static void mdlUpdate(SimStruct *S, int_T tid) { /* update the discrete states here! */ real_T *xD = ssGetDiscStates(S); }
The description code
DeclareCanBeConditionalExecWithState
indicates that you have state-like data or if you are using multiple sample times in your model, you cannot useSS_OPTION_CAN_BE_CALLED_CONDITIONALLY
option in your S-function source code.To fix the issue in this particular example, delete the
ssSetOptions
function.Original Code Modified Code 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); }
When you fix all issues in your model, the report shows green check marks for each group of checks.
Enable Undocumented API Checks
You can check for the use of undocumented APIs in your S-function source code
to avoid any incompatibilities in the future releases. To enable this check, in
the Simulink.sfunction.analyzer.Options object, set
EnableUsePublishedOnly
to 1. Alternatively, when building
your MEX files, use -DUSE_PUBLISHED_ONLY
option. For example,
try building sfcnModifyMinorStepDiscState.c
with this option
using:
mex sfcnModifyMinorStepDiscState.c -DUSE_PUBLISHED_ONLY
Enable Polyspace Checks
S-function analyzer gives you the option to run Polyspace
Code Prover checks on your code. To enable the check, in the
Simulink.sfunction.analyzer.Options object, set
EnablePolyspace
to 1. Polyspace
Code Prover divides checks into red, green, orange, and gray checks. For more
information on types of checks, see Code Prover Result and Source Code Colors (Polyspace Code Prover).
In the S-function analyzer, the most important error code is red. If the S-function source code fails execution in all paths, Polyspace Code Prover gives a red check error. For more information, see Interpret Code Prover Results in Polyspace Desktop User Interface (Polyspace Code Prover). Here is an example on how to troubleshoot the red check error.
The red Polyspace Code Prover check indicates that there is a problem in your S-function source code. To investigate the issue using Polyspace, click the hyperlink in the report. This link automatically opens a Polyspace Project window. In the Results List pane, expand Red Check and select the error. The source file opens in the Source window. From this window, you can fix and save your code the same way as you do in the MATLAB Editor.
The Polyspace
Code Prover error code indicates a problem with a pointer. Pointer
*p
is out of bounds because it is used in an earlier
loop. Correct the error by replacing this pointer with a variable of your
choice, or deleting *p
from this line of code.
Original Code | Modified Code |
---|---|
if (return_val < 3)
{
tmp = *p+5; /* Out of bounds */
tmp++;
return_val = 10;
} |
if (return_val < 3)
{
tmp = 5;
tmp++;
return_val = 10;
} |
See Also
Simulink.sfunction.Analyzer
| Simulink.sfunction.analyzer.BuildInfo
| Simulink.sfunction.analyzer.Options
| findSfunctions