Main Content

Analysis Function Constructs

Analyze architectures to choose between design alternatives or improve existing designs. You can use analysis functions with System Composer™ architecture models to perform systems analysis and trade studies.

An analysis function is a MATLAB® function that computes values necessary to evaluate the architecture using the properties of each element in the model instance and instance-specific parameters on the component and architecture level.

Use an analysis function to calculate the result of an analysis and determine the optimal parameters to use for behavior models to simulate the architectural system.

For more information on analysis functions and architecture instances, see Analyze Architecture.

Tip

To learn more about how System Composer concepts apply to systems engineering design, see System Composer Concepts.

Roll-Up Analysis for Quadcopter Design

Use a roll-up analysis function to calculate a total or average of model element property values. Assign properties to model elements using stereotypes. For more information, see Define and Style Stereotypes in Profiles.

In this example, the analysis function CostAndWeightRollupAnalysis calculates the total cost of all components in the model and is compatible with the Analysis Viewer tool.

function CostAndWeightRollupAnalysis(instance,varargin)
% Analysis function for the RobotPhysicalArchitecture.slx example

% Calculate total price
if instance.isComponent() && ~isempty(instance.Components)...
 && instance.hasValue('SystemProfile.PhysicalElement.UnitCost')
    sysComponent_unitPrice = 0;
    for child = instance.Components
        if child.hasValue('SystemProfile.PhysicalElement.UnitCost')
           comp_price = child.getValue('SystemProfile.PhysicalElement.UnitCost');
           sysComponent_unitPrice = sysComponent_unitPrice + comp_price;
        end
    end
    instance.setValue('SystemProfile.PhysicalElement.UnitCost',sysComponent_unitPrice);
end

This analysis function iterates through an architecture instance. First, the sysComponent_unitPrice variable is set to zero so that every time the analysis is run, sums do not accumulate indefinitely. Each component instance is checked for a UnitCost property value. All UnitCost property values are summed up and saved in the sysComponent_unitPrice variable. Finally, the UnitCost property of the current component instance is updated with the value of sysComponent_unitPrice. For more information, see Write Analysis Function and Simple Roll-Up Analysis Using Robot System with Properties.

In this example, a section of the analysis function calculateEndurance calculates endurance for a quadcopter using component instance properties. The calculated endurance value is then set for the architecture instance of the quadcopter with the setValue function.

if payloadBatteryCapacity == 0
      totalPower = powerConsumption + hoverPower/efficiency;
      endurance = (batteryCapacity/1000)/(totalPower/voltage)*60;
else
      payloadEndurance = (payloadBatteryCapacity/1000)/(powerConsumption/voltage)*60;
      flightEndurance = (batteryCapacity/1000)/((hoverPower/efficiency)/voltage)*60;
      if flightEndurance < payloadEndurance
            endurance = flightEndurance;
      else
            endurance = payloadEndurance;
            warning('Endurance is limited by payload electronics.')
      end
end
instance.setValue('AirVehicle.Endurance',endurance)

For more information and for the supporting files, see Calculate Endurance Using Quadcopter Architectural Design.

Class-Based Analysis for Battery Sizing

Use MATLAB classes for an analysis function to iterate over an object, or instantiation of the class.

In this example, the class called computeBatterySizing involves properties and methods useful for the analysis function computeLoad.

classdef computeBatterySizing < handle

    properties 
        totalCrankingInrushCurrent;
        totalCrankingCurrent;        
        totalAccesoriesCurrent;
        totalKeyOffLoad;
        batteryCCA;
        batteryCapacity;
        puekertcoefficient;        
    end

    methods
        function obj = computeBatterySizing(obj)
            obj.totalCrankingInrushCurrent = 0;
            obj.totalCrankingCurrent = 0;            
            obj.totalAccesoriesCurrent = 0;
            obj.totalKeyOffLoad = 0;
            obj.batteryCCA = 0;
            obj.batteryCapacity = 0;
            obj.puekertcoefficient = 1.2;
        end
        
        function obj = displayResults(obj)
            tempNumdaysToDischarge = ...
            (((obj.batteryCapacity/obj.puekertcoefficient)*0.3)/(obj.totalKeyOffLoad*1e-3))/24;
disp("Total KeyOffLoad: " + num2str(obj.totalKeyOffLoad) + " mA");
disp("Number of days required for KeyOffLoad to discharge 30% of battery: " + ...
                 num2str(tempNumdaysToDischarge) + ".");
disp("Total CrankingInRush current: " + num2str(obj.totalCrankingInrushCurrent) + " A");
disp("Total Cranking current: " + num2str(obj.totalCrankingCurrent) + " A");
            
            if(obj.totalCrankingCurrent > obj.batteryCCA) 
disp("The Cold Cranking Amps of the specified battery is not sufficient to start the car 0 F.")   
            else
disp("CCA of the specified battery is sufficient to start the car at 0 F.")    
            end
        end
    end
end

For more information and for the supporting files, see Battery Sizing and Automotive Electrical System Analysis.

Allocation-Based Analysis for Tire Pressure Monitoring

A functional-to-logical allocation matrix allocates components in a functional architecture to components in a logical architecture. Coverage analysis is the most basic form of analysis to determine whether all elements have been allocated.

First, open the project for this example. Then, load the allocation set and collect the scenarios.

scExampleTirePressureMonitorSystem
allocSet = systemcomposer.allocation.load('FunctionalAllocation');
  scenario = allocSet.Scenarios;

Verify that each function in the system is allocated.

import systemcomposer.query.*;
  [~, allFunctions] = ...
allocSet.SourceModel.find(HasStereotype(IsStereotypeDerivedFrom("TPMSProfile.Function")));
  unAllocatedFunctions = [];
  for i = 1:numel(allFunctions)
      if isempty(scenario.getAllocatedTo(allFunctions(i)))
          unAllocatedFunctions = [unAllocatedFunctions allFunctions(i)];
      end
  end

  if isempty(unAllocatedFunctions)
      fprintf('All functions are allocated');
  else
      fprintf('%d Functions have not been allocated', numel(unAllocatedFunctions));
  end
All functions are allocated

The output verifies that all functions are allocated.

For more information and for the supporting files, see Allocate Architectures in Tire Pressure Monitoring System.

Remaining Useful Life Analysis for Mobile Robot Design

Remaining useful life (RUL) analysis estimates the time remaining before different subsystems fail. The goal is to anticipate maintenance and thus minimize system disruptions.

In this example, the analysis function scMobileRobotAnalysis is compatible with the Analysis Viewer tool.

function scMobileRobotAnalysis(instance,varargin)
    
    ExpectedYearsBeforeFirstMaintenance = 2; 
    
    if ~instance.isArchitecture() 
        if instance.hasValue("HardwareBaseStereotype.Life")
            Life = instance.getValue("HardwareBaseStereotype.Life");
            UsagePerDay = instance.getValue("HardwareBaseStereotype.UsagePerDay");
            UsagePerYear = instance.getValue("HardwareBaseStereotype.UsagePerYear");
            WillSurvive = Life > UsagePerDay * UsagePerYear * ExpectedYearsBeforeFirstMaintenance; 
            instance.setValue("HardwareBaseStereotype.ExceedExpectedMaintenance", WillSurvive);
        end 
    end 
end

After running this analysis function, you can optimize the desired first expected maintenance time in years. Each component that exceeds the expected maintenance time, in this case set to two years, is flagged with a check box. Unchecked components should be optimized or replaced with longer-lasting parts.

For more information and for the supporting files, see Define Stereotypes and Perform Analysis for Mobile Robot.

Variant Analysis for Insulin Infusion Pump Design

Use variant analysis to choose one optimal combination of variants by comparing them with a calculated metric.

In this example, the analysis function OutcomeAnalysis is used to determine the best configuration for an insulin infusion pump. This standalone analysis function does not involve the Analysis Viewer tool. Instead, the analysis function uses the iterate function and can be executed directly from the MATLAB Command Window.

The OutcomeAnalysis function first gathers all variant choice components named Pump and BGSensor.

function outcomes = OutcomeAnalysis()

modelname = 'InsulinInfusionPumpSystem';

therapyModel = systemcomposer.openModel(modelname);
components = therapyModel.Architecture.Components;
for idx = 1:numel(components)
    if strcmp(components(idx).Name,'Pump')
        pumps = components(idx).getChoices;
        pumpNames = {};
        for jdx = 1:numel(pumps)
            pumpNames{end+1} = pumps(jdx).Name;
        end
    elseif strcmp(components(idx).Name,'BGSensor')
        sensors = components(idx).getChoices;
        sensorNames = {};
        for jdx = 1:numel(sensors)
            sensorNames{end+1} = sensors(jdx).Name;
        end
    end
end

The analysis function then collects all variant combinations to iterate over.

config.Sensor = sensorNames{1};
config.Pump = pumpNames{1};
configs = {};

for idx = 1:numel(sensorNames)
    for jdx = 1:numel(pumpNames)
        config.Sensor = sensorNames{idx};
        config.Pump = pumpNames{jdx};
        configs{end+1} = config;
    end
end

The analysis function activates the variants one by one, iterates over the model properties, and collects outcomes. To set variant combinations, OutcomeAnalysis uses the setVariants function. To compute the outcomes, OutcomeAnalysis uses the computeOutcome function.

outcomes = {};

for idx = 1:numel(configs)
    hOutcome = OutcomeContainer(configs{idx});
    therapyModel.iterate('Topdown',@setVariants,configs{idx});
    therapyModel.iterate('BottomUp',@computeOutcome,hOutcome);
    hOutcome.setWeights([1e-6 1 10 1 1000]');
    outcomes{end+1} = hOutcome;
end

Finally, the analysis function plots the net outcome to reveal the optimal design choice.

properties = {'Lower NRE','Higher Accuracy','Better Compliance',...
'Sooner To Market','Lower Operating Cost'};
plotMatrix = zeros(numel(outcomes), numel(properties));
plotStrings = {};
for idx = 1:numel(outcomes)
    plotStrings{idx} = [outcomes{idx}.Sensor '+' outcomes{idx}.Pump];
    plotMatrix(idx,1) = 1/(outcomes{idx}.NRE);
    plotMatrix(idx,2) = outcomes{idx}.Accuracy;
    plotMatrix(idx,3) = outcomes{idx}.Compliance;
    plotMatrix(idx,4) = 1/(outcomes{idx}.TimeToMarket);
    plotMatrix(idx,5) = 1/(outcomes{idx}.AnnualCost);
end

colmin = zeros(1,5);
colmax = max(plotMatrix);
normalizedMatrix = rescale(plotMatrix,'InputMin',colmin,'InputMax',colmax);

if exist('spider_plot') == 2
    fig = figure;
    spider_plot(normalizedMatrix,'AxesLabels',properties,'FillOption','on',...
        'FillTransparency',0.1,'AxesDisplay','one');

    title(sprintf('Trade Study Outcome'),...
        'FontSize', 14);
    legend(plotStrings, 'Location', 'eastoutside');
    pos = fig.Position;
    pos(2) = pos(2) - pos(4);
    pos(3) = 2*pos(3);
    pos(4) = 2*pos(4);
    fig.Position = pos;
else
    vals = sum(normalizedMatrix,2)/5;
    x_labels = categorical(plotStrings);
    h = bar(x_labels,vals);
    title('Net outcome');
    ax = h.Parent;
    ax.YLabel.String = 'Normalized units';
end

For more information and for the supporting files, see Design Insulin Infusion Pump Using Model-Based Systems Engineering.

Analysis with Parameters for Average Wear of Tires in Automobile

Parameters in an architecture model provide a way to define instance-specific parameter values. These parameter values are unique to different instances of the same model referenced across multiple components. You can use a reference component of the standard template for a wheel, and use that wheel four times in an automobile architecture model, by linking the mWheel.slx model to four different components.

Use parameters in analysis to analyze the Wear parameter value across four wheels and calculate the average wear of the tires as a measure of durability.

function calculateAverages(instance,varargin)
% Analysis function calculating the average wear of tires in a vehicle

% Pass the number of tires as an input to the analysis function
if numel(varargin) > 0
    numTires = eval(varargin{1});
end

% Get the architecture instance as a place to accumulate the total wear using a
% stereotype property
if instance.isArchitecture
    archInst = instance;
else
    % Get the architecture instance from the path of the node currently being
    % iterated
    instName = strsplit(instance.QualifiedName,'/');
    archInst = systemcomposer.analysis.lookup(string(instName{1}));
end

if instance.isComponent && any(instance.getParameterNames.matches("Wear"))

    % Get the stored stereotype property value on the architecture instance
    accumulatedValue = archInst.getValue('AxleProfile.Metrics.total_wear');

    % Get the evaluated parameter value from the instance
    currentValue = instance.getEvaluatedParameterValue("Wear");

    % Update the accumulated value
    newValue = accumulatedValue + currentValue;

    % Update the stereotype property value on the architecture instance
    archInst.setValue('AxleProfile.Metrics.total_wear',num2str(newValue));

    if newValue > 0
        fprintf(sprintf("Average wear of tires: %f\n", ...
            newValue/numTires));
    end
end

end

For more information and for the supporting files, see Analysis for Average Wear of Tires in Automobile.

See Also

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

Related Topics