This example shows how to create a customized Model Advisor pass/fail check with a fix action. When a model does not contain a check violation, the results contain the check description and result status. When a model contains a check violation, the results contain the check description, result status, and the recommended action to fix the issue. This example adds a custom check to a Model Advisor By Product > Demo subfolder.
For this example, the custom check identifies blocks whose names do not appear below the blocks. The fix action is to make the block names appear below the blocks.
This example also shows you how to collect results into groups that violate a check (that is, detailed result collections), such as blocks in a subsystem. In the Model Advisor, you can review results by selecting:
View By > Recommended Action ─ When a check is violated, this view shows a list of model elements that violate the check. When there is no violation, this view provides a brief description stating that the check was not violated.
View By > Subsystem ─ This view shows a table of model elements that violate the check, organized by model or subsystem (when applicable).
View By > Block ─ This view provides a list of check violations for each block.
When a check does not pass, the results include a hyperlink to each model element that
violates the check. Use these hyperlinks to easily locate areas in your model or
subsystem. The code for this example consists of an
sl_customization.m
file and a
defineDetailStyleCheck.m
file.
sl_customization
FileIn your working folder, create an sl_customization.m
file.
To register the custom checks, create an
sl_customization(cm)
function as shown here. This
function accepts one argument, a customization manager object. The
customization manager object includes the
addModelAdvisorCheckFcn
method for registering the
custom check. The input to this method is a handle to the check definition
function.
function sl_customization(cm) % SL_CUSTOMIZATION - Model Advisor customization demonstration. % Copyright 2019 The MathWorks, Inc. % register custom checks cm.addModelAdvisorCheckFcn(@defineDetailStyleCheck); % ----------------------------- % defines Model Advisor Checks % ----------------------------- function defineDetailStyleCheck;
The check definition function defines the check and fix actions that the Model
Advisor takes when you run the check. For this example, the completed check
definition function file is defineDetailStyleCheck.m
, and it
contains this
code:
function defineDetailStyleCheck mdladvRoot = ModelAdvisor.Root; % Create ModelAdvisor.Check object and set properties. rec = ModelAdvisor.Check('com.mathworks.sample.detailStyle'); rec.Title = 'Check whether block names appear below blocks'; rec.TitleTips = 'Check position of block names'; rec.setCallbackFcn(@DetailStyleCallback,'None','DetailStyle'); % Create ModelAdvisor.Action object for setting fix operation. myAction = ModelAdvisor.Action; myAction.Name='Make block names appear below blocks'; myAction.Description='Click the button to place block names below blocks'; rec.setAction(myAction); myAction.setCallbackFcn(@ActionCB); mdladvRoot.publish(rec, 'Demo'); % publish check into Demo group. end % ----------------------------- % This callback function uses the DetailStyle CallbackStyle type. % ----------------------------- function DetailStyleCallback(system, CheckObj) mdladvObj = Simulink.ModelAdvisor.getModelAdvisor(system); % get object % Find all blocks whose name does not appear below blocks violationBlks = find_system(system, 'Type','block',... 'NamePlacement','alternate',... 'ShowName', 'on'); if isempty(violationBlks) ElementResults = ModelAdvisor.ResultDetail; ElementResults.IsInformer = true; ElementResults.Description = 'Identify blocks where the name is not displayed below the block.'; ElementResults.Status = 'All blocks have names displayed below the block.'; mdladvObj.setCheckResultStatus(true); else ElementResults(1,numel(violationBlks))=ModelAdvisor.ResultDetail; for i=1:numel(ElementResults) ElementResults(i).setData(violationBlks{i}); ElementResults(i).Description = 'Identify blocks where the name is not displayed below the block.'; ElementResults(i).Status = 'The following blocks have names that do not display below the blocks:'; ElementResults(i).RecAction = 'Change the location such that the block name is below the block.'; end mdladvObj.setCheckResultStatus(false); mdladvObj.setActionEnable(true); end CheckObj.setResultDetails(ElementResults); end % ----------------------------- % This action callback function changes the location of block names. % ----------------------------- function result = ActionCB(taskobj) mdladvObj = taskobj.MAObj; checkObj = taskobj.Check; resultDetailObjs = checkObj.ResultDetails; for i=1:numel(resultDetailObjs) % take some action for each of them block=Simulink.ID.getHandle(resultDetailObjs(i).Data); set_param(block,'NamePlacement','normal'); end result = ModelAdvisor.Text('Changed the location such that the block name is below the block.'); mdladvObj.setActionEnable(false); end
The following steps explain how to create completed the
defineDetailStyleCheck.m
file.
Create a ModelAdvisor.Root
object.
mdladvRoot = ModelAdvisor.Root;
Create a ModelAdvisor.Check
object and
define the unique check ID. For this check, the ID is
com.mathworks.sample.detailStyle
.
rec = ModelAdvisor.Check('com.mathworks.sample.detailStyle');
Specify the ModelAdvisor.Check.Title
and
ModelAdvisor.Check.TitleTips
properties.
rec.Title = 'Check whether block names appear below blocks'; rec.TitleTips = 'Check position of block names';
Use the setCallbackFcn
method to
call the callback function. The setCallbackFcn
method
arguments are a handle to the callback function and the
ModelAdvisor.Check.CallbackStyle
property value. For
this example, the CallbackStyle
property value is
DetailStyle
. This style allows you to view results by
block, subsystem, or recommended action. Applying this style produces
default formatting, so that you do not have to use the ModelAdvisor.FormatTemplate
class or the other Model Advisor formatting APIs to format the results that
appear in the Model Advisor.
rec.setCallbackFcn(@DetailStyleCallback,'None','DetailStyle');
To set the fix operation, create a ModelAdvisor.Action
object
and define its properties.
myAction = ModelAdvisor.Action; myAction.setCallbackFcn(@ActionCB); myAction.Name='Make block names appear below blocks'; myAction.Description='Click the button to place block names below blocks';
Use the setCallback
method to call
the action callback function. The input to this method is a handle to the
action callback function.
myAction.setCallbackFcn(@ActionCB);
Use the setAction
method to set the
action for the check.
rec.setAction(myAction);
Use the publish
method to publish
the check to a folder within the By Product folder. For
this example, the folder name is Demo.
mdladvRoot.publish(rec, 'Demo'); % publish check into Demo group.
In the defineDetailStyleCheck.m
file, create the
check callback function. In this example, the function name is
DetailStyleCallback
. The inputs to this function
are a ModelAdvisor.CheckObject
and the path to the
model or system that the Model Advisor analyzes.
function DetailStyleCallback(system, CheckObj)
To create a Simulink.ModelAdvisor
object, use the Simulink.ModelAdvisor.getModelAdvisor
method.
mdladvObj = Simulink.ModelAdvisor.getModelAdvisor(system); % get object
To identify blocks that violate the check, use the find_system
function.
For each model element, this function creates a ModelAdvisor.ResultDetail
object.
violationBlks = find_system(system, 'Type','block',... 'NamePlacement','alternate',... 'ShowName', 'on');
Write code for the case when the find_system
function does not identify blocks whose names do not appear below the
block. In this case, ElementResults
is one instance
of a ModelAdvisor.ResultDetail
object and provides
information content only. The method specifies that there is
no check violation and displays
Passed in the Model Advisor.
if isempty(violationBlks) ElementResults = ModelAdvisor.ResultDetail; ElementResults.IsInformer = true; ElementResults.Description = 'Identify blocks where the name is not displayed below the block.'; ElementResults.Status = 'All blocks have names displayed below the block.'; mdladvObj.setCheckResultStatus(true);
Write code for the case when the find_system
function returns a list of blocks whose names do not appear below the
block (violationBlks
).
ElementResults
includes each
ModelAdvisor.ResultDetail
object that violates
the check and provides a recommended action message for fixing the check
violation.
For this case, the setCheckResultStatus
method specifies the check violation
and displays Warning or Failed
in the Model Advisor. The
Simulink.ModelAdvisor.setActionEnable(true)
method enables the ability to fix the check violation issue from the
Model Advisor.
else ElementResults(1,numel(violationBlks))=ModelAdvisor.ResultDetail; for i=1:numel(ElementResults) ElementResults(i).setData(violationBlks{i}); ElementResults(i).Description = 'Identify blocks where the name is not displayed below the block.'; ElementResults(i).Status = 'The following blocks have names that do not display below the blocks:'; ElementResults(i).RecAction = 'Change the location such that the block name is below the block.'; end mdladvObj.setCheckResultStatus(false); mdladvObj.setActionEnable(true); end
To associate the results with a check object, use the setResultDetails
method.
CheckObj.setResultDetails(ElementResults);
end
In the defineDetailStyleCheck.m
file, create the
action callback function. In this example, the function name is
sampleActionCB
. The input to this function is a
ModelAdvisor.Task
object.
function result = ActionCB(taskobj)
Create handles to Simulink.ModelAdvisor
and
ModelAdvisor.Check
objects.
mdladvObj = taskobj.MAObj; checkObj = taskobj.Check;
Create an array of ModelAdvisor.ResultDetail
objects for storing the information for blocks that violate the
check.
resultDetailObjs = checkObj.ResultDetails;
Write code that changes the block name location to below the block.
for i=1:numel(resultDetailObjs) % take some action for each of them block=Simulink.ID.getHandle(resultDetailObjs(i).Data); set_param(block,'NamePlacement','normal'); end result = ModelAdvisor.Text('Changed the location such that the block name is below the block.');
Disable the Action box.
mdladvObj.setActionEnable(false);
Save the sl_customization.m
and
defineDetailStyleCheck.m
files.
In the MATLAB command window, enter:
Advisor.Manager.refresh_customizations
From the MATLAB window, open the sldemo_fuelsys
model.
In the top model, right-click the Engine Speed
block
and select Rotate & Flip > Flip Block Name.
Open the fuel_rate_control
subsystem. Right-click the
validate_sample_time
block and select Rotate & Flip > Flip Block Name.
Return to the top model and save as
example_sldemo_fuelsys
.
In the Modeling tab, select Model Advisor. A System Selector ― Model Advisor dialog box opens. Click OK. The Model Advisor opens.
In the left pane, select By Product > Demo > Check whether block names appear below blocks.
Note
If the By Product folder is not displayed in the Model Advisor window, select Settings > Preferences > Show By Product Folder
Select Run This Check. The Model Advisor check fails for the blocks you changed.
Review the results by selecting one of the View by options.
The report provides a recommended action for each check. You can click the
hyperlink path to open the violating block in the model editor. For example:
Follow the recommended action for fixing the violating blocks by using one of these methods:
Update each violation individually by double-clicking the hyperlink to open the block. Right-click the block and select Rotate & Flip > Flip Block Name.
Select the Make block names appear below blocks button. The Model Advisor automatically fixes the issues in the model. Notice that the button is dimmed after the violations are fixed.
Save the model and rerun the Model Advisor check. The check passes.
ModelAdvisor.Check
| ModelAdvisor.Check.CallbackContext
| ModelAdvisor.FormatTemplate
| ModelAdvisor.FormatTemplate