This example shows how to use allocations to analyze a tire pressure monitoring system.
In Systems Engineering, it is common to describe a system at different levels of abstraction. For example, you can describe a system in terms of its high-level functions. These functions may not have any behavior associated with them but most likely trace back to some operating requirements the system must fulfill. We refer to this layer (or architecture) as the functional architecture. In this example, an automobile tire pressure monitoring system is described in three different architectures:
Functional Architecture — Describes the system in terms of its high-level functions. The connections show dependencies between functions.
Logical Architecture — Describes the system in terms of its logical components and how data is exchanged between them. Additionally, this architecture specifies behaviors for model simulation.
Platform Architecture — Describes the physical hardware needed for the system at a high level.
The allocation process is defined as linking these three architectures that fully describe the system. The linking captures the information each architectural layer and makes it accessible to the others.
Use this command to open the project.
scExampleTirePressureMonitorSystem
Open the FunctionalAllocation.mldax
file which displays allocations from TPMS_FunctionalArchitecture
to TPMS_LogicalArchitecture
. The elements of TPMS_FunctionalArchitecture
are displayed in the first column and the elements of TPMS_LogicalArchitecture
are displayed in the first row. The arrows indicate the allocations between model elements.
This figure displays allocations in the architectural component level. The arrows display allocated components in the model. You can observe allocations for each element in the model hierarchy.
The rest of the example shows how you can use this allocation information to further analyze the model.
This section shows you how to perform coverage analysis to verify that all functions have been allocated. This process requires using the allocation information specified between the functional and logical architectures.
To start the analysis, load the allocation set.
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(end+1) = allFunctions(i); end end
if isempty(unAllocatedFunctions) fprintf('All functions are allocated'); else fprintf('%d Functions have not been allocated', numel(unAllocatedFunctions)); end
The result displays All functions are allocated
to verify that all functions in the system are allocated.
This example shows how to identify which functions will be provided by which suppliers using the specified allocations. The supplier information is stored in the logical model, since these are the components that the suppliers will be delivering to the system integrator.
suppliers = {'Supplier A', 'Supplier B', 'Supplier C', 'Supplier D'}; functionNames = arrayfun(@(x) x.Name, allFunctions, 'UniformOutput', false); numFunNames = length(allFunctions); numSuppliers = length(suppliers); allocTable = table('Size', [numFunNames, numSuppliers], 'VariableTypes', repmat("double", 1, numSuppliers)); allocTable.Properties.VariableNames = suppliers; allocTable.Properties.RowNames = functionNames; for i = 1:numFunNames elem = scenario.getAllocatedTo(allFunctions(i)); for j = 1:numel(elem) elemSupplier = elem(j).getEvaluatedPropertyValue("TPMSProfile.LogicalComponent.Supplier"); allocTable{i, strcmp(elemSupplier, suppliers)} = 1; end
end
The table shows which suppliers are responsible for the corresponding functions.
You can determine if the Engine Control Unit(ECU) has enough capacity to house all the software components. The software components are allocated to the cores themselves, but the ECU is the component that has the budget property.
Get the platform architecture.
platformArch = systemcomposer.loadModel('PlatformArchitecture');
Load the allocation.
softwareDeployment = systemcomposer.allocation.load('SoftwareDeployment');
frontECU = platformArch.lookup('Path', 'PlatformArchitecture/Front ECU'); rearECU = platformArch.lookup('Path', 'PlatformArchitecture/Rear ECU');
scenario1 = softwareDeployment.getScenario('Scenario 1'); scenario2 = softwareDeployment.getScenario('Scenario 2'); frontECU_availMemory = frontECU.getEvaluatedPropertyValue("TPMSProfile.ECU.MemoryCapacity"); rearECU_availMemory = rearECU.getEvaluatedPropertyValue("TPMSProfile.ECU.MemoryCapacity");
frontECU_memoryUsed1 = getUtilizedMemoryOnECU(frontECU, scenario1); frontECU_isOverBudget1 = frontECU_memoryUsed1 > frontECU_availMemory; rearECU_memoryUsed1 = getUtilizedMemoryOnECU(rearECU, scenario1); rearECU_isOverBudget1 = rearECU_memoryUsed1 > rearECU_availMemory;
frontECU_memoryUsed2 = getUtilizedMemoryOnECU(frontECU, scenario2); frontECU_isOverBudget2 = frontECU_memoryUsed2 > frontECU_availMemory; rearECU_memoryUsed2 = getUtilizedMemoryOnECU(rearECU, scenario2); rearECU_isOverBudget2 = rearECU_memoryUsed2 > rearECU_availMemory;
Build a table to showcase the results.
softwareDeploymentTable = table([frontECU_memoryUsed1;frontECU_availMemory; ... frontECU_isOverBudget1;rearECU_memoryUsed1;rearECU_availMemory;rearECU_isOverBudget1], ... [frontECU_memoryUsed2; frontECU_availMemory; frontECU_isOverBudget2;rearECU_memoryUsed2; ... rearECU_availMemory; rearECU_isOverBudget2], ... 'VariableNames',{'Scenario 1','Scenario 2'},... 'RowNames', {'Front ECUMemory Used (MB)', 'Front ECU Memory (MB)', 'Front ECU Overloaded', ... 'Rear ECU Memory Used (MB)', 'Rear ECU Memory (MB)', 'Rear ECU Overloaded'})
function memoryUsed = getUtilizedMemoryOnECU(ecu, scenario) % For each of the components in the ECU, accumate the binary size % required for each of the allocated software components.
coreNames = {'Core1','Core2','Core3','Core4'}; memoryUsed = 0; for i = 1:numel(coreNames) core = ecu.Model.lookup('Path', [ecu.getQualifiedName '/' coreNames{i}]); allocatedSWComps = scenario.getAllocatedFrom(core); for j = 1:numel(allocatedSWComps) binarySize = allocatedSWComps(j).getEvaluatedPropertyValue("TPMSProfile.SWComponent.BinarySize"); memoryUsed = memoryUsed + binarySize; end end
end
getAllocatedFrom
| getAllocatedTo
| getScenario
| load