Documentation Center

  • Trial Software
  • Product Updates

Creating Composite Components

About Composite Components

A composite component is constructed out of other components. To create a composite component, you have to list the names of the member (constituent) components and then specify how the ports of the member components are connected to each other and to the external ports of the composite component. You also specify which parameters of the member components are to be visible, and therefore adjustable, in the block dialog box of the composite component.

In certain ways, this functionality is similar to creating a subsystem in a Simulink® block diagram, however there are important differences. Simscape™ language is a textual environment, and therefore you cannot "look under mask" and see a graphical representation of the underlying component connections. At the same time, the textual environment is a very powerful tool for modeling complex modular systems that consist of multiple interconnected member components.

Declaring Member Components

A components declaration block begins with a components keyword and is terminated by an end keyword. This block contains declarations for member components included in the composite component. A components declaration block must have its Hidden attribute value set to true (for more information on member attributes, see Attribute Lists).

When declaring a member component, you have to associate it with an existing component file, either in the Simscape Foundation libraries or in your custom package. You need to refer to the component name using the full path starting with the top package directory. For more information on packaging your Simscape files, see Generate Custom Block Libraries from Simscape Component Files.

The following example includes a Rotational Spring block from the Simscape Foundation library in your custom component:

components(Hidden=true)
    rot_spring = foundation.mechanical.rotational.spring;
end

The name of the top-level package directory is +foundation. It contains a subpackage +mechanical, with a subpackage +rotational, which in turn contains the component file spring.ssc.

If you want to use your own customized rotational spring called spring.ssc and located at the top level of your custom package directory +MechanicalElements, the syntax would be:

components(Hidden=true)
    rot_spring = MechanicalElements.spring;
end

Once you declare a member component, use its identifier (in the preceding examples, rot_spring) to refer to its parameters, variables, nodes, inputs, and outputs. For example, rot_spring.spr_rate refers to the Spring rate parameter of the Rotational Spring block.

Parameterizing Composite Components

Composite component parameters let you adjust the desired parameters of the underlying member components from the top-level block dialog box when building and simulating a model.

Specify the composite component parameters by declaring a corresponding parameter in the top-level parameters declaration block, and then assigning it to the desired parameter of a member component. The declaration syntax is the same as described in Declaring Component Parameters.

For example, the following code includes a Foundation library Resistor block in your custom component file, with the ability to control the resistance at the top level and a default resistance of 10 Ohm:

component MyCompositeModel
[...]
  parameters
     p1 = {10, 'Ohm'};
     [...]
  end
  components(Hidden=true)
     r1 = foundation.electrical.elements.resistor(R = p1);
     [...]
  end
[...]
end

You can establish the connection of the top-level parameter with a member component parameter either in the components declaration block, or later, in the setup section. The following code is equivalent to the example above:

component MyCompositeModel
[...]
  parameters
     p1 = {10, 'Ohm'};
     [...]
  end
  components(Hidden=true)
     r1 = foundation.electrical.elements.resistor;
     ...
  end
   [...]
   function setup
      r1.R = p1;
   end
   [...]
end

    Note:   In case of conflict, assignments in the setup section override those made in the declaration section.

Components are instantiated using default parameter values in the declaration section before setup is run. Therefore, if you make adjustments to the parameters in the setup section, use a subsequent setup section assignment to establish proper connection between the top-level parameter with a member component parameter, as shown in the following example:

component RC
  nodes
    p = foundation.electrical.electrical; % :right
    n = foundation.electrical.electrical; % :left
  end
  parameters
    R = {1 , 'Ohm'}; % Resistance
    tc = {1 , 's'};  % RC time constant
  end
  parameters(Hidden=true)
    C = {1 , 'F'};
  end
  components(Hidden=true)
    c1 = foundation.electrical.elements.capacitor(c=C);
    r1 = foundation.electrical.elements.resistor(R=R);
  end
  function setup
    C = tc/R;
    c1.c = C; % This assignment ensures correct operation
  end
  connections
    connect(c1.p, p);
    connect(c1.n, r1.p);
    connect(r1.n, n);
  end
end

You do not have to assign all the parameters of member blocks to top-level parameters. If a member block parameter does not have a corresponding top-level parameter, the composite model uses the default value of this parameter, specified in the member component. You can also use the setup section of the composite component to override the default value of the member component parameter and set it to a value applicable to your composite model.

Specifying Initial Target Values for Member Variables

Member components have to be declared as hidden, and therefore their variables do not appear in the Variables tab of the top-level block dialog box. However, if a certain member component variable is important for initialization, you can tie its value to an initialization parameter in the top-level parameters declaration block. In this case, the block user will be able to adjust the initial target value of the member component variable from the top-level block dialog box when building and simulating a model.

    Note:   The block user can not change the initialization priority of the member component variable. You specify the variable initialization priority when you declare the member component. The syntax is the same as described in Variable Priority for Model Initialization.

For example, you have a composite DC Motor block (similar to the one described in Composite Component — DC Motor) and want the block user to specify the initial target value for the inductor current, with low priority. The following code includes a Foundation library Inductor block in your custom component file, with the ability to control its inductance at the top level (by using the Rotor Inductance block parameter) and also to specify a low-priority initial target for the inductor current variable:

component DCMotor2
[...]
  parameters
     rotor_inductance = { 12e-6, 'H' };    % Rotor Inductance
     i0 = { 0, 'A' };  % Initial current target for Rotor Inductor
     [...]
  end
  components(Hidden=true)
     rotorInductor = foundation.electrical.elements.inductor(l = rotor_inductance, 
                                      i_L = {value = i0, priority = priority.low});
     [...]
  end
[...]
end

In this case, the block user can specify a value for the Initial current target for Rotor Inductor parameter, which appears in the block dialog box of the composite component. This value gets assigned as the initial target to variable i_L (Initial current variable of the member Inductor block), with low initialization priority. Depending on the results of the solve, the target may or may not be satisfied when the solver computes the initial conditions for simulation. For more information, see About Variable Initialization.

You can use an alternative syntax that lets you assign the variable value and priority data fields separately, using the dot notation. For example, the following statement:

      rotorInductor = foundation.electrical.elements.inductor(l = rotor_inductance, 
                                      i_L.value = i0, i_L.priority = priority.low);
     

is equivalent to the Inductor component declaration from the previous example.

Specifying Component Connections

The structure section of a Simscape file follows the declaration and setup sections. It is executed once during compilation. This section contains information on how the constituent components' ports are connected to one another, as well as to the external inputs, outputs, and nodes of the top-level component.

The structure section begins with a connections keyword and is terminated by an end keyword. This connections block contains a set of connect constructs, which describe both the conserving connections (between nodes) and the physical signal connections (between the inputs and outputs).

In the following example, the custom component file includes the Foundation library Voltage Sensor and Electrical Reference blocks and specifies the following connections:

  • Positive port of the voltage sensor to the external electrical conserving port + of the composite component

  • Negative port of the voltage sensor to ground

  • Physical signal output port of the voltage sensor to the external output of the composite component, located on the right side of the resulting block icon

component VoltSG
  nodes
     p = foundation.electrical.electrical; % +
  end
  outputs
     Out = { 0.0, 'V' }; % V:right
  end
  components(Hidden=true)
     VoltSensor = foundation.electrical.sensors.voltage;
     Grnd = foundation.electrical.elements.reference;
  end
  connections
     connect(p, VoltSensor.p);
     connect(Grnd.V, VoltSensor.n);
     connect(VoltSensor.V, Out);
  end
end

In this example, the first two connect constructs specify conserving connections between electrical nodes. The third connect construct is a physical signal connection. Although these constructs look similar, their syntax rules are different.

Conserving Connections

For conserving connections, the connect construct can have two or more arguments. For example, the connections in the following example

  connections
     connect(R1.p, R2.n);
     connect(R1.p, R3.p);
  end

can be replaced with

  connections
     connect(R1.p, R2.n, R3.p);
  end

The order of arguments does not matter. The only requirement is that the nodes being connected are all of the same type (that is, are all associated with the same domain).

In the following example, the composite component consists of three identical resistors connected in parallel:

component ParResistors
  nodes
     p = foundation.electrical.electrical;
     n = foundation.electrical.electrical;
  end
  parameters
    p1 = {3 , 'Ohm'};
  end
  components(Hidden=true)
    r1 = foundation.electrical.elements.resistor(R=p1);
    r2 = foundation.electrical.elements.resistor(R=p1);
    r3 = foundation.electrical.elements.resistor(R=p1);
  end
  connections
    connect(r1.p, r2.p, r3.p, p);
    connect(r1.n, r2.n, r3.n, n);
  end
end

Physical Signal Connections

Physical signal connections are directional, therefore the connect construct has the following format:

  connect(s, d);

where s is the signal source port and d is the destination port.

There can be more than one destination port connected to the same source port:

  connect(s, d1, d2);

The source and destination ports belong to the inputs or outputs member classes. The following table lists valid source and destination combinations.

SourceDestination
External input port of composite componentInput port of member component
Output port of member componentInput port of member component
Output port of member componentExternal output port of composite component

For example, consider the following block diagram.

It represents a composite component CompMeas, which, in turn, contains a composite component Valve Subsystem, as well as several Foundation library blocks. The Simscape file of the composite component would specify the equivalent signal connections with the following constructs.

ConstructExplanation
connect(In, subt.I1);Connects port In to the input port + of the PS Subtract block. Illustrates connecting an input port of the composite component to an input port of a member component.
connect(subt.O, gain.I);Connects the output port of the PS Subtract block to the input port of the PS Gain block. Illustrates connecting an output port of a member component to an input port of another member component at the same level.
connect(fl_rate.Q, subt.I2, Out);Connects the output port Q of the Hydraulic Flow Rate Sensor block to the input port - of the PS Subtract block and to the output port Out of the composite component. Illustrates connecting a single source to multiple destinations, and also connecting an output port of a member component to an output port of the enclosing composite component.

Also notice that the output port of the PS Gain block is connected to the input port of the Valve Subsystem composite block (another member component at the same level). Valve Subsystem is a standalone composite component, and therefore if you connect the output port of the PS Gain block to an input port of one of the member components inside the Valve Subsystem, that would violate the causality of the physical signal connections (a destination port cannot be connected to multiple sources).

Nonscalar Physical Signal Connections

Multidimensional physical signals can be useful for:

  • Aggregating measurements at different spatial points, such as temperatures along a coil or a 2-D grid of elements

  • Using 3-D body positions or velocities

  • Using rotation matrices or quaternions in 3-D

  • Using tensors

Simscape language supports nonscalar (vector-valued or matrix-valued) physical signals in inputs and outputs declarations. All signals in such vector or matrix should have the same units. For example, the following declaration

 inputs
   I = {zeros(3), 'm/s'}; % :left
 end

initializes a component input as a 3-by-3 matrix of linear velocities.

When you connect input and output ports carrying nonscalar physical signals, you can use signal indexing and concatenation at the source, but not at the destination. Scalar expansion is not allowed.

The following table shows valid syntax examples, assuming subcomponent A with output signal port A.o is being connected to subcomponent B with input signal port B.i, and all sizes and units are compatible.

ConstructExplanation
connect(A.o(1,2), B.i);Source indexing, to connect to a scalar destination: take entry (1,2) of the output A.o and connect it to the input B.i.
connect(A.o(1:2:5,2:3), B.i);Index by rows and columns to specify a submatrix.
connect(A.o(1:2:end,:), B.i);Use colon notation to specify array boundaries (pass every other column of the output A.o to input B.i.
connect([A1.o, A2.o], B.i);Concatenate outputs A1.o and A2.o column-wise and pass the result to the input B.i.

You can use block parameter values for indexing inside a connect statement, for example:

connect(a.o(value(param_name, '1'), 3), b.i);

When you connect two physical signals, their units must be directly convertible. If one of the signals is declared as unitless (that is, with units of ‘1') , then you can connect a signal with any base units to it. However, unit conversion is not supported in this case. For example, if a.i is a 2x1 unitless input port, then this statement is valid:

connect([out1_in_meters, out2_in_seconds], a.i);

If you connect signals with different scales of the same unit with a unitless input port, the compiler alerts you to the fact that unit conversion is ignored. For example, the following statement produces a warning at compile time:

connect([out1_in_km, out2_in_mm], a.i);

Was this topic helpful?