Main Content

创建和部署模型顾问自定义配置

要检查模型是否符合公司的标准和建模规范,您可以自定义模型顾问。此示例说明如何向模型顾问添加自定义检查并删除不需要的出厂检查。您可以保存自定义检查配置,并为开发组中的其他人部署这些配置。通过部署自定义配置,您的开发团队可以使用相同的检查集来检查模型。

定义自定义检查

此示例定义四种类型的自定义检查:

  • 编辑时检查,会提供修复操作。

  • 仅在模型顾问中运行的检查,会按模块和子系统对结果进行分组并提供修复操作。

  • 仅在模型顾问中运行的检查,会验证模型配置参数设置。

  • 编辑时检查,会指定模块参数设置的约束并提供修复操作。

示例文件包括 sl_customization.m 文件。此文件包含 sl_customization 函数,该函数包含对定义自定义检查的函数的调用。打开并检查 sl_customization.m 文件。

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;

sl_customization 函数接受自定义管理器对象,该对象包含用于注册自定义检查的 addModelAdvisorCheckFcn 方法。此方法的输入是函数 defineModelAdvisorChecks 的句柄,该函数包含对四个检查定义函数的调用,这四个函数对应于四个自定义检查。

带修复的编辑时检查

defineEditTimeCheck.m 文件包含 defineEditTimeCheck 检查定义函数,该函数定义了一项检查,用于检查 Inport 和 Outport 模块是否根据其输出数据类型具有特定颜色。此项检查必须检查其他已编辑的模块,但不必检查同一级别或整个模型层次结构中受影响的模块。此项检查还提供了一种修复方法,可以更新未正确着色的模块的颜色。此检查的名称是检查 Inport 和 Outport 模块的颜色。此检查可在编辑时和模型顾问中运行。打开并检查 defineEditTimeCheck.m 文件。

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');

编辑时检查包含一个从 ModelAdvisor.EdittimeCheck 基类派生而来的类定义 PortColor。有关如何创建这种类型的检查的详细信息,请参阅Define Edit-Time Checks to Comply with Conditions That You Specify with the Model Advisor。创建一个名为 +MyEditTimeChecks 的文件夹,并将 PortColor.m 保存到此文件夹中。

copyfile PortColor.m* +MyEditTimeChecks

打开并检查 PortColor.m 文件。

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 = 'warn';
                        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 = 'warn';
                        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 = 'warn';
                        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 = 'warn';
                    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 = 'warn';
                    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 = 'warn';
                    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

带修复的模型顾问检查

defineDetailStyleCheck.m 文件包含 defineDetailStyleCheck 检查定义函数,该函数定义一项检查,该项检查会列出名称未显示在模块下方的模块。此检查还提供一种修复方法,可以将这些名称移至模块下方。此检查的名称是检查模块名称是否出现在模块下方。这种检查编写样式适用于仅在模型顾问中运行的检查。打开并检查 defineDetailStyleCheck.m 文件。

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.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.';
        ElementResults(i).ViolationType = 'warn'|'info'|'fail';    
    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

此检查使用 DetailStyle 类型的 setCallbackFcn,它生成默认格式,因此您不必使用 ModelAdvisor.FormatTemplate 或其他模型顾问格式 API 来格式化出现在模型顾问中的结果。有关如何创建这种类型的检查定义函数的详细信息,请参阅修复模型以符合您使用模型顾问指定的条件

模型配置参数设置检查

defineConfigurationParameterCheck.m 文件包含 defineConfigurationParameterCheck 检查定义函数,该函数定义一项检查,用于标识可能影响 MISRA C:2012 合规代码生成的模型配置参数设置。此检查的名称是检查模型配置参数

此检查需要一个支持 XML 数据文件,该文件必须位于 MATLAB 路径中并且包含要检查的模型配置参数设置。对于此示例,该文件为 configurationParameterDataFile.xml。有关如何创建此类型的检查的详细信息,请参阅为模型配置参数创建模型顾问检查

打开并检查 defineConfigurationParameterCheck.m 文件。

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

模块参数约束检查

defineNewBlockConstraintCheck.m 文件包含 defineNewBlockConstraintCheck 检查定义函数,该函数定义一项检查,用于标识不具有矩形形状的 Logical Operator 模块。此检查的名称是检查 Logical Operator 模块的图标形状

模块参数约束检查支持编辑时检查。有关此类型的检查的详细信息,请参阅针对支持和不支持的模块和参数定义模型顾问检查

打开并检查 defineNewBlockConstraintCheck.m 文件。

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

createBlockConstraints 函数定义模块约束 c1Advisor.authoring.createBlockConstraintCheck 函数有一个用来调用约束创建函数 createBlockConstraints'Constraints' 名称-值参量。

在模型顾问中查看自定义检查

要确认自定义检查可用,请打开模型顾问。

1.为了使您的自定义检查在模型顾问中可见,您必须刷新模型顾问检查信息缓存。在 MATLAB 命令提示符下,输入:

Advisor.Manager.refresh_customizations();

2.打开示例模型。

open_system('AdvisorCustomizationExample.slx');

3.在建模选项卡上,打开 Model Advisor。您也可以通过在 MATLAB 命令提示符下输入以下命令来打开模型顾问:

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.展开按产品 > Demo 文件夹。在检查定义函数中,publish 命令将检查添加到按产品 > Demo 文件夹中。

customModelAdvisor.png

指定并部署模型顾问自定义配置

要指定在模型顾问中包含哪些检查以及在编辑时检查期间使用哪些检查,请使用模型顾问配置编辑器。

1.要打开配置编辑器,请在模型顾问中,点击打开 > 打开配置编辑器

2.要添加或删除检查和文件夹,请从模型顾问配置编辑器的编辑部分中选择选项。

3.要保存配置,请选择保存。将打开一个窗口,提示您将配置另存为 JSON 文件。对于此示例,您不必保存配置,因为文件 demoConfiguration.json 包含此示例的四个自定义检查。

4.关闭模型和模型顾问配置编辑器。

bdclose;

将自定义检查配置与模型相关联并解决检查问题

要解决检查问题,先要将配置与模型相关联。然后,您就可以在编辑时或在模型顾问中解决问题了。

1.打开示例模型。

open_system('AdvisorCustomizationExample.slx');

2.将自定义配置 demoConfiguration.json 与模型相关联。如果将自定义配置与模型相关联,则每次打开模型时模型都会使用相同的检查配置。点击建模选项卡,然后选择 Model Advisor > 编辑时检查。在“配置参数”对话框中,为 Model Advisor 配置文件参数指定配置文件的路径。或者,在命令提示符下输入以下命令:

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

3.点击建模选项卡并选择 Model Advisor > 编辑时检查,打开编辑时检查。将打开“配置参数”对话框。选择编辑时检查参数。您也可以在命令提示符下输入以下命令:

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

在模型的顶层,两个 Inport 模块的输出数据类型为 int32。这些模块引发编辑时警告,因为它们本应为青色。Outport 模块未引发警告,因为其数据类型为 auto 并且为白色。

modelHighlight.png

4.对于每个 Inport 模块,点击编辑时警告窗口。然后点击修复。模块的颜色变为青色,警告消失。

5.Logical Operator 模块会引发警告,因为它应为矩形。点击编辑时警告窗口,然后点击修复。Logical Operator 模块的形状变为矩形,警告消失。

6.现在您已解决编辑时检查警告,请打开模型顾问来解决任何其余的检查问题。

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

7.模型顾问包含自定义配置中的四项检查。点击运行检查。您在编辑时期间已解决的两项检查会通过。其他两项检查引发警告。

modelCheckStatus.png

8.点击检查模块名称是否出现在模块下方检查。要应用修复并解决警告,请在右窗格中点击修复

9.点击检查模型配置参数检查。要应用修复并解决警告,请点击修复

10.重新运行检查。它们现在全部通过。

11.关闭模型和模型顾问。

bdclose;

12.从工作目录中删除文件。通过输入以下命令刷新模型顾问检查信息缓存:

Advisor.Manager.refresh_customizations

以编程方式运行模型顾问自定义配置并查看结果

您可以通过编程方式运行模型顾问配置,然后在模型顾问中打开结果。

1.调用 ModelAdvisor.run 函数。

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

2.在模型顾问中查看结果:

viewReport(SysResultObjArray{1},'MA')

3.点击对话框中的继续。您现在可以应用修复并解除警告。

4.关闭模型和模型顾问。

bdclose;

5.从工作目录中删除文件。通过输入以下命令刷新模型顾问检查信息缓存:

Advisor.Manager.refresh_customizations

另请参阅

|

相关主题