In this section, we’ll show how to create basic components for modeling one-dimensional rotational systems. We’ll build on our discussion of rotational connectors and show how they can be used to define the interfaces for basic rotational components. Finally, we’ll show how those rotational components can then be assembled into a system model that replicates the behavior of the equation-based version of the same system presented in the first chapter.
In the first chapter, we considered A Mechanical Example modeled strictly in terms of equations (i.e., without component models). In this section, we will start by recreating that system model using components. To do this, we first have to define models for the fundamental components we require. These will consist of models for an inertia, a spring, a damper and a mechanical ground.
As in the previous section, we will first define the component models using verbose formulations and then we will revisit these definitions and attempt to factor out common code to avoid repetition across component models.
The method for creating these models will be very similar to how we previously created component models in the heat transfer and electrical domains. But before we start building component models, we should first discuss one of the complexities associated with mechanical systems, coordinate systems.
In the mechanical domain, the conserved quantity we will be tracking is momentum. What makes momentum different from the conserved quantities we’ve already covered, heat and charge, is that it is directional. Since we are only concerning ourselves with the one dimensional case here, the consequence of this directionality is that momentum is a signed quantity (i.e., it can be positive or negative).
Consider a rotating mass with a moment of inertia, . If the angular position of the inertia is represented by , then the angular velocity of the inertia, , is defined as:
Obviously, a positive value of will result in an increase in over time. Furthermore, the angular acceleration of the inertia, , is defined as:
As with the angular velocity, we can see that a positive value for will result in an increase in the angular velocity. Finally, the angular momentum of this rotating inertia is defined as and we know from Euler’s laws of motion that (assuming J is a constant):
From this relationship, it is clear that a positive value for the torque, , will increase the amount of momentum stored in the mass.
The point of presenting all these relationships is to underscore the sign conventions associated with , , and . They are all tied to the fundamental definition of what a positive angular position is. Whatever direction causes to increase is the same direction that corresponds to a positive velocity, a positive acceleration and a positive torque.
With this discussion about sign conventions and coordinate systems out of the way, we can start creating our component models. We’ll start with the inertia model:
within ModelicaByExample.Components.Rotational.VerboseApproach;
model Inertia "Rotational inertia without inheritance"
parameter Modelica.SIunits.Inertia J;
Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
annotation ...
Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
annotation ...
protected
Modelica.SIunits.Angle phi_rel;
Modelica.SIunits.Torque tau;
Modelica.SIunits.AngularVelocity w;
equation
// Variables
phi_rel = flange_a.phi-flange_b.phi;
tau = flange_a.tau;
w = der(flange_a.phi);
// Conserviation of angular momentum (includes storage)
J*der(w) = flange_a.tau + flange_b.tau;
// Kinematic constraint (inertia is rigid)
phi_rel = 0;
annotation
The Inertia
model includes two “flanges”, one on either end. The
significance of these flanges is made clearer from the icon of the
Inertia
model:
In other words, the Inertia
model includes a flange on either end.
You can think of this model as a shaft with connectors on either end.
Now, the fundamental equation we wish to capture in the Inertia
model
is:
J*der(w) = flange_a.tau + flange_b.tau;
This is basically expressing the fact that the increase in momentum
stored within the inertia is equal to the sum of the torques applied
to the inertia. Recall, from our previous discussions on
Acausal Connections, that the sign convention for flow
variables on connectors (flange_a.tau
and flange_b.tau
in this
case) is that a positive value represents a flow of the conserved
quantity into the component model. The fact that flange_a
and
flange_b
have the same sign convention means that the Inertia
model is symmetric (i.e., it can be flipped over and it doesn’t
change the behavior).
However, this equation refers to the internal variables w
(which
represents ) and tau
so we need to include
declarations and definitions for those variables as well.
Next, let us consider the definition of a spring model:
within ModelicaByExample.Components.Rotational.VerboseApproach;
model Spring "Rotational spring without inheritance"
parameter Modelica.SIunits.RotationalSpringConstant c;
Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
annotation ...
Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
annotation ...
protected
Modelica.SIunits.Angle phi_rel;
Modelica.SIunits.Torque tau;
equation
// Variables
phi_rel = flange_a.phi-flange_b.phi;
tau = flange_a.tau;
// No storage of angular momentum
flange_a.tau + flange_b.tau = 0;
// Hooke's law
tau = c*phi_rel;
end Spring;
The icon for our spring model is rendered as:
Like the Inertia
model, the Spring
model has two connectors,
one on each end. It also defines many of the same internal
variables. Ultimately, the behavior of the spring comes down to this
equation:
tau = c*phi_rel;
In fact, apart from this equation and the parameter c
, much of the
content in the Spring
model is the same as the content in the
Inertia
model.
The Damper
model is also very similar to the Spring
model.
Again, the main differences are the parameter (d
in this case) and
one equation:
within ModelicaByExample.Components.Rotational.VerboseApproach;
model Damper "Rotational damper without inheritance"
parameter Modelica.SIunits.RotationalDampingConstant d;
Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
annotation ...
Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
annotation ...
protected
Modelica.SIunits.Angle phi_rel;
Modelica.SIunits.Torque tau;
equation
// Variables
phi_rel = flange_a.phi-flange_b.phi;
tau = flange_a.tau;
// No storage of angular momentum
flange_a.tau + flange_b.tau = 0;
// Damping relationship
tau = d*der(phi_rel);
end Damper;
The icon for the Damper
model is rendered as:
We already have models for an inertia, a spring and a damper. The only model we are missing in order to complete our dual spring mass damper system is a model of mechanical ground. But before we complete that model, let’s take a moment to revisit the models we’ve already created with the goal of factoring out the large amount of code shared between these models. As in the previous section, let’s take the time to apply the DRY (Don’t Repeat Yourself) principle.
It is worth noting that because the Modelica Standard Library has an
extensive collection of rotational components, it was forced to deal
with this issue of redundant code almost from the start. However, we
will not be using the partial
models from the Modelica Standard
Library here simply because they are designed to deal with many other
cases that are not relevant in this context. As a result, it’s
complexity (although necessary) makes it unsuitable pedagogically.
But one thing we will preserve from the Modelica Standard Library is
the need for multiple partial
models. This need arises from the
fact that, unlike in our previous discussion of
Electrical Components, our rotational component models share
different amounts of code with each other.
What is common to all of our models is the existence of two flange
connectors, flange_a
and flange_b
. However, while the
Inertia
model has the capacity to store angular momentum, the
Spring
and Damper
models do not. As a result, the
conservation equations are different among these components.
Let’s start with the elements that are common to all three models.
These are represented by the following TwoFlange
model:
within ModelicaByExample.Components.Rotational.Interfaces;
partial model TwoFlange
"Definition of a partial rotational component with two flanges"
Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
annotation ...
Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
annotation ...
protected
Modelica.SIunits.Angle phi_rel;
equation
phi_rel = flange_a.phi-flange_b.phi;
end TwoFlange;
In addition to defining the two flanges, flange_a
and
flange_b
, this model also defines the relative angle between these
flanges, i.e., phi_rel
. Of course, this model is also marked as
partial
since it is missing any description of the component’s
behavior.
We could have all three models inherit from this model. But then we
would still have some redundant equations between our Spring
and
Damper
model. So we will instead create a slightly more
specialized version of the TwoFlange
model to represent compliant
models that do not store momentum:
within ModelicaByExample.Components.Rotational.Interfaces;
partial model Compliant "A compliant rotational component"
extends ModelicaByExample.Components.Rotational.Interfaces.TwoFlange;
protected
Modelica.SIunits.Torque tau;
equation
tau = flange_a.tau;
flange_a.tau + flange_b.tau = 0
"Conservation of angular momentum (no storage)";
end Compliant;
The Compliant
model adds on additional internal variable (to
represent the torque that passes through the component from
flange_a
to flange_b
) and an equation indicating that no
angular momentum is stored by the component.
With these base classes defined, let us quickly revisit the various component model definitions to see how much more succinct they can be made by using inheritance.
Leveraging the TwoFlanges
model, our Inertia
model can be
simplified to:
within ModelicaByExample.Components.Rotational.Components;
model Inertia "A rotational inertia model"
parameter Modelica.SIunits.Inertia J;
extends ModelicaByExample.Components.Rotational.Interfaces.TwoFlange;
Modelica.SIunits.AngularVelocity w "Angular Velocity"
annotation ...
Modelica.SIunits.Angle phi "Angle"
annotation ...
equation
phi = flange_a.phi;
w = der(flange_a.phi) "velocity of inertia";
phi_rel = 0 "inertia is rigid";
J*der(w) = flange_a.tau + flange_b.tau
"Conservation of angular momentum with storage";
end Inertia;
In the same way, inheriting from the Compliant
model our
Spring
model can be much more compactly represented as:
within ModelicaByExample.Components.Rotational.Components;
model Spring "A rotational spring component"
parameter Modelica.SIunits.RotationalSpringConstant c;
extends ModelicaByExample.Components.Rotational.Interfaces.Compliant;
equation
tau = c*phi_rel "Hooke's Law";
end Spring;
Likewise, the Damper
model is similarly simplified:
within ModelicaByExample.Components.Rotational.Components;
model Damper "A rotational damper"
parameter Modelica.SIunits.RotationalDampingConstant d;
extends ModelicaByExample.Components.Rotational.Interfaces.Compliant;
equation
tau = d*der(phi_rel) "Damping relationship";
end Damper;
Finally, we can complete the one model remaining in order to complete our dual spring mass damper system. The mechanical ground model is defined as follows:
within ModelicaByExample.Components.Rotational.Components;
model Ground "Mechanical ground"
Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
annotation ...
equation
flange_a.phi = 0;
end Ground;
Finally, we have all the parts we need in order to reconstruct the example we saw in the first chapter. Using the various components already defined in this section, the Modelica code for our component based system model looks like this:
within ModelicaByExample.Components.Rotational.Examples;
model SMD
Components.Ground ground annotation ...
Components.Damper damper2(d=1)
annotation ...
Components.Spring spring2(c=5)
annotation ...
Components.Inertia inertia2(
J=1,
phi(fixed=true, start=1),
w(fixed=true, start=0))
annotation ...
Components.Damper damper1(d=0.2)
annotation ...
Components.Spring spring1(c=11)
annotation ...
Components.Inertia inertia1(
J=0.4,
phi(fixed=true, start=0),
w(fixed=true, start=0))
annotation ...
equation
connect(ground.flange_a, damper2.flange_b) annotation ...
connect(ground.flange_a, spring2.flange_b) annotation ...
connect(damper2.flange_a, inertia2.flange_b) annotation ...
connect(spring2.flange_a, inertia2.flange_b) annotation ...
connect(inertia2.flange_a, damper1.flange_b) annotation ...
connect(inertia2.flange_a, spring1.flange_b) annotation ...
connect(damper1.flange_a, inertia1.flange_b) annotation ...
connect(spring1.flange_a, inertia1.flange_b) annotation ...
end SMD;
The diagram for this model, when rendered, looks like this:
This completes our discussion of basic rotational components. But there is quite a bit more to say about rotational components in the next section on Advanced Rotational Components.