© Apress 2015

Michael Paluszek and Stephanie Thomas, MATLAB Recipes, 10.1007/978-1-4842-0559-4_6

6. The Double Integrator

Michael Paluszek and Stephanie Thomas2

(1)Princeton, New Jersey, USA

(2)Princeton Junction, New Jersey, USA

Electronic supplementary material: The online version of this chapter (doi: 10.​1007/​978-1-4842-0559-4_​6) contains supplementary material, which is available to authorized users.

A double integrator is a dynamical model for a wide variety of physical systems. This includes a mass moving in one dimension and an object rotating around a shaft. It represents a broad class of systems with two states. In this chapter, you will learn how to model a double integrator and how to control it. In the process, you will create some very important functions for implementing control systems, plotting, and performing numerical integration. This will provide a springboard to other, more complex systems in later chapters.

6.1 Writing Equations for the Double Integrator Model

Problem

A double integrator is a second-order model, with a second derivative, where the derivative is independent of the state. This model appears in many engineering disciplines.

Solution

You will write the equations for the model dynamics and implement these in a function.

How It Works

One-dimensional linear motion can be modeled with the following differential equations: 
$$ dot{r}=upsilon $$
(6.1)

$$ moverset{.}{upsilon }=F $$
(6.2)
r and υ are states; m, the mass, is a parameter; and F, the force, is an input. The state vector is

$$ x=left[egin{array}{r}hfill r\ {}hfill upsilon end{array}
ight] $$
(6.3)

The variable x is represented by a MATLAB two rows × one column array. The first element of the array is r and the second is υ.

Tip

This equation works equally well for rotational motion. Just replace m with I for inertia, r with θ for angle, υ with ω for angular velocity, and F with T for torque.

To write a function for the derivatives, divide by m to isolate the derivatives on the left-hand side of the equations. The terms on the right-hand side are what you will calculate in this so-called RHS function.

$$ dot{r}=upsilon $$
(6.4)

$$ overset{.}{upsilon }=frac{F}{m}equiv a $$
(6.5)

Writing these equations in vector notation, you have 
$$ dot{x}=left[egin{array}{r}hfill upsilon \ {}hfill aend{array}
ight] $$
(6.6)

Now you can write the function, RHSDoubleIntegrator, for the derivative of the state vector x. Note the prefix of RHS in the name, which you use to identify all functions that can be integrated. The velocity term is the second element of state x, and is passed as the derivative of the position state r. The derivative of the velocity state is the acceleration a. The RHS function has a placeholder ∼ for the first argument, where the integrator will pass the time t, which this function doesn’t require.

function xDot = RHSDoubleIntegrator(∼, x, a)

xDot = [x(2);a];

6.2 Creating a Fixed-Step Numerical Integrator

Problem

You need to use numerical integration in the simulations to evolve the state of the systems.

Solution

You will review the equations for a fourth-order Runge-Kutta integrator and develop a function to perform fixed-step integration.

How It Works

Let’s look at a simple model for linear motion. You need to put the equations in state equation form, which is a set of first-order differential equations with the derivatives on the left-hand side. Take, for example, the one-dimensional motion model from Recipe 6-1, with the derivative terms for r and υ on the left-hand side of the equations.

$$ frac{dr}{dt}=upsilon $$
(6.7)

$$ frac{dupsilon }{dt}=frac{F}{m} $$
(6.8)

Multiply both sides by dt.

$$ dr=upsilon dt $$
(6.9)

$$ dupsilon =frac{F}{m}dt $$
(6.10)

Replace dt with the fixed-time interval h. You can now write the simplest type of numerical integrator for computing the state at step k + 1 from the state at step k.

$$ {r}_{k+1}={r}_k+{upsilon}_kh $$
(6.11)

$$ {upsilon}_{k+1}={upsilon}_k+frac{F_k}{m}h $$
(6.12)

Step k is at time t k and step k + 1 is at time t k+1, where t k+1 = t k + h.

This simple integrator is called Euler integration. It assumes that the force F k is constant over the time interval h. Euler integration works fairly well for simple systems, like the preceding one. For example, for a spring system

$$ ddot{r}+{omega}^2r=a $$
(6.13)
the natural frequency of oscillation is ω. If the time step is greater than half the period of the oscillation 2π/ω, the numerical integration cannot capture the dynamics. In practice, the time step, h, must be much lower than half.

Euler integration is rarely used for engineering due to its limited accuracy. One of the most popular methods used for control system simulation is the fourth-order Runge-Kutta method. The equations are as follows: 
$$ egin{array}{l}{k}_1=fleft(x,u(t),t
ight)\ {}{k}_2=fleft(x+frac{h}{2}{k}_1,u(t)+frac{h}{2},t+frac{h}{2}
ight)\ {}{k}_3=fleft(x+frac{h}{2}{k}_2,u(t)+frac{h}{2},t+frac{h}{2}
ight)\ {}{k}_4=left(x+h{k}_3,uleft(t+h-varepsilon 
ight),t+h
ight)\ {}x=x+frac{h}{6}left({k}_1+2left({k}_2+{k}_3
ight)+{k}_4
ight)+Oleft({h}^4
ight)end{array} $$
(6.14)
f  (x, u, t) is the right-hand side of the differential equations. O(h 4) means the truncation error due to the order of the integration goes as the fourth power of the time step. This means that if you halve this time step, the error drops to 0.0625 of the error with the bigger time step. In the preceding system, the right-hand sides are computed at four different points, twice at h/2 and once at t and t + h.

$$ fleft(x,F,t
ight)=left[egin{array}{l}upsilon hfill \ {}frac{F}{m}hfill end{array}
ight] $$
(6.15)

Note

There are other fourth-order Runge-Kutta methods with different coefficients.

MATLAB has many numerical integrators. They are designed to integrate over any interval. Some, such as ode113, adjust the step size and the order of the integration (Euler is first-order, the preceding Runge-Kutta is fourth-order), between the desired interval. For digital control, you need to integrate between the step size of the digital controller. You could use ode113 for this, but usually the fourth-order Runge-Kutta is sufficient. This method is used for all of the examples in this book.

You next want to look at the RungeKutta function that implements equation 6.14. Note the use of feval to evaluate the right-hand-side function in the following code.

function x = RungeKutta( Fun, t, x, h, varargin )

hO2 = 0.5*h;

tPHO2 = t + hO2;

k1 = feval ( Fun, t, x, varargin{:} );

k2 = feval ( Fun, tPHO2, x + hO2*k1, varargin{:} );

k3 = feval ( Fun, tPHO2, x + hO2*k2, varargin{:} );

k4 = feval ( Fun, t+h, x + h*k3, varargin{:} );

x = x + h*(k1 + 2*(k2+k3) + k4)/6;

Fun is a pointer to the right-hand-side function. varargin is passed to that function, which enables the dynamics model to have any number of parameters. This RungeKutta function is used in all of the examples in this book. You precompute all values that are used multiple times, such as 
$$ t+frac{h}{2} $$
. This is particularly important in functions that are called repeatedly.

You pass this function a handle to the right-hand-side function, RHSDoubleIntegrator, which implements equation 6.1.

Tip

Replace unused variables in function calls with the tilde.

In order to integrate the model one step, you call

xNew = RungeKutta( @RHSDoubleIntegrator, ∼, x, h, a )

Our RungeKutta function, and all MATLAB integrators, have the dependent variable first, which is t in this case. Since it isn’t used here, you replace it with the tilde. MATLAB’s code analyzer will suggest this for efficiency for all unused function inputs and outputs in your code.

6.3 Implement a Discrete Proportional-Derivative Controller

Problem

You want digital control software that can control a double integrator system and other dynamical systems.

Solution

You will derive the equations for a damped second-order system in the time domain and then create a sampled data version and implement it a MATLAB function.

How It Works

If a constant force F is applied to the system, the mass m will accelerate and its position will change with the square of time. The analytical solution for the two states, r and υ, is

$$ r(t)=r(0)+upsilon (0)left(t-t(0)
ight)+frac{1}{2}frac{F}{m}{left(t-t(0)
ight)}^2 $$
(6.16)

$$ upsilon (t)=upsilon (0)+frac{F}{m}left(t-t(0)
ight) $$
(6.17)

If you wish to have the position of mass stay close to zero, you can use a control system known as a regulator. You will use a proportional-derivative regulator. This regulator measures position and applies a control force proportional to the position error and to the derivative of the position error. Let’s look at a particularly simple form of this control:

$$ {F}_c=-{k}_rr-{k}_{upsilon}upsilon $$
(6.18)

F c is the control force. You don’t have to be able to measure the disturbance force, F, for this to work. Picking the gains, k r and k υ , is easy if you write the dynamical system as a second-order system:

$$ mddot{r}={F}_c+F $$
(6.19)

$$ mddot{r}=F-{k}_rr-{k}_{upsilon}upsilon $$
(6.20)

$$ mddot{r}+{k}_{upsilon}dot{r}+{k}_rr=F $$
(6.21)

The controlled system is a damped second-order oscillator. You can write the desired differential equation as 
$$ ddot{r}+2zeta sigma dot{r}+{sigma}^2r=frac{F}{m} $$
(6.22)
where the gains are 
$$ {k}_r=m{sigma}^2 $$
(6.23)

$$ {k}_{upsilon }=mzeta sigma $$
(6.24)
σ is the undamped natural frequency and ζ is the damping ratio. This system will always be stable as long as the gains are positive. If F if constant the position will settle to an offset. This is

$$ r=frac{F}{m{sigma}^2} $$
(6.25)

This method of control design is called “pole-placement”.

Virtually all control systems are implemented on digital computers, so you must transform this controller into a digital form. Assume that you only measure position. The first step is to assemble the control in a continuous time state space form. For this implementation, you add a rate filter to the PD controller. 
$$ omega ={omega}_r+2zeta {omega}_n $$
(6.26)

$$ k={omega}_r{omega}_n^2*m/w $$
(6.27)

$$ 	au =left(frac{m}{k}{omega}_nleft({omega}_n+2zeta {omega}_r
ight)-1
ight)/omega $$
(6.28)

$$ a=-omega $$
(6.29)

$$ b=omega $$
(6.30)

$$ c=-komega 	au $$
(6.31)

$$ d=k*left(	au omega +1
ight) $$
(6.32)
where ω r is the cutoff frequency for the first-order filter on the rate term; ω n is the undamped natural frequency for the controller; and ζ is the controller damping ratio. m is the “mass” or inertia. You can always set this to 1 and scale the control output. The undamped natural frequency gives the bandwidth of the controller. The higher the bandwidth, the faster it responds to errors. The higher the bandwidth, the smaller the offset error will be due to a constant input.

$$ dot{x}= ax+bu $$
(6.33)

$$ y=-cx-du $$
(6.34)
x is the controller state and u is the position measurement. The state space form is convenient for computation but still assumes that you are sampling continuously. There are many ways to convert this to digital form. You will use a zero-order-hold, meaning you will compute the control each sample and hold the value over that sample period. You convert this using the matrix exponential function in MATLAB, expm. If T is the sample period, you assemble the matrix

$$ sigma =left[egin{array}{ll}aThfill & bThfill \ {}0hfill & 0hfill end{array}
ight] $$
(6.35)

The sampled time versions of a and b are

$$ left[egin{array}{r}hfill {a}_d\ {}hfill {b}_dend{array}
ight]={e}^{sigma } $$
(6.36)

The digital controller is now 
$$ {x}_{k+1}={a}_d{x}_k+{b}_d{u}_k $$
(6.37)

$$ {y}_k=-c{x}_k-d{u}_k $$
(6.38)

Let’s now look at PDControl. This function designs and implements the control system derived in equation 6.26. The name stands for Proportional-Derivative Control. It has several child functions. The header is shown below. It has a link to the help for one of the subfunctions, which is active when the header is displayed at the command line. You list each data structure field for the input and output.

%% PDCONTROL Design and implement a PD Controller in sampled time .

%% Forms

% d = PDControl ( ' struct ' )

% d = PDControl ( ' initialize ', d )

% [ y , d ] = PDControl ( ' update ', u , d )

%

%% Description

% Designs a PD controller and implements it in discrete form .

%

% y = -c*x - d*u

% x = a*x + b*u

%

% where u is the input and y is the output. This controller has a first

% order rate filter on the derivative term.

%

% Set the mode to initialize to create the state space matrices for the

% controller. Set the mode to update to update the controller and get a

% new output.

%

% Utilizes the subfunction C2DZOH to discretize, see <a href="matlab: help PDControl>

CToDZOH">CToDZOH help</a>

%

%% Inputs

% mode (1,1) ' initialize ' or ' update '

% u (1,1) Measurement

% d (.) Data structure

% .m (1,1) Mass

% .zeta (1,1) Damping ratio

% .wN (1,1) Undamped natural frequency

% .wD (1,1) Derivative term filter cutoff

% .tSamp (1,1) Sampling period*

% .x (1,1) Controller state

%

%% Outputs

% y (1,1) Control

% d (.) Data structure additions

% .a (1,1) State transition matrix

% .b (1,1) Input matrix

% .c (1,1) State output matrix

% .d (1,1) Feedthrough matrix

% .x (1,1) Updated controller state

Next, the body of the function. Note the switch statement and the two child functions, CToDZOH and DefaultStruct, at the bottom.

function [y, d] = PDControl( mode, u, d )

% Demo

if ( nargin < 1 )

disp ('DemoofPDControlusingthedefaultstruct')

d = PDControl('struct');

d = PDControl('initialize',d);

disp (d)

return

end

switch lower (mode)

case 'initialize'

d = u;

w = d.wD + 2*d.zeta*d.wN;

k = d.wD*d.wNˆ2*d.m/w;

tau = ((d.m/k)*d.wN*(d.wN + 2*d.zeta*d.wD) - 1 )/w;

d.a = -w;

d.b = w;

d.c = -k*w*tau;

d.d = k*(tau*w + 1);

[d.a, d.b] = CToDZOH(d.a,d.b,d.tSamp);

y = d;

case 'update'

y = -d.c*d.x - d.d*u;

d.x = d.a*d.x + d.b*u;

case 'struct'

y = DefaultStruct;

otherwise

error ('%sisnotavalidmode',mode);

end

function [f, g] = CToDZOH( a, b, T )

%% CToDZOH

% Continuous to discrete transformation using a zero order hold. Discretize

% using a matrix exponential , < matlab:doc (' expm ') expm >.

%

% [f, g] = C2DZOH( a, b, T )

%

% * Inputs *

%

% a (1,1) Continuous plant matrix

% b (1,1) Input matrix

% T (1,1) Time step

%

% * Outputs *

%

% f (1,1) Discrete plant

% g (1,1) Discrete input

%

% See also

% expm

q = expm ([a*T b*T; zeros (1,2)]);

f = q(1,1);

g = q(1,2);

function d = DefaultStruct

d.m = 1.0;

d.zeta = 0.7;

d.wN = 0.1;

d.wD = 0.5;

d.tSamp = 1.0;

d.x = 0.0;

d.a = [];

d.b = [];

d.c = [];

d.d = [];

This is our standard format for an engineering function. The following are its important features:

  • It combines design and implementation in one function.

  • It returns the default data structure that it uses.

  • It has modes.

  • It has a built-in demo.

  • It has nested functions.

The built-in demo uses the default values. The default values give the user an idea of reasonable parameters for the function. This built-in demo generates the state space matrices, which are scalars in this case.

Demo of PDControl using the default struct

m: 1

zeta: 0.7000

wN: 0.1000

wD: 0.5000

tSamp: 1

x: 0

a: 0.5273

b: 0.4727

c: -0.0722

d: 0.0800

A more elaborate demo, with a simulation, could have been added. The built-in demos are very useful because they show the user a simple example of how to use the function. It also is helpful in developing the function, because you can test the function by just typing the function name in the command line.

The first argument is the mode variable that indicates which case in the switch statement the function should execute. The “initialize” mode must always be run first. The initialization modifies the data structure, which is used as the function’s memory. You could also have used persistent variables for the function memory. Using an output makes it easier to programmatically inspect the contents of memory. The “update” is used to update the controller as new inputs arrive. The switch statement has an “otherwise” case to warn the user of mode errors. This throws an error, stopping execution of the script. You may not always want to do this and may just use a warning to warn the user.

The nested function CToDZOHconverts the continuous control system to a sampled-data control system using equation 6.35. The name stands for Continuous to Discrete Zero-Order Hold. A non-controls expert wouldn’t immediately understand the acronym, but the expanded name is too long to be a useful function name.

Tip

Make function names consistent in form and use terms that are standard for your field. Remember that not all readers of your code will be native English-language speakers!

If you were building a toolbox, the CToDZOH function would likely be a separate file. For this book, it is only used by PDControl, so you put it into that function file.

6.4 Simulate the Double Integrator with Digital Control

Problem

You want to simulate digital control of the double integrator model.

Solution

You will write a script that calls the control function and integrator sequentially in a loop and plots the results.

How It Works

Table 6-1 presents the nominal values for the control parameters that you will use for the double integrator simulation.

Table 6-1. Control Parameters

Zeta

Damping ratio

1.0

wN

Undamped natural frequency

0.1 rad/sec

wD

Derivative term filter cutoff

1.0 rad/sec

dT

Time step

0.1 sec

The simulation script is implemented in DoubleIntegratorSim.m. Note the use of cell breaks to divide the script into sections that can be run independently. The “See also” section lists the functions used, which are links when the header is displayed via the command-line help.

%% Double Integrator Demo

% Demonstrate control of a double integrator .

%% See also

% PDControl, RungeKutta, RHSDoubleIntegrator, TimeLabel

%% Initialize

tEnd = 100; % Simulation end time (sec)

dT = 0.1; % Time step (sec)

aD = 1.0; % Disturbance acceleration (m/sˆ2)

controlIsOn = false; % True if the controller is to be used

x = [0;0]; % [position;velocity]

% Controller parameters

d = PDControl( 'struct' );

d.zeta = 1.0;

d.wN = 0.1;

d.wD = 1.0;

d.tSamp = dT;

d = PDControl( 'initialize', d );

%% Simulation

nSim = tEnd/dT+1;

xPlot = zeros (3,nSim);

for k = 1:nSim

if ( controlIsOn )

[u, d] = PDControl('update',x(1),d);

else

u = 0;

end

xPlot(:,k) = [x;u];

x = RungeKutta( 'RHSDoubleIntegrator', 0, x, dT, aD+u );

end

%% Plot the results

yL = {'r(m)' 'v(m/s)' 'u(m/sˆ2)'};

[t,tL] = TimeLabel(dT*(0:(nSim-1)));

PlotSet( t, xPlot, 'x⊔label', tL, 'y⊔label', yL );

The first code block sets up simulation parameters that the user can change. The controlIsOn variable is set to true if the controller is to be used. This makes it easy to test the script without the controller. When the controller is disabled, you get the “open loop” response. It is a good idea to make sure that the open-loop response makes sense before testing the controller.

Tip

Put all parameters that the user can change at the beginning of the script.

The second block sets up the controller. Recall that PDControl has three arguments: 'struct' 'initialize', 'update'. The first returns the data structure required by the function. You fill the structure fields with the values selected for the problem in the lines that follow that statement. At the end of this block, you initialize the controller. This sets the controller state to zero and creates the sampled time state space matrices, which in this case are four scalars.

The third block is the simulation with the check to see if the controller is on. Note the sequential use of the control function followed by the integrator. This is discrete control because the control, u, is constant over the integration time step. The final block plots the results.

Figure 6-1 shows the open-loop response obtained by setting the controlIsOn flag to false and executing DoubleIntegratorSim. The velocity increases linearly and the position increases with the square of time, as it should. The output agrees with the analytical solution in equation 6.16. Figure 6-2 shows the closed-loop response, with controlIsOn set to true. The velocity goes to zero and the position reaches a constant, though not zero. The control acceleration u exactly matches the disturbance acceleration a. You could have eliminated the position offset by using a proportional integral differential (PID) controller.

A335353_1_En_6_Fig1_HTML.gif
Figure 6-1. The open-loop response with a constant disturbance acceleration of 1 m/s2
A335353_1_En_6_Fig2_HTML.gif
Figure 6-2. The closed-loop response with a constant disturbance acceleration of 1 m/s2

The two examples show that the simulation works without the control and that the control performs as expected. This script is an integrated test of all of the functions listed in the header. It does a good job of testing their functionality. However, one test isn’t sufficient to understand the controller. Let’s make the controller underdamped by setting ζ in the field d.zeta, to 0.2. Now the response oscillates (see Figure 6-3). You set tEnd to 300 to show that it damps.

A335353_1_En_6_Fig3_HTML.gif
Figure 6-3. The closed-loop response with a constant disturbance acceleration of 1 m/s2 and ζ equal to 0.2

Another thing to try is setting the bandwidth really high. Set ω n , in field d.wN, to 8, and the rate filter bandwidth d.wD to 50. The result is shown in Figure 6-4. The controller is unstable because the bandwidth is much higher than that allowed by the sampling rate.

A335353_1_En_6_Fig4_HTML.gif
Figure 6-4. The closed-loop response using a bandwidth too high for the sampling

Your bandwidth has to be less than half the sampling bandwidth, which is 
$$ {omega}_s=frac{2pi }{T} $$
(6.39)

All the results are expected behavior. The last case is what is known as an edge or corner case that shows that the expected instability does happen. These four cases are a minimalist set of tests for this admittedly simple control system example.

6.5 Create Time Axes with Reasonable Time Units

Problem

You want your time axes to have easy-to-read units, not just seconds.

Solution

You will create a function that checks the duration and converts from seconds to minutes, hours, days, or years.

How It Works

You check the maximum time in the array of times and scale it to larger time units. The time units implemented are seconds, minutes, hours, days, and years. You return the scaled time vector, the label string, and the units string, as it might be useful.

function [t, c, s] = TimeLabel( t )

secInYear = 365.25*86400;

secInDay = 86400;

secInHour = 3600;

secInMinute = 60;

tMax = max (t);

if ( tMax > secInYear )

c = 'Time⊔(years)';

s = 'years';

t = t/secInYear;

elseif ( tMax > 3*secInDay )

c = 'Time⊔(days)';

t = t/secInDay;

s = 'days';

elseif ( tMax > 3*secInHour )

c = 'Time(hours)';

t = t/secInHour;

s = 'hours';

elseif ( tMax > 3*secInMinute )

c = 'Time(min)';

t = t/secInMinute;

s = 'min';

else

c = 'Time(sec)';

s = 'sec';

end

6.6 Create Figures with Multiple Subplots

Problem

You frequently generate figures with multiple subplots during control analysis, and this results in large blocks of repetitive code at the bottom of every script.

Solution

You make a function that can easily generate subplots with a single line.

How It Works

You will write a function that uses parameter pairs to flexibly create subplot figures in a single function call. The y input can have multiple rows, and the x input can have one row or the same number of rows as y. You supply default labels so that the function can be called with just two inputs.

The only parameters supported in this version are various labels and the plot type—standard plot, semilogx, semilogy, and loglog—but you can easily add functionality for line thickness, plot markers, shading, and so forth. You use a for loop to check every other component of varargin in a switch statement. Remember that varargin provides a cell array of arguments.

Note the use of a built-in demo showing both main branches of the function, for one x series and for two.

The plotting code creates subplots in the figure for each plot based on the number of rows in x and y. This function assumes the subplots are in a single column, but you could extend the logic to create multiple columns or any arrangement of subplots that suits your application. The grid is turned on.

function PlotSet( x, y, varargin )

% Demo

%-----

if ( nargin < 1 )

x = linspace (1,1000);

y = [ sin (0.01*x); cos (0.01*x)];

disp ('PlotSet:Onexandtwoyrows')

PlotSet( x, y )

disp ('PlotSet:Twoxandtwoyrows')

PlotSet( [x;y(1,:)], y )

return ;

end

% Defaults

nCol = 1;

n = size (x,1);

m = size (y,1);

yLabel = cell (1,m);

xLabel = cell (1,n);

plotTitle = cell (1,n);

for k = 1:m

yLabel{k} = 'y';

end

for k = 1:n

xLabel{k} = 'x';

plotTitle{k} = 'yvs.x';

end

figTitle = 'PlotSet';

plotType = 'plot';

% Handle input parameters

for k = 1:2: length (varargin)

switch lower (varargin{k} )

case 'xlabel'

for j = 1:n

xLabel{j} = varargin{k+1};

end

case 'ylabel'

temp = varargin{k+1};

if ( ischar(temp) )

yLabel{1} = temp;

else

yLabel = temp;

end

case 'plottitle'

plotTitle{1} = varargin{k+1};

case 'figuretitle'

figTitle = varargin{k+1};

case 'plottype'

plotType = varargin{k+1};

otherwise

fprintf (1,'%sisnotanallowableparameter ',varargin{k});

end

end

h = figure ;

set (h,'Name',figTitle);

% First path is for just one row in x

if ( n == 1 )

for k = 1:m

subplot (m,nCol,k);

plotXY(x,y(k,:),plotType);

xlabel (xLabel{1});

ylabel (yLabel{k});

if ( k == 1 )

title (plotTitle{1})

end

grid on

end

else

for k = 1:n

subplot (n,nCol,k);

plotXY(x(k,:),y(k,:),plotType);

xlabel (xLabel{k});

ylabel (yLabel{k});

title (plotTitle{k})

grid on

end

end

%% Implement different plot types

function plotXY(x,y, type )

switch type

case 'plot'

plot (x,y);

case {'log' 'loglog' 'log⊔log'}

loglog (x,y);

case {'xlog' 'semilogx' 'x⊔log'}

semilogx (x,y);

case {'ylog' 'semilogy' 'y⊔log'}

semilogy (x,y);

otherwise

error ('%sisnotanavailableplottype', type );

end

This function allows DoubleIntegratorSim.m to generate its plots with one line of code.

Summary

The double integrator is a very useful model for developing control systems, as it represents an ideal version of many systems, such as a spring attached to a mass. In this chapter, you developed the mathematical model for the double integrator and wrote the dynamics in a right-hand-side function. You were introduced to numerical integration and wrote the Runge-Kutta integrator, which will be used throughout the remaining applications in this book. The recipe for the control function combines design and implementation, contains a built-in demo, and defines a data structure that is used for memory between calls. The first demo script showed how to initialize a controller for a double integrator, simulate it, and plot the results. Table 6-2 lists the code developed in the chapter. This is the basis for almost any mathematical or control analysis that you will do in MATLAB!

Table 6-2. Chapter Code Listing

File

Description

RHSDoubleIntegrator

Dynamical model for the double integrator.

RungeKutta

Fourth-order Runge-Kutta integrator.

PDControl

Proportional-derivative controller.

DoubleIntegratorSim

Simulation of the double integrator with discrete control.

PlotSet

Create two-dimensional plots from a data set.

TimeLabel

Produce time labels and scaled time vectors.

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

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