| |
|
7.3 Assignment Solutions - Lecture 7
|
We begin with the first task of including regen braking. This requires us to change only one line from
exercise_terrain. Instead of keeping the cumulative energy level Ecsum the same in case angle alpha < 0, we merely add the amount of energy that would have been required by travelling at the opposite angle. We must also multiply the amount of energy by the efficiency value effoverall. The statement in exercise_terrain was:
else Ecsum(:, i + 1) = Ecsum end
We change this statement to:
else Ecsum(:, i + 1) = Ecsum(:, i) + (dE(:, i) * effoverall) end
|
|
Figure 7.27 Click to enlarge
|
|
|
We can now run the assignment in the
Command Window.
The resulting graph has a few parts in which the cumulative energy level increases somewhat - these parts correspond to the downhill motion in which energy is regained.
|
|
Figure 7.28 Click to enlarge
|
|
We now begin changing the code from computing a vector of results (distance travelled) to computing a matrix of results (distance travelled per weight of rider). We will have to make several changes throughout the m-file, most of which deal with converting a computation of a scalar to a computation of a vector. The advantageous aspect of this is that an operation of a scalar and a scaler is not too different from an operation of a scalar and a vector. Thus, we don't have to worry about changing the equations at all.
|
First, we need to define the vector of weights:
mrider = [40:1:110]
|
|
Figure 7.29 Click to enlarge
|
|
The block of code that computes angles for the specified terrain does not change. After all, the terrain remains the same regardless of weight.
|
Since the energy level depends on the weight of the rider, we will need to change the next block of code. The computation of Torque and
Pmech effective remains the same, because the operations work for both scalars and vectors.
The resulting vector, however, needs to be stored in the matrix dE. Before we stored a scalar in each column of a vector (remember that a vector is a single row matrix). Now, we would like to store each result vector in a column of the matrix, where each column represents values for each different weight of the rider. To address a column in a matrix, we use the notation
A(:, c), where A is the matrix, c is the column of the matrix, and : denotes that we are not addressing all rows. The code changes from:
dE(i) = Pmech effective * ds(i) / vkmh2msec(vconst) * (1 / effoverall)
to:
dE(:, i) = (Pmech effective * ds(i) / vkmh2msec(vconst) * (1 / effoverall))'
Note that we are transposing the result vector using the single quote
' operator. Without transposing, the result is a vector (a row), but we instead require a column. Hence we transpose the row.
|
|
Figure 7.30 Click to enlarge
|
|
|
We previously initialized an empty array for the results of cumulative energy level Ecsum. This definition remains the same. We also set the first element of the array to be the energy level of a fully charged battery:
Ecsum(1) = Ebatteries total
Because our result is now a matrix, in which every row accounts for a different weight of the rider, we need to initialize a matrix. Since at the very beginning, every rider starts out with the same amount of energy in their Segway's batteries, we need to initialize the first column (previously the first element) of the matrix with the initial energy level:
for i=1:length(mrider) Ecsum = [Ecsum; Ebatteries total] end
|
|
Figure 7.31 Click to enlarge
|
|
|
We continue changing the next block of code in a similar fashion. We now only need to add the notation for addressing columns in the matrices of
Ecsum and dE. The code changes on two lines from:
Ecsum(i + 1) = Ecsum(i) - dE(i) Ecsum(i + 1) = Ecsum(i) + (dE(i) * effoverall)
to:
Ecsum(:, i + 1) = Ecsum(:, i) - dE(:, i) Ecsum(:, i + 1) = Ecsum(:, i) + (dE(:, i) * effoverall)
|
|
Figure 7.32 Click to enlarge
|
|
|
Instead of using function
plot to plot a 2D graph, we now use mesh to plot the 3D graph:
mesh(x, mrider, Ecsum), xlabel('Distance in meters'), ylabel('Weight of rider in kg'), zlabel('Energy left in batteries')
|
|
Figure 7.33 Click to enlarge
|
|
|
The result is a step-like surface denoting the energy levels for the various weights and distances travelled.
|
|
Figure 7.34 Click to enlarge
|
|
|
While not required, you may wish to plot a plane at the z=0, which corresponds to an energy level of 0. This would help in distinguishing the two states of energy levels. A plane at z=0 is represented by a matrix of zeros, which must have the same dimensions as the matrix of results. We use function
zeros to initialize a matrix of this kind:
zeroplane = zeros(length(mrider), length(x))
To plot 2 or more graphs in the same window, we use the command
hold on
between all pairs of plots:
mesh(x, mrider, Ecsum), xlabel('Distance in meters'), ylabel('Weight of rider in kg'), zlabel('Energy left in batteries') hold on mesh(x, mrider, zeroplane)
|
|
Figure 7.35 Click to enlarge
|
|
|
The resulting graph includes 2 meshes. However, the plane is not very distinct in color.
|
|
Figure 7.36 Click to enlarge
|
|
|
To change the color of the plane, we can issue the
mesh function with 4 instead of 3 arguments. The 4th argument is a matrix with dimensions of the result matrix, whose values set the color scheme used for the mesh. The color scheme is a scale that corresponds in index values to the result from the first mesh. We note that values below 0 are drawn in dark blue colors, while values above 0 are drawn in light colors. In order to set the color of the plane to be darker, we need to some low value below 0, which corresponds to the lowest value in the previous graph. We merely use the zero matrix and subtract some large value from it (1000000), in order to obtain a dark color. The value of 1000000 was experimentally derived:
mesh(x, mrider, zeroplane - 1000000)
|
|
Figure 7.37 Click to enlarge
|
|
|
The result is much easier to look at and better distinguishable.
|
|
Figure 7.38 Click to enlarge
|
|
|
Finally, we compute the values of distance at which the energy level becomes 0. Instead of printing out the verbal response for each weight value, we print out a table.
First, we initialize the result vector:
distempty = []
|
|
Figure 7.39 Click to enlarge
|
|
|
We now encapsulate the previous
while loop in another loop, which iterates over the different weights of the rider. The statement
while (i <= n) end
becomes:
for m=1:length(mrider) while (i <= n) end end
|
|
Figure 7.40 Click to enlarge
|
|
|
The previously used
Ecsum(i) pointed to a scalar. In our changed version, it now points to a vector. However, we still need to work with a scalar, as the computation for exhaustive energy level requires us to look at each individual element of Ecsum. Since Ecsum is now a matrix, we need to address an element by row and column as Ecsum(m, i), where m is the index for weight, and i is the index for cumulative energy level. The code changes on two lines from:
if (Ecsum(i) < 0) xcross = interp1([Ecsum(i - 1), Ecsum(i)], [x(i - 1), x(i)], 0)
to:
if (Ecsum(m, i) < 0) xcross = interp1([Ecsum(m, i - 1), Ecsum(m, i)], [x(i - 1), x(i)], 0)
We also put the result into the results vector distempty:
distempty(m) = dtravelled
|
|
Figure 7.41 Click to enlarge
|
|
|
Finally we print out the results using function
disp:
disp('Weight of rider Distance after which batteries are empty') disp([mrider; distempty]');
Note that mrider and distempty are vectors that are combined in a matrix of 2 rows and N many columns. We transpose this matrix using the quote ' operator to obtain a matrix of N rows and 2 columns.
|
|
Figure 7.42 Click to enlarge
|
|
|
Looking at the results, we notice that below a weight of 48kg, the results are 0. This is due to the fact that the energy has not been exhausted on the modelled terrain for riders with such low weights. We can append a few more kilometer intervals to the terrain in order to obtain more useful data.
|
|
Figure 7.43 Click to enlarge
|
|
|
|