© Michael Paluszek and Stephanie Thomas 2020
M. Paluszek, S. ThomasMATLAB Recipeshttps://doi.org/10.1007/978-1-4842-6124-8_6

6. Classes

Michael Paluszek1   and Stephanie Thomas2
(1)
Princeton, NJ, USA
(2)
Princeton Junction, NJ, USA
 

MATLAB provides a framework for object-oriented programming. MATLAB created a new framework in 2008a, although the old one is still available. The new framework will be familiar to those of you who program in Python and C++.

Basically, objects contain both data and the operations that work on the data in one package. Classes conceptually derive from the struct which only contains data. Combining data with the code that operates on the data can lead to more reliable software. Once you create a class, you can create new classes that inherit from the old class, without changing the old class adding functionality. A new class can inherit from multiple classes. Subclasses get you out of the habit of adding flags to change the functionality of a block of code and data. The subclass usually adds features that are not available in the original class (i.e., the code/data conglomerate).

In this chapter, we will give an example of a class for state space systems. We will create two subclasses, one that is for a continuous system and one that is for discrete systems. This is in line with the many examples in this book.

6.1 Object-Oriented Programming

Object-oriented programming can be thought of as a method for the software designer to impose restrictions on how the software is used by a programmer. In compiled software, the restrictions are imposed at compile time rather than when the software is executed. This, hopefully, catches many errors. In MATLAB, and other scripting languages, the restrictions are imposed whenever you use the function.

Generally, software has moved from unfettered access to memory to more restrictions. In FORTRAN (MATLAB was originally written in FORTRAN), all variables were pointers. You could pass any variable of any size to a function, and the function only saw the first spot in memory. The old linear algebra package, LAPACK, would have you pass the sizes of each variable. Or you could do all sorts of interesting programming, taking advantage of that feature, much to the detriment of anyone wanting to use your code. MATLAB was designed to solve many of the problems of using LAPACK. A really fun thing you could use was the COMMON block. This is perfectly good FORTRAN code.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figa_HTML.gif

Everything starting with an i was an integer. Everything else was float. If you did this, you were mapping i1 and i2 into x. Confusing?

Problems would arise in practice when multiple people used the same code base and changed COMMON blocks without letting other programmers know. Languages like C required all data to be type defined, but even that wasn’t enough as software became more complex. Object-oriented programming was devised to catch as many problems as possible at the compile stage.

An object is a conglomeration of data and operations on that data. Classes evolved from structures. A MATLAB structure is

../images/335353_2_En_6_Chapter/335353_2_En_6_Figb_HTML.gif

This organizes your variables with names that indicate their purpose. Now your function can take as an input s:

../images/335353_2_En_6_Chapter/335353_2_En_6_Figc_HTML.gif

rather than

../images/335353_2_En_6_Chapter/335353_2_En_6_Figd_HTML.gif

However, even with the structure, we still have to know that ControlFunction takes s as an argument. Object-oriented programming helps in this regard.

A class is a definition of the object. An object is an instantiation of the class. The operations are often called methods. At the very least, we want to be able to add data to the object and read data from the object. So the minimal class is
  1. 1.

    Data

     
  2. 2.

    Input methods

     
  3. 3.

    Output methods

     

The input and output methods control access to the data in the object. You might not want the user of the object to be able to change all of the data, and you might not want a user to have access to all of the data. For example, you might have constants in the object that are fundamental to the functioning of the object that you don’t want users to ever change.

After this minimal object definition, you then can add methods that operate on the data in the object. These methods are just functions. This leads to the concept of overloading when a function can have one name but operate on different classes. For example, you could create a member function Add for your double class.

../images/335353_2_En_6_Chapter/335353_2_En_6_Fige_HTML.gif

And then create a member function for your image class.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figf_HTML.gif

So you don’t need names like AddDouble and AddImage.

6.2 State Space Systems Base Class

Problem

We want to create a class for state space systems.

Solution

Create the base class for state space systems.

How It Works

A state space system consists of four matrices that connect the system inputs to the system outputs. In between are the states of the systems. The states are dynamical quantities that can change with time. The inputs are external inputs and the outputs are what we see outside. Two versions of a state space system are the continuous and discrete. The continuous system is

$$displaystyle egin{aligned} egin{array}{rcl} dot{x}(t) & =&displaystyle ax(t) + bu(t) end{array} end{aligned} $$
(6.1)

$$displaystyle egin{aligned} egin{array}{rcl} y & =&displaystyle cx(t) + du(t) end{array} end{aligned} $$
(6.2)
and the discrete system is

$$displaystyle egin{aligned} egin{array}{rcl} x_{k+1}& =&displaystyle ax_k + bu_k end{array} end{aligned} $$
(6.3)

$$displaystyle egin{aligned} egin{array}{rcl} y_k & =&displaystyle cx_k + du_k end{array} end{aligned} $$
(6.4)
t is the time and k is the step. A step usually means a value taken at a fixed interval of time. Define a time vector:

../images/335353_2_En_6_Chapter/335353_2_En_6_Figg_HTML.gif

If you use this vector, your step is every 10 time units.

Both systems have the vectors x, y, and u and the matrices a, b, c, and d. Our base class will just involve the vectors and matrices along with their names.

If we were using functional programming, as opposed to object-oriented programming, we would create the structure:

../images/335353_2_En_6_Chapter/335353_2_En_6_Figh_HTML.gif

We’d then create a set of functions to operate on this structure. There are a couple of problems with this approach. The first is that the arrays have specific sizes. If we have n states, m inputs, and p outputs, then a is n by n, b is n by m, c is p by n, and d is p by m. Another problem is that the name fields don’t restrict the matrix dimensions which can lead to bugs. Also, there is nothing that says 'xName' is a cell array. Another issue in MATLAB is that anyone can change the structure on the fly, leading to more issues when sharing software, or even using your old software!

To create a class, select “Class” from the New pull-down in the command window.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figi_HTML.gif

This provides a good starting framework for the class. There is a method to create an instance of the class, the function that is untitled. Internally, you see that obj is a data structure. properties are the data stored in the class. methods are operations that work on the data stored in the class. We create the StateSpace class to have only data. It does input validation so that once you have created the class, all the matrices are the right sizes. The class definition is

StateSpace.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figj_HTML.gif

The properties, that is, the data, are in the next block of code.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figk_HTML.gif

We made n,m,p private to restrict its visibility to subclasses. There are many possible properties. Each set goes with its own block. If it were private, subclasses could not see it. You would use private if you didn’t want people who are deriving subclasses to have access to that property.

We use property validation by specifying

../images/335353_2_En_6_Chapter/335353_2_En_6_Figl_HTML.gif

If we don’t set the property correctly, we will get

../images/335353_2_En_6_Chapter/335353_2_En_6_Figm_HTML.gif

However, if we do, we will get

../images/335353_2_En_6_Chapter/335353_2_En_6_Fign_HTML.gif

It happily makes a a 1-by-4 array. This is because char is numeric. For example, in the char “Mike”, each character is an integer, which is of course numeric. A more sophisticated property validation is possible. You should use as much property validation as you deem necessary for your class.

The remaining code is the class constructor.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figo_HTML.gif

../images/335353_2_En_6_Chapter/335353_2_En_6_Figp_HTML.gif

These methods are all fully implemented in the code. We add one to compute the eigenvalues since this is common to all state space systems.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figq_HTML.gif

We can then create a double integrator using our class.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figr_HTML.gif

n,m,p are not listed.

The first argument to every member class is obj. You don’t pass this as an argument; it is implicit in the member function call.

The eigenvalues are

../images/335353_2_En_6_Chapter/335353_2_En_6_Figs_HTML.gif

which is what we expect.

6.3 State Space Systems Discrete Class

Problem

We want to create a class to propagate discrete time state space systems.

Solution

Create a subclass of StateSpace and add a step propagator and a general propagator.

How It Works

We make StateSpaceDiscrete a subclass of StateSpace in the first line with the > operator.

StateSpaceDiscrete.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figt_HTML.gif

If you have multiple super classes, list multiple superclasses superclass1 & superclass2 & superclass3, for example:

../images/335353_2_En_6_Chapter/335353_2_En_6_Figu_HTML.gif

The constructor just passes the inputs to the super class.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figv_HTML.gif

We add two methods to propagate the discrete time class.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figw_HTML.gif

6.4 Using the State Space Class

Problem

We want to create a script to use the state space class.

Solution

Create a script to propagate the continuous subclass of StateSpace.

How It Works

We create a script to use both propagation methods. We assign values to u by using the dot operator, just like any structure. We don’t need to write setter methods.

DiscretePropagate.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figx_HTML.gif

method uses whatever u is in the object when you used Propagate. You can add help using % just below the method names and at the top.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figy_HTML.gif

The resulting plots are shown in Figure 6.1.
../images/335353_2_En_6_Chapter/335353_2_En_6_Fig1_HTML.jpg
Figure 6.1

Propagated states. The step response is on the left. The pulse response is on the right.

You can see how compact the code is. StateSpaceDiscrete can handle any linear time-invariant (i.e., the state space matrices are constant) discrete time state space system.

6.5 Using a Mocking Framework

Problem

We want to test an incomplete class for which other needed classes are unavailable.

Solution

Use a mocking framework which is a framework that allows us to interface to an incomplete class, that is, a “mock” class.

How It Works

We create a class to test a function that calls a class that does not exist or is unavailable. In this case, we have a function Drag:

Drag.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figz_HTML.gif

that uses the density class DensityModel. When you are testing Drag, the density table is not yet available. Create the class for DensityModel with an abstract method.

DensityModel.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figaa_HTML.gif

Now write the test class using the matlab.unittest.TestCase and matlab. mock.TestCase superclasses. The mock framework allows us to fake the existence of the density model. The unittest framework allows us to evaluate the results of the test.

DragTest.m

../images/335353_2_En_6_Chapter/335353_2_En_6_Figab_HTML.gif

The question mark, ?, is used to get a metaclass of DensityModel. In this code snippet, the Drag function is called with an altitude of h= -1, a velocity of v=1, and a surface area of s=2. It is given a “stubDensity” class that is created just for the purpose of this test, using the mock framework createMock.

We create a mock object, stubDensity. The method is implemented with density ModelBehavior.LookUpDensity(0). When we pass a negative altitude, we get a negative density and negative drag.

Run the test.

../images/335353_2_En_6_Chapter/335353_2_En_6_Figac_HTML.gif

This verifies that we get the correct behavior from Drag.

Summary
This chapter has demonstrated how to use MATLAB classes and mocking frameworks in classes. Table 6.1 lists the code developed in the chapter.
Table 6.1

Chapter Code Listing

File

Description

StateSpace

State space dynamical system class

StateSpaceDiscrete

Subclass of StateSpace for discrete systems

DragTest

A test class for Drag and DensityModel

Drag

A test class for Drag

DensityModel

A placeholder class for DensityModel

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.6.114