Using Mapping Modes with Custom-Mapped External Inputs
This example shows how to implement a custom mapping algorithm similar to a Simulink® mapping mode. It uses the getSlRootInportMap
and getRootInportMap
functions to implement the custom mapping.
Before running this example, make sure that you are familiar with the getRootInportMap
command and the Root Inport Mapper Tool. For more information, see Map Root Inport Signal Data.
Workflow
This example shows how you can use a built-in Simulink mapping mode to perform as many mappings as possible. It then flags the root inports that were not able to be assigned a signal. The algorithm then overrides the flagged mappings with custom mappings to map the remaining signals. To implement such a solution, create a custom mapping function using the getSlRootInportMap.
This example uses a list of inputs with two kinds of signals:
Signals that can be mapped using the Simulink block name mapping mode.
Signals that cannot be mapped using the Simulink block name mapping mode. You must map these signals with a custom mapping mode.
Assume the following scenario:
You want to use a group of signals as inputs to your Simulink model.
The signals are named such that the variable names match the block name of the root-level inport.
Each signal that uses this naming convention is within tolerance.
Each signal that has the 'x' character appended to its name is considered outside tolerance.
This example uses a mapping mode similar to the Simulink block name mapping method.
The root-level inport block names are:
Throttle
Brake
The signal variable names are:
Throttlex
Brake
To map inputs to root-level inport blocks in this scenario, you need a custom mapping function for the Root Inport Mapper tool. This example uses the AlmostBlockName custom mapping function.
For this example, you will use the slexAutotransRootInportsExample
model to validate your custom mapping function.
Declare the Custom Mapping Function
Declare the function name, inputs, and outputs. To do this, copy and paste the following code snippet into a MATLAB® file and save the file as AlmostBlockName.m.
function inputMap = AlmostBlockName( modelName, signalNames, signals )
Get the Simulink BlockName Mapping
Next, map all the signals. To do this, first map all the signals within tolerance using the Simulink block name mapping mode, then map the signals outside tolerance.
To map signals within tolerance to a model using one of the Simulink mapping modes, use the function getSlRootInportMap
. This function returns the inputMap
and a vector of logical values. Each logical value indicates a successful or unsuccessful mapping of inputMap
to a signal. To map by block name, insert the following lines of code just after the function declaration.
inputMap = getRootInportMap('empty'); if ~bdIsLoaded(modelName) load_system(modelName); end
[inputMap, hasASignal] = getSlRootInportMap('Model', modelName, ... 'MappingMode','BlockName',... 'signalName',signalNames, 'signalValue', signals);
Find the Missing Input Signals
In the previous step, you created a mapping using a block name mapping mode. You must now account for an empty inputMap
and for inputMap(s)
that were not associated with a signal within tolerance. The function getSlRootInportMap
has flagged these signals with the output variable hasASignal
. To do this:
Check the
inputMap
variable.If the
inputMap
variable is not empty, determine which elements of theinputMap
vector were not assigned a signal. To do this, use the logical ~ on thehasASignal
vector as shown below. TheemptyIndex
vector now contains a logical vector where true means theinputMap
does not have a signal mapped to it.Copy and paste the following code snippet under the call to the
getSlRootInportMap
and before the end to the ifbdIsLoaded(modelName)
.
if ~isempty(inputMap) emptyIndex = ~hasASignal; end
The code snippet performs steps one and two for you.
Complete the Mapping
In the previous step, you created a logical vector emptyIndex
to see if any of the inputMap objects were not associated to a signal. If all the elements of the emptyIndex vector are false, you have a complete mapping and the code added in this section will not be executed.
If the emptyIndex
vector contains at least one value that is true, you have inputMap
objects that are not associated to a signal. Manually assign the variable signal(s) to that inputMap. Then, override the inputMap
with the signal name that matches the expected signal name:
In the emptyIndex vector, find all the items that are true. These items point to the
inputMap(s)
that still need to be associated with a signal.For each
inputMap
, use the 'BlockName' property to get the name of the inport block that theinputMap
is assigned to.Append an 'x' to the block name to get the name of the signal to be assigned to the
inputMap
.Compare the result to each item in the signalNames variable cell array.
If a match is found, override the
inputMap
with the signal name that matches the expected signal name. To override theinputMap
object, use the getRootInportMap function with the 'InputMap' and the 'SignalName' properties.
if isa( signals{1}, 'Simulink.SimulationData.Dataset') signalNames = signals{1}.getElementNames'; end
idxEmpty = find(emptyIndex==true); for kEmpty =1:length(idxEmpty) idxOfEmpty = idxEmpty(kEmpty); destBlockName = get(inputMap(idxOfEmpty),'BlockName'); outSideToleranceSig = [destBlockName 'x']; isAMatch = strcmp(signalNames, outSideToleranceSig); if any(isAMatch) inputMap(idxOfEmpty) = getRootInportMap('InputMap', ... inputMap(idxOfEmpty),'SignalName',outSideToleranceSig); end end
The Custom Map File
When you are done, the file AlmostBlockName.m should resemble the following code.
function inputMap = AlmostBlockName(modelName, signalNames, signals) inputMap = getRootInportMap('empty'); if bdIsLoaded(modelName)
[inputMap, hasASignal] = getSlRootInportMap('Model', modelName, ... 'MappingMode','BlockName',... 'signalName',signalNames, 'signalValue', signals);
if ~isempty(inputMap) emptyIndex = ~hasASignal; idxEmpty = find(emptyIndex==1);
if isa( signals{1}, 'Simulink.SimulationData.Dataset') signalNames = signals{1}.getElementNames'; end
for kEmpty =1:length(idxEmpty) idxOfEmpty = idxEmpty(kEmpty); destBlockName = get(inputMap(idxOfEmpty),'BlockName'); nonNominalSig = [destBlockName 'x']; isAMatch = strcmp(signalNames, nonNominalSig); if any(isAMatch) inputMap(idxOfEmpty) = getRootInportMap('InputMap', ... inputMap(idxOfEmpty),'SignalName',nonNominalSig); end end
end end
Validate the Custom Mapping
To validate your custom mapping:
Save the AlmostBlockName function in a file on the MATLAB path.
To see the results of your mapping function, copy and paste the following code snippet to the MATLAB Command Window.
modelName = 'slexAutotransRootInportsExample'; Throttlex = timeseries(zeros(10,1)); Brake = timeseries(ones(10,1)); signalNames= {'Throttlex' ,'Brake'}; signals = { Throttlex , Brake }; open_system(modelName); inputMap = AlmostBlockName(modelName, signalNames, signals); inputStr = getInputString(inputMap,'base'); close_system(modelName);
After running the code snippet, the variable inputStr
contains the string 'Throttlex,Brake'.
If your signals are in a Simulink.SimulationData.Dataset, to see the results of your mapping function, use the following code snippet at the MATLAB Command Window.
modelName = 'slexAutotransRootInportsExample'; Throttlex = timeseries(zeros(10,1)); Brake = timeseries(ones(10,1)); ds = Simulink.SimulationData.Dataset; ds = ds.addElement( Throttlex, 'Throttlex' ); ds = ds.addElement( Brake, 'Brake' ); signalNames= {'ds'}; signals = { ds }; open_system(modelName); inputMap = AlmostBlockName(modelName, signalNames, signals); inputStr = getInputString(inputMap,'base'); close_system(modelName);
After running the code snippet for signals in a Simulink.SimulationData.Dataset, the variable inputStr
contains the string 'ds.getElement('Throttlex'),ds.getElement('Brake')'.
See Also
getRootInportMap
| getSlRootInportMap