Block Diagram Components

So far, the focus of this chapter has been on acausal modeling. But Modelica also supports causal formalisms. The main reason for the emphasis on acausal modeling is that it lends itself very well to the modeling of physical systems. It enables models of physical systems to be assembled schematically rather than mathematically while also automatically formulating conservation equations to ensure proper bookkeeping.

Block diagrams are a different way of approach modeling. The emphasis in block diagram is on creating component models that represent a wide range of mathematical operations. The operations are then performed on (generally time-varying) signals and yield, in turn, other signals. In fact, we will introduce a special kind of model in this section, called a block, that is restricted to having only input and output signals.

In this section, we’ll first look at how to construct causal blocks representing some basic mathematical operations. We’ll then see how those blocks can be used in two different ways. The first way will be to model a simple physical system. We’ll include some discussion contrasting the causal and acausal approaches. The second way to use such blocks is to model control systems. As we’ll see, using blocks to construct control systems is a much more natural fit for the block diagram formalism.

Fortunately, Modelica allows both causal and acausal approaches and, as we’ll see shortly, even allows them to be mixed. The result is that Modelica allows the model developer to use whichever approach works best in a given context.

Blocks

Modelica Standard Library

In this section, we will leverage several definitions from the Modelica Standard Library starting with the connectors:

connector RealInput = input Real "'input Real' as connector";
connector RealOutput = output Real "'output Real' as connector";

As the names suggest, RealInput and RealOutput are connectors for representing real valued input and output signals respectively. When drawn in a diagram, the RealInput connector takes the form of a blue solid triangle:

The RealOutput connector is a blue triangle outline:

We will leverage the Modelica Standard Library for several different partial block definitions. The first partial definition we’ll use is the SO, or “single output”, definition:

partial block SO "Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;

  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end SO;

Obviously, this definition is used for blocks that have a single output. By convention, this output signal is named y. Another definition we’ll use is the SISO or “single input, single output” block:

partial block SISO "Single Input Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;

  RealInput u "Connector of Real input signal" annotation (Placement(
        transformation(extent={{-140,-20},{-100,20}}, rotation=0)));
  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end SISO;

This model adds an input signal, u, in addition to the output signal, y. Finally, for blocks with multiple inputs, the MISO block defines the input signal, u, as a vector:

partial block MISO "Multiple Input Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;
  parameter Integer nin=1 "Number of inputs";
  RealInput u[nin] "Connector of Real input signals" annotation (Placement(
        transformation(extent={{-140,-20},{-100,20}}, rotation=0)));
  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end MISO;

The parameter nin is used to specify the number of inputs to the block.

It is worth pointing out that all of the blocks we are about to define are also available in the Modelica Standard Library. But we’ll create our own versions here just to demonstrate how such models can be defined.

Constant

Probably the simplest block we can imagine is one that simply outputs a constant value. Since this model has a single output, it extends from the SO block:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Constant "A constant source"
  parameter Real k "Constant output value";
  extends Icons.Axes;
  extends Interfaces.SO;
equation
  y = k;
end Constant;

When rendered, the block looks like this:

Gain Block

Gain

Another simple block is a “gain block” which multiplies an input signal by a constant to compute its output signal. Such a block will have a single input signal and a single output signal. As such, it extends from the SISO model as follows:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Gain "A gain block model"
  extends Interfaces.SISO;
  parameter Real k "Gain coefficient";
equation
  y = k*u;
end Gain;

When rendered, the block looks like this:

Gain Block

Sum

The Sum block can operate on an arbitrary number of input signals. For this reason, it extends from the MISO block:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Sum "Block that sums its inputs"
  extends Interfaces.MISO;
equation
  y = sum(u);
end Sum;

The Sum block uses the sum function to compute the sum over the array of input signals, u, to compute the output signal y.

When rendered, the block looks like this:

Gain Block

Product

The Product block is nearly identical to the Sum block except that it uses the product function:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Product "Block that outputs the product of its inputs"
  extends Interfaces.MISO;
equation
  y = product(u);
end Product;

When rendered, the block looks like this:

Gain Block

Feedback

The Feedback block differs from the previous blocks because it doesn’t extend from any definitions in the Modelica Standard Library. Instead, it explicitly declares all of the connectors it uses:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Feedback "A block to compute feedback terms"
  Interfaces.RealInput u1
    annotation (Placement(transformation(extent={{-120,-10},{-100,10}})));
  Interfaces.RealInput u2 annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=90,
        origin={0,-110})));
  Interfaces.RealOutput y
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
equation
  y = u1-u2;
end Feedback;

The output of the Feedback block is the difference between the two input signals u1 and u2.

When rendered, the block looks like this:

Gain Block

Integrator

The Integrator block is another SISO block that integrates the input signal, u, to compute the output signal, y. Since this block performs an integral, it requires an initial condition which is specified using the parameter y0:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Integrator
  "This block integrates the input signal to compute the output signal"
  parameter Real y0 "Initial condition";
  extends Interfaces.SISO;
initial equation
  y = y0;
equation
  der(y) = u;
end Integrator;

When rendered, the block looks like this:

Gain Block

Systems

Now that we’ve created this assortment of blocks, we’ll explore how they can be used to model a couple of example systems. As we’ll see, the suitability of causal block components varies from application to application.

Cooling Example

The first system that we will model using our block definitions is the heat transfer example we presented earlier in this chapter. However, this time, instead of using acausal components to build our model, we’ll build it up in terms of the mathematical operations associated with our block definitions.

Since these blocks represent mathematical operations, let us first revisit the equation associated with this example:

\[m c_p \dot{T} = h A (T_{\infty}-T)\]

The following block diagram will solve for the temperature profile, \(T\):

Gain Block

The Modelica source code for this example is:

within ModelicaByExample.Components.BlockDiagrams.Examples;
model NewtonCooling "Newton cooling system modeled with blocks"
  import Modelica.SIunits.Conversions.from_degC;
  parameter Real h = 0.7 "Convection coefficient";
  parameter Real A = 1.0 "Area";
  parameter Real m = 0.1 "Thermal mass";
  parameter Real c_p = 1.2 "Specific heat";
  parameter Real T_inf = from_degC(25) "Ambient temperature";
  Components.Integrator T(y0=from_degC(90))
    annotation (Placement(transformation(extent={{-30,-10},{-10,10}})));
  Components.Gain gain(k=-1)
    annotation (Placement(transformation(extent={{10,-10},{30,10}})));
  Components.Constant ambient(k=T_inf)
    annotation (Placement(transformation(extent={{10,-40},{30,-20}})));
  Components.Sum sum(nin=2)
    annotation (Placement(transformation(extent={{52,-20},{72,0}})));
  Components.Gain gain1(k=h*A/(m*c_p))
    annotation (Placement(transformation(extent={{-70,-10},{-50,10}})));
equation
  connect(T.y, gain.u) annotation (Line(
      points={{-9,0},{9,0}}, color={0,0,255},
      smooth=Smooth.None));
  connect(sum.y, gain1.u) annotation (Line(
      points={{73,-10},{80,-10},{80,60},{-80,60},{-80,0},{-71,0}},
      color={0,0,255}, smooth=Smooth.None));
  connect(gain.y, sum.u[2]) annotation (Line(
      points={{31,0},{40,0},{40,-9.5},{51,-9.5}},
      color={0,0,255}, smooth=Smooth.None));
  connect(ambient.y, sum.u[1]) annotation (Line(
      points={{31,-30},{40,-30},{40,-10.5},{51,-10.5}},
      color={0,0,255}, smooth=Smooth.None));
  connect(gain1.y, T.u) annotation (Line(
      points={{-49,0},{-31,0}},
      color={0,0,255}, smooth=Smooth.None));
end NewtonCooling;

The temperature, \(T\), is represented in this model by the variable T.y. Simulating this system, we get the following solution for the temperature:

../../../_images/BNC.png

As we can see, the solution is exactly the same as it has been for all previous incarnations of this example.

So far, we’ve seen this particular problem formulated three different ways. The first formulation described the mathematical structure using a single equation. The second formulation used acausal component models of individual physical effects to represent the same dynamics. Finally, we have this most recent block diagram formulation. But the real question is, which ones of these approaches is the most appropriate for this particular problem?

There are really two extreme cases to consider. If we wanted to solve only this one particular configuration of this problem with a single thermal capacitance convecting heat to some infinite ambient reservoir, the equation based version would probably be the best choice since the behavior of the entire problem can be expressed by the single equation:

m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";

Such an equation can be typed in very quickly. In contrast, the component based versions would require the user to drag, drop and connect component models which would invariably take longer.

However, if you intend to create variations of the problem combining different modes of heat transfer, different boundary conditions, etc., then the acausal version is better. This is because while some investment is required to create the component models, they can be reconfigured almost trivially.

One might say the same is true for the block diagram version of the model (i.e., that it can be trivially reconfigured), but that is not the case. The block diagram version of the model is a mathematical representation of the problem, not a schematic based formulation. If you create variations of this heat transfer problem that specify alternative boundary conditions, add more thermal inertias or include additional modes of heat transfer, the changes to a schematic will be simple. However, for a block diagram formulation you will need to completely reformulate the block diagram. This is because the resulting mathematical equations might be very different when expressed in state-space form. One of the big advantages of the acausal, schematic based approach is that the Modelica compiler will translate the textbook equations into state-space form automatically. This saves a great deal of tedious, time-consuming and error prone work on the part of the model developer and this is precisely why the acausal approach is preferred.

Thermal Control

For the next example, we’ll mix both causal components, the blocks we’ve developed in this section, with acausal components, the Heat Transfer Components developed earlier in this chapter. This will prove to be a powerful combination, since it allows us to represent the physical components schematically, but allows us to express the control strategy mathematically.

Here is a schematic diagram showing how both approaches can be combined:

Gain Block

When modeling a physical system together with a control system, the physical components and effects will use an acausal formulation. The components representing the control strategy will typically use a causal formulation. What bridges the gap between these two approaches are the sensors and actuators. The sensors measure some aspect of the system (temperature in this example) and the actuators apply some “influence” over the system (in this case, a heat flux).

The actuator models will generally have signals as inputs combined with an acausal connection to the physical system (through which the “influence”, like a force or an electric current, will be applied). This is reversed for the sensor models where the causal connectors will be outputs and the acausal connectors will be used to “sense” some aspect of the physical system (like a voltage, temperature, etc.).

Our example model can be expressed in Modelica as:

within ModelicaByExample.Components.BlockDiagrams.Examples;
model MultiDomainControl
  "Mixing thermal components with blocks for sensing, actuation and control"

  import Modelica.SIunits.Conversions.from_degC;

  parameter Real h = 0.7 "Convection coefficient";
  parameter Real A = 1.0 "Area";
  parameter Real m = 0.1 "Thermal maass";
  parameter Real c_p = 1.2 "Specific heat";
  parameter Real T_inf = from_degC(25) "Ambient temperature";
  parameter Real T_bar = from_degC(30.0) "Desired temperature";
  parameter Real k = 2.0 "Controller gain";

  Components.Constant setpoint(k=T_bar)
    annotation (Placement(transformation(extent={{-40,30},{-20,50}})));
  Components.Feedback feedback
    annotation (Placement(transformation(extent={{-10,30},{10,50}})));
  Components.Gain controller_gain(k=k) "Gain for the proportional control"
    annotation (Placement(transformation(extent={{20,30},{40,50}})));
  HeatTransfer.ThermalCapacitance cap(C=m*c_p, T0 = from_degC(90))
    "Thermal capacitance component"
    annotation (Placement(transformation(extent={{-30,-30},{-10,-10}})));
  HeatTransfer.Convection convection2(h=h*A)
    annotation (Placement(transformation(extent={{10,-30},{30,-10}})));
  HeatTransfer.AmbientCondition
                   amb(T_amb(displayUnit="K") = T_inf)
    annotation (Placement(transformation(extent={{50,-30},{70,-10}})));
  Components.IdealTemperatureSensor sensor annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=90,
        origin={0,10})));
  Components.HeatSource heatSource
    annotation (Placement(transformation(extent={{-60,-30},{-40,-10}})));
equation
  connect(setpoint.y, feedback.u1) annotation (Line(
      points={{-19,40},{-11,40}}, color={0,0,255},
      smooth=Smooth.None));
  connect(feedback.y, controller_gain.u) annotation (Line(
      points={{10,40},{19,40}}, color={0,0,255},
      smooth=Smooth.None));
  connect(convection2.port_a, cap.node) annotation (Line(
      points={{10,-20},{-20,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(amb.node, convection2.port_b) annotation (Line(
      points={{60,-20},{30,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(sensor.y, feedback.u2) annotation (Line(
      points={{0,21},{0,24.5},{0,24.5},{0,29}},
      color={0,0,255},
      smooth=Smooth.None));
  connect(heatSource.node, cap.node) annotation (Line(
      points={{-40,-20},{-20,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(controller_gain.y, heatSource.u) annotation (Line(
      points={{41,40},{50,40},{50,60},{-70,60},{-70,-20},{-61,-20}},
      color={0,0,255},
      smooth=Smooth.None));
  connect(sensor.node, cap.node) annotation (Line(
      points={{0,0},{0,0},{0,-20},{-20,-20}},
      color={191,0,0},
      smooth=Smooth.None));
end MultiDomainControl;

Looking at the model, we can see that the initial temperature is \(90\,^{\circ}\mathrm{C}\) and the ambient temperature is \(25\,^{\circ}\mathrm{C}\). In addition, the setpoint temperature (the desired temperature) is \(30\,^{\circ}\mathrm{C}\). So unlike our previous examples where the system temperature eventually came to rest at the ambient temperature, this system should approach the setpoint temperature due to the influence of the control system. Simulating this system, we get the following temperature response:

../../../_images/MDC.png

We can increase the “gain” of the controller, k, and we see a different response:

../../../_images/MDC_hg.png

However, we can see from the following plot that much more heat output was required from our actuator in order to achieve the faster response in the second case:

../../../_images/MDC_heat.png

This is just a very simple example of how combining physical response with control allows model developers to explore how overall system performance is impacted by both physical and control strategy design.

Conclusion

In this section, we’ve seen how to define causal block components and use them to model both the physical and control related behavior. We’ve even seen how these causal components can be combined with acausal components to yield a “best of both worlds” combination where control features are implemented with causal components while physical components use acausal components.