.. _speed-measurement:


Speed Measurement
-----------------

Baseline System
^^^^^^^^^^^^^^^

There are many applications where we need to model the interaction
between continuous behavior and discrete behavior.  For this section,
we'll look at techniques used to measure the speed of a rotating
shaft.  For our discussion here, we will reuse the :ref:`mechanical
example <mech-example>` we discussed previously in our discussion of
:ref:`basic-equations`:

.. literalinclude:: /ModelicaByExample/BasicEquations/RotationalSMD/SecondOrderSystem.mo
   :language: modelica
   :lines: 2-

.. index:: extends

We will reuse this model by adding an ``extends`` clause to our
model.  This essentially imports everything from the model we are
extending from.  We'll talk more about the ``extends`` clause later when we
discuss :ref:`packages`.  For now, just think of it as copying the
contents of another model into the current model.

Recall the solution for the ``SecondOrderSystem`` model looks like
this:

.. plot:: ../plots/SOSIP.py
   :class: interactive

In this case, we are simply plotting the solution that we computed.
But in a real system, we can't directly know the rotational velocity
of a shaft.  Instead, we have to measure it.  But measurement
introduces error and each measurement technique introduces different
kinds of errors.  In this section, we'll look at how we can model
different kinds of measurement techniques.

.. _sample-and-hold:

Sample and Hold
^^^^^^^^^^^^^^^

The first type of measurement we will examine is a sample and hold
approach to measurement.  Some speed sensors have circuits for
measuring the rotational speed of the system.  But instead of
providing a continuous value for the speed, they sample it at a given
point in time and then store it somewhere.  This is called "sample and
hold".  The following model demonstrates how to implement a sample
and hold approach to measuring the angular velocity ``omega1``:

.. literalinclude:: /ModelicaByExample/DiscreteBehavior/SpeedMeasurement/SampleAndHold.mo
   :language: modelica
   :lines: 2-

.. index:: discrete

Note the presence of the ``discrete`` qualifier in the declaration of
``omega1_measured``.  This special qualifier indicates that the
specified variable does not have a continuous solution.  Instead, the
value of this variable will make (only) discrete jumps during the
simulation.  It is not required to include the ``discrete`` keyword
but it is useful because it provides additional information about the
intent of the model that the compiler can check (*e.g.,* making sure
we never request the derivative of that variable).

Let us now examine the solution generated by this model:

.. plot:: ../plots/SampleAndHold.py
   :class: interactive

The important thing to note in the solution is how the measured value
is piecewise-constant.  This is because the value of
``omega1_measured`` is set only when the ``when`` statement becomes
active.  The ``sample`` function is a special built-in function that
first becomes true at the time indicated by the first argument (``0``
in this case) and then at regular intervals after that.  The duration
of these regular intervals is indicated by the second argument
(``sample_time`` in this case).

.. _interval-measurement:

Interval Measurement
^^^^^^^^^^^^^^^^^^^^

In the previous example, we weren't actually making any estimates for
the speed, we were simply reporting the value of the variable
``omega1`` only at specific times.  In other words, at the moment that
we sampled ``omega1`` our sample was completely accurate.  But by
"holding" our measured value (instead of continuing to track
``omega1``), we introduced some artifact in the measurement.

In the remaining examples, we will focus on techniques used to
estimate the speed of a rotating shaft.  In these cases, we will never
make direct use of the actual speed in our measurement.  Instead, we
will respond to events generated by the physical system and attempt to
use these events to reconstruct an estimate of the rotational speed.

The events that we will be responding to are generated by the discrete
elements attached to the spinning shaft.  For example, a typical way
to produce these events is to use a "tooth wheel encoder".  A tooth
wheel encoder includes a gear on the rotating shaft.  On either side of
the gear, we place a light source and a light sensor.  As the gear
teeth pass in front of the light source, they block the light.  The
result is that the signal from the light sensor will include an
approximate square wave.  The leading edge of these square waves are
the events we will be responding to.

The first estimation method we will examine computes the speed of the
shaft by measuring the time interval that passes between events.
Knowing that these events occur whenever the shaft has rotated by
an angle of :math:`\Delta\theta`, we can estimate the speed as:

.. math::

    \hat{\omega} = \frac{\Delta\theta}{\Delta t}

This technique for speed estimation can be represented in Modelica as:

.. literalinclude:: /ModelicaByExample/DiscreteBehavior/SpeedMeasurement/IntervalMeasure.mo
   :language: modelica
   :lines: 2-

where ``tooth_angle`` represents :math:`\Delta\theta`.  Note how
``tooth_angle`` is not something the user needs to specify.  Instead,
the user specifies the number of teeth using the ``teeth`` parameter.
The ``tooth_angle`` parameter is then computed using the value of
``teeth`` (note that while we have hand coded the value of :math:`pi`
here, we'll learn how to avoid this later in the book when we talk
about :ref:`constants`).

Let's take a close look at the ``when`` statement in this model:

.. literalinclude:: /ModelicaByExample/DiscreteBehavior/SpeedMeasurement/IntervalMeasure.mo
   :language: modelica
   :lines: 13-19

Here, we use the vector expression syntax used previously in the
:ref:`bouncing-ball` example.  Recall that the ``when`` statement
becomes active if **any** of the conditions become true.  In this
case, the ``when`` statement becomes active if the angle, ``phi1``,
becomes greater than ``next_phi`` or less than ``prev_phi``.

Another thing to note is the use of the ``pre`` operator throughout
the ``when`` statement.  When an event occurs in a model, there is a
chance that the value of some variables may change discontinuously.
During an event, while we are trying to resolve what values all the
variables should have as a result of the event, the ``pre`` operator
allows us to reference the value of a variable **prior** to the event.
The ``pre`` operator is used in this model to refer to the previous
(pre-event) values of ``next_phi``, ``prev_phi`` and ``last_time``.
The ``pre`` operator is necessary because all of these variables are
affected by the statements inside the ``when`` statement.  So, for
example, ``last_time`` (without the ``pre`` operator) refers to the
value of ``last_time`` at the conclusion of the event while
``pre(last_time)`` refers to the value of ``last_time`` prior to any
event occurring.

.. topic:: Use of the ``pre`` operator

    In general, if a variable changes as a result of a ``when``
    statement becoming active, you **almost always** want to use the
    ``pre`` operator when referring to that variable in the
    conditional expression associated with the ``when`` statement (as we
    have done in the previous example).  This makes it clear that you
    are responding to what was happening before the ``when`` statement
    was triggered.

Let's take a look at the speed estimates provided by this approach:

.. plot:: ../plots/IntervalMeasure.py
   :class: interactive

There are two important properties of this estimation algorithm that
we can immediately see in these results.  The first is that the
estimate is unsigned.  In other words, we cannot tell from a device
like a tooth wheel encoder which **direction** the shaft is rotating.
Also, low speeds and changes in rotational direction can degrade the
accuracy of the estimate significantly.  The results are also very
sensitive the number of teeth involved.  If we were to reduce the
number of teeth used in our encoder by setting ``teeth`` to 20, we'd
get very different results.

.. plot:: ../plots/IntervalMeasure_Coarse.py
   :class: interactive

To understand exactly why the measured signal is so inaccurate, it
helps to consider the following plot which shows how the angle,
``phi1`` compares to the angles associated with the adjacent teeth,
``next_phi`` and ``prev_phi``.

.. plot:: ../plots/IntervalMeasure_Coarse_phi.py
   :class: interactive

In this plot, we can clearly see how relatively low speeds and speed
reversals create irregular events that introduce significant
estimation error.

.. _pulse-counting:

Pulse Counting
^^^^^^^^^^^^^^

The interval measuring technique mentioned above requires hardware
that can perform speed calculations on hardware interrupts.  Another
approach to estimating speed is the count how many events occur within
a given (fixed) time interval and use that as an estimate of speed.
Using this method, only the summation of events occurs when the events
occur and the calculations are deferred to a regularly scheduled
update.

Building on the previous examples in this section, the following
seems like a natural way to create a model that implements this
estimation technique:

.. literalinclude:: /ModelicaByExample/DiscreteBehavior/SpeedMeasurement/Counter.mo
   :language: modelica
   :emphasize-lines: 17,21
   :lines: 2-

However, there is a problem in this model.  Note that there are
actually **two** equations for ``count``.  Trying to compile such a
model will lead to a situation where there are more equations than
variables (*i.e.,* the problem is singular).

So what can we do about this?  We need two different equations because
the updates to ``count`` occur in response to different events.  We could
try to formulate everything under a single ``when`` statement, like this:

.. code-block:: modelica

  when {phi1>=pre(next_phi),phi1<=pre(prev_phi),sample(0,sample_time)} then
    if sample(0,sample_time) then
      omega1_measured := pre(count)*tooth_angle/sample_time;
      count :=0;
    else
      next_phi := phi1 + tooth_angle;
      prev_phi := phi1 - tooth_angle;
      count :=pre(count) + 1;
    end if;
  end when;

.. index:: algorithm section

But this kind of code quickly becomes hard to read.  Fortunately, we
can address this situation by placing all the ``when`` statements in an
``algorithm`` section.

The nature of an ``algorithm`` section is that it is treated as one
single equation for any variables that are assigned within it.  This
allows multiple assignments to ``count``, for example.  When using an
``algorithm`` section, it is very important to understand that the
**order** of assignment becomes important.  If a conflict should arise (*e.g.,* a
variable is assigned two values within the same ``algorithm``
section), the last one is the one that will be used.  Another thing to
note about ``algorithm`` sections is that you cannot write general
equations.  Instead, you must write *assignment statements*.

In this way, an ``algorithm`` section is very much like the way most
programming languages work.  The statements in the algorithm section
are executed in order and each statement isn't interpreted as an
equation, but rather as an assignment of an expression to a variable.
The familiarity of assignment statements may make using ``algorithm``
sections attractive to people with a programming background who find
the otherwise equation oriented aspects of Modelica disorienting and
unfamiliar.  But be aware that one big reason to avoid ``algorithm``
sections is because they interfere with the symbolic manipulation
performed by the Modelica compiler.  This can result in both poor
simulation performance and a loss of flexibility in how you compose
your models.  So it is best to use an ``equation`` section whenever
possible.

In our case, there are no significant consequences to using the
``algorithm`` section.  Here is an example of how the previous
estimation algorithm could be refactored using an ``algorithm``
section:

.. literalinclude:: /ModelicaByExample/DiscreteBehavior/SpeedMeasurement/CounterWithAlgorithm.mo
   :language: modelica
   :lines: 2-

The simulated results of this estimation technique can be seen in the
following plot:

.. plot:: ../plots/SpeedCounter.py
   :class: interactive

Again, we see that this approach cannot determine the direction of
rotation.  With the following plot, we can get a sense of how many
events occur within each sample interval:

.. plot:: ../plots/SpeedCounter_count.py
   :class: interactive

In general, the higher the count gets in an interval, the more
accurate the estimate.

Conclusion
^^^^^^^^^^

This section demonstrates how we can use the ``when`` construct to
respond to physical events that occur in our system.  These kinds of
events and the impact they have on our system are just as important as
the continuous dynamics we've covered previously.  The ability to
capture and respond to these physical events is an important part of
why Modelica is so well suited to model complete systems since those
system frequently include both continuous and discrete behavior.
