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.

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.

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.