Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
You'll log on or invoke MATLAB, do a few trivial calculations and log off. Launch MATLAB. You can start it from your Start Menu, as any other Windows-based program. You see now something similar to this Figure:
The History Window is where you see all the already typed commands. You can scroll through this list. The Workspace Window is where you can see the current variables. The Comand Window is your main action window. You can type your commands here. At the top of the window, you can see your current directory. You can change it to start a new project. Once the command window is on screen, you are ready to carry out this first lesson. Some commands and their output are shown below. Enter 5+2 and hit the enter key. Note that the result of an unassigned expression is saved in the default variable 'ans'. >> 5+2 ans =
7 >> The '>>' sign means that MATLAB is ready and waiting for your input. You can also assign the value of an expression to a variable. >> z=4 z= 4 >> A semicolon (at the end of your command) suppresses screen output for that instruction. MATLAB remembers your variables, though. You can recall the value of x by simply typing x >> x=4; >> x x= 4 >> MATLAB knows trigonometry. Here is the cosine of 6 (default angles are in radians). >> a=cos(6) a= 0.9602 >> The floating point output display is controlled by the 'format' command. Here are two examples. >> format long >> a a= 0.96017028665037
>> format short >> a a= 0.9602 >> Well done! Close MATLAB (log off). You can also quit by selecting 'Exit MATLAB' from the file menu.
Tutorial Lesson: Vector Algebra (Algebra with many numbers, all at once...)
You'll learn to create arrays and vectors, and how to perform algebra and trigonometric operations on them. This is called Vector Algebra. An array is an arbitrary list of numbers or expressions arranged in horizontal rows and vertical columns. When an array has only one row or column, it is called a vector. An array with m rows and n columns is a called a matrix of size m x n. Launch MATLAB and reproduce the following information. You type only what you see right after the '>>' sign. MATLAB confirms what you enter, or gives an answer. Let x be a row vector with 3 elements (spaces determine different columns). Start your vectors with '[' and end them with ']'. >> x=[3 4 5] x= 3 >> Let y be a column vector with 3 elements (use the ';' sign to separate each row). MATLAB confirms this column vector. >> y=[3; 4; 5] y= 3 4 5 4 5
>> You can add or subtract vectors of the same size: >> x+x ans = 6 >> y+y ans = 6 8 10 >> You cannot add/subtract a row to/from a column (Matlab indicates the error). For example: >> x+y ??? Error using ==> plus Matrix dimensions must agree. You can multiply or divide element-by-element of same-sized vectors (using the '.*' or './' operators) and assign the result to a different variable vector: >> x.*x ans = 9 16 25 8 10
>> b=x./[7 6 5] b=
0.4286 >>
0.6667
1.0000
Multiplying (or dividing) a vector with (or by) a scalar does not need any special operator (you can use just '*' or '/'): >> c=3*x c= 9 12 15
>> d=y/2 d= 1.5000 2.0000 2.5000 >> The instruction 'linspace' creates a vector with some elements linearly spaced between your initial and final specified numbers, for example: r = linspace(initial_number, final_number, number_of_elements) >> r=linspace(2,6,5) r= 2 >> or >> r=linspace(2,3,4) r= 2.0000 >> Trigonometric functions (sin, cos, tan...) and math functions (sqrt, log, exp...) operate on vectors element-by-element (angles are in radians). >> sqrt(r) ans = 2.3333 2.6667 3.0000 3 4 5 6
1.5275
1.6330
1.7321
-0.6908
-0.8893
-0.9900
Well done! So far, so good? Experimenting with numbers, vectors and matrices is good for you and it does not hurt! Go on!
>> ylabel('y') >> xlabel('x') Gridding the plot is always optional but valuable: >> grid on You now see the figure:
The 'print' command sends the current plot to the printer connected to your computer: >> print The arguments of the axis, title, xlabel, and ylabel commands are text strings. Text strings are entered within single quotes ('). Do you like your plot? Interesting and funny, isn't it?
Tutorial Lesson: Matlab Code (Creating, Saving, and Executing a Script File)
You'll learn to create Script files (MATLAB code) and execute them. A Script File is a user-created file with a sequence of MATLAB commands in it. You're actually creating MATLAB code, here. The file must be saved with a ' .m' extension, thereby, making it an m-file. The code is executed by typing its file name (without the '.m' extension') at the command prompt.
Now you'll write a script file to draw the unit circle of Tutorial Lesson 3. You are esentially going to write the same commands in a file, save it, name it, and execute it within MATLAB. Follow these directions: Create a new file. On PCs, select 'New' -> 'M-File' from the File menu, or use the related icons.
A new edit window appears. Type the following lines into this window. Lines starting with a '%' sign are interpreted as comments and are ignored by MATLAB, but are very useful for you, because then you can explain the meaning of the instructions.
% CIRCLE - A script file to draw a pretty circle angle = linspace(0, 2*pi, 360); x = cos(angle); y = sin(angle); plot(x,y) axis('equal') ylabel('y') xlabel('x') title('Pretty Circle') grid on
Write and save the file under the name 'prettycircle.m'. On PCs select 'Save As...' from the File menu. A dialog box appears. Type the name of the document as prettycircle.m. Make sure the file is being saved in the folder you want it to be in (the current working folder / directory of MATLAB). Click on the 'Save' icon to save the file. Now go back to the MATLAB command window and type the following command to execute the script file. >>prettycircle
And you achieve the same 2D plot that you achieved in Tutorial Lesson 3, but the difference is that you saved all the instructions in a file that can be accessed and run by other m-files! It's like having a custom-made code! You're doing great!
function [x, y] = prettycirclefn(r) % CIRCLE - A script file to draw a pretty circle % Input: r = specified radius
% Output: [x, y] = the x and y coordinates angle = linspace(0, 2*pi, 360); x = r * cos(angle); y = r * sin(angle); plot(x,y) axis('equal') ylabel('y') xlabel('x') title(['Radius r =',num2str(r)]) grid on
Now, write and save the file under the name prettycirclefn.m as follows: On PCs, select 'Save As...' from the 'File' menu. A dialog box appears. Type the name of the document as prettycirclefn. Make sure the file is saved in the folder you want (the current working folder/directory of MATLAB). Click on the ' Save' icon to save the file. In the command window write the following: >> prettycirclefn(5); and you get the following figure (see the title):
Then, try the following: >> radius=3; >> prettycirclefn(radius); >> and now you get a circle with radius = 3 Notice that a function file must begin with a function definition line. In this case is
function [x, y] = prettycirclefn(r), where you define the input variables and the output ones. The argument of the 'title' command in this function file is a combination of a fixed part that never changes (the string 'Radius r= '), and a variable part that depends on the argumments passed on to the function, and that converts a number into a string (instruction 'num2str'). You can generate now a circle with an arbitrary radius, and that radius can be assigned to a variable that is used by your MATLAB program or function! Great!
Polynomials
Polynomials are used so commonly in algebra, geometry and math in general that Matlab has special commands to deal with them. The polynomial 2x4 + 3x3 10x2 11x + 22 is represented in Matlab by the array [2, 3, -10, -11, 22] (coefficients of the polynomial starting with the highest power and ending with the constant term). If any power is missing from the polynomial its coefficient must appear in the array as a zero. Here are some examples of the things that Matlab can do with polynomials. I suggest you experiment with the code
Roots of a Polynomial
% Find roots of polynomial p = [1, 2, -13, -14, 24]; r = roots(p) % Plot the same polynomial (range -5 to 5) to see its roots x = -5 : 0.1 : 5; f = polyval(p,x); plot(x,f) grid on
Multiply Polynomials
The command conv multiplies two polynomial coefficient arrays and returns the coefficient array of their product:
a = [1 2 1]; b = [2 -2]; c = conv(a,b)
Look (and try) carefully this result and make sure its correct.
Divide Polynomials
Matlab can do it with the command deconv, giving you the quotient and the remainder (as in synthetic division). For example:
% % a b a b = = = 2x^3 + 2x^2 - 2x - 2 = 2x - 2 [2 2 -2 -2]; [2 -2];
% now divide b into a finding the quotient and remainder [q, r] = deconv(a,b)
You find quotient q = [1 2 1] (q = x2 + 2x + 1), and remainder r = [0 0 0 0] (r = 0), meaning that the division is exact, as expected from the example in the multiplication section
First Derivative
Matlab can take a polynomial array and return the array of its derivative:
a = [2 2 -2 -2] ap = polyder(a)
If you have some data in the form of arrays (x, y), Matlab can do a least-squares fit of a polynomial of any order you choose to this data. In this example we will let the data be the cosine function between 0 and pi (in 0.01 steps) and well fit a polynomial of order 4 to it. Then well plot the two functions on the same figure to see how good were doing.
clear; clc; close all x = 0 : 0.01 : pi; % make a cosine function with 2% random error on it f = cos(x) + 0.02 * rand(1, length(x)); % fit to the data p = polyfit(x, f, 4); % evaluate the fit g = polyval(p,x); % plot data and fit together plot(x, f,'r:', x, g,'b-.') legend('noisy data', 'fit') grid on
Got it?
To code this formula: , you can write the following instruction in the Matlab command window (or within an m-file): >> 5^3/(2^4+1) ans = 7.3529 >>
To compute this formula: , you can always break down the commands and simplify the code (a final value can be achieved in several ways). >>numerator = 3 * (sqrt(4) - 2) numerator = 0 >>denominator = (sqrt(3) + 1)^2 denominator = 7.4641 >>total = numerator/denominator 5 total = -5 >>
The following expression: (assuming that x and y have values already): >> exp(4) + log10(x) - pi^y
The basic MATLAB trigonometric functions are 'sin', 'cos', 'tan', 'cot', 'sec', and 'csc'. The inverses, are calculated with 'asin', 'atan', etc. The inverse function 'atan2' takes two arguments, y and x, and gives the four-quadrant inverse tangent. Angles are in radians, by default.
MATLAB recognizes the letters i and j as the imaginary number. A complex number 4 + 5i may be input as 4+5i or 4+5*i in MATLAB. The first case is always interpreted as a complex number, whereas the latter case is taken as complex only if i has not been assigned any local value.
Can you verify in MATLAB this equation (Euler's Formula)? You can do it as an exercise!
Row vector y can represent a straight line by doubling the x value (just as a slope = 2) and adding a constant. Something like y = mx + c. It's easy to perform algebraic operations on vectors since you apply the operations to the whole vector, not to each element alone.
Now, let's create two row vectors (v and w), each with 5 linearly spaced elements (that's easy with function 'linspace': v = linspace(3, 30, 5) w = linspace(4, 400, 5) Obtain a row vector containing the sine of each element in v: x = sin(v) Multiply these elements by thir correspondig element in w: y = x .* w And obtain MATLAB's response: y= 0.5645 -32.9105 -143.7806 -286.4733 -395.2126 >> Did you obtain the same? Results don't appear on screen if you end the command with the ';' sign.
y = x .* w;
You can create an array (or matrix) by combining two or more vectors: m = [x; y] The first row of m above is x, the second row is y. m= 0.1411 -0.3195 -0.7118 -0.9517 -0.9880 0.5645 -32.9105 -143.7806 -286.4733 -395.2126 >> You can refer to each element of m by using subscripts. For example, m(1,2) = 0.3195 (first row, second column); m(2,1) = 0.5645 (second row, first column). You can manipulate single elements of a matrix, and replace them on the same matrix: m(1,2) = m(1,2)+3 m(2,4) = 0 m(2,5) = m(1,2)+m(2,1)+m(2,5) m= 0.1411 2.6805 -0.7118 -0.9517 -0.9880 0.5645 -32.9105 -143.7806 0 -391.9677 >> Or you can perform algebraic operations on the whole matrix (using element-byelement operators): z = m.^2 z= 1.0e+005 * 0.0000 0.0000 >> 0.0001 0.0108 0.0000 0.2067 0.0000 0.0000 0 1.5364
MATLAB automatically presents a coefficient before the matrix, to simplify the notation. In this case .
If we use 100 points rather than 10, and evaluate two cycles instead of one (like this): x = linspace(0, 4*pi, 100); We obtain a different curve:
Now, a variation with line-syles and colors (type 'help plot' to see the options for line-types and colors): clear; clc; close all; % Simple script to plot a cosine % vector x takes only 10 values x = linspace(0, 4*pi, 100); y = cos(x); plot(x,y, 'ro') xlabel('x (radians)') ylabel('cos(x)') title('Plotting a cosine') grid on
Space curve Use the command plot3(x,y,z) to plot the helix: If x(t)=sin(t), y(t)=cos(t), z(t)=(t) for every t in , then, you can type this code in an 'm-file' or in the command window:
You can use the 'help plot3' command to find out more details.
Examples: MATLAB programming Script Files In this example, we are going to program the plotting of two concentric circles and mark the center point with a black square. We use polar coordinates in this case (for a variation). We can open a new edit window and type the following program (script). As already mentioned, lines starting with a '%' sign are comments, and are ignored by MATLAB but are very useful to the viewer.
% The initial instructions clear the screen, all % of the variables, and close any figure clc; clear; close all % CIRCLE - A script file to draw a pretty circle % We first generate a 90-element vector to be used as an angle angle = linspace(0, 2*pi, 90); % Then, we create another 90-element vector containing only value 2 r2 = linspace(2, 2, 90); % Next, we plot a red circle using the 'polar' function polar(angle, r2, 'ro') title('One more Circle')
% We avoid deletion of the figure hold on % Now, we create another 90-element vector for radius 1 r1 = linspace(1, 1, 90); polar(angle, r1, 'bx') % Finaly, we mark the center with a black square polar(0, 0, 'ks')
We save the script and run it with the 'run' icon (within the Editor):
Or we can run it from the Command Window by typing the name of the script. We now get:
Type this example in the editor window, and assign it the name 'temperature' ('File' -> 'New' -> 'M-File'):
% This function is named 'temperature.m'. % It has one input value 'x' and two outputs, 'c' and 'f'. % % % % If 'x' is a Celsius number, output variable 'f' contains its equivalent in Fahrenheit degrees. If 'x' is a Fahrenheit number, output variable 'c' contains its equivalent in Celsius degrees.
% Both results are given at once in the output vector [c f] function [c f] = temperature(x) f = 9*x/5 + 32; c = (x - 32) * 5/9;
Then, you can run the Matlab function from the command window, like this: >> [cent fahr] = temperature(32) cent = 0 fahr = 89.6000 >> [c f]=temperature(-41) c= -40.5556 f= -41.8000 The receiving variables ([cent fahr] or [c f]) in the command window (or in another function or script that calls 'temperature') may have different names than those assigned within your just created function.
a = [1 2; 3 4] b = [5 6 7 9] c = [-1 -5; -3 9] d = [-5 0 4; 0 -10 3] e = [8 6 4 318 9 8 1] Note that a new row can be defined with a semicolon ';' as in a, c or d, or with actual new rows, as in b or e.
You can see that Matlab arranges and formats the data as follows: a= 1 3 b= 5 7 c= -1 -3 2 4 6 9 -5 9 4 3 4 8 1
d= -5 0 0 -10 e= 8 3 9 6 1 8
Now, we are going to test some properties relative to the boolean algebra... We can use the double equal sign '==' to test if some numbers are the same. If they are, Matlab answers with a '1' (true); if they are not the same, Matlab answers with a '0' (false). See these interactive examples: Is matrix addition commutative?
Yes, all of the elements in a+b are the same than the elements in b+a. Is matrix addition associative? (a + b) + c == a + (b+c) Matlab compares all of the elements and answers: ans = 1 1 1 1
Yes, all all of the elements in (a + b) + c are the same than the elements in a + (b+c). Is multiplication with a matrix distributive? a*(b+c) == a*b + a*c ans = 1 1 1 1
Yes, indeed. Obviously, the matrices have to have appropriate dimensions, otherwise the operations are not possible. Are matrix products commutative? a*d == d*a No, not in general. a*d = -5 -20 -15 -40 10 24
d*a ... is not possible, since dimensions are not appropriate for a multiplication between these matrices, and Matlab launches an error: ??? Error using ==> mtimes Inner matrix dimensions must agree.
We extract all the elements of row 2 in g (like this g(2, :)), transpose them (with an apostrophe, like this g(2, :)') and join them to what we already have in h. As an example, we put all the elements again in h to increase its size: h = [h g(2, :)'] Matlab produces: h= -1 -3 1 3 5 7 -5 9 2 4 6 9 3 4 7 9 -3 9
Extract columns 2 and 3 from rows 3 to 6. j = [h(3:6, 2:3)] And Matlab produces: j=
2 4 6 9
7 9 -3 9
Besides, there is another way to define the inner product, if you know the angle between the two vectors:
We can conclude that if the inner product of two vectors is zero, the vectors are orthogonal. In Matlab, the appropriate built-in function to determine the inner product is 'dot(u,v)'. For example, let's say that we have vectors u and v, where u = [1 0] and v = [2 2]. We can plot them easily with the 'compass' function in Matlab, like this:
x = [1 2] y = [0 2] compass(x,y)
x represents the horizontal coordinates for each vector, and y represents their vertical coordinates. The instruction 'compass(x,y)' draws a graph that displays the vectors with components (x, y) as arrows going out from the origin, and in this case it produces:
We can see that the angle between the two vectors is 45 degrees; then, we can calculate the scalar product in three different ways (in Matlab code):
Code that produces these results: a=2 b = 2.0000 c=2 Note that the angle has to be expressed in radians, and that the instruction 'norm(vector, 2)' calculates the Euclidian norm of a vector (there are more types of norms for vectors, but we are not going to discuss them here).
Cross Product
In this example, we are going to write a function to find the cross product of two given vectors u and v. If u = [u1 u2 u3] and v = [v1 v2 v3], we know that the cross product w is defined
as w = [(u2v3 u3v2) (u3v1 - u1v3) (u1v2 - u2v1)]. We can check the function by taking cross products of unit vectors i = [1 0 0], j = [0 1 0], and k = [0 0 1] First, we create the function in an m-file as follows:
function w = crossprod(u,v) % We're assuming that both u and v are 3D vectors. % Naturally, w = [w(1) w(2) w(3)] w(1) = u(2)*v(3) - u(3)*v(2); w(2) = u(3)*v(1) - u(1)*v(3); w(3) = u(1)*v(2) - u(2)*v(1);
Then, we can call the function from any script, as follows in this example:
% Clear screen, clear previous variables and closes all figures clc; close all; clear % Supress empty lines in the output format compact % Define unit vectors i = [1 0 0]; j = [0 1 0]; k = [0 0 1]; % Call the previously created function w1 = crossprod(i,j) w2 = crossprod(i,k) disp('*** compare with results by Matlab ***') w3 = cross(i,j) w4 = cross(i,k)
0 >>
-1
Complex Numbers
The unit of imaginary numbers is and is generally designated by the letter i (or j). Many laws which are true for real numbers are true for imaginary numbers as well. Thus .
Matlab recognizes the letters i and j as the imaginary number . A complex number 3 + 10i may be input as 3 + 10i or 3 + 10*i in Matlab (make sure not to use i as a variable). In the complex number a + bi, a is called the real part (in Matlab, real(3+5i) = 3) and b is the coefficient of the imaginary part (in Matlab, imag(4-9i) = -9). When a = 0, the number is called a pure imaginary. If b = 0, the number is only the real number a. Thus, complex numbers include all real numbers and all pure imaginary numbers. The conjugate of a complex a + bi is a - bi. In Matlab, conj(2 - 8i) = 2 + 8i. To add (or subtract) two numbers, add (or subtract) the real parts and the imaginary parts separately. For example: (a+bi) + (c-di) = (a+c)+(b-d)i In Matlab, it's very easy to do it: >> a = 3-5i a= 3.0000 - 5.0000i >> b = -9+3i b= -9.0000 + 3.0000i >> a + b ans = -6.0000 - 2.0000i >> a - b ans = 12.0000 - 8.0000i To multiply two numbers, treat them as ordinary binomials and replace i2 by -1. To divide two complex nrs., multiply the numerator and denominator of the fraction by the conjugate of the denominator, replacing again i2 by -1. Don't worry, in Matlab it's still very easy (assuming same a and b as above): >> a*b ans = -12.0000 +54.0000i
>> a/b ans = -0.4667 + 0.4000i Employing rectangular coordinate axes, the complex nr. a+bi is represented by the point whose coordinates are (a,b). We can plot complex nrs. this easy. To plot numbers (3+2i), (-2+5i) and (-1-1i), we can write the following code in Matlab:
% Enter each coordinate (x,y) separated by commas % Each point is marked by a blue circle ('bo') plot(3,2,'bo', -2,5,'bo', -1,-1,'bo') % You can define the limits of the plot [xmin xmax ymin ymax] axis([-3 4 -2 6]) % Add some labels to explain the plot xlabel('x (real axis)') ylabel('y (imaginary axis)') % Activate the grid grid on
of the same complex nr. The distance is always positive and is called the absolute value or modulus of the complex number. The is called theangle argument or amplitude of the complex number. In Matlab, we can effortlessly know the modulus and angle (in radians) of any number, by using the 'abs' and 'angle' instructions. For example: a = 3-4i magnitude = abs(a) ang = angle(a) a= 3.0000 - 4.0000i magnitude = 5 ang = -0.9273
De Moivre's Theorem
The nth power of is
This relation is known as the De Moivre's theorem and is true for any real value of the exponent. If the exponent is 1/n, then . It's a good idea if you make up some exercises to test the validity of the theorem.
Any number (real or complex) has n distinct nth roots, except zero. To obtain the n nth roots of the complex number x + yi, or successive values 0, 1, 2, ..., n-1 in the above formula. , let k take on the
Again, it's a good idea if you create some exercises in Matlab to test the validity of this affirmation.
Future Value
This program is an example of a financial application in Matlab. It calculates the future value of an investment when interest is a factor. It is necessary to provide the amount of the initial investment, the nominal interest rate, the number of compounding periods per year and the number of years of the investment. Assuming that there are no additional deposits and no withdrawals, the future value is based on the folowing formula:
where: t = total value after y years (future value) y = number of years p = initial investment i = nominal interest rate n = number of compounding period per year We can achieve this task very easily with Matlab. First, we create a function to request the user to enter the data. Then, we perform the mathematical operations and deliver the result.
This is the function that requests the user to enter the necessary information: function [ii, nir, ncppy, ny] = enter_values ii = input('Enter initial investment: '); nir = input('Enter nominal interest rate: '); ncppy = input('Enter number of compounding periods per year: '); ny = input('Enter number of years: ');
This is the function that performs the operations: function t = future_value(ii, nir, ncppy, ny) % Convert from percent to decimal ni = nir / (100 * ncppy); % Calculate future value by formula t = ii*(1 + ni)^(ncppy * ny); % Round off to nearest cent t = floor(t * 100 + 0.5)/100;
And finally, this is the Matlab code (script) that handles the above: % Instruction format bank delivers fixed format for dollars and cents % Instruction format compact suppresses extra line-feeds clear; clc; format compact format bank [ii, nir, ncppy, ny] = enter_values; t = future_value(ii, nir, ncppy, ny) This is a sample run: Enter initial investment: 6800 Enter nominal interest rate: 9.5 Enter number of compounding periods per year: 4 Enter number of years: 10
We can also test of the function, like this: ii = 6800; nir = 9.5; ncppy = 4; ny = 10; t = future_value(ii, nir, ncppy, ny) with exactly the same result, as expected t= 17388.64
The result is: a= 0.1667 0.1429 0.1250 0.1111 0.0909 0.0833 0.0769 0.0714 0.0625 0.0588 0.0556 0.0526 0.0476 0.0455 0.0435 0.0417 0.0385 0.0370 0.0357 0.0345
0.1000
0.0667
0.0500
0.0400
0.0333
The semicolon terminating the inner statement suppresses repeated printing, and the a after the loop displays the final result. It is a good idea to indent the loops for readability, especially when they are nested.
Matrix Multiplication
If A is a matrix of dimension m x r, and B is a matrix of dimension r x n, you can find the product AB of dimension m x n by doing the following: 1. To find the element in row i and column j of matrix AB, you take row i of matrix A and column j of matrix B. 2. You multiply the corresponding elements of that row and that column and add up all the products. In this example, we show a code in Matlab that performs a matrix multiplication step-by-step. The algorithm displays all the elements being considered for the multiplication and shows how the resulting matrix is being formed in each step. Obviously, Matlab can do it with just one operation, but we want to show every step of the process, as well as an example of how nested iterations work in Matlab. Example:
% Clear screen, clear previous variables and closes all figures clc; close all; clear % Avoid empty lines format compact % Define matrices, for example these A = [2 1 4 1 2; 1 0 1 2 -1; 2 3 -1 0 -2] B = [-2 -1 2; 0 2 1; -1 1 4; 3 0 1; 2 1 2] % The size of each matrix is considered for these calculations [r1 c1] = size(A); [r2 c2] = size(B); % prevent unappropriate matrix size if c1 ~= r2 disp ('*** not able to multiply matrices ***') end % Main code % Vary each row of matrix A for i = 1 : r1 % Vary each column of matrix B for j = 1 : c2
% Reset every new element of the final result s = 0; % Vary each column of matrix A and row of matrix B for k = 1 : c1 % Display every element to take into account A(i,k) B(k,j) % Prepare the addition in the iteration s = s + A(i,k) * B(k,j); end % Assign the total of the appropriate element % to the final matrix C(i,j) = s end end % Compare our result with a multiplication by Matlab A*B
then, the command window shows all the elements being considered and how the product AB (C) is being formed, and finalizes with our result and the multiplication achieved by Matlab itself. C = -1 1 -7 ans = -1 1 -7 >> 6 -1 1 6 -1 1 26 6 -1 26 6 -1
counter = 100; while (counter > 95) disp ('counter is still > 95') counter = counter -1; end disp('counter is no longer > 95')
Matlab response is: counter counter counter counter counter counter >> is is is is is is still > 95 still > 95 still > 95 still > 95 still > 95 no longer > 95
The cautions involving matrix comparisons that are discussed in the section on the if statement also apply to the while statement.
if statement
The if statement evaluates a logical expression and executes a group of statements when the expression is true. The optional elseif and else keywords provide for the execution of alternate groups of statements. An end keyword, which matches the if, terminates the last group of statements. The groups of statements are delineated by the four keywords (no braces or brackets are involved). The general form of the statement is: if expression1 statements1
It is important to understand how relational operators and if statements work with matrices. When you want to check for equality between two variables, you might use if A == B ... This '==' code is fine, and it does what you expect when A and B are scalars. But when A and B are matrices, A == B does not test if they are equal, it tests where they are equal; the result is another matrix of 0s and 1s showing element by-element equality. In fact, if A and B are not the same size, then A == B is an error. The proper way to check for equality between two variables is to use the isequal function: if isequal(A,B) ...
Here's an example code: if m == n a(m,n) = 3; elseif abs(m-n) == 3 a(m,n) = 1; else a(m,n) = 0; end If m equals n, then a(m,n) becomes 3, and the routine continues after the end. If not, the routine tests if abs(m-n) equals 3. If it does, then a(m,n) becomes 1, and the routine continues after the end. In any other case a(m,n) becomes 0, and the routine continues after the end.
Several functions are helpful for reducing the results of matrix comparisons to scalar conditions for use with if, including:
break statement
The break statement lets you exit early from a for or while loop. In nested loops, break exits from the innermost loop only.
Example 1: for i = length(x) % check for positive y if y(x) > 0 % terminate loop execution break end % follow your code a = a + y(x); ... end
Example 2: x = sin(sqrt(variable)); while 1 n = input('Enter number of loops: ') if n <= 0 % terminate loop execution break end for i = 1 : n % follow your code x = x + 20; ... end end
Matrix Inversion
This program performs the matrix inversion of a square matrix step-by-step. The inversion is performed by a modified Gauss-Jordan elimination method. We start with an arbitrary square matrix and a same-size identity matrix (all the elements along its diagonal are 1).
We perform operations on the rows of the input matrix in order to transform it and obtain an identity matrix, and perform exactly the same operations on the accompanying identity matrix in order to obtain the inverse one. If we find a row full of zeros during this process, then we can conclude that the matrix is singular, and so cannot be inverted. We expose a very naive method, just as was performed in the old-Basic- style. Naturally, Matlab has appropriate and fast instructions to perform matrix inversions, but we want to explain the Gauss-Jordan concept and show how nested loops and control flow work. First, we develop a function like this (let's assume we save it as 'mat_inv2.m'):
function b = mat_inv2(a) % Find dimensions of input matrix [r,c] = size(a); % If input matrix is not square, stop function if r ~= c disp('Only Square Matrices, please') b = []; return end % Target identity matrix to be transformed into the output % inverse matrix b = eye(r); %The following code actually performs the matrix inversion for j = 1 : r for i = j : r if a(i,j) ~= 0 for k = 1 : r s = a(j,k); a(j,k) = a(i,k); a(i,k) = s; s = b(j,k); b(j,k) = b(i,k); b(i,k) = s; end t = 1/a(j,j); for k = 1 : r a(j,k) = t * a(j,k); b(j,k) = t * b(j,k); end for L = 1 : r if L ~= j t = -a(L,j); for k = 1 : r a(L,k) = a(L,k) + t * a(j,k); b(L,k) = b(L,k) + t * b(j,k); end end end
end break end % Display warning if a row full of zeros is found if a(i,j) == 0 disp('Warning: Singular Matrix') b = 'error'; return end end % Show the evolution of the input matrix, so that we can % confirm that it became an identity matrix. a
And then, we can call it or test it from any other script or from the command window, like this: % Input matrix a = [3 5 -1 -4 1 4 -.7 -3 0 -2 0 1 -2 6 0 .3]; % Call the function to find its inverse b = mat_inv2(a) % Compare with a result generated by Matlab c = inv(a)
Matlab produces this response: First, we see how the original matrix transformet into an identity matrix: a= 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1
Then, our function show its result: b= 0.6544 -0.9348 -0.1912 0.0142 0.1983 -0.2833 -0.1034 0.1558 0.3683 -1.9547 -4.2635 -0.4249 0.3966 -0.5666 0.7932 0.3116 Finally, this is the inversion produced by a direct instruction from Matlab (inv(a)): c= 0.6544 -0.9348 -0.1912 0.0142
Another example: % Input matrix a = [1 1 1 1]; % Call the function to find its inverse b = mat_inv2(a) % Compare with a result generated by Matlab c = inv(a) And Matlab display is: Warning: Singular Matrix b= error Warning: Matrix is singular to working precision. > In test_mat_inv at 42 c= Inf Inf Inf Inf
In this case, our algorithm found a singular matrix, so an inverse cannot be calculated. This agrees with what Matlab found with its own built-in function.
Switch Statement
The switch statement in Matlab executes groups of instructions or statements based on the value of a variable or expression. The keywords case and otherwise delineate the groups. Only the first matching case is executed. There must always be an end to match the switch. The syntax is: switch switch_expr case case_expr statement ... case {case_expr1,case_expr2,case_expr3,...} statement
... otherwise statement ... end MATLAB switch does not fall through. If the first case statement is true, the other case statements do not execute. So, break statements are not required. Example:
To execute a certain block of code based on what the string 'color' is set to: color = 'rose'; switch lower(color) case {'red', 'light red', 'rose'} disp('color is red') case 'blue' disp('color is blue') case 'white' disp('color is white') otherwise disp('Unknown color.') end
Boolean Operator
In Matlab, there are four logical (aka boolean) operators:
Boolean operator: & | ~ xor Meaning: logical AND logical OR logical NOT (complement) exclusive OR
These operators produce vectors or matrices of the same size as the operands, with 1 when the condition is true, and 0 when the condition is false.
Given array x = [0 7 3 5] and array y = [2 8 7 0], these are some possible operations: Operation: n = x & y m = ~(y | x) p = xor(x, y) Result: n = [0 m = [0 p = [1 1 0 0 1 0 0 0] 0] 1]
Since the output of the logical or boolean operations is a vector or matrix with only 0 or 1 values, the output can be used as the index of a matrix to extract appropriate elements. For example, to see the elements of x that satisfy both the conditions (x<y) and (x<4), you can type x((x<y)&(x<4)). Operation: Result: x<y ans = [1 x<4 ans = [1 q = x((x<y)&(x<4)) q = [0 1 0 3] 1 0 0] 0]
Additionally to these boolean operators, there are several useful built-in logical functions, such as:
any all exist isempty isinf isnan find true if any element of a vector is true true if all elements of a vector are true true if the argument exists true for an empty matrix true for all infinite elements of a matrix true for all elements of a matrix that ara not-a-number finds indices of non-zero elements of a matrix
Relational Operators
There are six relational operators in Matlab:
Relational operator: < <= > >= == ~= Meaning: less than less than or equal greater than greater than or equal equal (possibility, not assignation) not equal
These operations result in a vector of matrix of the same size as the operands, with 1 when the relation is true, and 0 when its false. Given arrays x = [0 7 3 5] and y = [2 8 7 0], these are some possible relational operations: Operation: k = x<y k = x <= y k = x == y Result: k = [1 k = [1 k = [0 1 1 0 1 1 0 0] 0] 0]
Although these operations are usually used in conditional statements such as if-else to branch out to different cases, they can be used to do very complex matrix manipulation. For example x = y(y > 0.45) finds all the elements of vector y such that yi > 0.45 and stores them in vector x. These operations can be combined with boolean operators, too.
Descript. Axiom
OR form x+0 = x
AND form x.1 = x x.y = y.x x+y.z = (x+y).(x+z) x.x = 0 x.x = x x.0 = 0 x.(y.z) = (x.y).z
Commutative x+y = y+x Distributive Axiom Theorem Theorem Theorem Associativity x.(y+z) = (x.y)+(x.z) x+x = 1 x+x = x x+1 = 1 x = x x+(y+z) = (x+y)+z
Other way to express it: AVF=A A^T=A AVB=BVA A^B=B^A A ^ (B V C) = (A ^ B) V (A ^ C) A V B ^ C = (A V B) ^ (A V C) A V A = T A ^ A = F AVA=A A^A=A AVT=T A^F=F (A) = A A V (B V C) = (A V B) V C A ^ (B ^ C) = (A ^ B) ^ C
AVA^B=A A ^ (A V B) = A A V B = (A ^ B) A ^ B = (A V B)
Using logical gates, the commutative property for a logical AND is:
The De Morgan's laws can transform logical ORs into logical ANDs (negations are necessary) and can electronically be described this way:
Or
De Morgan Laws
In Boolean Algebra, there are some very important laws which are called the De Morgan's laws (the spelling can change from author to author). These laws teach us how to interchange NOT with AND or OR logical operators.
Using gates (commonly used in Digital Electronics), they can be expressed in two forms: the OR form:
In Matlab, these laws can be demonstrated very easily. Let's create a script file like this:
% Let x and y be column vectors x = [0 0 1 1]' y = [0 1 0 1]' % We can demonstrate the OR form of the law % with these two lines x_or_y = x|y DeMorg1 = not(not(x)& not(y)) % We can demonstrate the AND form of the law % with these two lines x_and_y = x&y DeMorg2 = not(not(x) | not(y))
When we run it, we get this output: x= 0 0 1 1 x_or_y = 0 1 1 1 x_and_y = y= 0 1 0 1 DeMorg1 = 0 1 1 1 DeMorg2 =
0 0 0 1
0 0 0 1
Logical AND
A 0 0 1 1 B 0 1 0 1 A&B 0 0 0 1
A & B performs a logical AND of arrays A and B and returns an array containing elements set to either logical 1 (TRUE) or logical 0 (FALSE). An element of the output array is set to 1 if both input arrays contain a non-zero element at that same array location. Otherwise, that element is set to 0. A and B must have the same dimensions unless one is a scalar. Example: If matrix A is: A= 0 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1
Then, the AND operation between A and B is: >> A & B ans = 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 0
>>
Then, the AND operation between x and y is: >> x & y ans = 0 >> 1 1 0 0
Logical OR
A 0 0 1 1 B 0 1 0 1 A|B 0 1 1 1 containing
A | B performs a logical OR of arrays A and B and returns an array elements set to either logical 1 (TRUE) or logical 0 (FALSE).
An element of the output array is set to 1 if either input array contains a non-zero element at that same array location. Otherwise, that element is set to 0. A and B must have the same dimensions unless one is a scalar. Example: If matrix A is: A= 0 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1
B= 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0
For the logical exclusive OR, XOR(A,B), the result is logical 1 (TRUE) where either A or B, but not both, is nonzero. The result is logical 0 (FALSE) where A and B are both zero or nonzero. A and B must have the same dimensions (or one can be a scalar).
This is the common symbol for the 'Exclusive OR' Example: If matrix A is: A= 0 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1
Then, the logical EXCLUSIVE OR between A and B is: >> xor(A,B) ans = 0 0 0 0 >> 0 0 1 1 1 1 0 0 1 1 1 1
y= 1 2 3 0 0
Logical NOT
A 0 1 ~A 1 0
In MATLAB, ~A performs a logical NOT of input array A, and returns an array containing elements set to either logical 1 (TRUE) or logical 0 (FALSE). An element of the output array is set to 1 if A contains a zero value element at that same array location. Otherwise, that element is set to 0.
x= 0 1 2 -3 0
Determinants in Matlab
The symbol
which consists of the four numbers a1, b1, a2, b2 arranged in two rows and two columns is called a determinant of second order or of order two. The four numbers are called its elements. By definition,
Thus . Here, the elements 2 and 3 are in the first row, and the elements 4 and 1 are in the second row. Elements 2 and 4 are in column one, and elements 3 and 1 are column two. The method of solution of linear equations by determinants is called the Cramers Rule. A system of two linear equations in two unknowns may be solved using a second order det. Given the system of equations
a1x + b1y = c1 a2x + b2y = c2
it is possible to obtain
These values for x and y may be written in terms of second order dets, as follows:
Example:
2x + 3y = 16 4x + y = -3
Then
, and
In Matlab, a determinant can be calculated with the built-in function 'det()'. Using the same numbers as in the example above, if A = [2 3; 4 1], then det(A) = -10; if B = [16 3; -3 1], then x = det(A)/det(B) = -2.5; if C = [2 16; 4 -3], then y = det(C)/det(A) = 7 Naturally, you can use the function det() to find determinants of higher order.
Simultaneous Equations - Linear Algebra Solving a system of simultaneous equations is easy in Matlab. It is, maybe, the most used operation in science and engineering, too. Solving a set of equations in linear algebra on a computer is nowadays as basic as doing arithmetic additions using a
calculator. Let's see how easy Matlab makes this task. We'll solve the set of linear equations given below. To solve these equations, no prior knowledge of matrix algebra or linear methods is required. The first two steps described below are really basic for most people who know a just little bit of linear algebra. Consider the following set of equations for our example. -6x = 2y - 2z + 15 4y - 3z = 3x + 13 2x + 4y - 7z = -9 First, rearrange the equations. Write each equation with all unknown quantities on the left-hand side and all known quantities on the right side. Thus, for the equations given, rearrange them such that all terms involving x, y and z are on the left side of the equal sign. -6x - 2y + 2z = 15 -3x + 4y - 3z = 13 2x + 4y - 7z = -9 Second, write the equations in a matrix form. To write the equations in the matrix form Ax = b, where x is the vector of unknowns, you have to arrange the unknowns in vector x, the coefficients of the unknowns in matrix A and the constants on the rigth hand of the equations in vector b. In this particualar example, the unknown column vector is x = [x y z]' the coefficient matrix is A = [-6 -2 2 -3 4 -3 2 4 -7] and the known constant column vector is b = [15 13 -9]' Note than the columns of A are simply the coefficients of each unknown from all the three expressed equations. The apostrophe at the end of vectors x and b means that those vectors are column vectors, not row ones (it is Matlab notation). Third, solve the simultaneous equations in Matlab. Enter the matrix A and vector b, and solve for vector x with the instruction 'x = A\b' (note that the '\' sign is different from the ordinary division '/' sign).
-2 2 4 -3 4 -7
You can test the result by performing the substitution and multiplying Ax to get b, like this: A*x And the Matlab answer is: ans = 15.0000 13.0000 -9.0000 >> which corresponds to b, indeed.
Cramer's Rule
The method of solution of linear equations by determinants is called Cramer's Rule. This rule for linear equations in 3 unknowns is a method of solving by determinants the following equations for x, y, z
If
The solution involving determinants is easy to remember if you keep in mind these simple ideas:
The denominators are given by the determinant in which the elements are the coefficients of x, y and z, arranged as in the original given equations.
The numerator in the solution for any variable is the same as the determinant of the coefficients with the exception that the column of coefficients of the unknown to be determined is replaced by the column of constants on the right side of the original equations.
That is, for the first variable, you substitute the first column of the determinant with the constants on the right; for the second variable, you substitute the second column with the constants on the rigth, and so on...
Example:
For x, take the determinant above and replace the first column by the constants on the right of the system. Then, divide this by the determinant:
For y, replace the second column by the constants on the right of the system. Then, divide it by the determinant:
For z, replace the third column by the constants on the right of the system. Then, divide it by the determinant:
In Matlab, its even easier. You can solve the system with just one instruction. Let D be the matrix of just the coefficients of the variables: D = [2 4 -2; 6 2 2; 2 -2 4]; Let b be the column vector of the constants on the rigth of the system : b = [-6 8 12]'; % the apostrophe is used to transpose a vector Find the column vector of the unknowns by 'left dividing' D by b (use the backslash), like this: variables = D\b
Linear Algebra and its Applications - Circuit Analyisis One important linear algebra application is the resolution of electrical circuits. We can describe this type of circuits with linear equations, and then we can solve the linear system using Matlab. For example, let's examine the following electrical circuit (resistors are in ohms, currents in amperes, and voltages are in volts):
We can describe the circuit with the following system of linear equations: 7 - 1(i1 - i2) - 6 - 2(i1 - i3) = 0 -1(i2 - i1) - 2(i2) - 3(i2 - i3) = 0 6 - 3(i3 - i2) - 1(i3) - 2(i3 - i1) = 0 Simplifying and rearranging the equations, we obtain: -3i1 + i2 + 2i3 = -1 i1 - 6i2 + 3i3 = 0 2i1 + 3i2 - 6i3 = -6 This system can be described with matrices in the form Ax = b, where A is the matrix of the coefficients of the currents, x is the vector of unknown currents, and b is the vector of constants on the right of the equalities. One possible Matlab code to solve this is:
and naturally:
As we mentioned before, we are going to formulate this as an optimization problem using the 'fminsearch' built-in function. In Matlab, the instruction works as follows: X = FMINSEARCH(FUN,X0,OPTIONS) minimizes with the default optimization parameters replaced by values in the structure OPTIONS, created with the OPTIMSET function. FMINSEARCH uses these options: Display, TolX, TolFun, MaxFunEvals, MaxIter, FunValCheck, and OutputFcn. This is one possible approach for our objective function, which is saved as an m-file (in this case 'OF_P.m'):
function OFValue = OF_P(x) % Here we embed the constraints or inequalities. % If the constraints are not met, we penalize the optimization by % giving an arbitrary high value to the objective function. if 120 * x(1) + 210 * x(2) > 15000 |... 110 * x(1) + 30 * x(2) > 4000 |... x(1) + x(2) > 75 | ... x(1) < 0 |... x(2) < 0 OFValue = 10; return end % fminsearch tries to minimize the function, so we invert its sign P = 143 * x(1) + 60 * x(2); OFValue = -P;
Then, we can call it from another script, which includes the 'fminsearch' function calling the objective function file (in 'OF_P'):
% We have to start with a 'seed' for the search x = [1 10]'; % We can perform the optimization with different number of % iterations or tolerances options = optimset('MaxFunEvals', 2000, 'TolX', 1e-2); [x_opt, FunVal, EF, output] = fminsearch('OF_P', x, options) % Finally, we display the profit using the found solution P = 143 * x_opt(1) + 60 * x_opt(2)
And the Matlab response is: x_opt = 21.87 53.12 FunVal = -6315.62 EF = 1.00 output = iterations: funcCount: algorithm: message: P = 6315.62 >> This means that the farmer should consider 21.87 roods for wheat, 53.12 roods for corn, and his profit would be $6,315.62. It is important to notice that this is a numerical approximation, which means that if we start with another 'seed' or use other parameters in the 'options' set, we can get to another result. The number found is a possible solution, but there's no guarantee that it is the best one, according to tolerances or to number of iterations or evaluations desired. For example, we can use the seed 'x = [10 10]' instead (without moving any other instruction), and the Matlab answer now is: x_opt = 32.31 14.88 FunVal = -5512.50 EF = 1.00
Now, the 'best' profit found is only $5,512.50. So, it is a good idea to try with several 'seeds' and different parameters in the 'options' set to compare with and select the best solution. Most of the times the solutions will be very close (at least for linear programming problems).
LU Factorization
In Matlab there are several built-in functions provided for matrix factorization (also called decomposition). The name of the built-in function for a Lower-Upper decomposition is 'lu'. To get the LU factorization of a square matrix A, type the command '[L, U] = lu(A)'. Matlab returns a lower triangular matrix L and an upper triangular matrix U such that L*U = A. Suppose that A= [ 1 2 -3 -3 -4 13 2 1 -5] We can verify that if L=[1 0 0 -3 1 0 2 -1.5 1] and U = [1 2 -3 0 2 4 0 0 7] Then, A = L*U The decomposition of the matrix A is an illustration of an important and well known theorem. If A is a nonsingular matrix that can be transformed into an upper diagonal form U by the application or row addition operations, then there exists a lower triangular matrix L such that A = LU.
Row addition operations can be represented by a product of elementary matrices. If n such operations are required, the matrix U is related to the matrix A in the following way:
U = En En-1 ... E2 E1 A
The lower triangular matrix L is found from
In Matlab, let's find the LU decomposition of the matrix A = [-2 1 -3; 6 -1 8; 8 3 -7] Write this instruction in the command window or within a script: [L, U] = lu(A) And the Matlab answer is: L= -0.2500 0.7500 1.0000 -0.5385 1.0000 0 1.0000 0 0
U= 8.0000 3.0000 -7.0000 0 -3.2500 13.2500 0 0 2.3846 We can test the answer, by typing L*U And, finnally, the Matlab answer is: ans = -2.0000 1.0000 -3.0000 6.0000 -1.0000 8.0000 8.0000 3.0000 -7.0000 >>
If the matrix A is square, then we can use the singular value decomposition to find the inverse, which is is A-1 = (USV')-1 = (V')-1S-1U-1 = VS-1U' since (AB)-1 = B-1A-1, UU' = I, and VV' = I. If A is a square matrix then
And so,
If an SVD of a matrix A can be calculated, so can be its inverse. Therefore, we can find a solution to a system Ax = b x = A-1b = VS-1U'b that would otherwise be usolvable. Example:
We simply type: [U,S,V] = svd(A) and the above operation produces a diagonal matrix S, of the same dimension as A and with nonnegative diagonal elements in decreasing order, and unitary matrices U and V so that A = U*S*V'. The Matlab answer is: U = -0.1826 0.9129 -0.3651 S = 2.4495 0 0 V = -0.8944 0.4472 >> 0 1.0000 0 0.4472 0.8944 -0.8944 0.0000 0.4472 0.4082 0.4082 0.8165
We can confirm the values of UU', VV' and USV, by executing these instructions in Matlab
U*U' V*V' U*S*V The confirming responses are: ans = 1.0000 -0.0000 -0.0000 ans = 1 0 ans = -0.0000 -2.0000 1.0000 >> 0 1 -1.0000 1.0000 0.0000 -0.0000 1.0000 -0.0000 -0.0000 -0.0000 1.0000
2D Plots
Matlab includes fancy tools for visualization. Basic 2D plots, good 3D graphics, and even animation possibilities are available in an easy environment. The most basic and useful command for producing simple 2D plots is: plot(xvalues, yvalues, 'style') xvalues is the value of the horizontal points to be plotted. yvalues is the value of the function to be plotted. xvalues and yvalues have to have the same length. 'style' is an optional argument that specifies the color, line style and pointmarker style.
Examples: plot(x,y) plot(x,y,'-.') plot(x) plot(x,y,'r--') plot(a,b,'k+') plots plots plots plots plots y vs x with a solid line y vs x with a dash-dot line the elements of x against their own index y vs x with a red dashed line b vs a with black plus signs
You may annotate your plots with 'xlabel', 'ylabel' and 'title'. Other useful functions are 'legend', 'axis', 'grid' and 'hold'.
% Clears variables, command window, and closes all figures clear, clc,close all % Defines value of x and two functions x = 0: .1 : 2*pi; y1 = cos(x); y2 = sin(x); % Plots two functions with different style, and wider lines plot(x,y1,'b', x, y2, 'r-.', 'linewidth', 2) % Activates the grid grid on % Defines limits for x and y axes, and sets title, labels and legends axis([0 2*pi -1.5 1.5]) title('2D plots', 'fontsize', 12) xlabel('angle') ylabel('f1(x), f2(x)') legend('cos(x)', 'sin(x)') % Keeps figure on screen, in order to add a third function hold on % Defines another function y3 = 0.5 * x; % Plots over the previous figure plot(x, y3, 'm')
We plan the usage of our function like this (its name will be 'plot_limit'): Usage: where L_min = starting point L_max = ending point y = y value of horizontal line d = direction (1 or -1) r = y range So, we need to know in advance where we want to put our line (sure!). We define our horizontal and vertical values. We arbitrarily define 300 horizontal points and use a linewidth = 1.5. The instruction 'hold on' keeps the current figure, instead of overwriting it. This Matlab code displays just a horizontal line. a = linspace(L_min, L_max, 300); b = linspace(y, y, 300); plot(a,b,'k-','linewidth',1.5) hold on Then, we add some tiny vertical lines on each side of the horizontal one. If direction 'd' is 1, the vertical lines are below the horizontal line (going 'up'). If direction 'd' is 1, the vertical lines are above the horizontal one (going 'down'). We take the vertical range into account, in 'r', to display a vertical line of just 3% of the total 'height' of the current figure. You can try different values to suit your needs, obviously. We find the initial or final points of the vertical lines with an 'if-statement'. This is the code to achieve it. L = [L_min L_max y d r]; plot_limit(L);
% Initial vertical line a = linspace(L_min, L_min, 10); if d == 1 b = linspace(y-r*.03, y, 10); else b = linspace(y, y+r*.03, 10); end plot(a,b,'k-','linewidth',1.5) hold on % Final vertical line a = linspace(L_max, L_max, 10); if d == 1 b = linspace(y-r*.03, y, 10); else b = linspace(y, y+r*.03, 10); end plot(a,b,'k-','linewidth',1.5)
Now, we'll test our function with this script. clear; clc; close all x = 0 : 2*pi/360 : 2*pi; y = sin(x); plot(x,y) grid on xlabel('angle') ylabel('sin(x)') title('Plot showing horizontal and vertical lines') hold on plot_limit([0.8, 2.5, 0.4, 1, 2]) plot_limit([4, 5.4, -0.6, -1, 2]) The result is:
The first line starts at 0.8, ends at 2.5, and has a vertical value of 0.4. The vertical lines simulate an up-arrow (d = 1). The second line starts at 4, ends at 5.4, and has a vertical value of -0.6. Direction goes down (d = -1).
Pie Plots
pie(x) draws pie plots of the data in the vector x. The values in x are normalized via x/sum(x) to determine the area of each slice of pie. If sum(x) is less or equal to 1, the values in x directly specify the area of the pie slices. Only a partial pie will be drawn if sum(x) is less than < 1. The '%' sign indicates that there is a comment in that line and Matlab does not do anything with it. It is as if it were inexistent, and it exists only for explanatory purposes. Example:
% Clears variables, command window, and closes all figures clc; clear; close all % These are the names of the slices names = char('Region 1', 'Region 2', 'Distr. 3', 'Distr. 4'); % These are the numbers to be plotted data = [1200, 500, 300, 120]; pie(data)
% gtext('string') displays the graph window, puts up a % cross-hair, and waits for a mouse button or keyboard % key to be pressed. for i=1:4 gtext(names(i,:)); end title('Sales', 'fontsize', 15)
This Matlab code creates a histogram with 3 bars. The first bar has two '1' values, the second bar has three '2' values, and the third bar has one '3' values. y = [1 1 2 2 2 3] hist(y)
The horizontal axis has the different values in the vector to be plotted. The vertical axis has the number of those values in the vector. Example:
This Matlab code generates a histogram of 15 randomly distributed numbers between 0 and 1. a = randn(15,1) hist(a) a = -0.8468 -0.2463 0.6630 -0.8542 -1.2013 -0.1199 -0.0653 0.4853 -0.5955 -0.1497 -0.4348 -0.0793 1.5352 -0.6065 -1.3474 >>
Note that each column includes a range of values, otherwise the histogram would contain 15 bars.
Comet Plot
comet(a) displays an animated comet plot of the vector a. comet(a, b) displays an animated comet plot of vector b vs. a. comet(a, b, p) uses a comet of length p*length(b). Default is p = 0.10. Example:
If you want to plot the following function: , for the range , you can write this script in Matlab:
% Clears variables, command window, and closes all figures clc; clear; close all % Generates 300 linearly spaced points from 0 to 8*pi x = linspace(0, 8*pi, 300); % Creates the formula to be plotted % (it's a multiplication between vector 'x' and vector 'cos(x)') y = x .* cos(x); % Plot it! comet(x, y, .6)
It is much better to see it on your own screen, because it moves like a ribbon! You can experiment with different p values to see the length of the comet changing...
Example:
We can develop a script like this: % Avoid superimposed operations and close previous figs. clc; clear; close all % First, we define 51 values of our independant variable x = 0 : 2*pi/50 : 2*pi; % Second, we define the function to be ploted y = exp(-x/3) .* sin(x); % Third, we use the 'stem' function to plot discrete values stem(x,y) % We can add title and labels (as strings in arguments)
If we define our independant variable using less points, as in x = 0 : 2*pi/20 : 2*pi; we get the following visual change:
clear; clc; close all % Define your independent variable t = 0 : 2*pi/360 : 2*pi; % Define values along your x-axis x = exp(t); % Define values along your y-axis y = 50 + exp(3*t); % Plot your function with a wider line and grid the figure loglog(x, y, 'LineWidth', 2) grid % Use a title for the figure title('Demonstration of logarithmic plots') % Label your x-axis with a double line. % Note the special characters
xlabel([{'e^{t}'}; {'0 \leq t \leq 2\pi'}]) % Label your y-axis ylabel('50 + e^{3t}')
between 0 and 2pi. You can also specify the centers of the bins by passing a vector, bin_centers, to the rose function, like this: rose(angle_vector, bin_centers). The following code produces a rose plot of data which is normally distributed in angle about 90. angle_vector = angle(exp(i*randn(1, 500))) + pi/2; rose(angle_vector)
where
The formula above can me coded in Matlab easily, like this: function f = gauss_distribution(x, mu, s) p1 = -.5 * ((x - mu)/s) .^ 2; p2 = (s * sqrt(2*pi)); f = exp(p1) ./ p2; Now, lets use it in an example. We produce 500 random numbers between -100 and 100, with mean m = 0 and standard deviation s = 30. The code is: a x m s = = = = -100; b = 100; a + (b-a) * rand(1, 500); (a + b)/2; 30;
Then, we plot this information using our bell curve: f = gauss_distribution(x, m, s); plot(x,f,'.') grid on title('Bell Curve') xlabel('Randomly produced numbers') ylabel('Gauss Distribution') The produced shape is:
An important property of this bell-shaped curve is that the values less than one standard deviation from the mean (between green lines below) represent approximately 68.2% of the area under the curve, while two standard deviations from the mean (between red lines below) take about 95.4%, and three standard deviations account for about 99.7% of the area.
If we have some data representing a system or a function at several time intervals, we may want to take advantage of Matlabs simple animation capabilities. We're going to expose the basic method or algorithm for animations. In this example were going to work with just three special instructions. The idea is to store every figure as a frame of the movie, with each frame stored as a column vector of a matrix, an then play all the frames on the screen. moviein(nr_frames): we initialize the matrix that will keep the frames, with the number of frames to be generated. getframe: with this instruction we keep the information of a given figure and load a temporary matrix with information. movie(matrix, times, FPS): this is used to play the movie after its generation. Parameter matrix is the saved data, times the number of times that the movie will be played back, and FPS means frames per second (the default is 12). Lets try this simple animation example: % Define number of frames nr_fr = 10; % Initialize matrix using 'moviein' frames = moviein(nr_fr); % Generate frames with any plotting function. % We use a cosine with variable frequency. t = 0 : .01 : 6; f = 1; for i = 1 : nr_fr f = f * 1.25; w = 2 * pi * f; y = cos(w*t); plot(t, y); title('Recording movie...') % Get every frame with 'getframe' and load the appropriate % matrix. frames(:, i) = getframe; end % Save the matrix so that this movie can be loaded later save frames This is the first frame of the recording:
Now you can play back the movie: % Play the movie once, 2 FPS. title('Movie being played back...') movie(frames, 1, 2)
Done!
3D Plot Part 1
From '3D Plot Part 1' to 3D Main Matlab provides many powerful instructions for the visualization of 3D data. The instructions provided include tools to plot wire-frame objects, 3D plots, curves, surfaces... and can automatically generate contours, display volumetric data, interpolate shading colors and even display non-Matlab made images. Here are some commonly used functions (there are many more): plot3 stem3 pie3 comet3 contour3 mesh meshc surf surfc sphere ellipsoid cylinder
Among these instructions, plot3 and comet3 are the 3D matches of plot and comet commands mentioned in the 2D plot section. The general syntax for the plot3 command is plot3(x, y, z, 'style') This command draws a 3D curve with the specified line style. The argument list can be repeated to make overlay plots, just the same way as with the plot command in 2D. We have to make some necessary comments before any example can be introduced. Plots in 3D may be annotated with instructions already mentioned for 2D plots: xlabel, ylabel, title, legend, grid, etc., plus the addition of zlabel. The grid command in 3D makes the appearance of the plots better, especially for curves in space. View The viewing angle of the observer is specified by the command view(azimuth, elevation), where azimuth (in degrees): specifies the horizontal rotation from the y-axis, measured positive counterclockwise (default value is -37.5 degrees). elevation (in degrees): specifies the vertical angle measured positive above the xy-plane (default value is 30 degrees).
By specifying appropriate values of azimuth and elevation, one can plot projections of 3D objects on different 2D planes. For example, the command 'view(90,0)' places the viewer toward the positive x-axis, looking straigth on the yz-plane, and thus produces a 2D projection of the object on the yz-plane. 'view(0, 90)' shows the figure on a 2D xy-plane. The following script generates data, plots the curves and obtains different views. Example:
% clears variables, command window and closes all previous figures clear; clc; close all % generates an angle vector with 101 values a = 0: 3*pi/100 : 3*pi; % calculates x, y, and z x = cos(a); y = sin(a); z = a; % divides the figure window into 4 subwindows (2x2) % plots on the 1st. one subplot(2,2,1) plot3(x,y,z) grid on title('A helix - 3D view') xlabel('x = cos(a)') ylabel('y = sin(a)') zlabel('z = a') % plots on the 2nd. subwindow subplot(2,2,2) plot3(x,y,z) axis('square') % rotates the figure to show only the xy-plane
view(0,90) grid on title('A helix, xy-plane') xlabel('x = cos(a)') ylabel('y = sin(a)') zlabel('z = a') % plots on the 3rd. subwindow subplot(2,2,3) plot3(x,y,z) % rotates the figure to show only the xz-plane view(0,0) grid on title('A helix, xz-plane') xlabel('x = cos(a)') ylabel('y = sin(a)') zlabel('z = a') % plots on the 4th. subwindow subplot(2,2,4) plot3(x,y,z) % rotates the figure to show only the yz-plane view(-90,0) grid on title('A helix, yz-plane') xlabel('x = cos(a)') ylabel('y = sin(a)') zlabel('z = a')
3D plot Part 2
The 3D plot functions intended for plotting meshes and surfaces ' mesh' and 'surf', and their several variants 'meshc', 'meshz', 'surfc', and 'surfl', take multiple optional input arguments, the most simple form being 'mesh(z)' or 'surf(z)', where z represents a matrix. Usually, tridimensional curves are represented by the values of z-coordinates samples on a grid of (x,y) values. Thus, to create a surface or 3D plot we first need to generate a grid of (x,y) coordinates and find the height (z-coordinate) of the surface at each of the grid points. Matlab provides the function 'meshgrid' to create a grid of points over a specified range. Meshgrid Suppose that you want to plot the function z = x2 10y + 2 over the domain 0 x 4 and 0 y 4. To do so, we first take several points in the domain, say 25 points, as shown in this Fig.:
We can create two matrices x and y, each of size 5 x 5, and write the xy-coordinates of each point in these matrices. We can then evaluate z with the command z = x.^2 10*y + 2. However, creating the two matrices x and y is much easier with the meshgrid command.
% creates vectors x and y, from 0 to 4 vx = 0 : 4 vy = vx % creates meshgrid to be used in 3D plot [x,y] = meshgrid(vx,vy)
The commands shown above generate the 25 points shown in the figure. All we need to do is generate two vectors, vx and vy, to define the region of interest and distribution or density of our grid points. Also, the two vectors need not be either same sized or linearly spaced. It is very important to understand the use of meshgrid. Matlab response is as follows:
vx = 0 vy = 0 x= 0 0 0 0
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4 4
0 y= 0 1 2 3 4 >>
1 0 1 2 3 4
2 0 1 2 3 4
3 0 1 2 3 4
4 0 1 2 3 4
See the columns of x and the rows of y. When a surface is plotted with the 'mesh(z)' command (where z is a matrix), the tickmarks on the x and y axes do not indicate the domain of z but the row and column indices of the z-matrix. Typing 'mesh(x,y,z)' or 'surf(x,y,z)' (where x and y are vectors used by 'meshgrid' to create a grid), result in the surface plot of z, with x and y values shown along the respective axes. The folowing script could be an example of how tho use the 'meshgrid', 'plot3', 'meshc', and 'surfc' commands. We'll 3D plot the following surface:
% clears command window, clears variables and closes figures clc; clear; close all % defines vectors x and y vx = -4 : 0.2: 4; vy = -3 : 0.2: 3; % calculates the necessary grid [x,y] = meshgrid(vx, vy); % calculates z and avoids a null denominator adding 'eps' % (eps is the least possible number in Matlab) z = x .* y .* (x.^2 - y.^2) ./ (x.^2 + y.^2 + eps); % generates the first figure using 'plot3' figure plot3(x,y,z) grid on % generates the second figure using 'meshc' to include the
% contour in the figure, and rotates the figure with 'view' figure meshc(x,y,z) view(-37, 15) % generates the third 3D figure using 'surfc' to include the % contour in the image, and also rotates the figure with 'view' figure surfc(x,y,z) view(-47, 25)
Do you like it? Use the instruction 'rotate3d on' to manipulate the view angle of your plot. Include it in your script or type it in the command window to change the view with your mouse over the figure...
3D plot Part 3
In this part, we demonstrate the use of the function 'sphere'. We are going to draw a unit sphere centered at the origin and generated by matrices x, y and z, of size 31 x 31 each.
Just as an excercise, we also add a line going from the center of the sphere to one of the corners in the figure (within the 3D plot). Example:
% cleans the workspace clc; clear; close all % returns the coordinates of a sphere in three % matrices that are (n+1)-by-(n+1) in size [x, y, z] = sphere(30); plot3(x,y,z) % keeps the proportions in place and writes appropriate info. axis('square') title('Transparent Sphere') xlabel('x axis') ylabel('y axis') zlabel('z axis') % keeps the above sphere in order to superimpose a line hold on % the line goes from (-1, 1, 1) to (0, 0, 0) a = -1 : .1 : 0; b = 1 : -.1 : 0; c = b; plot3(a, b, c) % draws the sphere in another format and in another figure % see what happens if we don't use the axis('square') instruction figure mesh(x,y,z) hold on plot3(a, b, c)
3D plot Part 4
In this example we make a summarization of the use of the following 3D plot instructions: meshgrid figure contour3 mesh surfc surfl
It is better if you've already read Parts 1 to 3. We're plotting exactly the same 3D data (a function depending on two variables) using several instructions, so the visualization is pretty different from each other. Example:
% cleans the memory workspace clc; clear; close all; % defines the range of axes x and y vx = -3 : 0.1 : 3; vy = vx; % generates the powerful grid [x, y] = meshgrid(vx, vy); % defines the function to be plotted z = -10 ./ (3 + x.^2 + y.^2); % opens figure 1 and plots the function using only contours figure(1) contour3(x,y,z) % opens figure 2 and draws the function using a mesh figure(2) mesh(x,y,z) % opens figure 3 and draws the function using surface with contours figure(3) surfc(x,y,z) % opens figure 4 and draws the function using a enlightened surface figure(4) surfl(x,y,z) shading interp colormap hot
3D Pie Charts
In Matlab, the expression 'pie3(V)' draws a 3D pie chart using the data in V. Each element in V is represented as a slice (with a %) in the plot. Example 1:
In the expression 'pie3(V, explode, labels)', 'explode' specifies whether to separate a slice from the center of the plot. V(i,j) is apart from the center of the pie plot if explode(i,j) is nonzero. 'explode' must be the same size as V. 'labels' specifies text labels for the slices. The number of labels must equal the number of elements in V. Example 2:
d = [1 2 3 2.5]; pie3(d, [1 0 1 0],... {'Label 1', 'Label 2', 'Label 3', 'Label 4'}) title('Pie Chart showing explosions...') results in:
3D Simple Animation
In this short article were going to experiment with simple animation in 3D. In the first experiment, we are going to work with a sphere and are going to rotate our view angle without changing any size. In the second experiment, were going to draw a paraboloid, change its size and rotate. These basic techniques are the foundation of 3D animation with Matlab.
The code that accomplishes this is the following: clear; clc; close all % Draw a sphere sphere % Make the current axis box square in size axis('square') % Define title and labels for reference title('Rotation of a sphere...') xlabel('x'); ylabel('y'); zlabel('z') % Modify azimuth (horizontal rotation) and update drawing for az = -50 : .2 : 30 view(az, 40) drawnow end % Modify elevation (vertical rotation) and update drawing for el = 40 : -.2 : -30 view(30, el) drawnow end
and after the two soft rotations we end with an image like this:
values within a loop using the function set (used to modify the handle graphics properties). Finally, we rotate the azimuth of the figure to achive another view of the box. Thats how we achieve this simple animation in 3D.
The code is the following: clear; clc; close all % Define X = -2 : [x, y] = z = .5 * paraboloid .1 : 2; Y = X; meshgrid(X, Y); (x.^2 + y.^2);
% Draw 3D figure, keep track of its handle h = surf(x,y,z); % Keep axes constant axis([-2 2 -2 2 0 20]) % Define title and labels for reference xlabel('x'); ylabel('y'); zlabel('z') % Stretch paraboloid and show updates for i = 1 : .1 : 5; set(h, 'xdata', x, 'ydata', y, 'zdata', i*z) drawnow end % Modify azimuth (horizontal rotation) and update drawing for az = -37.5 : .5 : 30 view(az, 30) drawnow end
Quadratic Equations
We are going to create now a Matlab program that calculates the quadratic roots (roots of quadratic equations). The equation must be in the following form: ax2 + bx + c = 0, where a, b, and c are real coefficients.
Naturally, we have to deliver two x-values. The m-file that we might use to accomplish this task is very simple: function x = rqe(a,b,c) x(1) = (-b + sqrt(b^2 - 4 * a * c))/(2*a); x(2) = (-b - sqrt(b^2 - 4 * a * c))/(2*a);
We enter the coefficients as parameters when we call the function. We assign to variables x(1) and x(2) the calculated values using the formula, and the returning result x is a vector containing x(1) and x(2). We could use the following Matlab code instead, to return two separate variables: function [x,y] = rqe2(a,b,c) x = (-b + sqrt(b^2 - 4 * a * c))/(2*a); y = (-b - sqrt(b^2 - 4 * a * c))/(2*a);
If we want to compute the roots of the following expression: 2x2 + x - 1 = 0 We can call our function (first code) like this: x = rqe(2,1,-1) and we get from Matlab: x= 0.5000 -1.0000 We can call our second function (second code above) like this: [m, n] = rqe2(2, 1, -1)
Polygon Area
This program calculates the area of a polygon, using Matlab . You must supply the x and y coordinates of all vertices. Coordinates must be entered in order of successive vertices. The formula used to calculate the area is
If we use the instruction 'area(x,y)', we obtain the following figure (to learn another way to plot vectors):
Now, we prepare a function with the vertices in input vectors x and y. The output scalar variable is p_area.
function p_area = area_calc(x,y) % Get the number of vertices n = length(x); % Initialize the area p_area = 0; % Apply the formula
for i = 1 : n-1 p_area = p_area + (x(i) + x(i+1)) * (y(i) - y(i+1)); end p_area = abs(p_area)/2;
We can call the function with a simple line, like this: a1 = area_calc(x,y) And we obtain from Matlab: a1 = 108 It's important to mention that we can save all the code above, since Matlab includes the built-in function 'polyarea', that we can call in this manner: a2 = polyarea(x,y) which produces the same result. a2 = 108 Another example? Let's execute this code... x=[0 0 3 3]; y=[0 1 1 0]; a1 = area_calc(x,y) a2 = polyarea(x,y) And the result is... a1 = 3 a2 = 3 ... as expected.
Angle, side, angle Side, angle, side Angle, angle, side Side, side, side
Data must be entered in the order it appears in a triangle, either clockwise or counterclockwise. We are going to start our Matlab coding with a simple menu for the options opt = menu('Parts 'Angle Side 'Side Angle 'Angle Angle 'Side Side of a Triangle', ... Angle',... Side',... Side',... Side');
This code launches a menu window with four buttons, one for each option according to the problem in our trigonometry. Note that the first string in the menu is used to write any message that we want at the top. Note also that we can separate long lines of code with the '...' ending. The value of the option (in this case an integer from 1 to 4) is kept in the 'opt' variable. This nice window appears
Then, we can define some useful constants % Define useful constants c = pi/180; ea = 'Enter angle (in degrees): '; es = 'Enter side: '; The 'c' value is used as a converter from radians to degrees. All trigonometric functions in Matlab work in radians by default. The last strings are used to ask for information from the keyboard. Instead of writing 'input('Enter angle (in degrees): ')' many times along the code, we can define the string 'ea' and write 'input(ea)', achieving exactly the same result. If we change the string in the definition, we don't have to change all the other lines that contain this string.
Then, we use the 'switch statement' to develop all of the options that solve this problem in trigonometry, case by case. % Develop all the different cases switch opt % Ask for 'angle side angle' case 1 a(1) = input(ea) * c; s(3) = input(es); a(2) = input(ea) * c; a(3) = pi - a(1) - a(2); s(1) = s(3) * sin(a(1)) / sin(a(3)); s(2) = s(3) * sin(a(2)) / sin(a(3)); ... If the user choses button 1 in the menu, the code will ask to enter three things from the keyboard, so this is actually an interactive code. It asks for an angle, then for a side, and finally for another angle of the triangle under study. Then, the code solves the problem according to basic trigonometric rules, skips all the other cases and goes to the final of the program, where the results are displayed... if min(a) < 0 error('Angles of a triangle cannote be less than zero...') end % Show results disp(' ') disp('Sides...') s disp('Opposite angles...') a = a/c The complete code, including the four cases, is as follows:
% Clear memory, clear screen and save empty lines clc; clear; format compact % Display menu window opt = menu('Parts of a Triangle', ... 'Angle Side Angle',... 'Side Angle Side',... 'Angle Angle Side',... 'Side Side Side'); % Define useful constants c = pi/180; ea = 'Enter angle (in degrees): '; es = 'Enter side: '; % Develop all the different cases switch opt % Ask for 'angle side angle'
= = = = = =
input(ea) * c; input(es); input(ea) * c; pi - a(1) - a(2); s(3) * sin(a(1)) / sin(a(3)); s(3) * sin(a(2)) / sin(a(3));
% Ask for 'side angle side' case 2 s(3) = input(es); a(1) = input(ea) * c; s(2) = input(es); s(1) = sqrt(s(3)^2+s(2)^2-2*s(3)*s(2)*cos(a(1))); a(2) = sin(a(1)) * s(2) / s(1); a(2) = asin(a(2)); a(3) = pi - a(1) - a(2); % Ask for 'angle angle side' case 3 a(3) = input(ea) * c; a(2) = input(ea) * c; s(3) = input(es); a(1) = pi - a(2) - a(3); s(1) = s(3) * sin(a(1)) / sin(a(3)); s(2) = s(3) * sin(a(2)) / sin(a(3)); % Ask for 'side side side' case 4 s(1) = input(es); s(2) = input(es); s(3) = input(es); a(1) = (s(2)^2 + s(3)^2 - s(1)^2)/(2 * s(2) * s(3)); a(1) = acos(a(1)); a(2) = sin(a(1)) * s(2) / s(1); a(2) = asin(a(2)); a(3) = pi - a(1) - a(2); end if min(a) < 0 error('Angles of a triangle cannote be less than zero...') end % Show results disp(' ') disp('Sides...') s disp('Opposite angles...') a = a/c
We try it like this: choose the first button on the menu, and answer... Enter angle (in degrees): 25.7 Enter side: 21.67
Enter angle (in degrees): 33.92 Then, Matlab response is: Sides... s = 10.8931 14.0173 Opposite angles... a = 25.7000 33.9200
21.6700 120.3800
Note that there is one option missing in the menu. The option of 'side side angle' is not included in the code... Try to develop it yourself. If you can do it then you know that your Matlab knowledge is becoming great!!! Good luck!
Matrix decomposition
Matlab includes several functions for matrix decomposition or factorization.
LU decomposition: the name of the built-in function is 'lu'. To get the LU factorization of a square matrix M, type the command [L,U] = lu(M). Matlab returns a lower triangular matrix L and an upper triangular matrix U such that L*U = M. Example: Type M = [2 3 2 9 3 2 3 8 4 6 1 0 5 1 7 2];
[l,u] = lu(M) l*u Matlab answer is: l = 0.2222 0.3333 0.2222 1.0000 u = 9.0000 0 0 8.0000 1.2222 0 0 1.0000 6.5455 2.0000 6.5556 3.9091 1.0000 -0.5455 1.0000 0 0.4583 1.0000 0 0 1.0000 0 0 0
-3.7917 5.0000 1.0000 7.0000 2.0000 See another example for LU factorization
QR factorization: the name of the appropriate built-in function for this purpose is 'qr'. Typing the command [Q,R] = qr(M) returns an orthogonal matrix Q and an upper triangular matrix R such that Q*R = M. Example (assuming the same matrix M as above): Type [q,r] = qr(M) q*r and the fast Matlab answer is: q = -0.2020 -0.3030 -0.2020 -0.9091 r = -9.8995 0 0 0 ans = 2.0000 3.0000 2.0000 9.0000 -9.0914 1.8295 0 0 3.0000 2.0000 3.0000 8.0000 -2.8284 0.7028 -6.6713 0 4.0000 6.0000 1.0000 -0.0000 -4.5457 6.9274 -2.2896 2.2595 5.0000 1.0000 7.0000 2.0000 0.6359 -0.4127 0.6359 -0.1450 -0.4469 -0.8144 0.0027 0.3702 -0.5959 0.2731 0.7449 -0.1241
Cholesky decomposition: if you have a positive definite matrix A, you can factorize the matrix with the built-in function 'chol'. The command R = chol(A); produces an upper triangular matrix R such that R'*R = A for a positive definite A. This is a brief reminder of what a positive definite matrix is: An n by n matrix M is positive definite if
xT Mx = 0 implies x = 0
If matrix M is symmetric, diagonally dominant, and has positive diagonal elements, then M is positive definite If matrix M is positive definite, then M is diagonally dominant and has positive diagonal elements. Example: Type M = [1 1 1 1 r = chol(M) r'*r and Matlab answer is: r = 1 0 0 0 ans = 1 1 1 1 1 2 3 4 1 3 6 10 1 4 10 20 1 1 0 0 1 2 1 0 1 3 3 1 1 2 3 4 1 3 6 10 1 4 10 20];
Singular value decomposition (svd): the name of the built-in function is svd. Typing [U,S,V] = svd(M); produces a diagonal matrix S, of the same dimension as M and with nonnegative diagonal elements in decreasing order, and unitary matrices U and V so that M = U*S*V'. Example (considering the same matrix M as above): Type [u,s,v] = svd(M) u*s*v' and you get: u = -0.0602 -0.2012 -0.5304 -0.6403 0.7873 -0.1632 -0.3087 0.7231
-0.4581 -0.8638 s = 26.3047 0 0 0 v = -0.0602 -0.2012 -0.4581 -0.8638 ans = 1.0000 1.0000 1.0000 1.0000
-0.3918 0.3939 0 2.2034 0 0 -0.5304 -0.6403 -0.3918 0.3939 1.0000 2.0000 3.0000 4.0000
-0.5321 0.2654 0 0 0.4538 0 0.7873 -0.1632 -0.5321 0.2654 1.0000 3.0000 6.0000 10.0000
-0.5946 0.1684 0 0 0 0.0380 -0.3087 0.7231 -0.5946 0.1684 1.0000 4.0000 10.0000 20.0000
If the matrix A is square, then we can use the singular value decomposition to find the inverse, which is is A-1 = (USV')-1 = (V')-1S-1U-1 = VS-1U' since (AB)-1 = B-1A-1, UU' = I, and VV' = I.
And so,
If an SVD of a matrix A can be calculated, so can be its inverse. Therefore, we can find a solution to a system Ax = b x = A-1b = VS-1U'b that would otherwise be usolvable. Example:
We simply type: [U,S,V] = svd(A) and the above operation produces a diagonal matrix S, of the same dimension as A and with nonnegative diagonal elements in decreasing order, and unitary matrices U and V so that A = U*S*V'. The Matlab answer is: U = -0.1826 0.9129 -0.3651 -0.8944 0.0000 0.4472 0.4082 0.4082 0.8165
We can confirm the values of UU', VV' and USV, by executing these instructions in Matlab U*U' V*V' U*S*V The confirming responses are: ans = 1.0000 -0.0000 -0.0000 ans = 1 0 ans = -0.0000 -2.0000 1.0000 >> 0 1 -1.0000 1.0000 0.0000 -0.0000 1.0000 -0.0000 -0.0000 -0.0000 1.0000
this means that it is the nth-root of the product of all the elements being considered. n is the number of elements in the set. The geom. deviation is given by this formula
where q is a sum including the natural logarithms of the elements in the set.
We can use iterations to calculate what we need. In Matlab, this is not the most efficient way to do it, but we can implement the same algorithm in other languages...
function [gm, gd] = geo_mean_dev(x) % Take into account the number of elements in the vector n = length(x); % Initialize some variables gm = 1; q = 0; % Iterate through all of the elements for i = 1 : n d = x(i); % Compute mean gm = gm * d^(1/n); % Accumulate intermediate term for deviation q = q + log(d)^2; end % Compute deviation gd = abs(exp(sqrt(q/(n-1)-(n/(n-1)*(log(gm))^2))));
We can test our function as follows (from the command window or from another script): x = [3 5 8 3 7 2]; [gm1, gd1]= geo_mean_dev(x)
We can also use the vectorized form to make it easier and faster... (note that the 'log' function performs the natural logarithm of a number, while the 'log10' function performs the log in base 10) n = length(x); % The 'prod' function gets the multiplication of all the elements gm2 = prod(x)^(1/n) % The 'sum' function gets the sum of the vector q = sum(log(x).^2); % and now we can imlement the last formula gd2 = exp(sqrt(q/(n-1)-(n/(n-1)*log(gm2)^2))) Again, Matlab response is gm2 = 4.1407 gd2 = 1.7237
Interpolation
This page shows the most usual and general interpolation concept. This code calculates the y-coordinates of points on a line given their x-coordinates. It is necessary to know coordinates of two points on the same line. The point is interpolated using the following formula:
We can develop then the following Matlab function. Input parameters are the two known coordinates and the desired x-value to interpolate. Note that with this formula we can also extrapolate a coordinate on the same line.
Let's assume that our known coordinates are (60, 15.56) and (90, 32.22), and our xvalues to be interpolated are 73 and 85.6. Now, we can use the above function, for example calling it like this: y = interpolate(60, 15.56, 90, 32.22, 73) y = interpolate(60, 15.56, 90, 32.22, 85.6) Matlab response is: y= 22.7793 y= 29.7765
Fortunately, Matlab has also several built-in function to interpolate values with different methods ('interp1', 'interp2', 'interp3', and 'interpn'). 'interp1' is called one dimensional interpolation because vector y depends on a single variable vector x. The calling syntax is ynew = interp1(x, y, xnew, method) The parameter 'method' can be 'nearest', 'linear', 'cubic' or 'spline'. The default method is 'linear' (type help interp1 on the Matlab command window to see more details). We can use this function (instead of our own developed function above), like this: x = [60 90]; y = [15.56 32.22]; xnew = 73; ynew = interp1(x, y, xnew) xnew = 85.6; ynew = interp1(x, y, xnew) And Matlab response is: ynew = 22.7793 ynew = 29.7765
Example 1
Consider the curve y = x3 - 3x + 3. We now that points x = [-3 -2 -1 0 1 2 3]; y = [-15 1 5 3 1 5 21]; are on the curve. What are the values of y when x = -1.65 and 0.2? x1 = -1.65; y1 = lagrange_interp(x,y,x1) x2 = .2; y2 = lagrange_interp(x,y,x2)
The result are: y1 = 3.4579 y2 = 2.4080 Lets plot our approach: plot(x, y, axis([-4 title(y xlabel(x) ylabel(y) 'bo', = x1, 4 x^3 y1, 'ro', x2, -17 3x y2, + 'ro') 23]) 3)
Example 2
Given the following points from a sine curve, what are the y-values for x = -2,47 and 1.5? x = [-5 -4 -3 -2 -1 0 1 2 3 4 5]; y = [.958 .757 -.141 -.909 -.841 0 .841 .909 .141 -.757 .959]; x3 = -2.47; y3 = lagrange_interp(x,y,x3) x4 = 1.5; y4 = lagrange_interp(x,y,x4)
And our plot is: plot (x, y, 'bo', x3, y3, 'ro', x4, y4, 'ro') title('sin(x)') xlabel('x') ylabel('y')
Linear Regression
This program fits a straight line to a given set of coordinates using the method of least squares ( linear regression ). The coefficients of the line, coefficient of determination, coefficient of correlation and standard error of estimate are calculated. Once the line has been fitted, you may predict values of y for given values of x. We develop the following Matlab code (note that Matlab has its own built-in functions to make linear regression easier for all of us, but we'd like to show a step-by-step way to do it, to understand the inner concepts):
function [y0, a, b, r2, r, k2] = lin_reg(x, y, x0) % Number of known points n = length(x); % Initialization j = 0; k = 0; l = 0; m = 0; r2 = 0; % Accumulate intermediate sums j = sum(x); k = sum(y); l = sum(x.^2); m = sum(y.^2); r2 = sum(x.*y); % Compute curve coefficients b = (n*r2 - k*j)/(n*l - j^2); a = (k - b*j)/n; % Compute regression analysis j = b*(r2 - j*k/n); m = m - k^2/n; k = m - j; % Coefficient of determination r2 = j/m; % Coefficient of correlation r = sqrt(r2); % Std. error of estimate k2 = sqrt(k/(n-2)); % Interpolation value y0 = a + b*x0;
If we have the following data available (where every yi has its correspondent xi): x = [71 73 64 65 61 70 65 72 63 67 64]; y = [160 183 154 168 159 180 145 210 132 168 141]; we can call the function above in this manner (to obtain interpolated values for x = 70 and x = 72): [y0, a, b, r2, r, k2] = lin_reg(x, y, 70) [y0] = lin_reg(x, y, 72) And Matlab response is: y0 = 176.5139
We can use the 'polyfit' and 'polyval' instructions in Matlab for this purpose, like this: a = polyfit(x,y,1) y0 = polyval(a,70) y0 = polyval(a,72) Fitting a straight line through the data means thet we want to find the polynomial coefficients of a first order polynomial such that a1xi + a0 gives the best approximation for yi. We find the coefficients with 'polyfit' and evaluate any xi with 'polyval'. Matlab result is a= 4.0472 -106.7917 y0 = 176.5139 y0 = 184.6083 confirming our previous results.
Numerical Derivative
We are going to develop a Matlab function to calculate the numerical derivative of any unidimensional scalar function fun(x) at a point x0. The function is going to have the following functionality: Usage: D = Deriv(fun, x0) fun: name of the unidimensional scalar function (string) x0: point of interest (scalar) D: derivative of fun at x0 (scalar)
As you may remember, the very well known way to analytically derivate any function is:
This roughly means that we have to find the value of the function in two very close values (one of them is the point of interest), get the difference of those values and divide it by the displacement of the independent variable. In other words, First step: Find , where is a very small value compared to x.
The result is the numerical derivative of your function. We can implement this algorithm very easily in Matlab, in this way: function D = Deriv(fun, x0) % |delta| is relative to |x0| delta = x0 / 1000; if x0 == 0 % avoids delta = 0 (**arbitrary value**) delta = 1e-12; end f1 = feval ( fun, x0 + delta ); f2 = feval ( fun, x0 - delta ); D = (f1 - f2) / (2 * delta); Note, that we are really evaluating
which should be the same as explained above, since the displacement is almost zero. You can try both options.
Function 'feval' evaluates a given function (the string in the parameter fun) in a specific value (number in second parameter of 'feval'). Now, let's try our derivative function. We create a function in a separate m-file: function y = inverse(x) y = 1/x; And we can call it like this: Deriv('inverse', 1) The result is: Expected: -1
Obtained:
-1.0000
Obtained:
-0.0400
We can save another totally arbitrary (unidimensional scalar) function in a different mfile: function y = myfun(x) y = 3*x^2 + 2*x; And we can perform the derivative in several ways... f = 'myfun' x=0 Deriv(f, x) The result is: Expected: 2 x=5 Deriv(f, x) The result is: Expected: 32 Deriv(f, -3) The result is: Expected: -16
Obtained:
Obtained:
32.0000
Obtained:
-16.0000
Gradient
We are going to include the concepts in our Derivative function created before, to develop a Matlab function to calculate the gradient of a multidimensional scalar function. The function is going to have the following functionality: % Usage: g = Grad(fun, x0) % fun: name of the multidimensional scalar function % (string). This function takes a vector argument of % length n and returns a scalar. % x0: point of interest (vector of length n) % g: column vector containing the gradient of fun at x0. The % size(g) = size(x) function g = Grad(fun, x0) % |delta(i)| is relative to |x0(i)| delta = x0 / 1000; for i = 1 : length(x0) if x0(i) == 0 % avoids delta(i) = 0 (**arbitrary value**) delta(i) = 1e-12; end % recovers original x0 u = x0; u(i) = x0(i) + delta(i); % fun(x0(i-1), x0(i)+delta(i), x0(i+1), ...) f1 = feval ( fun, u ); u(i) = x0(i) - delta(i); % fun(x0(i-1), x0(i)-delta(i), x0(i+1), ...) f2 = feval ( fun, u ); % partial derivatives in column vector g(i,1) = (f1 - f2) / (2 * delta(i)); end We can try this algorithm, creating a function bowl (which includes two variables) in an separate m-file, as follows: function y = bowl(x) y = (x(1)-6)^2 + (x(2)-4.5)^4 / 25; Then, we can test it from the command window: x = [0 0] f = 'bowl' Grad(f, x) Expected: [-12 x = [1 1] Grad(f, x) Expected: [-10 x = [6 4.5] Grad(f, x)
-14.58]'
Obtained: [-12.0011
-14.5803]'
-6.86]'
Obtained: [-10.0000
-6.8600]'
0]'
Obtained: [0
0]'
-4.32]'
Obtained: [-8.0000
-4.3200]'
Now, another test with a different multivariable function: function y = semirosen(x) y = 100 * ( x(2) - x(1)^2 ) + ( 1 - x(1) )^2 ; x = [0 0] f = 'semirosen' Grad(f, x) Expected: [-2 x = [1 1] Grad(f, x) Expected: [-200 x = [9 15] Grad(f, x) Expected: [-1784
100]'
Obtained: [-2.0001
100.0000]'
100]'
Obtained: [-200.0000
100.0000]'
100]'
0.1000]'
Trapezoidal Rule
This code approximates the definite integral of a function. The integral is calculated using the trapezoidal rule. Parameters of the function are the limits of integration and the number of intervals within the limits. The function to be integrated is another parameter and must be defined before running this program. For example, if we want to integrate the function f(x) = y = x3, we can define it, in Matlab, like this:
function y = trap2(lower_lim, upper_lim, interv, fun) % initialize the result y = 0; % 'step' is related to the size of each interval
step = (upper_lim - lower_lim) / interv; % add up the area of each trapezoid for j = lower_lim : step : upper_lim y = y + feval(fun,j); end % compute integral y = (y - (feval(fun, lower_lim) + feval(fun, upper_lim))/2) * step;
Now, we can call our integration function from another Matlab script or from the command window, for example z1 = trap2(0, 2, 10, 'fun_for_integration') z2 = trap2(0, 2, 100, 'fun_for_integration') z3 = trap2(0, 2, 1000, 'fun_for_integration') and we get the Matlab results z1 = 4.0400 z2 = 4.0004 z3 = 4.0000 Note that this is a numerical integration, and so we have to be very aware of the possible inaccuracies of the method. The first two parameters given to the function are the lower and upper limits, respectively. The third parameter is related to the size of each interval: the higher the number the better accuracy in the evaluation we can reach. The fourth parameter is the name of the function to be integrated (the instruction 'feval' is in charge of evaluating that function in the main body of the code). Now, the best part is that Matlab has its own function to do the integration using the trapezoidal rule ('trapz'), so we can save all of our programming thinking for other things... However, the built-in 'trapz' function, works a little different. We first define our interval and desired step in a variable vector x, and define the value of the corresponding function in a variable vector y. For example, we want to evaluate the same function as above, within the interval [0 2], in 0.1 increments, so we use x = 0 : .1 : 2. If we want a finer tunning of the integration function, we can set the step in our independent variable. Then we can call the Matlab function like this (three different cases)
x = 0 : .1 : 2; y = x.^3;
and we get the Matlab response, with different approximations z4 = 4.0100 z5 = 4.0001 z6 = 4.0000
Simpson's Rule
This code approximates the definite integral of a function. The integral is calculated using Simpson's rule. You must supply the limits of integration, the increment between points within the limits, and the function of the curve to be integrated. For example, if we want to integrate the function f(x) = y = x3, we can define it, in Matlab, like this:
And then, we can create the actual integration function, like this:
function y = simpson2(lower_lim, upper_lim, incr, fun) % Check that the provided increment has sense for our purpose if (upper_lim - lower_lim)/incr ~= floor((upper_lim - lower_lim)/incr) disp('Warning: increment must divide interval into equal subintervals') disp('Please change the increment') y = 'error'; return end
% Evaluate the function in the lower and upper limits y1 = feval(fun, lower_lim); y2 = feval(fun, upper_lim); % Initialize the intervals c = 0; d = 0; % Loop for each subinterval for i = 1 : (upper_lim - lower_lim)/incr - 0.5; % Calculate the function at each subinterval y = feval(fun, lower_lim + i*incr); % Interval even or odd? if i/2 == floor(i/2) % Sum all even-interval function values d = d + y; continue else % Sum all odd-interval function values c = c + y; continue end end % Calculate integral y = incr/3 * (y1 + 4*c + 2*d + y2);
Now, we can call our integration function from another Matlab script or from the command window, for example z1 = simpson2(0, 2, .01, 'fun_for_integration') z2 = simpson2(0, 2, .2, 'fun_for_integration') and we get the Matlab results, which in this case are the same z1 = 4.0000 z2 = 4 Note that this is a numerical integration, and so we have to be very aware of the inaccuracies of the Simpson's Rule method. The first two parameters given to the function are the lower and upper limits, respectively. The third parameter is related to the size of each interval. The fourth parameter is the name of the function to be integrated (the instruction 'feval' is in charge of evaluating that function in the main body of the integration code). Now, the best part is that Matlab has its own function to do the integration using the
Simpson's rule ('quad'), so we can save all of our programming efforts for other things... However, the built-in 'quad' function, works a little different. It integrates a specified function over specified limits, based on adaptive Simpson's rule. This adaptive rule attempts to improve accuracy by adaptively selecting the size of the subintervals (instead of keeping it constant) within the limits of integration while evaluating the sums that make up the integral. You can call this 'quad' function, like this z = quad('fun_for_integration', 0,2)
Then, we can call the 'quad' function from another script or try it from the Matlab command window, like this z = quad('fun_for_integration2', 0.5, 1.5)
Prime Factors
This program lists the prime factors (PFs) of an integer. It will test neither 0 nor 1.
It is well known that PFs of a positive integer are the primes that divide into that integer exactly, without leaving a remainder. The process of finding these numbers is called integer factorization, or prime factorization. Heres the full Matlab script: % Clears variables and screen clear; clc % Asks user for input z = input('Enter your positive number: '); % Loops to test all integers (2 through z) as PFs for i = 2 : z s = 0; % Is z/i an integer? Is the remainder 0? while z/i == floor(z/i) z = z/i; s = s + 1; end % A PF is found and displayed if s > 0 str = [num2str(i) '^' num2str(s)]; disp(str) % If z = 1, no more divisions are necessary, % thus breaks the loop and quits if z == 1 break end end end
Example 1:
What are the prime factors of 49? Run the code above and enter your number Enter your positive number: 90 Matlab answer is 2^1 3^2 5^1
a) 'factor(x)' returns a vector containing the PFs of x. For example: factor(390), results in ans = 2 3
13
b) 'primes(x)' is a row vector of the primes less than or equal to x. For example: primes(10), results in ans = 2 3
c) 'isprime(x)' is true for prime numbers. For example: isprime(10) results in ans = 0
Euclidean Algorithm
This program calculates the Greatest Common Denominator (GCD) of two integers. It is based on the Euclidean algorithm for finding the GCD.
This is the full Matlab program that follows the flow-chart above, without using the builtin 'gcd' instruction. % Clears screen and deletes all the variables in the workspace clear; clc % Asks the user for input and takes only positive numbers into account a = input('First number: '); b = input('Second number: '); a = abs(a); b = abs(b); % This is the real trick, normally performed a number of times r = a - b*floor(a/b); % Repeats the operation until updates of a equal updates of b while r ~= 0 a = b; b = r; r = a - b*floor(a/b); end % Displays the result GCD = b Example 1:
Find the greatest common denominator of 18 and 50.
Run the algorithm above and enter data: First number: 18 Second number: 50 GCD = 2
The built-in Matlab command 'gcd' also works on vectors. For example: a = [50 150 20] b = [18 115 5] >> gcd(a,b) ans = 2 5
These are the functions: function [x,y]= polar2cart (mag, ang_in_deg) x = mag * cos(ang_in_deg*pi/180); y = j * mag * sin(ang_in_deg*pi/180);
And now we test them: % Clear memory and screen. Avoid double-blank lines clear; clc; format compact [x, y] = polar2cart(2, 30.5) [r, ar, ad] = cart2polar(7 + 18i) [r, ar, ad] = cart2polar(0 - 46.8i)
The results are: x = 1.7233 y = 0 + 1.0151i r = 19.3132 ar = 1.1999 ad = 68.7495 r = 46.8000 ar = -1.5708 ad = -90
Data Analysis - reading text files and processing them with Matlab
In this article, we're going to read text files with Matlab, perform data analysis or processing, and finally we are going to write out our results to another text file. The procedure is easily adaptable to many situations. Let's assume that we have 3 text files (it could be hundreds). They all have to have the same format, and have to have a basic file name, with numbered tag endings (otherwise it is harder to automate the reading process). For example, we have files 'data_sheet1.txt', 'data_sheet2.txt' and 'data_sheet3.txt'. So, the basic file name is 'data_sheet'; then, the numbered tag is 1, 2 or 3, respectively, and they all end with the '.txt' extension. Let the content for each file be something simple, for example, for 'data_sheet1.txt' the hypothetical content is: dummy line 1 dummy line 2 dummy line 3 1 2 3 4 5 1234 2345 4320 4567 9876
This file has four text lines (three dummy lines and one blank line) at the beginning, and then the real data in two columns. In our case, the content for 'data_sheet2.txt' is: dummy line 1 dummy line 2 dummy line 3
1 2 3 4 5
and the content for 'data_sheet3.txt' is dummy line 1 dummy line 2 dummy line 3 1 2 3 4 5 123 234 432 456 987
Note that all the three files have four text lines at the beginning and all of them have the relevant data in the same format, with the same number of elements (two columns and five rows). The number of columns or rows is not relevant for our purpose, but the files have to keep the same format or structure. We are going to use Matlab functions 'fopen', 'textscan' and 'num2str' to read data from all those '.txt' files (it's a good idea if you investigate those three functions a little bit, but I'll give you the recipe). We are not interested in the four text lines at the beginning of the files, and we want to read the first column of the first file (which is the same for all the files, let's say for identification purposes) and the second column of each of the files, so, we want to end with something like 1 2 3 4 5 1234 2345 4320 4567 9876 12340 23452 43203 45674 98765 123 234 432 456 987
In this way, we now have the information in one matrix, and we can do data analysis thereafter. This is the function that I propose to read the files. You have two input parameters (the base file name and the number of files to read) and one output (one cell array with your relevant data). Fair, isn't it? To automatically change the name of the file we use an array in this form: [BaseFile num2str(i) '.txt'] This array concatenates the string BaseFile name (input parameter) with a counting number (by changing the iteration counter into a string), and then concatenates the '.txt' extension.
For the first file, the idea can be replaced by: [BaseFile '1' '.txt'], or better [BaseFile '1.txt'] The full code would be: function R = get_data(BaseFile, n) % Open the first file d(1) = fopen([BaseFile '1.txt']); % Read the first two columns, skip the first 4 headerlines R = textscan(d(1), '%f %f', 'headerLines', 4); % Close the file, you don't need it any longer fclose(d(1)); for i = 2 : n % Open consecutively each of the remaining files d(i) = fopen([BaseFile num2str(i) '.txt']); % Skip the first column of the new file (an '*' to do this) and keep on building the array R = [R textscan(d(i), '%*f %f', 'headerLines', 4)]; % Close the file fclose(d(i)); end
You end with your data in cell array R. Instruction 'textscan' produces a cell array (not an ordinary array) so you have to alter this (only if necessary). How are you going to use the above function to read text files and process data from Matlab? This is one suggestion. You may process it the way you want... % Reset your memory and clear your screen clear; clc % Provide base file name and number of files to be read BaseFile = 'data_sheet'; n = 3; % Use the developed function to read data R = get_data(BaseFile, n); % Transform your cell array into an ordinary matrix my_data = R{1}; for i = 2 : n+1 my_data = [my_data R{i}]; end % Show your data my_data
At this point 'my_data' is a matrix that has the information as you need it (exactly as shown before). You can study it, or plot it or perform data analysis of any kind... % Calculate the average of all of the columns and show my_average = mean(my_data) % Calculate the standard deviation for each column my_std = std(my_data) % Calculate the maximum my_max = max(my_data) % Calculate the minimum my_min = min(my_data) % Arrange your information to be saved my_results = [my_average' my_std' my_max' my_min'] % Save your my_results matrix in file 'data.txt' save data.txt -ascii my_results Done! Now, you have a text file with your data analysis or processed information.
Then, an untitled figure will pop-up. You have some components on the left menu, which you can drag onto your interface.
In this example we are going to use only two push buttons and one static text.
Drag and drop a static text onto your Matlab GUI. You can reduce or increase the size of your interface window by dragging its low-rigth corner, as its done in other drawing programs.
Double click on this static text and a Property Inspector window will appear. Scroll down and look for the String property and delete what's in there. For the moment we want it to be blank. Then, make the Tag property to be output_line. You can use whatever name you want, but output_line seems good to me... (hehehe) Your windows must look similar to what Im showing here:
Then, drag-and-drop a push button onto your interface. Modify its String property to read Launch Message. Let its Tag property intact. You could change this tag... its the name or identifier of the object as its going to be recognized in the rest of the code. Your windows must look similar to what Im showing here:
Drag-and-drop another push button. Modify its String property to read Clear Message and leave its Tag as it is. Youll produce these results.
Now, rigth-click on the Launch Message button and choose View Callbacks -> Callback
Youll be asked to save your figure. A good name (only my suggestion) is hello_world.fig... use the name that you like. Youll be taken to the Matlab code (in the editor window) that will drive your interface. Matlab has automatically created functions related to your components. You have to make the final touches... For the moment, dont care about the many lines automatically created. Just focus on what we need to do. The Callback functions are the instructions that will be executed when the user pushes the buttons or does something with the components that you have included in your Matlab GUI. In this case, youll see something like this code. % --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) % hObject handle to pushbutton1 (see GCBO) % eventdata reserved - to be defined in a future version of MAT % handles structure with handles and user data (see GUIDATA)
A set instruction sets the properties of the elements that you indicate. Do you remember that you have a static text with the tag (identifier) output_line? We are going to modify it when the user pushes the button with the string Launch Message. This is accomplished with the instruction set(handles.output_line,'String','Hello World!!') The first parameter is the object (component) that youre going to modify. It starts with handles.. The second argument is the objects property that youre going to modify, and in this case is the String property. The third argument is the value that you want to assign to the property. So, the result is that when the user presses the Launch Message button, a
message reading Hello World!! will appear in the output line (officialy named handles.output_line). Add this single line to the code, so that it looks like this: % --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) % hObject handle to pushbutton1 (see GCBO) % eventdata reserved - to be defined in a future version of MAT % handles structure with handles and user data (see GUIDATA) set(handles.output_line,'String','Hello World!!')
Well do something similar to the callback corresponding to the Clear Message button. So change this original code... % --- Executes on button press in pushbutton2. function pushbutton2_Callback(hObject, eventdata, handles) % hObject handle to pushbutton2 (see GCBO) % eventdata reserved - to be defined in a future version of MAT % handles structure with handles and user data (see GUIDATA) into this... % --- Executes on button press in pushbutton2. function pushbutton2_Callback(hObject, eventdata, handles) % hObject handle to pushbutton2 (see GCBO) % eventdata reserved - to be defined in a future version of MAT % handles structure with handles and user data (see GUIDATA) set(handles.output_line,'String','')
The result is that when the user presses the Clear Message button, a blank message will appear in the output line (officialy named handles.output_line). Magic is about to happen! Now, run your interface by clicking the run icon at the top of the editor window...
and... presto! a hello_world window has appeared! Its your first Matlab GUI!
Try, it! Press the Launch Message button... and an interesting message appears...
Well done! You did it! So, lets summarize: You can drag-and-drop your components onto your graphic interface to start your Matlab GUI. Matlab will automatically create callback-functions, related to the buttons or other components that you include. The set instruction assigns values to properties of the elements that you want to modify. The general format is: set(handles.tag_of_your_component, 'Property', value)
Resize your elements, figure and window as necessary (by dragging their anchors on the corners). You must end-up having something similar to this:
Now, double-click on each element, look and modify their properties as indicated on this table:
Component Top Edit Text Bottom Edit Text Left Static Text Rigth Static Text Push-button HorizontalAlignment right right center right center String 0 0 = 0 + Tag edit1 edit2 text1 result pushbutton1
You must now have something similar to this (save it with any name, for example: adder.fig):
Before we develop the code for this interface, we must mention that there are three very important instructions when working with GUIs: get, guidata, and set. The get instruction, gets the string value from an input component. For example, if we want to get the number that the user inputs in edit1, we can do it like this (preceed the identifier tag with handles.):
get(handles.edit1, 'String')
However, this instruction gets a string, not a number; thus, if we need to numerically manipulate that value, we have to transform it into a number first. For example, something typical is: num = str2double(get(handles.edit1,'String')); Now, our variable num does contain a number (double), and we can manipulate it. Finally, we must update the value of the component and keep that variable in our memory-workspace (using the guidata instruction) to be used in other callback functions. We can achieve it by doing this: handles.edit1 = num; guidata(hObject,handles)
Generally speaking, we need to finish every callback function with guidata(hObject,handles) in order to maintain in memory the values of the variables. The set instruction sets the properties of the element that you indicate. The property Tag is the identifier to use for this purpose. Do you remember that you have one static text with the tag (identifier) result? We are going to modify it when the user pushes the button with the string +. This is to be accomplished with the instruction set(handles.output_line,'String',value) where value contains the addition edit1 + edit2
To modify the Matlab code for the components displayed in your interface, right-click on any of them and choose View Callbacks -> Callback. You will be taken to the corresponding m-file (there are many automatically written lines, just add the new ones). We can test for the input value from the user. Lets check the code for the callback function related to edit1: function edit1_Callback(hObject, eventdata, handles) % hObject handle to edit1 (see GCBO) % eventdata reserved - to be defined in a future version of MLB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit1 as text % str2double(get(hObject,'String')) returns contents of % edit1 as a double num = str2double(get(hObject,'String')); if isnan(num) num = 0; set(hObject,'String',num); errordlg('Input must be a number', 'Error')
In this callback function, we first read the input from the user and transform it to a number (since we are within the edit1_Callback, using get(handles.edit1,String) is the same as using get(hObject,'String')). Then, we use the isnan (for IS Not A Number) to launch an error message if the value is not a number, and set the value to 0, too. Finally, we keep the corresponding numerical value in the variable edit1 (officially recognized by Matlab as handles.edit1).
We can do the same thing for the 'edit2' callback function (you only need to add the last 8 lines): function edit2_Callback(hObject, eventdata, handles) % hObject handle to edit2 (see GCBO) % eventdata reserved - to be defined in a future version of MLB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit2 as text % str2double(get(hObject,'String')) returns contents of % edit2 as a double num = str2double(get(hObject,'String')); if isnan(num) num = 0; set(hObject,'String',num); errordlg('Input must be a number', 'Error') end handles.edit2 = num; guidata(hObject,handles) And, since the values are kept in memory due to the 'guidata' instruction used in both callback functions (in variables handles.edit1 and handles.edit2), we can easily code the section for the push-button, like this (you have to add only the last two lines): % --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) % hObject handle to pushbutton1 (see GCBO) % eventdata reserved - to be defined in a future version of MLB
% handles structure with handles and user data (see GUIDATA) addition = handles.edit1 + handles.edit2; set(handles.result, 'String', addition); Bingo! Were almost done! We need to consider the initialization part. What if the user press the + button without entering any data? Will everything work fine? Unfortunately not. edit1 and edit2 dont have zero values, they display a 0 string (not a number). So, if the user press the + button without entering any data, your GUI will display a number, but nothing to do with the expected numerical 0 value. To tackle this down, we just add some lines in the section code that runs just before adder (your m-file, remember?) is made visible (most of the lines are written by Matlab automatically, you just add three lines), like this: % --- Executes just before adder is made visible. function adder_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MLB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to adder (see VARARGIN) % Choose default command line output for adder handles.output = hObject; num = 0; handles.edit1 = num; handles.edit2 = num; % Update handles structure guidata(hObject, handles); % UIWAIT makes adder wait for user response (see UIRESUME) % uiwait(handles.figure1); Done! Run your GUI by clicking on the run icon at the top of your editor window...
I strongly suggest you read the first and second articles in this series, where I explain in detail how to create a Matlab GUI, and how to use the three most important instructions for GUIs (set, get and guidata). In this article, Im going to elaborate on how to use the axes and radio buttons, as well as the associated callback-functions. First, type guide on your command window. Select the default option (blank gui).
You can see on the left several buttons that you can drag-and-drop onto your gui canvas or layout area.
Add an axes button and double-click on it to inspect and modify its properties. Set its position to [x y width heigth] = [10 22 8 2.5]. Try to reproduce this figure:
Click once on axes1 and copy-paste (Ctl-C, Ctl-V) this element six more times (vertically). You can align the objects by clicking on the Align Objects icon, on the top menu.
Select all of the 7 axes and copy-paste two more times (horizontally). You have now 21 axes on a 7x3 matrix. Add then a Static box to the right of your canvas, and you get something similar to this figure:
Add more elements (and modify their properties) until you match the figure below:
You have 22 axes, 3 Static boxes, 3 Radio buttons, and 1 Push button, right? You can modify their sizes by dragging the anchors on the corners. For the 3 Static boxes, update their properties like this:
Property Tag String FontAngle FontSize FontWeight HorizontalAlignment Box 1 Box 2 text1 text2 This is a great trick! (empty) italic normal 10 8 bold bold left left Box 3 text3 (empty) normal 8 bold right
For the 3 Radio buttons, just erase their String property and reduce their sizes to fit each column. For the Push button, update its properties like this:
Save the Matlab GUI (I used the name trick1.fig), and Matlab will produce a template for your figure (named trick1.m), with appropriate names and comments or suggestions to get the values of the elements on it.
For our trick, well need 5 functions that will be handled from our main module (trick1.m). These functions will be:
initialize_trick: to shuffle the cards, show them for the first time and perform a reset showcards: to display 21 out of 52 cards available display_instructions: to display instructions on the Static text boxes to let the user know whats going on and whats next go_on: to keep the trick going once the user selects the column of his/her card rearrange: to pick-up the cards, rearrange and deal them again on the 7x3 matrix
This is the implementation of the function named initialize_trick.m. These names are going to be associated with a jpg file.
% Copyright 2009 by www.matrixlab-examples.com function initialize_trick() global ha cards % Define the 52 cards to be card_deck = {'ad' 'ah' 'as' '3d' '3h' '3s' '5d' '5h' '5s' '7d' '7h' '7s' '9d' '9h' '9s' 'jd' 'jh' 'js' 'kd' 'kh' 'ks' card_nr = 52; used 'ac' '2d' '2h' '2s' '2c' ... '3c' '4d' '4h' '4s' '4c' ... '5c' '6d' '6h' '6s' '6c' ... '7c' '8d' '8h' '8s' '8c' ... '9c' '10d' '10h' '10s' '10c' ... 'jc' 'qd' 'qh' 'qs' 'qc' ... 'kc'};
% Select one random card from the remaining deck r = ceil(card_nr .* rand); cards{i,j} = card_deck{r}; % Delete that card from the deck card_deck(r) = []; % Reduce the card account in the remaining deck card_nr = card_nr - 1; end end
% Display cards and first instructions showcards; display_instructions(1); % Make sure to delete the last guess str = ''; set(ha(24),'String',str); % Hide button set(ha(25),'Visible','off'); % Make the radio-buttons available set(ha(26),'Visible','on') set(ha(27),'Visible','on') set(ha(28),'Visible','on')
This is the implementation of the function named showcards.m. Here we actually associate a jpg file (a card) with its corresponding place on the matrix. We show a plain gray image on the axes22 position. % Copyright 2009 by www.matrixlab-examples.com function showcards() global ha cards % Take one .jpg file for each 'axes' (21 cards to deal). for i = 1 : 21 axes(ha(i)); [bg] = imread(strcat(cards{i},'.jpg')); image(bg); axis off; end % Delete the guess axes(ha(22)); [bg] = imread('gray.jpg');
This is the implementation of the function named display_instructions .m. It launches instructions on the text2 Static-box, according to the evolution of the trick. % Copyright 2009 by www.matrixlab-examples.com function display_instructions(i) global ha % Display instructions according to evolution of trick switch i case 1 str = {'Step 1: '; ''; 'Think of a card and select its column below...'}; set(ha(23),'String',str); case 2 str = {'Step 2: '; ''; 'Hard to guess...'; ''; 'Could you please select its column again?'}; set(ha(23),'String',str); case 3 str = {'I cannot see it clearly... '; ''; 'Please concentrate and select its column only once more...'}; set(ha(23),'String',str); case 4 str = ''; set(ha(23),'String',str); str = {'Ah! Got it! '; 'Your card is: '}; set(ha(24),'String',str); end
This is the implementation of the function named go_on.m. Its executed each time the user clicks on a radio button to choose a column. After three clicks, the selection is revealed!
% Copyright 2009 by www.matrixlab-examples.com function go_on(hObject,handles,c) global ha cards % Take into account the number of choices by the user handles.t = handles.t + 1; % Reset the current radio-button set(hObject,'Value',0); % Display the cards in a new order. rearrange(c); if handles.t < 4 showcards(); display_instructions(handles.t); else % Perform the trick! display_instructions(4); axes(ha(22)); [bg] = imread(strcat(cards{4,2},'.jpg')); image(bg); axis off; % Make the pushbutton appear set(ha(25),'Visible','on') % Make the radio-buttons disappear set(ha(26),'Visible','off') set(ha(27),'Visible','off') set(ha(28),'Visible','off') end guidata(hObject,handles);
This is the implementation of the function named rearrange.m. It takes the three columns of cards, each time the column with the selected card is put in second place. The other two columns are irrelevant for this trick. % Copyright 2009 by www.matrixlab-examples.com function rearrange(c) global cards % Take the cards and the column of the selected card % is kept as second column switch c case 1
cards_aux = {cards{:,3} cards{:,1} cards{:,2}}; case 2 cards_aux = {cards{:,3} cards{:,2} cards{:,1}}; otherwise cards_aux = {cards{:,2} cards{:,3} cards{:,1}}; end % Deal the cards with the new order k = 1; for i = 1 : 7 for j = 1 : 3 cards{i,j} = cards_aux{k}; k = k + 1; end end
This is the main wrapper (trick1.m). I deleted some of the comments automatically written by the Matlab GUI -DE (Development Environment), to simplify the explanation.
% Copyright 2009 by www.matrixlab-examples.com function varargout = trick1(varargin) % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @trick1_OpeningFcn, ... 'gui_OutputFcn', @trick1_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % --- Executes just before trick1 is made visible. function trick1_OpeningFcn(hObject, eventdata, handles,varargin) % This function has no output args, see OutputFcn. % hObject handle to figure
% handles % varargin
structure with handles and user data (see GUIDATA) command line arguments to trick1 (see VARARGIN)
% Choose default command line output for trick1 handles.output = hObject; global ha clc ha(1) = handles.axes1; ha(8) = handles.axes8; ha(15) = handles.axes15; ha(2) = handles.axes2; ha(9) = handles.axes9; ha(16) = handles.axes16; ha(3) = handles.axes3; ha(10) = handles.axes10; ha(17) = handles.axes17; ha(4) = handles.axes4; ha(11) = handles.axes11; ha(18) = handles.axes18; ha(5) = handles.axes5; ha(12) = handles.axes12; ha(19) = handles.axes19; ha(6) = handles.axes6; ha(13) = handles.axes13; ha(20) = handles.axes20; ha(7) = handles.axes7; ha(14) = handles.axes14; ha(21) = handles.axes21; ha(22) = handles.axes22; ha(23) = handles.text2; ha(24) = handles.text3; ha(25) = handles.pushbutton1; ha(26) = handles.radiobutton1; ha(27) = handles.radiobutton2; ha(28) = handles.radiobutton3; initialize_trick; handles.t = 1; % Update handles structure guidata(hObject, handles); % UIWAIT makes trick1 wait for user response (see UIRESUME) % uiwait(handles.figure1); % --Outputs from this function are returned to the command line. function varargout = trick1_OutputFcn(hObject, eventdata, handles) % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get default command line output from handles structure varargout{1} = handles.output;
% --- Executes on button press in radiobutton1. function radiobutton1_Callback(hObject, eventdata, handles) % hObject handle to radiobutton1 (see GCBO) % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton1 global ha go_on(hObject,handles,1);
% --- Executes on button press in radiobutton2. function radiobutton2_Callback(hObject, eventdata, handles) global ha go_on(hObject,handles,2);
% --- Executes on button press in radiobutton3. function radiobutton3_Callback(hObject, eventdata, handles) global ha go_on(hObject,handles,3); % --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) % hObject handle to pushbutton1 (see GCBO) % handles structure with handles and user data (see GUIDATA) global ha initialize_trick; handles.t = 1; % Update handles structure guidata(hObject, handles);
To run the program and see the Matlab GUI, save all these files with their respective names, put them into a single directory, go to that directory with Matlab and just type trick1 on your command window.
Let's say that we choose the ace of spades, so we click on the right radio button.
The cards are reshuffled and we now click on the central radio button...
We concentrate once more, to send clearer thoughts through our mental interface... click on the right column again and...
Drag-and-drop an axes button, a static text button and a push button to your layout-area so that you get something similar to this figure:
To modify the properties of each element on your layout-area, you must double-click on each. You can modify properties such as size and position, font, font weight and allignment. Set these properties (you can experiment with others) and save your figure with the name trick2.fig:
axes1 4 6 75 22
The editor will open with a prepared template, where you can edit the callbackfunctions for each element involved in the card trick. For the opening function, you can complete it as follows (there are some comments included by Matlab, you just have to add the missing lines): % --- Executes just before trick2 is made visible. function trick2_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to trick2 (see VARARGIN) % Choose default command line output for trick2 handles.output = hObject; clc axes(handles.axes1); bg = imread('trick2_001.jpg'); image(bg); axis off;
% Update handles structure guidata(hObject, handles); % UIWAIT makes trick2 wait for user response (see UIRESUME) % uiwait(handles.figure1);
For the callback associated with the push-button, complete it like this:
% --- Executes on button press in pushbutton1. function pushbutton1_Callback(hObject, eventdata, handles) % hObject handle to pushbutton1 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) str = {'I see it clearly... '; ''; ''; 'I have made your card vanish!!'}; set(handles.text1,'String',str); axes(handles.axes1); bg = imread('trick2_002.jpg'); image(bg); axis off; set(handles.pushbutton1,'Visible','off')
If you download the images and files that Ive included, and you run the trick2.m file with Matlab, youll get this result:
Done!
GUI. The intention is to be able to use pull-down menus to decode the colors of fourband resistors.
Find one of the four-band resistors. Hold the resistor with the gold or silver band to the right. The first two bands from the left show the value. If they are red and red, the value is 22. The third band shows the number of zeros after the value. If it is yellow, then the number of zeros is 4.
So the above resistor is 220000, or 220 K ohms (for easier reading). The 'K' multiplier means 1,000 (kilo-ohms); the 'M' multiplier means 1,000,000 (mega-ohms). The gold band indicates that the resistors are of 5% tolerance. A silver band indicates a 10% tolerance. An orange-red-brown-gold code equals a 320 +/-5% resistor. Now with Matlab... If this is your first GUI, I suggest you read these two initial articles, Matlab GUI intro Callback functions and then come-back and continue with this new project. If you're ready, then type on the command window > guide and a GUI window appears. Choose 'Blank GUI' and you'll get something like this figure:
Use the buttons on the left to drag-and-drop 4 'pop-up' menus, 4 'axes', and 3 'static-text' boxes. 'Static-text1' is used to give the message below the menus. It's 'String' property is 'Select one color from each pull-down menu'. You can make it a bold font (double-click on each menu and choose the different properties). 'Static-text2' is used to display the resistor value. It starts with a '0' (zero) in its string property. 'Static-text3' just displays the word 'ohms'. Arrange the elements and change their properties to achieve something like this:
Include these values in the 'String' property of the first 3 pop-up menus (double-click on each menu and choose the 'String' property):
For the 4th menu, you have to write ' 5% gold' and '10% silver' in its 'String' property. Save the figure as resistor_code.fig. A template code is automatically created with the name 'resitor_code.m'. We're going to modify it and we're going to create other functions to make it work... We'll create some Matlab functions and then we'll link them to this initial template.
First, a function to initialize the GUI axes. I suggest the following code: % Initialize resistor code (bands) % Show 0 ohm +/- 5% function init_bands(handles) axes(handles.axes1); image(imread('black.jpg')); axis off; axes(handles.axes2); image(imread('black.jpg')); axis off; axes(handles.axes3); image(imread('black.jpg')); axis off; axes(handles.axes4); image(imread('gold.jpg')); axis off;
This will display a 0-value with a 5% tolerance code in the GUI (colors for the 4 bands are black - black - black - gold).
Now, to update the colors when the values are entered using the pull-down menus, I suggest the following code: function update_color(ax, val, handles) % Select the appropriate color to update switch ax case 1 axes(handles.axes1); case 2 axes(handles.axes2); case 3 axes(handles.axes3); case 4 axes(handles.axes4); end % Choose the correct image to display color = val(5 : length(val)); image(imread([color '.jpg'])); axis off;
The input parameters of this function are 'ax' (includes the correct band number), 'val' (includes the selected option), and 'handles' (all the handles to the objects in our created figure). We have to choose the correct image to display. The name of the image is included in the 'val' parameter. You have to have .jpg images for each color.
Then, to update the total value of the resistor (values are entered using the pulldown menus, too) I suggest the following code: function update_value(handles) b = handles.b; b_ttl = (b(1) + b(2)) * b(3); if b_ttl < 1000 b_str = num2str(b_ttl); end % Format the number to make it more readable % Consider to format only values >= 1000 k ohms bs1 = num2str(b(1)/10); bs2 = num2str(b(2)); switch b(3) case 1e2 b_str = [bs1 '.' bs2 ' K']; case 1e3 b_str = [bs1 bs2 ' K']; case 1e4
b_str case 1e5 b_str case 1e6 b_str case 1e7 b_str case 1e8 b_str case 1e9 b_str end
= [bs1 bs2 '0 K']; = [bs1 '.' bs2 ' M']; = [bs1 bs2 ' M']; = [bs1 bs2 '0 M']; = [bs1 '.' bs2 ' G']; = [bs1 bs2 ' G'];
% Actual display of the value in the 'static text' set(handles.text2, 'String', b_str);
This function reads the total value of the resistor bands and formats it to make it more readable. It displays the number as a string, not as a number, and adds appropriate multipliers (such as 'K' or 'M'). The resulting string is displayed in 'StaticText2'. Please note that not all the combinations are real standard resistor values .
This is a portion of the script that appears in the 'resistor_code.m' file (the template created by Matlab). We have to fill in the necessary code to achieve what we need. Instructions contents = get(hObject,'String'), and contents{get(hObject,'Value')} are the key Matlab functions to read data from a pull down menu. This code is for pop-up menu1. We read the menu, then we call our previous function to update the color of the corresponding image, we update the value of the resistor and finally save current data in the handles. This has to be adapted for the other three menus and axes. % - Executes on selection change in popupmenu1. function popupmenu1_Callback(hObject, eventdata, handles) % Hints: % contents = get(hObject,'String') returns menu1 contents as % cell array % contents{get(hObject,'Value')} returns selected item from % menu1 contents = get(hObject,'String'); v = contents{get(hObject,'Value')}; % Update color of appropriate band update_color(1, v, handles); % Update resistor value handles.b(1) = str2num(v(1)) * 10; update_value(handles);
The full code for the main routine is: function varargout = resistor_code(varargin) % RESISTOR_CODE M-file for resistor_code.fig % % See also: GUIDE, GUIDATA, GUIHANDLES % Last Modified by GUIDE v2.5 09-Jan-2010 19:48:33 % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @resistor_code_OpeningFcn, ... 'gui_OutputFcn', @resistor_code_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % --- Executes just before resistor_code is made visible. function resistor_code_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to resistor_code (see VARARGIN)
% Choose default command line output for resistor_code clc handles.output = hObject; % Initialize color of bands init_bands(handles); % Initialize and save resistor value b(1) = 0; b(2) = 0; b(3) = 1; handles.b = b; % Update handles structure guidata(hObject, handles); % --- Outputs from this function are returned to the command line. function varargout = resistor_code_OutputFcn(hObject, eventdata, handles) varargout{1} = handles.output;
% --- Executes on selection change in popupmenu1. function popupmenu1_Callback(hObject, eventdata, handles) % Hints: % contents = get(hObject,'String') returns menu1 contents as cell array % contents{get(hObject,'Value')} returns selected item from menu1 contents = get(hObject,'String'); v = contents{get(hObject,'Value')}; % Update color of appropriate band update_color(1, v, handles); % Update resistor value handles.b(1) = str2num(v(1)) * 10; update_value(handles); % Save data guidata(hObject, handles); % - Executes during object creation, after setting all properties. function popupmenu1_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), ... get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end % --- Executes on selection change in popupmenu2. function popupmenu2_Callback(hObject, eventdata, handles) % Hints: % contents = get(hObject,'String') returns menu1 contents as cell array % contents{get(hObject,'Value')} returns selected item from menu1 contents = get(hObject,'String'); v = contents{get(hObject,'Value')};
% Update color of appropriate band update_color(2, v, handles); % Update resistor value handles.b(2) = str2num(v(1)); update_value(handles); % Save data guidata(hObject, handles); % --- Executes during object creation, after setting all properties. function popupmenu2_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), ... get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end % --- Executes on selection change in popupmenu3. function popupmenu3_Callback(hObject, eventdata, handles) % Hints: % contents = get(hObject,'String') returns menu1 contents as cell array % contents{get(hObject,'Value')} returns selected item from menu1 contents = get(hObject,'String'); v = contents{get(hObject,'Value')}; % Update color of appropriate band update_color(3, v, handles); % Update resistor value handles.b(3) = 10^(str2num(v(1))); update_value(handles); % Save data guidata(hObject, handles);
% --- Executes during object creation, after setting all properties. function popupmenu3_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), ... get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end % --- Executes on selection change in popupmenu4. function popupmenu4_Callback(hObject, eventdata, handles) % Hints: % contents = get(hObject,'String') returns menu1 contents as cell array % contents{get(hObject,'Value')} returns selected item from menu1 contents = get(hObject,'String'); % Update color of appropriate band update_color(4, contents{get(hObject,'Value')}, handles);
% Save data guidata(hObject, handles); % --- Executes during object creation, after setting all properties. function popupmenu4_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), ... get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
Theres a couple of things to note from this example: The polynomials coefficients are listed starting with the one corresponding to the largest power. It is important that zero-coefficients are included in the sequence where necessary. A polynomial of order p has p + 1 coefficients, this is, a quadratic has three coefficients and a polynomial of degree p will have p roots. As long as the coefficients of the polynomial are real, the roots will be real or occur in complex conjugate pairs.
So we need to set up the code: function mf = myfunction(x) mf = 3*x 2*x.2.*sin(x); and later we may use the inline command fzero like this (no input vector is needed) >> fzero('myfunction', 2)
Polynomials
Polynomials are used so commonly in algebra, geometry and math in general that Matlab has special commands to deal with them. The polynomial 2x4 + 3x3 10x2 11x + 22 is represented in Matlab by the array [2, 3, -10, -11, 22] (coefficients of the polynomial starting with the highest power and ending with the constant term). If any power is missing from the polynomial its coefficient must appear in the array as a zero. Here are some examples of the things that Matlab can do with polynomials. I suggest you experiment with the code
Roots of a Polynomial
% Find roots of polynomial p = [1, 2, -13, -14, 24]; r = roots(p) % Plot the same polynomial (range -5 to 5) to see its roots x = -5 : 0.1 : 5; f = polyval(p,x); plot(x,f) grid on
Multiply Polynomials
The command conv multiplies two polynomial coefficient arrays and returns the coefficient array of their product:
a = [1 2 1]; b = [2 -2]; c = conv(a,b)
Look (and try) carefully this result and make sure its correct.
Divide Polynomials
Matlab can do it with the command deconv, giving you the quotient and the remainder (as in synthetic division). For example:
% % a b a b = = = 2x^3 + 2x^2 - 2x - 2 = 2x - 2 [2 2 -2 -2]; [2 -2];
% now divide b into a finding the quotient and remainder [q, r] = deconv(a,b)
You find quotient q = [1 2 1] (q = x2 + 2x + 1), and remainder r = [0 0 0 0] (r = 0), meaning that the division is exact, as expected from the example in the multiplication section
First Derivative
Matlab can take a polynomial array and return the array of its derivative:
a = [2 2 -2 -2] ap = polyder(a)
% fit to the data p = polyfit(x, f, 4); % evaluate the fit g = polyval(p,x); % plot data and fit together plot(x, f,'r:', x, g,'b-.') legend('noisy data', 'fit') grid on
Got it?
We use cell arrays to handle the necessary strings, and the process consists in finding the correct index of an initial given dictionary. The Matlab function to work with the first three digits (thousands) is as follows. The string (named words) is updated after each digit is evaluated. function [words, h, u] = thousands(amount) global number words = []; % Find if there are thousands t = floor(amount/1000);
if (t == 0) h = 0; u = 0; return end % Find the hundreds h = floor(amount/100000); if h > 0 words = [number{h} ' HUNDRED']; end % Find the last two digits u = floor(amount/1000) - h*100; if (0 < u) & (u < 21) words = [words ' ' number{u}]; else words = [words tens(u, [])]; end % End string with word 'thousand' words = [words ' THOUSAND'];
The 'check writer' function to work with the three digits previous to the decimal point (hundreds) is as follows. Again, the string (named words) is updated after each digit is evaluated and the Matlab algorithm flows in a similar way than before.
function words = hundreds(amount, words, h, u) global number % Find if there are hundreds hu = floor(amount - h*1e5 - u*1e3); if (hu == 0) words = [words]; return end % Find the hundreds h = floor(hu/100); if h > 0 words = [words ' ' number{h} ' HUNDRED']; end % Find the last two digits u = hu - h*100; if (0 < u) & (u < 21)
words = [words ' ' number{u}]; else words = [words tens(u, [])]; end The section to translate the last two digits of each group of three elements is given below. Note that the index to locate the correct number in the given dictionary (defined in the control section, below) works only for numbers beyond the first 20 elements in the list, due to the way that English syntax works. For the first 20 elements, it 's not necessary to go through this script. function words = tens(u, words) global number % Work with the last two digits of the group of three if u == 0 words = [words]; return end % Find the correct index of the appropriate multiple of 10 words = [words ' ' number{floor((u - 20)/10 + 20)}]; units = u - floor(u/10)*10; if units == 0 return end % Add a dash and the appropriate number if there are units words = [words '-' number{units}]; Now, this is the function to add the remaining cents to the almost ready final string. It converts numbers into strings using command 'num2str'. function words = cents(amount, words) c = amount*100 - floor(amount)*100; if c < 10 cents = ['0' num2str(c)]; else cents = num2str(c); end words = [words ' AND ' cents '/100']; The control module that accesses the previous four routines for our check writer is as follows (name it check_writer.m, so you can run it from the command window):
clc; clear global number month = {'January', 'February', 'March', 'April', 'May',... 'June', 'July', 'August','September', 'October',... 'November', 'December'}; number = {'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE',... 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'TEN',... 'ELEVEN', 'TWELVE', 'THIRTEEN', 'FOURTEEN', 'FIFTEEN',... 'SIXTEEN', 'SEVENTEEN', 'EIGHTEEN', 'NINETEEN',... 'TWENTY', 'THIRTY', 'FORTY', 'FIFTY',... 'SIXTY', 'SEVENTY', 'EIGHTY', 'NINETY'}; disp('Check Writer -----') disp(' ') dat = input('Enter date (MMDDYY): ', 's'); m = str2num(dat(1:2)); name = input('Name of payee: ', 's'); a = input('Amount of check (include two decimals): ', 's'); amount = str2num(a); if (amount < 1)|(amount > 999999.99) disp('Sorry, amount is out of range...') return end x = input('Prepare printer... ', 's'); disp(' ') dat_str = [' month{m} ' ' dat(3:4) ', ' '20' dat(5:6)]; disp(dat_str) amount_str = [' '... '$' a]; disp(amount_str) name_str = [' disp(name_str) ' name]; '...
[words, h, u] = thousands(amount); words = [hundreds(amount, words, h, u)]; words = [cents(amount, words) ' DOLLARS']; disp(words)
Now, lets try our code: Check Writer ----Enter date (MMDDYY): 122309 Name of payee: Heavenly Bank of Algorithmland Amount of check (include two decimals): 23999.00 Prepare printer...
December 23, 2009 $23999.00 Heavenly Bank of Algorithmland TWENTY-THREE THOUSAND NINE HUNDRED NINETY-NINE AND 00/100 DOLLARS
Another run:
Check Writer ----Enter date (MMDDYY): 010110 Name of payee: Matrixlab-Examples.com Amount of check (include two decimals): 734100.15 Prepare printer...
January 01, 2010 $734100.15 Matrixlab-Examples.com SEVEN HUNDRED THIRTY-FOUR THOUSAND ONE HUNDRED AND 15/100 DOLLARS
%Clear screen and memory clear; clc; format compact % Initialize the first two values f(1) = 1; f(2) = 1; % Create the first 30 Fibonacci numbers for i = 3 : 30 % Perform the sum of terms accordingly f(i) = f(i-1) + f(i-2); % Calculate and display the ratio of 2 consecutive elements of the series golden_ratio = f(i)/f(i-1); str = [num2str(f(i)) ' ' num2str(f(i-1)) ' ' num2str(golden_ratio, 10)]; disp(str) end
The results in Matlab are: 2 1 2 3 2 1.5 5 3 1.666666667 8 5 1.6 13 8 1.625 21 13 1.615384615 34 21 1.619047619 55 34 1.617647059 89 55 1.618181818 144 89 1.617977528 233 144 1.618055556 377 233 1.618025751 610 377 1.618037135 987 610 1.618032787 1597 987 1.618034448 2584 1597 1.618033813 4181 2584 1.618034056 6765 4181 1.618033963 10946 6765 1.618033999 17711 10946 1.618033985 28657 17711 1.61803399 46368 28657 1.618033988 75025 46368 1.618033989 121393 75025 1.618033989 196418 121393 1.618033989 317811 196418 1.618033989 514229 317811 1.618033989 832040 514229 1.618033989 You can see that, in fact, the quotient of two consecutive numbers reaches the 'golden ratio' after just a few numbers in the series.
1528 (base 10) means 1 x 103 + 5 x 102 + 2 x 101 + 8 x 100 Following the same reasoning, a binary number (called to be in base 2) consists of additions of binary digits raised to the different powers of 2. For example:
bin_nr = '110101'; dec = 0; for i = 1 : length(bin_nr) dec = dec + str2num(bin_nr(i)) * 2^(length(bin_nr) i); end
dec
bin_nr = input('Enter your binary number: ', 's'); dec = 0; i = 1; while i < length(bin_nr) + 1 dec = dec + str2num(bin_nr(i)) * 2^(length(bin_nr) -
Since the latest quotient was less than 2, we know that we have finished our conversion. We take the last quotient and include it in our final binary result, and this is going to be the most significant bit (MSB) (bin = '1010', final).
dec_nr = 10; i = 1; q = floor(dec_nr/2); r = rem(dec_nr, 2); bin(i) = num2str(r(i)); while 2 <= q dec_nr = q; i = i + 1; q = floor(dec_nr/2); r = rem(dec_nr, 2); bin(i) = num2str(r); end bin(i + 1) = num2str(q); bin = fliplr(bin) The while-loop goes on until the quotient is less than 2. q is the quotient, r is the remainder and we keep all the remainders in variable (string) 'bin'. The last bit in our number is the MSB and it's the last quotient obtained, the one that was less than 2.
Since the binary digits (bits) are obtained from LSB to MSB, we have to flip the array in the last step, so that we can see the appropriate order.
To convert a value from binary to hexadecimal, you merely translate each 4-bit binary group to its hexadecimal equivalent. For example, the binary number 0011 1111 0111 1010 translates into the hex 3F7A equivalent.
Solution 1.
In Matlab, we can go from binary to decimal, and then, from decimal to hexadecimal. We can embed one instruction into the other, like this: hex_str = dec2hex(bin2dec(bin_str))
Its important to remember that both binary numbers and hexadecimal ones are treated as strings in Matlab. So, we can use this concept, like this: bin_str = '10001011110101' hex_str = dec2hex(bin2dec(bin_str)) Matlabs answer is: hex_str = 22F5
Solution 2.
Now, lets say that we want to explore how the binary groups are separated to form the hex symbols and we want to manipulate our own strings (binary and hexadecimal).
We can develop a function to translate the table shown before. Our proposed method uses a switch-case structure. % Binary to Hexadecimal conversion function h = b2h(b) switch b case {'0', '00', '000', '0000'} h = '0'; case {'1', '01', '001', '0001'} h = '1'; case {'10', '010', '0010'} h = '2'; case {'11', '011', '0011'} h = '3'; case {'100', '0100'} h = '4'; case {'101', '0101'} h = '5'; case {'110', '0110'} h = '6'; case {'111', '0111'} h = '7'; case '1000' h = '8'; case '1001' h = '9'; case '1010'
h = 'A'; case '1011' h = 'B'; case '1100' h = 'C'; case '1101' h = 'D'; case '1110' h = 'E'; case '1111' h = 'F'; end
Now, we have to call the function for every 4-bit group of binary numbers. One possible solution to separate the binary number into 4-bit groups is shown here: bin_str = input('Enter binary number: ', 's'); i = length(bin_str); n = ceil(i/4); for g = n : -1 : 1 if i > 4 hex_str(g) = b2h(bin_str(i-3 : i)); i = i - 4; else hex_str(g) = b2h(bin_str(1 : i)); end end hex_str Lets try it. Enter binary number: 101010 hex_str = 2A Enter binary number: 110001011110101 hex_str = 62F5
A major numbering system used in digital systems is the hex system, also known as base 16. In this system, the numbers are counted from 0 to F. In base 16 we need 16 different symbols, decimal numbers 10 through 15 are represented by letters A through F, respectively. The binary system (base 2) has only two symbols, '0' and '1'. The following table shows the meaning of all the symbols in the hexadecimal numbering system and their conversion to decimal or binary equivalents.
To convert a value from hex to binary, you merely translate each hex symbol to the equivalent 4-bit binary group. For example, the hex number A5A5 translates into the binary 1010010110100101 equivalent.
Solution 1.
In Matlab, we can go from decimal to binary, and then, from binary to hexadecimal. We can embed one instruction into the other, like this: bin_str = dec2bin(hex2dec(hex_str)) So, we can use this concept, like this: hex_str = 'AF5' bin_str = dec2bin(hex2dec(hex_str)) Matlabs answer is: bin_str = 101011110101
Its important to remember that both binary numbers and hexadecimal ones are treated as strings in Matlab.
Solution 2.
Now, lets say that we want to explore how the hex characters are separated to form the binary symbols and how we can manipulate our own strings (binary and hexadecimal).
We can develop a function to translate the table shown before. Our proposed method uses a switch-case structure. % Hex to binary conversion function b = h2b(h) switch h case {'0'} b = '0000'; case {'1'} b = '0001'; case {'2'} b = '0010'; case {'3'} b = '0011'; case {'4'} b = '0100'; case {'5'} b = '0101'; case {'6'} b = '0110'; case {'7'} b = '0111'; case {'8'} b = '1000'; case {'9'} b = '1001'; case {'A', 'a'} b = '1010'; case {'B', 'b'} b = '1011'; case {'C', 'c'} b = '1100'; case {'D', 'd'} b = '1101'; case {'E', 'e'} b = '1110'; case {'F', 'f'}
b = '1111'; end
Now, we have to call the function for every hex character in the string, to convert each to a 4-bit binary number. One possible solution to separate the hex characters into 4-bit groups is shown here: hex_str = input('Enter hexadecimal number: ', 's'); n = length(hex_str); bin_str = ''; for h = 1 : n bin_str = [bin_str h2b(hex_str(h))]; end bin_str
Lets try this routine. Enter hexadecimal number: af50 bin_str = 1010111101010000
Enter hexadecimal number: 15A7 bin_str = 1010110100111
within the WinSpice environment before any attempt is made to interact with Matlab. Second, we prepare the output of the simulator by writing necessary data to an external file, that is, we include 'write' commands in the .cir file, so that the results are saved as external (.csv) text files available to Matlab. Third, we now generate a new version of the .cir file using Matlab capabilities for manipulating cell-arrays (string matrices), we then insert a Matlab statement to run the Spice simulator from the command line with the .cir filename as a parameter. After the simulation, we can read the results in the .csv files, process them and act accordingly.
We use these values: R1 = 10k ohms, R2 = 5k ohms, R3 = 1k ohm, R4 = 50 ohms, R5 = 1k ohm, R6 = 3k ohms C1 = C2 = C3 = 10 uF Q1 = transistor 2N2222 V1(ac) = 0.1V amplitude @ 1k Hz V2(dc) = 30 V The .cir file (text file) needed is: --- Simple amplifier with Transistor ---V1 V2 Vin Vcc 0 0 dc 0 dc 30 ac 1 sin(0 0.1 1e3)
R1 R2 R3 R4 R5 R6 C1 C2 C3 Q1
b 0 c Vr 0 0 Vout 0 Vin b
.MODEL Q2N2222 NPN +(IS=3.108E-15 XTI=3 EG=1.11 VAF=131.5 BF=217.5 + NE=1.541 ISE=190.7E-15 IKF=1.296 XTB=1.5 BR=6.18 + NC=2 ISC=0 IKR=0 RC=1 CJC=14.57E-12 VJC=.75 + MJC=.3333 FC=.5 CJE=26.08E-12 VJE=.75 MJE=.3333 + TR=51.35E-9 TF=451E-12 ITF=.1 VTF=10 XTF=2) .control AC DEC 10 10 10MEGHZ plot vdb(Vout) TRAN 10E-6 5E-3 plot v(Vout) .endc .end
Second Step: We include appropriate 'write' commands in the .cir file, so that the results are saved as .csv files available to Matlab. The control block changes into: .control AC DEC 10 10 10MEGHZ write f_ac_out.csv vdb(Vout) TRAN 10E-6 5E-3 write f_tran_out.csv v(Vout) quit .endc .end
Third Step: We now create a function (to be run by Matlab) that can reproduce the above .cir file (simulation of the amplifier), modify relevant parameters with the command 'num2str' (which changes numbers into strings), and launch the circuit simulator. This is the full code that accomplishes it:
function [Rac Rtran] = spice_amp(x) % Create the file .cir to be run by WinSpice3. % Built-in function 'num2str' is used to modify parameters % wherever it is convenient.
b{1} = ['-------------Simple amplifier with Transistor----------- ']; b{2} = [' ']; b{3} = [' ']; b{4} = ['V1 Vin 0 dc 0 ac 1 sin(0 0.1 1e3) ']; b{5} = ['V2 Vcc 0 dc 30 ']; b{6} = [' ']; b{7} = ['R1 Vcc b 10e3 ']; b{8} = ['R2 b 0 5e3 ']; b{9} = ['R3 Vcc c ' num2str(x(1))]; b{10} = ['R4 e Vr ' num2str(x(2))]; b{11} = ['R5 Vr 0 1e3 ']; b{12} = ['R6 Vout 0 3e3 ']; b{13} = [' ']; b{14} = ['C1 c Vout 10e-6 ']; b{15} = ['C2 Vr 0 10e-6 ']; b{16} = ['C3 b Vin 10e-6 ']; b{17} = [' ']; b{18} = ['Q1 c b e Q2N2222 ']; b{19} = [' ']; b{20} = ['.MODEL Q2N2222 NPN ']; b{21} = ['+(IS=3.108E-15 XTI=3 EG=1.11 VAF=131.5 BF=217.5 ']; b{22} = ['+ NE=1.541 ISE=190.7E-15 IKF=1.296 XTB=1.5 BR=6.18 ']; b{23} = ['+ NC=2 ISC=0 IKR=0 RC=1 CJC=14.57E-12 VJC=.75 ']; b{24} = ['+ MJC=.3333 FC=.5 CJE=26.08E-12 VJE=.75 MJE=.3333 ']; b{25} = ['+ TR=51.35E-9 TF=451E-12 ITF=.1 VTF=10 XTF=2) ']; b{26} = [' ']; b{27} = ['.control ']; b{28} = ['AC DEC 10 10 10MEGHZ ']; b{29} = ['write amp_ac_out.csv vdb(Vout) ']; b{30} = [' ']; b{31} = ['TRAN 10E-6 5E-3 ']; b{32} = ['write amp_tran_out.csv v(Vout) ']; b{33} = ['quit ']; b{34} = ['.endc ']; b{35} = ['.end ']; b{36} = [' ']; % Save file .cir line-by-line [r,c] = size(b); fp = fopen('amplifier.cir', 'w+'); for i = 1 : c fprintf(fp, '%s\n', b{i}); end fclose(fp);
% Run WinSpice % Make sure wspice3.exe and .cir files are available in this directory ! wspice3 amplifier.cir % Read data saved in .csv files % (assuming name termination _ac_out.csv and _tran_out.csv) [Rac Rtran] = getWSpicedata('amp');
This is an important portion of additional code to read the .csv files. function [Rac Rtran] = getWSpicedata(WSpiceBaseFile) % Read csv files generated by a 'write' in a 'WSpiceBaseFile' (.cir file) % Rac{1} = Frequency Points % Rac{2} = AC response % Rtran{1} = Time Points % Rtran{2} = Tran response ac = fopen([WSpiceBaseFile '_ac_out.csv']); Rac = textscan(ac, '%f %*f %f %*f', 'delimiter',',','headerLines', 1); tran = fopen([WSpiceBaseFile '_tran_out.csv']); Rtran = textscan(tran, '%f %f', 'delimiter',',','headerLines', 1); fclose('all');
Now, we're ready to perform some simulations driving WinSpice from Matlab.
clear; clc; close all % We try some initial resistors R3 = 1e3; R4 = 50; x = [R3 R4]; % Matlab launches the simulator including our parameters [Ra Rt] = spice_amplifier(x); figure semilogx(Ra{1},Ra{2}) grid on
figure plot(Rt{1},Rt{2}) grid on % We try another gain modifying one of the resistors R3 = 500; x = [R3 R4]; [Ra Rt] = spice_amplifier(x); figure semilogx(Ra{1},Ra{2}) grid on figure plot(Rt{1},Rt{2}) grid on
For R3 = 1k and R4 = 50, the obtained results are:
We can now use WinSpice as if it was another built-in Matlab function! This means that we can work through circuit optimization using Matlab... We can try some numbers in our design, we can see the results and use Matlab to modify relevant values in the circuit, in iterations. Very powerful, isn't it?
Interchanging information between Matlab and WinSpice allows the implementation of optimization algorithms and graphical possibilities not included in the circuit simulator environment itself. The approach developed now is very flexible and utilizes the inherent capability of this SPICE simulator to include other circuit text files with parameters, and print data to external .csv (comma separated values) files. First, the circuit in Spice is defined (.cir file). This circuit is simulated and tested within the WinSpice environment before any attempt is made to interact with Matlab. We separate the components of interest and include them in a different .cir file (using the .include directive in the main file). Second, we prepare the output of the simulator by writing necessary data to an external file, that is, we include 'write' commands in the main .cir file, so that the results are saved as external (.csv) text files available to Matlab. Third, we now generate a version of the .cir file that includes parameters using Matlab capabilities for manipulating strings. We then run the circuit simulator from the command line. After the simulation, we can read the results in the .csv files, process them and act accordingly.
First Step: We create, test and simulate this simple RC circuit in WinSpice:
We initially use these values: R = 10k ohms, C = 1 nF The main .cir file (which is also a text file) is: ---- RC - LP filter ---V1 Vin 0 dc 0 ac 1
.include param.cir R vin out {RES1} C out 0 {CAP1} .control AC DEC 10 10 1MEGHZ plot vdb(out)
.endc .end The actual parameters are located in a separate file named 'param.cir', which in this case only contains one line: .param RES1=10e3 CAP1=1e-009 As expected, the AC analysis delivers this result (the cutoff frequency is about 16 KHz):
Second Step: We include appropriate 'write' commands in the main .cir file, so that the results are saved as .csv files available to Matlab. The control block changes into: .control AC DEC 10 10 1MEGHZ write RC_LP_filter_ac_out.csv vdb(out) quit .endc .end
Third Step: We now create a function (to be run by Matlab) that can reproduce the secondary .cir file (including the parameters), modify relevant parameters with the command 'num2str' (which changes numbers into strings), and launch the circuit simulator. This is the full code that accomplishes it:
function [Rac] = WS_RC_low_pass(x) % Create and save the file 'param.cir' to be included in % another file to be run by WinSpice3. % The built-in function 'num2str' is used to modify parameters % wherever it is convenient. p = ['.param RES1=' num2str(x(1)) ' CAP1=' num2str(x(2))]; dlmwrite('param.cir', p, 'delimiter',''); % % % ! Run WinSpice Make sure wspice3.exe and .cir files are available in this directory wspice3 RC_LP_filter.cir
% Read data saved in .csv files % (assuming name termination _ac_out.csv) [Rac] = getWSpicedata2('RC_LP_filter'); Compare the simplicity of this code against the previously developed code. We eliminated the need to re-build the complete '.cir' file with Matlab, and we concentrate only on the relevant parameters.
There is an important portion of additional code to read the .csv files. function [Rac] = getWSpicedata2(WSpiceBaseFile) % Read csv files generated by a 'write' in a 'WSpiceBaseFile' (.cir file) % Rac{1} = Frequency Points % Rac{2} = AC response ac = fopen([WSpiceBaseFile '_ac_out.csv']); Rac = textscan(ac, '%f %*f %f %*f', 'delimiter',',','headerLines', 1); fclose('all');
Now, we're ready to perform some simulations driving WinSpice from Matlab.
clear; clc; close all % We try some initial components R1 = 10e3; C1 = 1e-9;
x = [R1 C1]; [Ra] = WS_RC_low_pass(x); figure(1) semilogx(Ra{1},Ra{2}) grid on % We try another cutoff frequency by modifying the resistor R1 = 1e3; x = [R1 C1]; [Ra] = WS_RC_low_pass(x); figure(2) semilogx(Ra{1},Ra{2}) grid on
For R1 = 10k and C1 = 1 nF, the obtained result is:
As before, we can now use WinSpice as if it was another built-in Matlab function! This means that we can work through circuit optimization using functions such as 'fminbnd' or 'fminsearch'... We can try some numbers in our design, we can see the results and use Matlab to modify relevant values in the circuit, iteratively...
Mathematical Optimization
Matlab includes at least two standard functions intended for numerical or mathematical optimization. These instructions are fminbnd (for one single variable) and fminsearch (for one or more variables). Built-in function fminbnd tries to find a minimum of a function of one variable within a fixed interval. Built-in function fminsearch finds the minimum of a scalar function of several variables, starting at an initial estimate. This can be also considered as unconstrained nonlinear optimization. Both functions obtain a local minimum, not a global one. Since we can explore and express a function in terms of a predefined error, minimizing this error function equals optimizing the function. Lets work with this expression:
and it can be easily plotted like this: ezplot('x*cos(2*x)') axis([-6 6 -6 5]) grid on
We can implement a minimization method in the range [-5, 0], like this (the fminbnd algorithm is based on golden section search and parabolic interpolation): options = optimset('Display','iter','TolX',0.001); [xc, FunVal, EF, output] = fminbnd(xcos2, -5, 0, options)
Matlab displays the following answer. We get the number of times that the function was evaluated, the point of evaluation and the function value at each iterate. Func-count 1 2 3 4 5 6 7 8 9 x -3.09017 -1.90983 -3.81966 -3.02998 -3.21391 -3.22291 -3.21865 -3.21832 -3.21899 f(x) -3.07384 1.48735 -0.813651 -2.95481 -3.18035 -3.18038 -3.1805 -3.1805 -3.1805 Procedure initial golden golden parabolic parabolic parabolic parabolic parabolic parabolic
Optimization terminated: the current x satisfies the termination criteria using OPTIONS.TolX of 1.000000e-003 xc = -3.2187 FunVal = -3.1805 EF = 1 output = iterations: 8 funcCount: 9 algorithm: 'golden section search, parabolic interpolation' message: [1x112 char]
The value xc = -3.2187 is the best value found after our mathematical optimization. If we change the TolX parameter of the options included in the optimization function (fminbnd), we get a different amount of function evaluations and, naturally, a slightly different minimum value. We must be aware that changes in tolerances naturally affect our results. options = optimset('Display','iter','TolX',0.1); Func-count 1 2 3 4 5 6 7 x -3.09017 -1.90983 -3.81966 -3.02998 -3.21391 -3.24725 -3.18058 f(x) -3.07384 1.48735 -0.813651 -2.95481 -3.18035 -3.17502 -3.17092 Procedure initial golden golden parabolic parabolic parabolic parabolic
Optimization terminated: the current x satisfies the termination criteria using OPTIONS.TolX of 1.000000e-001 xc = -3.2139 FunVal = -3.1804 EF = 1 output = iterations: 6
funcCount: 7 algorithm: 'golden section search, parabolic interpolation' message: [1x112 char] If we now change the range of exploration to [0, 6], we find another minimum: Func-count 1 2 3 4 5 6 7 8 x 3.81966 6.18034 2.36068 2.47085 1.45898 1.66467 1.69841 1.73174 f(x) 0.813651 6.05006 0.0211764 0.561649 -1.42265 -1.63542 -1.64339 -1.6428 Procedure initial golden golden parabolic golden parabolic parabolic parabolic
Optimization terminated: the current x satisfies the termination criteria using OPTIONS.TolX of 1.000000e-001 xc = 1.6984 FunVal = -1.6434 EF = 1 output = iterations: 7 funcCount: 8 algorithm: 'golden section search, parabolic interpolation' message: [1x112 char] Now, lets explore the same function with fminsearch. Were going to run different starting points, with this code: fun = 'xcos2'; options = optimset('Display','iter','TolX',0.1); i = 1; for sx = -5 : .1 : 5 [xc, FunVal, EF, output] = fminsearch(fun, sx, options); x(i) = sx; xo(i) = xc; oi(i) = output.iterations; of(i) = output.funcCount;
i = i+1; end
We get these graphics:
These graphics say that if we start with x = -3, the minimum found after our mathematical optimization is y = -3.22, it takes 6 iterations to reach that value, and 12 function evaluations are needed to reach that minimum. If we start with x = 4, the minimum found is 4.8, it takes 9 iterations, and 18 function evaluations to reach that minimum. We must be very aware that different initial conditions and tolerances lead us to different results. Mathematical optimization is not straigthforward most of the times.
str1 = [num2str(p) ' permutations']; disp(str1) % Computes and displays combin. according to basic formulas str2 = [num2str(p/factorial(d)) ' combinations']; disp(str2)
Example 1:
How many permut. and combin. can be made of the 26 letters of the alphabet, taking five at a time?
We run the code above and enter: Total number of objects: 26 Size of subgroup: 5
The answer is: 7893600 permutations 65780 combinations Example 2: How many different ways can 12 computers be repaired if the workshop can only support 2 at a time? We run the Matlab m-file above and enter: Total number of objects: 12 Size of subgroup: 2 The answer (with no doubt) is: 132 permutations 66 combinations
Normal Distribution
This algorithm (program in Matlab) calculates the probability and frequency of given values on a standard normal distribution curve (Gauss bell). You have to enter the mean, the standard deviation and the value of interest. No special toolboxes or strange instructions are used.
The shaded area represents the probability of x, and its frequency is y. The normal probability is approximated using the following formula:
probability = 1 r(a1t + a2t2 + a3t3) + eps
where: a1 = 0.4361836 a2 = -0.1201676 a3 = 0.9372980 t = 1/(1 + 0.33267x) eps < 10-5 This is the Matlab code to accomplish the task,
% Clears screen and deletes all the variables in the workspace clc; clear; % m s y Asks the user for input = input('Mean: '); = input('Std. Dev: '); = input('x = ');
% Calculates the frequency (y coordinate) y = abs((y - m)/s); r = exp(-y^2/2)/sqrt(2*pi); str = ['Frequency: ' num2str(r)]; disp(str) z = y; % Approximates probability (area under curve) y = 1/(1 + 0.33267*abs(y));
a1 = 0.4361836; a2 = -0.1201676; a3 = 0.9372980; t = 1 - r*(a1*y + a2*y^2 + a3*y^3); if z < 0 t = 1 - t; end str = ['Probability: ' num2str(t)]; disp(str)
Example 1: The mean instructions per millisecond (IPMS) of a certain type of modern computers is 150. The standard deviation is 15 IPMS. If the IPMS are normally distributed, what is the probability that a computer executes between 150 and 180 instructions per millisecond? Easy. Run the Matlab code above and enter... Mean: 150 Std. Dev: 15 x = 180 The handy Matlab response is Frequency: 0.053991 Probability: 0.97724
Example 2: What if we need to know the probability of an execution of 130 and 150 instructions per milliseconds for the same type of modern computers? Dont worry, Matlab is here... Mean: 150 Std. Dev: 15 x = 130
Binomial Distribution
When a binomial distribution of events is being considered, we can use this algorithm to calculate the probability of obtaining a given number of successes in a given number of Bernoulli trials. It is necessary to provide the probability of succes on a single trial. We don't use any special toolbox or instruction here. First, we can clear the current Matlab workspace and also the screen, to keep things clean... clear; clc; Then, we ask the user to enter the three required numbers... We use the ' input' function in Matlab for this purpose, n = input('Number of trials: '); x = input('Exact number of successes: '); p = input('Probability of success: '); Now, this is the main algorithm to solve the problem, m1 = log(factorial(n)); m2 = log(factorial(x)); m3 = log(factorial(n-x)); r = exp(m1 - m2 - m3 + x*log(p) + (n-x)*log(1-p)); Finally, we display the answer (the instruction 'num2str' transforms a number into a string), str = ['Probability of ' num2str(x) ' successes in ' ... num2str(n) ' trials: ' num2str(r)]; disp(str) See the example running...
What is the probability of getting three heads in five tosses of a fair coin? Number of trials: 5 Exact number of successes: 3 Probability of success: .5 And the Matlab response is Probability of 3 successes in 5 trials: 0.3125
What is the probability that in five rolls of a fair die, a number 1 appears twice? Number of trials: 5 Exact number of successes: 2 Probability of success: 1/6 And the response is Probability of 2 successes in 5 trials: 0.16075
Poisson Distribution
Using the Poisson distribution, this program calculates the probability of an event occurring a given number of times. You must know the expected frequency of the event. No special instruction or toolboxes is used, so you can adapt the code to any other programming language... This is the code in Matlab:
% Clears screen and deletes all the variables in the workspace clc; clear; % Asks the user for input f = input('Calculated Frequency: '); x = input('Test Frequency: '); % Computes probability a = log(factorial(x)); a = exp(-f + x*log(f) - a); % Displays result str = ['Probability of ' num2str(x) ' occurrences = ' num2str(a)]; disp(str)
The instruction 'num2str' (number-to-string) transforms a number into a string, to be used along with the rest of the output message, launched by instruction 'disp'. Example 1:
Some programs are downloaded into 2000 computers. The probability of any one computer getting infected by a virus is 0.001 (nothing to do with reality, ok?) Thus we can expect 2 computers will suffer a bad reaction (0.001 x 2000 = 2). What is the probability that 4 computers will get infected? We launch our code above and enter known data as input: Calculated Frequency: 2 Test Frequency: 4 Matlab answer is Probability of 4 occurrences = 0.090224 Example 2:
What is the probability that only one computer will get infected? We re-launch our code and enter data: Calculated Frequency: 2 Test Frequency: 1
Matlab answer is Probability of 1 occurrences = 0.27067
F-distribution
This algorithm (program in Matlab) calculates percentile values for given values on an F-distribution curve. You must provide the value of F, the degrees of freedom in the numerator and the degrees of freedom in the denominator. This Matlab code does not use any special toolbox, it uses only standard built-in functions.
The area of the shaded region represents the percentile. The tail-end value (the area of the unshaded region) is also calculated. The F-distribution function is approximated using the following formula:
where,
This is the Matlab script to perform the task: clc; clear % Asks the user for the relevant input f = input ('Enter F-value: '); d1 = input('Enter degrees of freedom in numerator: '); d2 = input('Enter degrees of freedom in denominator: '); x = 1; % Computes using inverse for small F-values if f < 1 s = d2; t = d1; z = 1/f; else s = d1; t = d2; z = f; end j = 2/(9*s); k = 2/(9*t); % Uses approximation formulas y = abs((1 - k)*z^(1/3) - 1 + j)/sqrt(k*z^(2/3) + j); if t < 4
y = y*(1 + 0.08*y^4/t^3); end a1 = 0.196854; a2 = 0.115194; a3 = 0.000344; a4 = 0.019527; x = 0.5/(1 + y*(a1 + y*(a2 + y*(a3 + y*a4))))^4; x = floor(x*10000 + 0.5)/10000; % Adjusts if inverse was computed if f < 1 x = 1 - x; end % Displays results str1 = ['Percentile = ' num2str(1-x)]; str2 = ['Tail end value = ' num2str(x)]; disp(str1) disp(str2) Example 1:
What is the percentile on an F-distribution curve when the F-value is 0.474 and the degrees of freedom are 1 and 18? We run the code above and enter the data: Enter F-value: .474 Enter degrees of freedom in numerator: 1 Enter degrees of freedom in denominator: 18
Matlab response is: Percentile = 0.4937 Tail end value = 0.5063
Example 2:
What is the percentile the F-value is 23.7 and the degrees of freedom are 3 and 6? We run the code above and enter the data: Enter F-value: 23.7 Enter degrees of freedom in numerator: 3 Enter degrees of freedom in denominator: 6
Student's t distribution
This algorithm (Matlab program) calculates right-tail values for points on a t distribution curve. You must provide the value of t and the degrees of freedom.
The shaded area represents the right-tail value for t. The right-tail value is approximated using the following formula:
d = degrees of freedom
The Matlab program is: % Clears screen and deletes all the variables in the workspace clc; clear; % Asks the user for input t = input('T-value: '); d = input('Degrees of freedom: '); x = 1; y = 1; t = t^2; % Computes using inverse for small T-values if t < 1 s = d; r = y; z = 1/t; else s = y; r = d; z = t; end j = 2/(9*s); k = 2/(9*r); % Computes using approximation formulas l = abs((1 - k)*z^(1/3) - 1 + j)/sqrt(k*z^(2/3) + j); if r < 4 l = l*(1 + 0.08*l^4/r^3); end a1 = 0.196854; a2 = 0.115194; a3 = 0.000344; a4 = 0.019527; x = 0.25/(1 + l*(a1 + l*(a2 + l*(a3 + l*a4))))^4; x = floor(x*10000 + 0.5)/10000; % Adjusts if inverse was calculated if t < 1 x = 1 - x; end
% Displays result str = ['Rigth tail value: ' num2str(x)]; disp(str) Example 1:
What is the right-tail value when the t-value is 2.921 and there are 16 degrees of freedom? We run the code above and enter data: T-value: 2.921 Degrees of freedom: 16 Matlab answer is Rigth tail value: 0.0049 Example 2:
T-value is 11.178, with 5 degrees of freedom. Whats the tail value? Running the program and entering appropriate data, we get: T-value: 11.178 Degrees of freedom: 5 Rigth tail value: 0.0002
Chi-square distribution
This program calculates the tail-end and percentile values for points on a Chi-square (X2) distribution curve. You must provide the value of X2 and the degrees of freedom. No special instruction or Matlab toolbox is used.
The unshaded area represents the tail-end value of X2. The shaded area represents the percentile. The X2 distribution function is calculated using the following formulas: with v odd,
with v even,
Since the summation in the calculation of Z cannot actually extend to infinity, we stop summation when the next term is less than a chosen level of precision. Our precision is limited to approx. 110-7.
The Matlab program to accomplish this, is: % Clears screen and variables in workspace clc; clear % Asks the user for the relevant input v = input('Degrees of freedom: '); w = input('Chi-square: ');
% Calculates the denominator product r = 1; for i = v : -2 : 2 r = r*i; end % Calculates the numerator product k = w^(floor((v+1)/2))*exp(-w/2)/r; % If degrees of freedom are odd, then uses the pi factor if floor(v/2) == v/2 j = 1; else j = sqrt(2/(w*pi)); end l = 1; m = 1; v = v + 2; m = m*w/v; % Summation factor while m >= 1e-7 l = l + m; v = v + 2; m = m*w/v; end % Displays results str = ['Tail end value: ' num2str(1-j*k*l)]; disp(str) str = ['Percentile: ' num2str(j*k*l)]; disp(str)
Example:
A X2 statistic for a given study was computed to be 2.571108 with one degree of freedom. What are the tail-end and percentile values?
Running the Matlab program above, we enter and get:
In these sections we consider a set of data which well refer to as xi where i = 1 to N. Well not make any assumptions about the data in terms of its source or its form.
Averages
The mean is given by adding up all the data and dividing by the number of objects in the set. This is written as:
Theres a Matlab command which does exactly this: mean(x). Theres another related command, which is median(x) and its the value in the middle of a vector when the data has been sorted. If theres an odd number of pieces of data this is well defined, however if the number is even then the mean of the data at each end of the central interval is given, for example the median of [1 2 3 4] is (2+3)/2 = 2.5 whereas the median of [1 3 5] is 3. Note that the median can equal the mean but it is not necessarily so. This short code x = [4 0 5 3 2 1 3 5 9 3 7 5 6 8 2 0]; mn = mean(x) md = median(x) results in mn = 3.9375 md = 3.5000
The first curve is narrower than the second and this is quantified using the variance, which is given by
We can interpret this value as the mean of the sum of the squares of the distance from the mean. Theres the Matlab command var(x) to calculate this number. Another related measure is the standard deviation, which is the square root of the variance, std(x). This also is a measure of the width of the distribution and has the advantage that it has the same units as the data. There are other measures, some of which are called higher-order moments (mean is first and variance is second): the skewness is the third, and the kurtosis is the fourth.
We can use it like this: % Roll the die and keep the values in d for i = 1 : 1000 d(i) = roll_d; end % Find how many appearences of each possible value for i = 1 : 6 v(i) = length(find(d==i)); end % Display results disp(['Mean = ' num2str(mean(d))]) disp(['Variance = ' num2str(var(d))]) bar(v) The results are: Mean = 3.508 Variance = 2.7827
Obviously, every time that we run the program well get different results, since we are dealing with random numbers, but the results are similar to what we expected.
We can use this process for other chance games, for example tossing a coin: function r = toss() p = ['heads'; 'tails']; i = ceil(rand*2 + eps); r = p(i,:);
This can then be called just using 'toss' which generates either 'heads' or 'tails'.
Normal Distribution
A normal distribution has two parameters associated with it: the mean and the variance. The command randn generates random numbers which have a mean of zero and a variance of unity. By typing x = randn(1, 1000); hist(x,12) we set up an array and produce the plot
These lines on the command window mn = mean(x) v = var(x) produce, in our case mn = 0.0016 v = 0.9908 which are values very close to what was expected. There are many problems which require simulation, largely due to that it's not viable to actually run the real or physical tests. These cases cover things from experiments on aircrafts or cars (which are too dangerous or expensive) to population studies and economic strategies.