Main Content

Create and Deploy a Model Advisor Custom Configuration

To check that a model meets the standards and modeling guidelines of your company, you can customize the Model Advisor. This example shows you how to add custom checks to the Model Advisor and remove shipping checks that you do not require. You can save the custom check configuration and deploy it to others in your development group. Deploying a custom configuration allows your development group to review models using the same set of checks.

Define Custom Checks

This example defines four types of custom checks:

  • An edit-time check that provides a fix action.

  • A check that runs in only the Model Advisor and groups results by blocks and subsystems and provides a fix action.

  • A check that runs only in the Model Advisor and verifies model configuration parameter settings.

  • An edit-time check that specifies a constraint for a block parameter setting and provides a fix action.

The example files include the sl_customization.m file. This file contains the sl_customization function, which contains calls to functions that define the custom checks. Open and inspect the sl_customization.m file.

function sl_customization(cm)
% SL_CUSTOMIZATION - Model Advisor customization demonstration.

% Copyright 2019 The MathWorks, Inc.

% register custom checks 
cm.addModelAdvisorCheckFcn(@defineModelAdvisorChecks);

% -----------------------------
% defines Model Advisor Checks
% -----------------------------
function defineModelAdvisorChecks
defineEditTimeCheck
defineDetailStyleCheck;
defineConfigurationParameterCheck;
defineNewBlockConstraintCheck;

The sl_customization function accepts a customization manager object that includes the addModelAdvisorCheckFcn method for registering custom checks. The input to this method is a handle to a function, defineModelAdvisorChecks, which contains calls to the four check definition functions that correspond to the four custom checks.

Edit-Time Check with Fix

The defineEditTimeCheck.m file contains the defineEditTimeCheck check definition function, which defines a check that checks whether Inport and Outport blocks have certain colors depending on their output data types. This check must check other edited blocks, but it does not have to check for affected blocks at the same level or across the entire model hierarchy. This check provides a fix that updates the color of the blocks that do not have the correct colors. The name of this check is Check color of Inport and Outport blocks. This check runs at edit-time and in the Model Advisor. Open and inspect the defineEditTimeCheck.m file.

function defineEditTimeCheck

% Check the background color of Inport and Outport blocks.
rec = ModelAdvisor.Check("advisor.edittimecheck.PortColor");
rec.Title = 'Check color of Inport and Outport blocks';
rec.CallbackHandle = 'MyEditTimeChecks.PortColor'; 
mdladvRoot = ModelAdvisor.Root;
mdladvRoot.publish(rec,'Demo');

The edit-time check has a class definition, PortColor, that derives from the ModelAdvisor.EdittimeCheck base class. For more information on how to create this type of check, see Define Edit-Time Checks to Comply with Conditions that You Specify with the Model Advisor. Create a folder named +MyEditTimeChecks and save PortColor.m to this folder.

copyfile PortColor.m* +MyEditTimeChecks

Open and inspect the PortColor.m file.

classdef PortColor < ModelAdvisor.EdittimeCheck
    % Check that ports conform to software design standards for background color.
    %
    %   Background Color                Data Types
    %   orange                          Boolean
    %   green                           all floating-point
    %   cyan                            all integers
    %   Light Blue                      Enumerations and Bus Objects
    %   white                           auto
    %


    methods
        function obj=PortColor(checkId)
            obj=obj@ModelAdvisor.EdittimeCheck(checkId);
            obj.traversalType = edittimecheck.TraversalTypes.BLKITER;                       
        end
        
        function violation = blockDiscovered(obj, blk)
            violation = [];  
            if strcmp(get_param(blk,'BlockType'),'Inport') || strcmp(get_param(blk,'BlockType'),'Outport')
                
                dataType = get_param(blk,'OutDataTypeStr');
                currentBgColor = get_param(blk,'BackgroundColor');
                
                if strcmp(dataType,'boolean')
                        if ~strcmp(currentBgColor, 'orange')
                            % Create a violation object using the ModelAdvisor.ResultDetail class.
                            violation = ModelAdvisor.ResultDetail;
                            ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                            violation.CheckID = obj.checkId;
                            violation.Description = 'Inport/Outport blocks with Boolean outputs should be orange.';
                            violation.title = 'Port Block Color';
                            violation.ViolationType = 'Warning';
                        end
                elseif any(strcmp({'single','double'},dataType))
                        if ~strcmp(currentBgColor, 'green')
                            violation = ModelAdvisor.ResultDetail;
                            ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                            violation.CheckID = obj.checkId;
                            violation.Description = 'Inport/Outport blocks with floating-point outputs should be green.';
                            violation.title = 'Port Block Color';
                            violation.ViolationType = 'Warning';
                        end
                elseif any(strcmp({'uint8','uint16','uint32','int8','int16','int32'}, dataType))
                        if ~strcmp(currentBgColor, 'cyan')
                            violation = ModelAdvisor.ResultDetail;
                            ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                            violation.CheckID = obj.checkId;
                            violation.Description = 'Inport/Outport blocks with integer outputs should be cyan.';
                            violation.title = 'Port Block Color';
                            violation.ViolationType = 'Warning';
                        end
                elseif contains(dataType,'Bus:')
                    if ~strcmp(currentBgColor, 'lightBlue')
                        violation = ModelAdvisor.ResultDetail;
                        ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                        violation.CheckID = obj.checkId;
                        violation.Description = 'Inport/Outport blocks with bus outputs should be light blue.';
                        violation.title = 'Port Block Color';
                        violation.ViolationType = 'Warning';
                    end
                 elseif contains(dataType,'Enum:')
                    if ~strcmp(currentBgColor, 'lightBlue')
                        violation = ModelAdvisor.ResultDetail;
                        ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                        violation.CheckID = obj.checkId;
                        violation.Description = 'Inport/Outport blocks with enumeration outputs should be light blue.';
                        violation.title = 'Port Block Color';
                        violation.ViolationType = 'Warning';
                    end
                elseif contains(dataType, 'auto')
                    if ~strcmp(currentBgColor, 'white')
                        violation = ModelAdvisor.ResultDetail;
                        ModelAdvisor.ResultDetail.setData(violation,'SID',Simulink.ID.getSID(blk));
                        violation.CheckID = obj.checkId;
                        violation.Description = 'Inport/Outport blocks with auto outputs should be white.';
                        violation.title = 'Port Block Color';
                        violation.ViolationType = 'Warning';
                    end                    
                end
            end  
        end
        
        function violation = finishedTraversal(obj)            
            violation = [];
        end
        
        function success = fix(obj, violation)
            success = true;
            dataType = get_param(violation.Data,'OutDataTypeStr');
            if strcmp(dataType,'boolean')
                set_param(violation.Data,'BackgroundColor','orange');
            elseif any(strcmp({'single','double'},dataType))
                set_param(violation.Data,'BackgroundColor','green');
            elseif any(strcmp({'uint8','uint16','uint32','int8','int16','int32'}, dataType))
                set_param(violation.Data,'BackgroundColor','cyan');
            elseif contains(dataType,'Bus:')  || contains(dataType,'Enum:')
                set_param(violation.Data,'BackgroundColor','lightBlue');
            elseif contains(dataType,'auto')
                set_param(violation.Data,'BackgroundColor','white');
            end
        end
    end
end

Model Advisor Check with Fix

The defineDetailStyleCheck.m file contains the defineDetailStyleCheck check definition function, which defines a check that lists blocks whose names are not displayed below the blocks. This check provides a fix that moves those names below the blocks. The name of this check is Check whether block names appear below blocks. This check authoring style is for checks that only run in the Model Advisor. Open and inspect the defineDetailStyleCheck.m file.

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.setCallbackFcn(@ActionCB);
myAction.Name='Make block names appear below blocks';
myAction.Description='Click the button to place block names below blocks';
rec.setAction(myAction);
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
    
   for i=1:numel(violationBlks)
        ElementResults(1,i) = ModelAdvisor.ResultDetail;
    end 
    for i=1:numel(ElementResults)
        ModelAdvisor.ResultDetail.setData(ElementResults(i), 'SID',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

This check uses the setCallbackFcn type of DetailStyle, which produces default formatting, so that you do not have to use the ModelAdvisor.FormatTemplate or the other Model Advisor formatting APIs to format the results that appear in the Model Advisor. For more information on how to create this type of check definition function, see Fix a Model to Comply with Conditions that You Specify with the Model Advisor.

Model Configuration Parameter Settings Check

The defineConfigurationParameterCheck.m file contains the defineConfigurationParameterCheck check definition function, which defines a check that identifies model configuration parameter settings that might impact MISRA C:2012 compliant code generation. The name of this check is Check model configuration parameters.

This check requires a supporting XML data file that must be on the MATLAB path and contain the model configuration parameter settings that you want to check. For this example, that file is configurationParameterDataFile.xml. For more information on how to create this check type, see Create Model Advisor Check for Model Configuration Parameters.

Open and inspect the defineConfigurationParameterCheck.m file.

function defineConfigurationParameterCheck

% Create ModelAdvisor.Check object and set properties.
rec = ModelAdvisor.Check('com.mathworks.sample.configurationParameter');
rec.Title = 'Check model configuration parameters';
rec.setCallbackFcn(@(system)(Advisor.authoring.CustomCheck.checkCallback...
    (system)), 'None', 'StyleOne');
rec.TitleTips = 'Identify configuration parameters that might impact MISRA C:2012 compliant code generation.';

% --- data file input parameters
rec.setInputParametersLayoutGrid([1 1]);
inputParam1 = ModelAdvisor.InputParameter;
inputParam1.Name = 'Data File';
inputParam1.Value = 'configurationParameterDataFile.xml';
inputParam1.Type = 'String';
inputParam1.Description = 'Name or full path of XML data file.';
inputParam1.setRowSpan([1 1]);
inputParam1.setColSpan([1 1]);
rec.setInputParameters({inputParam1});

% -- set fix operation
act = ModelAdvisor.Action;
act.setCallbackFcn(@(task)(Advisor.authoring.CustomCheck.actionCallback...
    (task)));
act.Name = 'Modify Settings';
act.Description = 'Modify model configuration settings.';
rec.setAction(act);

% publish check into Demo folder.
mdladvRoot = ModelAdvisor.Root;
mdladvRoot.publish(rec, 'Demo'); 

end

Block Parameter Constraint Check

The defineNewBlockConstraintCheck.m file contains the defineNewBlockConstraintCheck check definition function, which defines a check that identifies Logical Operator blocks that do not have a rectangular shape. The name of this check is Check icon shape of Logical Operator blocks.

A block parameter constraint check supports edit-time checking. For more information on this check type, see Define Model Advisor Checks for Supported and Unsupported Blocks and Parameters.

Open and inspect the defineNewBlockConstraintCheck.m file.

function defineNewBlockConstraintCheck

rec = Advisor.authoring.createBlockConstraintCheck('com.mathworks.sample.blockConstraint',...
    'Constraints',@createBlockConstraints); % constraint creation is part of block constraint check definition
rec.Title = 'Check icon shape of Logical Operator blocks';
rec.TitleTips = 'Checks icon shape of Logical Operator blocks. Icon shape of Logical Operator should be rectangular.';

% Publish check into Demo folder.
mdladvRoot = ModelAdvisor.Root;
mdladvRoot.publish(rec, 'Demo'); 

end

function constraints = createBlockConstraints()

% Create block constraints.
c1 = Advisor.authoring.PositiveBlockParameterConstraint;
c1.ID = 'ID_c1';
c1.BlockType = 'Logic';
c1.ParameterName = 'IconShape';
c1.SupportedParameterValues = {'rectangular'};
c1.ValueOperator = 'eq';

constraints = {c1};

end

The createBlockConstraints function defines the block constraint c1. The Advisor.authoring.createBlockConstraintCheck function has a 'Constraints' name-value argument that calls the constraints creation function createBlockConstraints.

View Custom Checks in the Model Advisor

To confirm that your custom checks are available, open the Model Advisor.

1. In order for your custom checks to be visible in the Model Advisor, you must refresh the Model Advisor check information cache. At the MATLAB command prompt, enter:

Advisor.Manager.refresh_customizations();

2. Open the example model.

open_system('AdvisorCustomizationExample.slx');

3. On the Modeling tab, open the Model Advisor. You can also open the Model Advisor by entering this command at the MATLAB command prompt:

modeladvisor('AdvisorCustomizationExample.slx');
Updating Model Advisor cache...
Model Advisor cache updated. For new customizations, to update the cache, use the Advisor.Manager.refresh_customizations method.

4. Expand the By Product > Demo folder. In the check definition functions, the publish command adds the checks to the By Product > Demo folder.

Specify and Deploy a Model Advisor Custom Configuration

To specify which checks to include in the Model Advisor and which checks to use during edit-time checking, use the Model Advisor Configuration Editor.

1. To open the Configuration Editor, in the Model Advisor, click Open > Open Configuration Editor.

2. To add or remove checks and folders, select from the options in the Edit section of the Model Advisor Configuration Editor.

3. To save a configuration, select Save. A window opens and prompts you to save the configuration as a JSON file. For this example, you do not have to save the configuration, because the file demoConfiguration.json file contains the four custom checks for this example.

4. Close the model and the Model Advisor Configuration Editor.

bdclose;

Associate a Custom Check Configuration with a Model and Address Check Issues

To address check issues, first associate the configuration with a model. Then, you can address issues during edit-time and in the Model Advisor.

1. Open the example model.

open_system('AdvisorCustomizationExample.slx');

2. Associate the custom configuration, demoConfiguration.json, with the model. When you associate a custom configuration with a model, the model uses the same check configuration every time you open a model. Click the Modeling tab and select Model Advisor > Edit-Time Checks. In the Configuration Parameters dialog box, specify the path to the configuration file for the Model Advisor configuration file parameter. Alternatively, enter this command at the command prompt:

ModelAdvisor.setModelConfiguration('AdvisorCustomizationExample', 'demoConfiguration.json');

3. Turn on edit-time checking by clicking the Modeling tab and selecting Model Advisor > Edit-Time Checks. The Configuration Parameters dialog box opens. Select the Edit-Time Checks parameter. Alternatively, you can enter this command at the command prompt:

edittime.setAdvisorChecking('AdvisorCustomizationExample','on');

At the top level of the model, the two Inport blocks have an output data type of int32. The blocks produce edit-time warnings because they should be cyan. The Outport block does not produce a warning because it has an auto data type and is white.

4. For each Inport block, click the edit-time warning window. Then click Fix. The color of the blocks changes to cyan and the warning goes away.

5. The Logical Operator block produces a warning because it should have a rectangular shape. Click the edit-time warning window and then click Fix. The shape of the Logical Operator block changes to a rectangle, and the warning goes away.

6. Now that you have addressed the edit-time check warnings, open the Model Advisor to address any remaining check issues.

modeladvisor('AdvisorCustomizationExample.slx');
Model Advisor is removing the existing report.

7. The Model Advisor contains the four checks in the custom configuration. Click Run Checks. The two checks that you addressed during edit-time pass. The other two checks produce warnings.

8. Click the Check whether block names appear below blocks check. To apply a fix and resolve the warnings, in the right pane, click Fix.

9. Click the Check model configuration parameters check. To apply a fix and resolve the warnings, click Fix.

10. Rerun the checks. They now pass.

11. Close the model and the Model Advisor.

bdclose;

12. Remove the files from your working directory. Refresh the Model Advisor check information cache by entering this command:

Advisor.Manager.refresh_customizations

Programmatically Run a Model Advisor Custom Configuration and View Results

You can programmatically run a Model Advisor configuration and then open the results in the Model Advisor.

1. Call the ModelAdvisor.run function.

SysResultObjArray = ModelAdvisor.run({'AdvisorCustomizationExample'},...
'Configuration','demoConfiguration.json');

2. View the results in the Model Advisor:

viewReport(SysResultObjArray{1},'MA')

3. Click Continue in the dialog box. You can now apply fixes and resolve warnings.

4. Close the model and the Model Advisor.

bdclose;

5. Remove the files from your working directory. Refresh the Model Advisor check information cache by entering this command:

Advisor.Manager.refresh_customizations

See Also

|

Related Topics