Our next example of creating reusable subsystems will introduce a slight twist. In this section we will not only demonstrate how to create a reusable subsystem model, as in the previous examples from this chapter, but that subsystem model will use an array of component instances where the size of that array can be used to control the spatial resolution of the results. This is similar to the kind of model presented earlier in One-Dimensional Heat Transfer.
Let’s start, as usual, with a flat system level model like the one shown below:
This model consists of a collection of thermal capacitances with thermal conductors in between them. In practical terms, the thermal capacitances could reprsent segments of a metal pipe. The axial conduction could represent heat conduction axially along the length of the rod. The radial conduction could be the heat lost through some insulating material like plastic. In this example, there are 3 such thermal capacitances and 5 thermal conductors. On the left side, heat is applied to the system and on the right side a temperature sensor measures how the temperature of the rightmost thermal capacitance changes. So the example applies heat at one end and monitors the temperature increase at the other end.
When implemented in Modelica, the model looks like this:
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model FlatRod "Modeling a heat transfer in a rod in a without subsystems"
Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heating
"Heating actuator"
annotation ...
Modelica.Blocks.Sources.Step bc(height=10, startTime=0.5) "Heat profile"
annotation ...
Modelica.Thermal.HeatTransfer.Components.HeatCapacitor C1(C=0.1, T(fixed=true))
annotation ...
Modelica.Thermal.HeatTransfer.Components.ThermalConductor G1(G=1.2)
annotation ...
Modelica.Thermal.HeatTransfer.Components.HeatCapacitor C2(C=0.1, T(fixed=true))
annotation ...
Modelica.Thermal.HeatTransfer.Components.ThermalConductor G2(G=1.2)
annotation ...
Modelica.Thermal.HeatTransfer.Components.HeatCapacitor C3(C=0.1, T(fixed=true))
annotation ...
Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor sensor
annotation ...
Modelica.Thermal.HeatTransfer.Components.ThermalConductor wall1(G=0.9)
annotation ...
Modelica.Thermal.HeatTransfer.Sources.FixedTemperature ambient(T=293.15)
"Ambient temperature" annotation ...
Modelica.Thermal.HeatTransfer.Components.ThermalConductor wall2(G=0.9)
annotation ...
Modelica.Thermal.HeatTransfer.Components.ThermalConductor wall3(G=0.9)
annotation ...
equation
connect(bc.y, heating.Q_flow) annotation ...
connect(C1.port, G1.port_a) annotation ...
connect(C2.port, G2.port_a) annotation ...
connect(G2.port_b, C3.port) annotation ...
connect(G1.port_b, C2.port) annotation ...
connect(heating.port, C1.port) annotation ...
connect(wall1.port_b, C1.port) annotation ...
connect(wall1.port_a, ambient.port) annotation ...
connect(wall2.port_a, ambient.port) annotation ...
connect(wall3.port_a, ambient.port) annotation ...
connect(wall3.port_b, C3.port) annotation ...
connect(sensor.port, C3.port) annotation ...
connect(C2.port, wall2.port_b) annotation ...
end FlatRod;
Simulating this system, we can see the temperature response of the rightmost thermal capacitance in the following plot:
In our flat system model, we have 3 thermal capacitances and 5 conductances. This configuration represents a rod that has been divided into 3 equal segments and the conductance that occurs between those segments as well as between each segment and some ambient conditions. In theory, we can divide a rod into equal segments with conduction paths between them and conduction paths between each segment and the ambient conditions.
Our particular configuration was for . But we can create a subsystem model where is a parameter of the subsystem. In other words, we can create a subsystem model that is divided into equal segments. But to do so, we cannot simply drag and drop the capacitances into the model and connect them with conductances because we don’t know the exact number.
Instead, we’ll use an array of components to represent this
collection of capacitances and conductances. The resulting Rod
model can be written in Modelica as follows:
within ModelicaByExample.Subsystems.HeatTransfer.Components;
model Rod "Modeling discretized rod"
import HTC=Modelica.Thermal.HeatTransfer.Components;
parameter Integer n(start=2,min=2) "Number of rod segments";
parameter Modelica.SIunits.Temperature T0 "Initial rod temperature";
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a
"Thermal connector to ambient"
annotation ...
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b
"Thermal connector for rod end 'b'"
annotation ...
parameter Modelica.SIunits.HeatCapacity C
"Total heat capacity of element (= cp*m)";
parameter Modelica.SIunits.ThermalConductance G_wall
"Thermal conductivity of wall";
parameter Modelica.SIunits.ThermalConductance G_rod
"Thermal conductivity of rod";
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a ambient
"Thermal connector to ambient"
annotation ...
protected
HTC.HeatCapacitor capacitance[n](each final C=C/n, each T(start=T0, fixed=true))
annotation ...
HTC.ThermalConductor wall[n](each final G=G_wall/n)
annotation ...
HTC.ThermalConductor rod_conduction[n-1](each final G=G_rod*(n-1))
annotation ...
equation
for i in 1:n loop
connect(capacitance[i].port, wall[i].port_b) "Capacitance to walls";
connect(wall[i].port_a, ambient) "Walls to ambient";
end for;
for i in 1:n-1 loop
connect(capacitance[i].port, rod_conduction[i].port_a)
"Capacitance to next conduction";
connect(capacitance[i+1].port, rod_conduction[i].port_b)
"Capacitance to prev conduction";
end for;
connect(capacitance[1].port, port_a) "First capacitance to rod end";
connect(capacitance[n].port, port_b) "Last capacitance to (other) rod end";
end Rod;
There are several interesting things to note about this model. First,
the number of segments the rod will be divided into is represented by
the n
parameter:
parameter Integer n(start=2,min=2) "Number of rod segments";
The parameter n
is then used in the following declarations to
specify the number of capacitance and conductance elements in the rod:
HTC.HeatCapacitor capacitance[n](each final C=C/n, each T(start=T0, fixed=true))
annotation ...
HTC.ThermalConductor wall[n](each final G=G_wall/n)
annotation ...
HTC.ThermalConductor rod_conduction[n-1](each final G=G_rod*(n-1))
annotation ...
Note that if we wish to apply a modification, e.g., G=G_rod/n
to
every component in an array of components, we can use the each
qualifier on the modification. We’ll discuss the each
qualifier
and how to apply modifications to arrays of components later in this
chapter in the section on Modifications.
Now that we’ve declared our component arrays, we can then wire
together the capacitances and conductances using for
loops in an
equation
section:
for i in 1:n loop
connect(capacitance[i].port, wall[i].port_b) "Capacitance to walls";
connect(wall[i].port_a, ambient) "Walls to ambient";
end for;
for i in 1:n-1 loop
connect(capacitance[i].port, rod_conduction[i].port_a)
"Capacitance to next conduction";
connect(capacitance[i+1].port, rod_conduction[i].port_b)
"Capacitance to prev conduction";
end for;
We also need to connect the ends of the rod to the external connectors so that the rod can be connected to other models:
connect(capacitance[1].port, port_a) "First capacitance to rod end";
connect(capacitance[n].port, port_b) "Last capacitance to (other) rod end";
In this way, we are able to create a segmented rod model with an arbitrary number of equally divided segments.
Now that we have our parameterized Rod
model, we can look at how
the number of segments in the rod impacts the response we see.
Ultimately, what we should see is that as the number of segments gets
larger (or, as the size of the segments gets smaller), we should
converge on a solution.
We’ll start by considering a model where n=3
, i.e.,
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model ThreeSegmentRod "Modeling a heat transfer using 3 segment rod subsystem"
Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heating
"Heating actuator"
annotation ...
Modelica.Blocks.Sources.Step bc(height=10, startTime=0.5) "Heat profile"
annotation ...
Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor sensor
annotation ...
Modelica.Thermal.HeatTransfer.Sources.FixedTemperature ambient(T=293.15)
"Ambient temperature" annotation ...
Components.Rod rod(n=3, C=0.3, G_wall=2.7, T0=293.15, G_rod=1.2)
annotation ...
equation
connect(bc.y, heating.Q_flow) annotation ...
connect(heating.port, rod.port_a) annotation ...
connect(rod.ambient, ambient.port) annotation ...
connect(rod.port_b, sensor.port) annotation ...
end ThreeSegmentRod;
We can then extend this model to create additional models with more segments, e.g.,
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model SixSegmentRod "Rod divided into 6 pieces"
extends ThreeSegmentRod(rod(n=6));
end SixSegmentRod;
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model TenSegmentRod
extends SixSegmentRod(rod(n=10));
end TenSegmentRod;
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model OneHundredSegmentRod "Rod divided into 100 pieces"
extends ThreeSegmentRod(rod(n=100));
end OneHundredSegmentRod;
within ModelicaByExample.Subsystems.HeatTransfer.Examples;
model TwoHundredSegmentRod
extends OneHundredSegmentRod(rod(n=200));
end TwoHundredSegmentRod;
If we simulate all of these cases, we see that as n
gets larger,
they appear to converge to a common solution and that n=10
seems
to provide a reasonable solution without the need to introduce a large
number of superfluous components:
In this section, we’ve seen how we can build assemblies of arbitrary
size using arrays of components and for
loops to connect them
together.