Department of Engineering

IT Services

Matlab by Example

This document attempts to introduce you to matlab by leading you through a useful task, stopping off for some sightseeing on the way. If instead you want a tutorial, then Mathworks' own is as good as any. Some other references are at the end of this document.

Suppose you have a text file of data - 3 numbers per line - from an experiment where values have been obtained at various 2D position. A typical text line is

    45 77 12.78

which means that at (45, 77) the value's 12.78. This example will show you how to

Read the values into Matlab

First download the data file into a file called data.txt. Start matlab and use cd to change directory (i.e. change what folder you're in) so that you're where the data file is. For example, if the file is in a folder called Downloads, type cd Download in Matlab

Type

  load data.txt

Typing

  whos

will show you that there's now a variable called data

Name Size Bytes Class Attributes data 106x3 2544 double

Type

  data

and you'll see the values. data is a matrix. In fact, just about everything in matlab is a matrix, so once you can create and manipulate them you're well on the way to mastering matlab.

Matrix creation

Here are some ways of creating matrices. Note that you don't have to explicitly create matrices before using them, and you needn't specify their sizes - they can grow on demand.

  • x=[2 6 7] - create a row vector
  • x=[x 8] - add another element to x
  • x=[2 ; 6 ; 7 ] - create a column vector
  • x=1:6 - create a vector with elements 1, 2, 3 ...6
  • x=1:0.5:6 - create a vector with elements 1, 1.5, 2, 2.5 ... 6
  • x=linspace(1,6,11) - create a row vector with 11 equally spaced elements running from 1 to 6
  • x=ones(4,5) - create a matrix full of 1s with 4 rows and 5 columns
  • x=1:3; y=4:6; z=[x y] - join 2 vectors
  • x=1:3; bigx=repmat(x, 2, 3) - replicate x twice vertically and 3 times horizontally

Matrix manipulation

Before we continue, let's try some matrix operations.

  • size(data) - gets the number of rows and columns. Note that it returns a matrix called ans. We could instead do
       s=size(data)
    
    to put the answer into s. Now s(1) (the 1st element in the array) will be 106 and s(2) will be 3. To suppress screen output, put a semi-colon on the end of the line.
  • data(:,1) - shows the 1st column. data(1,:) shows the 1st row. data(:) returns all the elements as a single column.
  • data2=data+5 - returns a new array whose elements are each 5 more than data's elements.
  • data+data2 - adds the matrices
  • data' - returns the transpose of data. Typing size(data') shows you the size of the transpose
  • data' * data - multiplies a 3x106 matrix by a 106x3 matrix to give a 3x3 matrix.
  • data.*data2 - (note the dot) multiplies each element in data by the corresponding element in data2. The matrices need to be the same size.

Matrix functions

Matlab has many functions. To find out more about a particular function, type help followed by the function name.

  • sum(data) - sums each column.
  • mean(data) - finds the mean of each column. mean(data(:)) would find the mean of the whole matrix (though that's not useful to us in this situation).
  • max(data) - finds the maximum number in each column

Eliminate outliers and duplicates

Any experimental data is likely to contain erroneous or duplicate data. Here we'd first like to eliminate duplicate rows. Whenever you want to find out how to do something and you can think up a keyword you can use lookfor. So

  lookfor duplicate

will look for routines whose descriptions mention "duplicate". Alas there are none. So let's try this

  lookfor unique

This displays several routines. Typing

  help unique

tells us the details. So type

  udata=unique(data,'rows');
 

to create a new matrix with unique rows. It also sorts the rows. Sometimes we don't want that, but it's ok here.

Let's suppose that all z data less than -5 is bogus. We'll set these values to 0. One way to do this would be to use a for loop checking each value much as in a language like Fortran. Here's the code to do that

[rows,cols]=size(udata) for i=1:rows if(udata(i,3) < -5) udata(i,3) = 0 end end

but there's a quicker way, using the find command.

  toosmall=find(udata < -5)

will return the locations of all the elements in udata(:) that are less than 5. Doing

  udata(toosmall)=0

will set all those elements to 5. We could do this all in one line

  udata(find(udata < -5))=0

udata should now have 101 rows.

Creating commands

Until now you've been typing commands on the matlab command line. If you put these commands into a file into a file (called mycommand.m, say - the suffix is important), then typing mycommand will run the commands in the file. Any text in the file to the right of a % character is ignored. From now on you might prefer to create a file, add new commands to it and run the file. Use clear to clear out variables before re-running. Use close to close all graphics windows. Everything so far could be done using the following file

% demo script clear; close; load data.txt; udata=unique(data,'rows'); udata(find(udata < -5))=0;

Much of Matlab is compiled code, though there are many *.m files too. If you type

  which load

(asking where the load command is) you'll see that load is built-in (it's compiled code) but

  which flipud

shows the location of flipud.m which you can look at by typing type flipud. It's only 4 lines of code - see if you can understand it.

Show the z values as a 2D surface

Let's first create some vectors to aid code legibility

xvalues=udata(:,1); yvalues=udata(:,2); zvalues=udata(:,3);

Matlab has several ways to plot 3D data. First try

   plot3(xvalues, yvalues, zvalues ,'.')

Note that plot3 (like nearly all matlab commands) can cope with vector arguments. The final '.' puts a dot at each data point.

The results aren't easy to visualize. We'd like a surface. For that we need to do more work because some of the more useful matlab commands require the data to be on a regular grid. You can prepare this data for use with the griddata command

% First define a regular grid.
% We'll set up a 20x20 grid
steps = linspace(-1,1, 20);
[XI,YI] = meshgrid(steps, steps);
% XI and YI will both be 20x20. XI contains the x-coords of each point 
% on this new grid, and YI contains the y-coords.

% now interpolate - find z values at each of these grid points
ZI = griddata(xvalues, yvalues, zvalues,XI, YI);

% Display this as a surface
surf(XI,YI,ZI);
hold on ; % this stops the next command clearing the graphics window
% plot the original data too
plot3(xvalues, yvalues, zvalues,'.')

You should get a figure like this

Note that during interpolation, matlab warned that the data contained lines that have different z values for the same (x,y) point. It used the mean z in such situations.

Find a best-fit mathematical function for the data

We might already have in mind a model for the data. For this data, the z values peak at (0.0) and seem to depend on x periodically, so I'm going to try to fit the data to a formula like this

  A1*sin(A2*x) + A3./sqrt(0.5+x.^2 + y.^2);

and I'd like to find constants A1, A2, and A3 such that the values of this expression are as close to z as possible. Matlab has several optimisation routines. I'm going to use lsqnonlin (which you might not have - see later). To use this we have to set the problem up appropriately. We need to specify initial conditions and an expression to minimize. The optimisation functions are rather technical, so I won't go into details - they're online.

a0=[10 10 10 ]; % initial conditions for A1, A2 and A3 - just a guess
% the next line uses 'anonymous functions'. It sets up a function f
% that takes a (containing A1, A2, A3) as input. 
% It's this function that will be minimized
f=@(a) a(1)*sin(a(2)*XI) + a(3)./(0.5+sqrt(XI.^2+YI.^2)) -ZI;

% here we can choose options for the optimisation routine.
options=optimset('Display','iter');
% now we optimise. The returned af vector will contain the A1, A2, and A3 we want
af=lsqnonlin(f,a0,[],[], options)

When I run this I get

af = 3.2388 10.0295 7.6435

Is this a good fit? Let's see

Ztheoretical= af(1) * sin(af(2)*XI) + af(3)./(0.5 + sqrt(XI.^2+YI.^2));
max(Ztheoretical(:)-ZI(:))
mean(Ztheoretical(:)-ZI(:)) 

Let's also see this visually. We'll add the theoretical results as a grid. We'll also add titles, and save the result in a jpeg file.

 close; % clear the graphics
 surf(XI,YI,Ztheoretical);
 title('best fit');
 xlabel('x');
 ylabel('y'); 
 colorbar; % add a color-coded key to z values
 print -djpeg -zbuffer demo1.jpg

The result should be something like this

which isn't a perfect fit, but there was noise in the data.

Handle Graphics

We've been changing the figure using commands. We could also have used the menus to change many of these properties. Underlying both of these methods is a third, more direct way. Each part of the figure and the graphs in them has a unique identity number (its "handle") with a set of properties. Type

   get(gca)

and you'll get the list of properties for the current axes. To change any feature you can get its handle then use the set command to change a property. For example, to change the title we can use

   titlehandle=get(gca,'Title');
   set(titlehandle,'FontSize',20);

Toolboxes

Matlab has many add-ons called Toolboxes. lsqnonlin belongs to the Optimisation Toolbox. If you haven't paid for it, you won't have it. Typing

  ver

will show you what's installed, though even if a toolbox is listed, you may not be able to run its routines (the license may have expired, for example).

Fortunately, there are many add-ons that are free. The MATLAB Central: File Exchange has thousands of files to download.

Save the resulting data

Suppose we wanted to store the cleaned, interpolated values in XI, ZI, and ZI. We could do save XI YI ZI 'newdata.txt' but that would save all the elements in the matrices. If we wanted to save in a file with the same form as the original we need to use lower level commands which are like those of the C language.

fp=fopen('newdata.txt','w');
   [rows,cols]=size(XI);
   for i=1:rows
      for j=1:cols
        fprint('%f %f %f \n', XI(i,j), YI(i,j) Ztheoretical(i,j);
      end
   end
fclose(fp);

Make a movie

A figure can be saved into a 'frame' and the frames put together to make a movie. In the code below the viewpoint is changed for each frame. I've forced each frame to be the same size (436 by 344) because otherwise it's hard to make a movie from them.

i=1;
for az=0:-10:-90
 a=viewmtx(az, 30, 60+(az/2));
 view(a);
 M(i)=getframe(gcf,[0 0 436 344]);
 i=i+1;
end
viewmovie(M);

Octave

octave is free, and is similar to Matlab. The code in this example works on linux with octave 3.0.0 until the griddata line. With a different operating system, a newer version of Octave, or extra Octave modules you may have more luck!

References