Generate a System Design Report with the Report API

This example shows how to generate a Report API-based system design report. The system design report is a description of the design of a dynamic system generated from the Simulink® model of the system.

A Report API-based system design report uses objects of Report API classes to report on system components. See Report Generation for Simulink and Stateflow Elements. If a system component does not have a corresponding Report API reporter, you can create a reporter from a Report Explorer setup file that includes the component. See Create a Report Explorer-Based Reporter.

The gensdd Function

The gensdd function, which is included with this example, generates a report that includes these sections:

  • Title Page

  • Table of Contents

  • System Hierarchy

  • Root System chapter that contains the root block diagram and block properties of the model subsystems

  • SubSystems chapter that contains the diagram and block properties of the model subsystems

  • Charts chapter that contains the charts and chart object properties of each of the model charts

  • Design Data chapter that contains the model variables

The complete gensdd function is listed at the end of this example. You can modify the gensdd.m file to create a custom system design report.

Generate a PDF System Design Report for the sf_car Model

To call gensdd, the Report Explorer setup file beo.rpt must be in the current folder. The file is included with this example.

Generate a system design report for the sf_car model and specify that the document is a PDF.

gensdd('sf_car','PDF');

Here is the first page of the report:

A copy of the report is included with this example in the file sdd_sf_car_copy.pdf.

Customize the Report

The gensdd function uses objects of these Report API classes to find system design elements and report on the system design:

  • slreportgen.report.SystemHierarchy

  • slreportgen.report.Diagram

  • slreportgen.finder.DiagramResult

  • slreportgen.finder.DiagramElementResult

  • slreportgen.report.SystemIO

  • slreportgen.finder.SystemDiagramFinder

  • slreportgen.finder.ChartDiagramFinder

  • slreportgen.finder.StateflowDiagramElementFinder

  • slreportgen.finder.ModelVariableFinder

  • slreportgen.finder.ModelVariableResult

  • slreportgen.report.ModelVariable

  • slreportgen.finder.BlockFinder

  • slreportgen.finder.BlockResult

  • slreportgen.report.SimulinkObjectProperties

You can use the properties of these objects to filter and format the information that is reported. For example, in the makeSystemHierarchy function in the gensdd.m file, you can change the system hierarchy list format to an ordered list by setting the ListFormatter property of the slreportgen.report.SystemHierarchy reporter.

function makeSystemHierarchy(rpt, hModel)
% Create a chapter reporting on the system hiearchy
import mlreportgen.report.*
import slreportgen.report.*
ch = Chapter("Title", "System Hierarchy");
ol = mlreportgen.dom.OrderedList();
add(ch,SystemHierarchy("Source",hModel,"ListFormatter",ol));
add(rpt, ch);
end

The report also uses objects of these Report API classes to create and format the sections of the report:

  • mlreportgen.report.TitlePage

  • mlreportgen.report.TableOfContents

  • mlreportgen.report.Chapter

  • mlreportgen.report.Section

You can customize the appearance of the report and sections. See Report Formatting Approaches (MATLAB Report Generator).

Create a Report Explorer-Based Reporter

To report on a system component that does not have a corresponding Report API reporter:

  1. Create a Report Explorer setup file that includes the component.

  2. Use an slreportgen.report.RptFile object to include the content generated by the setup file in the Report API report.

For example, the makeBlockExecutionOrderSection function in the gensdd.m file uses slreportgen.report.RptFile to report on the block execution order:

function makeBlockExecutionOrderSection(parent, model, system)
import mlreportgen.report.*
import slreportgen.report.*
section = Section('Title','Block Execution Order');
beo = slreportgen.report.RptFile('beo.rpt');
modelName = get_param(model,'Name');
systemName = get_param(system,'Name');
beo.Model = modelName;
beo.System = systemName;
add(section,beo)
add(parent,section);
end

The Complete gensdd Function

 type gensdd.m
function gensdd(model,doctype)
%GENSDD Generates a system design description from the system's model
%   gensdd() generates a PDF system design description for the sf_car
%   model.
%
%   gensdd(model) generates a PDF system design description for the 
%   specified model. 
%
%   gensdd(model, doctype) generates a system design description document
%   from the specified model and document type: 'html', 'docx', or 'pdf'.
%
%   The generated document is a description of a dynamic system's design
%   generated from its Simulink model. The description contains the
%   following sections:
%
%   * Title Page
%   * Table of Contents
%   * System Hierarchy
%   * Root System Chapter -- Contains root block diagram and properties
%     of each block in the root diagram.
%   * Subsystems Chapter -- Contains diagram and block properties of 
%     model's subsystems
%   * Charts Chapter -- Contains charts and chart object properties of each
%     of the model's charts.
%   * Design Data Chapter

import mlreportgen.dom.*
import mlreportgen.report.*
import slreportgen.report.*

if nargin < 1
    model = 'sf_car';
    doctype = 'pdf';
end

if nargin < 2
    doctype = 'pdf';
end

hModel = load_system(model);
rpt = slreportgen.report.Report(['sdd_' get_param(model, 'Name')], doctype);
open(rpt);

makeTitlePage(rpt, hModel);
add(rpt, TableOfContents);
makeSystemHierarchy(rpt, hModel);
makeRootSystemChapter(rpt, hModel);
makeSubsystemsChapter(rpt, hModel);
makeChartsChapter(rpt, hModel);
makeDesignDataChapter(rpt, hModel);

close(rpt);
%rptview(rpt);

close_system(model);

end

function makeTitlePage(rpt, hModel)
import mlreportgen.report.*
import slreportgen.report.*

tp = TitlePage;
tp.Title = upper(get_param(hModel, 'Name'));
tp.Subtitle = 'System Design Description';
tp.Author = 'John Doe';

diag = Diagram(hModel);
diag.Scaling = 'custom';
diag.Height = '2in';
diag.Width = '3in';
tp.Image = getSnapshotImage(diag, rpt);
add(rpt, tp);
end

function makeSystemHierarchy(rpt, hModel)
% Create a chapter reporting on the system hierarchy
import mlreportgen.report.*
import slreportgen.report.*
ch = Chapter("Title", "System Hierarchy");
add(ch,SystemHierarchy(hModel));
add(rpt, ch);
end

function makeRootSystemChapter(rpt, hModel)
% Create a chapter reporting on the root system diagram and its blocks
% and add the chapter to the main report.
import mlreportgen.report.*
import slreportgen.report.*
import slreportgen.finder.*

ch = Chapter("Title", "Root System");
diag = Diagram(hModel);
add(ch, diag);

add(ch, SystemIO(hModel));

% Add block execution order section
makeBlockExecutionOrderSection(ch, hModel, hModel);

% Add subsections containing the properties for each block in the
% subsystem diagram.
makeBlockSections(ch, hModel);

add(rpt, ch);
end

function makeSubsystemsChapter(rpt, hModel)
% Create a chapter reporting on a model's subsystems and the blocks that
% they contain and add the chapter to the main report.
import mlreportgen.report.*
import slreportgen.report.*
import slreportgen.finder.*

% Create a chapter to hold the subsystems.
ch = Chapter("Title", "Subsystems");

% Use a finder to find all the subsystem diagrams in the model. The finder
% returns an array of SystemDiagramResult objects, each of which 
% contains a Diagram reporter that creates a snapshot of the subsystem
% diagram
finder = SystemDiagramFinder(hModel);
finder.IncludeRoot = false;
systems = find(finder);

% Add the subsystem diagram results to the chapter.
for system = systems
    
    % Create a subsection to contain the subsystem diagram.
    section = Section("Title", system.Name);
    
    % Add the subsystem diagram reporter to the diagram subsection.
    % Add the subsystem diagram results to the chapter.
    diag = getReporter(system);
    diag.MaskedSystemLinkPolicy = 'system';
    add(section, diag);
    
    ioSect = Section('Title', 'System Interface');
    add(ioSect, SystemIO('Object', system, 'ShowDetails', false));
    add(section, ioSect);
    
    % Add subsections containing the properties for each block in the
    % subsystem diagram.
    makeBlockSections(section, system);
    
    % Add the subsystem diagram section to the chapter.
    add(ch, section);
end

% Add the subsystems chapter to the main report.
add(rpt, ch);

end

function makeChartsChapter(rpt, hModel)
% Create a chapter reporting on a model's Stateflow charts and the  objects
% that they contain and add the chapter to the main report.

import mlreportgen.report.*
import slreportgen.report.*
import slreportgen.finder.*

finder = ChartDiagramFinder(hModel);
charts = find(finder);

if ~isempty(charts)
    ch = Chapter("Title", "Charts");    
    for chart = charts
        section = Section("Title", chart.Name);
        diag = getReporter(chart);
        add(section, diag);
        
        % Report the objects in this chart
        objFinder = StateflowDiagramElementFinder(chart);
        sfObjects = find(objFinder);
        for sfObj = sfObjects
            objSection = Section("Title", sfObj.Name);
            add(objSection, sfObj);            
            add(section, objSection);
        end
                
        add(ch, section);
    end   
    add(rpt, ch);    
end

end

function makeDesignDataChapter(rpt, hModel)
% Create a chapter reporting on the model variables

import mlreportgen.dom.*
import mlreportgen.report.*
import slreportgen.report.*
import slreportgen.finder.*

ch = Chapter("Title", "Design Data");

finder = ModelVariableFinder(hModel);

results = find(finder);

s = Section("Title", "Design Data Summary");

n = numel(results);
vars = cell(n, 4);
for i = 1:n
    result = results(i);
    lt = [result.Name result.Source result.SourceType];
    lt = mlreportgen.utils.hash(lt);
    value = getVariableValue(results(i));
    vars{i, 1} = InternalLink(lt, results(i).Name);
    vars{i, 2} = class(value);
    vars{i, 3} = results(i).Source;
    vars{i, 4} = results(i).SourceType;
end

t = FormalTable({'Name', 'Type', 'Source', 'Source Type'}, vars);
t.Width = "100%";

add(s, t);
add(ch, s);

s = Section("Title", "Design Data Details");
for result = results
    lt = [result.Name result.Source result.SourceType];
    lt = mlreportgen.utils.hash(lt);
    p = Paragraph;
    p.Style = {PageBreakBefore};
    append(p, LinkTarget(lt));
    add(s, p);
    add(s, result);
end
add(ch, s);

add(rpt, ch);


end

function section = makeBlockSections(parent, system)
% Create subsections containing the properties of each block in the
% system and add it to the parent chapter or subsection.
import mlreportgen.report.*
import slreportgen.finder.*

blocksSection = Section("Title", "Blocks");
finder = BlockFinder(system);
elems = find(finder);
for elem = elems
    section = Section("Title", strrep(elem.Name, newline, ' '));
    add(section, elem);
    add(blocksSection, section);
end
add(parent, blocksSection);
end

function makeBlockExecutionOrderSection(parent, model, system)
import mlreportgen.report.*
import slreportgen.report.*
section = Section('Title', 'Block Execution Order');
beo = slreportgen.report.RptFile('beo.rpt');
modelName = get_param(model, 'Name');
systemName = get_param(system, 'Name');
beo.Model = modelName;
beo.System = systemName;
add(section, beo)
add(parent, section);
end

See Also

| | | | | | | | | | | | |

Related Topics