Basic Rotational Components

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.

Component Models

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.

Coordinate Systems

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, \(J\). If the angular position of the inertia is represented by \(\varphi\), then the angular velocity of the inertia, \(\omega\), is defined as:

\[\omega = \dot{\varphi}\]

Obviously, a positive value of \(\omega\) will result in an increase in \(\varphi\) over time. Furthermore, the angular acceleration of the inertia, \(\alpha\), is defined as:

\[\alpha = \dot{\omega}\]

As with the angular velocity, we can see that a positive value for \(\alpha\) will result in an increase in the angular velocity. Finally, the angular momentum of this rotating inertia is defined as \(J \omega\) and we know from Euler’s laws of motion that (assuming J is a constant):

\[J \frac{\mathrm{d}\omega}{\mathrm{d}t} = \tau\]

From this relationship, it is clear that a positive value for the torque, \(\tau\), 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 \(\varphi\), \(\omega\), \(\alpha\) and \(\tau\). They are all tied to the fundamental definition of what a positive angular position is. Whatever direction causes \(\varphi\) to increase is the same direction that corresponds to a positive velocity, a positive acceleration and a positive torque.

Rotational Inertia

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 (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
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 ( Icon(graphics={
          extent={{-100,90},{100,50}},

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 \(\omega\)) and tau so we need to include declarations and definitions for those variables as well.

Spring Model

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 (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
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:

  // Hooke's law
  tau = c*phi_rel;
end Spring;

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.

Damper 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 (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
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:

DRY Component Models

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.

Common Code

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 (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
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.

Rotational Inertia

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(Dialog(group="Initialization", showStartAttribute=true));
  Modelica.SIunits.Angle phi "Angle"
    annotation(Dialog(group="Initialization", showStartAttribute=true));
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;

Spring Model

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;

Damper Model

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;

Mechanical Ground

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 Damper "A rotational damper"
  parameter Modelica.SIunits.RotationalDampingConstant d;
  extends ModelicaByExample.Components.Rotational.Interfaces.Compliant;
equation
  tau = d*der(phi_rel) "Damping relationship";
  annotation (Icon(graphics={

Dual Spring Mass Damper System

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 (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=90,
        origin={76,0})));
  Components.Damper damper2(d=1)
    annotation (Placement(transformation(extent={{30,10},{50,30}})));
  Components.Spring spring2(c=5)
    annotation (Placement(transformation(extent={{28,-30},{48,-10}})));
  Components.Inertia inertia2(
    J=1,
    phi(fixed=true, start=1),
    w(fixed=true, start=0))
    annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
  Components.Damper damper1(d=0.2)
    annotation (Placement(transformation(extent={{-50,10},{-30,30}})));
  Components.Spring spring1(c=11)
    annotation (Placement(transformation(extent={{-50,-30},{-30,-10}})));
  Components.Inertia inertia1(
    J=0.4,
    phi(fixed=true, start=0),
    w(fixed=true, start=0))
          annotation (Placement(transformation(extent={{-90,-10},{-70,10}})));
equation
  connect(ground.flange_a, damper2.flange_b) annotation (Line(
      points={{70,0},{66,0},{66,0},{60,0},{60,20},{50,20}},
      color={0,0,0},
      smooth=Smooth.None));

  connect(ground.flange_a, spring2.flange_b) annotation (Line(
      points={{70,0},{60,0},{60,-20},{48,-20}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(damper2.flange_a, inertia2.flange_b) annotation (Line(
      points={{30,20},{20,20},{20,0},{10,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(spring2.flange_a, inertia2.flange_b) annotation (Line(
      points={{28,-20},{20,-20},{20,0},{10,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(inertia2.flange_a, damper1.flange_b) annotation (Line(
      points={{-10,0},{-20,0},{-20,20},{-30,20}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(inertia2.flange_a, spring1.flange_b) annotation (Line(
      points={{-10,0},{-20,0},{-20,-20},{-30,-20}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(damper1.flange_a, inertia1.flange_b) annotation (Line(
      points={{-50,20},{-60,20},{-60,0},{-70,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(spring1.flange_a, inertia1.flange_b) annotation (Line(
      points={{-50,-20},{-60,-20},{-60,0},{-70,0}},
      color={0,0,0},
      smooth=Smooth.None));
end SMD;

The diagram for this model, when rendered, looks like this:

../../../_images/SMD.png

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.