Monday, May 5, 2008

Octave Tutorial

Link

http://homepages.nyu.edu/~kpl2/dsts6/octaveTutorial.html

Contents:

Octave resources:

  1. Type help help at the octave command line to find out about the built in documentation system

  2. Type help > to get documentation on a particular keyword, operator, or function. Here is an example of asking for documentation on the sin() function: octave:1>help sin

  3. On-line Tutorial: There are several on-line octave/MATLAB tutorials. Here is a link to one which gives a good introduction to the language: http://www.aims.ac.za/resources/tutorials/octave/

  4. On-line octave Manual: The octave manual is available as a PDF here: http://www.octave.org/docs.html

  5. octave-forge documentation: octave-forge is a library of octave functions for working on domain specific (including audio signal processing) problems. You can install octave-forge using fink. Here is the link to the octave-forge on-line documentation:http://octave.sourceforge.net/index/

Contents

Octave Tutorial and Notes:

  • Create a column vector named: v
    octave:2> v = [ 0; 1; 2]
    
    v =
    0
    1
  • Create a row vector named: v
    octave:1> v = [ 0 1 2 ]
    
    v =
    0 1 2
  • Create a 2 x 3 matrix named: m:
    octave:3> m = [ 0 1 2; 3 4 5 ]
    
    m =
    0 1 2
    3 4 5
  • Create vector containing 11 elements with values between 0 and 10:
    octave:4> s = [ 0:10]
    
    s =
    0 1 2 3 4 5 6 7 8 9 10
  • Create a vector containing 6 sequential even values.
    octave:5> v = [0:2:10]
    
    v =
    0 2 4 6 8 10
  • Create a vector as the composition of two vectors:
    octave:6> v = [ 3 4 5 [ 6 7 8 ] ]
    
    v2 =
    3 4 5 6 7 8
  • Create a vector as the composition of two previously created vectors.
    octave:8> x0 = [ 6 7 8];
    
    octave:9> x1 = [ 3 2 1 0];
    octave:10> x2 = [ x0 x1]
    x2 =
    6 7 8 3 2 1 0
  • When creating a vector or matrix using composition the sizes of the component vectors must be compatible. Notice that this example produces an error.
    octave:14> x1 = [0; 1; 3] % create a column vector
    
    x1 =
    0
    1
    3
    octave:15> x3 = [x0 x1] % compose a row and col vector
    error: number of rows must match (3 != 1) near line 15, column 11
    error: evaluating assignment expression near line 15, column 4
  • Use size() and length() to determine the number of rows/columns in a matrix or vector.
    octave:15> size(x1)
    
    ans =
    3 1
    octave:16> size(x0)
    ans =
    1 3
    octave:17> size(m)
    ans =
    2 3
    octave:18> length(x1)
    ans = 3
    octave:19> length(x0)
    ans = 3
  • Access the values in a matrix or vector by addressing the elements by their index.
     octave:23> disp(v2) % use disp() to display a mtx's values
    
    3 4 5 6 7 8
    octave:24> v2(4) % show the 4th element in vector v2
    ans = 6
  • Remember indexing begins with 1. In other words the first element in the vector is at index 1 (not index 0).
    octave:25> v2(1)
    
    ans = 3
    octave:26> v2(0) % error! index 0 is always invalid
    error: invalid vector index = 0
  • Likewise using an index greater than the length of a vector will produce an error.
    octave:26> v2(10)
    
    error: invalid vector index = 10
  • Extract a vector of values from a vector. Create a vector by extracting the values from v2 at indexes 2,3 and 4.
    octave:27> v4 = v2(2:4)
    
    ans =
    4 5 6
  • Extract a vector of values from a vector. Create a vector by extracting the values from v2 at indexes 1 and 3. Notice the index argument uses the sequential vector syntax to generate the index values.
    octave:30> v2(1:2:4)
    
    ans =
    3 5
  • Use the 'end' keyword to access all the elements from a start element to the last element in the vector.
    octave:34> v2(3:end)
    
    ans =
    5 6 7 8
  • Extract rows and columns from a matrix.
    octave:41> x = [ 0 1 2; 4 5 6; 7 8 9] % create a matrix
    
    x =
    0 1 2
    4 5 6
    7 8 9
    octave:42> x(1:2,:) % extract the first two rows
    ans =
    0 1 2
    4 5 6
    octave:43> x(:,2:3) % extract columns 2 and 3
    ans =
    1 2
    5 6
    8 9
  • Extract a matrix from a matrix.
    octave:44> x(1:2,2:3)
    
    ans =
    1 2
    5 6
    octave:45> x(1:end,2:3)
    ans =
    1 2
    5 6
    8 9
  • Extract all the elements of a matrix as a vector. This is a form of composition. The columns of the vector are concatenated beginning with the first column to form a column vector
    octave:46> m(:)
    
    ans =
    0
    3
    1
    4
    2
    5
  • Arithmetic operations with vectors and scalars.
    octave:53> v0 = [ 1 2 3];
    
    octave:54> v0 + 5 % sum of a vector and a scalar
    ans =
    6 7 8
    octave:55> v0 * 5 % product of a vector and a scalar
    ans =
    5 10 15
  • Arithmetic operations on vectors. Note the .* is used to perform an element for element multiply.
    octave:57> v0 .* [2 4 6]
    
    ans =
    2 8 18
  • Here is an example of the error generated when two matrices of the same size are multiplied.
    octave:59> v0 * [2 4 6]
    
    error: operator *: nonconformant arguments (op1 is 1x3, op2 is 1x3)
    error: evaluating binary operator `*' near line 59, column 4
  • To perform an element by element multiply the two vectors must be exactly the same size. Here is an example of the error generated when there is a size mismatch.
    octave:59> v0 .* [ 20 30 40 50 ]
    
    error: product: nonconformant arguments (op1 is 1x3, op2 is 1x4)
    error: evaluating binary operator `.*' near line 59, column
  • Matrix transposition: swapping rows and columns of a matrix
    octave:60> disp(m)
    
    0 1 2
    3 4 5
    octave:61> m' % apostrophe operator performs transposition
    ans =
    0 3
    1 4
    2 5
  • Comparison operators (>,<,>=,<=,==,!=) produce matrices of ones and zeros (boolean matrix). In this example the result vector has a one where the value in the vector is greater than 4 and 0 where the value is less than or equal to 4.
    octave:64> v % display the vector v
    
    v =
    0 2 4 6 8 10
    octave:65> v > 4 ans =
    0 0 0 1 1 1
  • Using the compare operation to select values from a vector. The expression in parenthesis returns [0 0 0 1 1 1] which in turn is multiplied by the vector v. Only those elements which have a corresponding 1 in the boolean vector will occur in the result.
    octave:69> (v > 4) .* v
    
    ans =
    0 0 0 6 8 10
  • Use the find() function to return the indexes whose position evaluates to true.
    octave:73> disp(v)
    
    0 2 4 6 8 10
    octave:74> find(v > 4)
    ans =
    4 5 6
  • Useful built-in functions: The following built in function will be particularly useful in this class. The versions of wavin() and wavout() linked here will read and write .wav files under OS-X correctly. Download and copy them to your octave folder to use them.
    size(), length()
    
    help()
    max(), min()
    zeros(), ones()
    rand()
    cumsum()
    mod()
    abs()
    pow()
    exp()
    floor()
    plot() and stem()
    wavout(), wavin()
  • Writing octave programs: Below is the simplest possible octave program. It takes two numbers add them together and returns the sum. Remember you must create octave programs using a plain text editor and the scripts must be stored in the folder specified by the LOADPATH variable in your .octaverc file. See the course software installation document for more about this. The name of the file should match the name of the function and use the file name extension .m. This function should therefore be saved as myadder.m.
    function y = myadder( a, b )
    
    y = a + b;
    endfunction
  • Calling an octave program: here is an example of calling the myadder().
    octave:82> myadder(3,2)
    
    ans = 5
  • Argument passing and return values: When you call an octave program the parameters listed in parenthesis on the first line of the program (a and b in myadder()) are assigned the values in their corresponding position in the function call. In this example a is set to 3 and b is set to 2. The return value (y in myadder()) is assigned the output value which then becomes the value of the function on the command line.
  • Putting the semicolon after an octave statement prevents the value of the statement from being printed. (The semicolon serves the same purpose on the command line). Try removing it from myadder() to see the result. Note that leaving the semicolon off of statements in a function is a good way of debugging the function because the result of the statements will be printed as they are executed. The printed values will allow you to trace the state of the function as it evaluates.
  • Multiple values and matrices can be returned from a program. Create a file named summDiff.m with the following code:
    function [v0 v1] = sumDiff( arg0, arg1 )
    
    v0 = arg0 + arg1; % create the sum or arg0 and arg1
    v1 = arg0 - arg1; % create the difference of arg0 and arg1
    endfunction
  • Accessing multiple return values: Note the syntax used to access the multiple return values. In this case x0 and x1 are assigned values of v0 and v1 from the function.
    [x0 x1] =sumDiff([1 2 3],[4 5 6])
    
    x0 =
    5 7 9
    x1 =
    -3 -3 -3
  • One reason to write a function is to take advantage of the program flow control that is available there. Two of the most common flow control constructs are if-else-endif and the for loop. This function uses both techniques:
    function outSig = sGen( srate, frqHz, durSeconds, cosFl )
    
    % sGen( srate, frqHz, durSeconds, cosFl )
    % Purpose: calculate a sine signal as a vector
    % Input:
    % srate = signal sample rate
    % frqHz = signal frequency in Hertz
    % durSeconds = length of the signal in seconds
    % cosFl = 0 to compute a sine 1 to compute a cosine.
    % Output: vector containing the a sinusoid of the specified sample rate
    % duration and frequency.

    % if a cosine was requested then set the initial phase to pi/2
    if cosFl != 0
    phaseOffset = pi/2;
    else
    % otherwise set initial phase to 0
    phaseOffset = 0;
    endif

    % calculate the number of samples in the output signal
    N = floor(durSeconds * srate);

    % initialize the output signal vector to all zeros
    outSig = zeros(1,N);

    % for each value of n between 0 and N calculate the output sample
    for n = 0:N-1
    outSig(n+1) = sin( (2*pi*frqHz*n/srate) + phaseOffset);
    endfor

    % a computationally faster and more succinct way to compute a sine signal
    % outSig = sin( initPhase + (2*pi*frqHz/srate) .* [0:N-1])

    endfunction
      Notes:
    1. The comment block immediately following the first line of the function is given as the help text for the function. At the octave prompt type: help sGen to see how it is used.
    2. Notice how the code is indented. The body of the if statement and for loop is indented. This is conventional text programming style and is generally considered to make the code easier to read. The indenting however has no bearing on the functionality of the program.
    3. The floor() function is used force the number of samples in the output signal to be an integer. Needless to say it wouldn't make sense to have a fractional count of samples in a signal (What would it mean to have ½ a sample?). Using floor() is a good idea when computing a value which must be an integer – like a sample count or matrix index. Use help floor to find out the algorithm floor() uses to convert fractional number into integers.
    4. Other useful flow control statements are: while(), switch(), and elseif. Look these up in the octave documentation to find out how they work.

Contents

Getting Started with Octave Programing

The easiest way to begin writing octave programs is to begin with an existing script and modify it in a series of small increments. This approach is often effective when learning a new programming language. The idea is to start from a simple working function, strip out it's contents, and incrementally replace it with new code. After each small change the program is executed. This way when the program doesn't work as expected or generates an error message it is clear which change produced the error. You can then back out of the change and try an alternative or search through the octave documentation to find a solution.

These directions assume that you have already gone over the tutorial above and feel comfortable with creating, manipulating and displaying octave matrices. If you want more practice you should go through the on-line tutorial also.

Directions for writing a new octave function:
  1. Make a copy of the sumDiff.m script given above.
  2. Rename the file and function to the to the name of the new function you are writing (e.g. myNewFunction) .
  3. From the octave command prompt run the new function. It should behave exactly like the original sumDiff function.
  4. Change the argument list of myNewFunction to the arguments for the new function and delete (or comment out) the body of the function left over from sumDiff.
  5. In the body of myNewFunction print out the values of the new argument list.
    function y = myNewFunction( arg0, arg1, arg2 )
    
    arg0
    arg1
    arg2
    y = 0
    endfunction
  6. Run the function again. This time the arguments that you pass should be printed to the console.
    octave:1> myNewFunction(1,2,[4 5 6])
    
    arg0 = 1
    arg1 = 2
    arg2 =
    4 5 6
    y = 10
    ans = 10
  7. Now begin inserting new code into the body of the function. Don't add more than a couple of lines without running the script again.
    • Debugging Tips:
    • If you get stuck on particular error or aren't sure how to proceed try experimenting at the octave command prompt with simple examples of the octave commands you are using.

    • While you are developing signal processing functions start with very low sample rates (e.g. 16 or 32). Low sample rates produce small signal vectors which you can easily verify using the plot() function or by examining the values directly. As a rule listening to the output of an audio signal processing function should only be done after you have verified the process numerically or graphically at a low sample rate.

    • Leave the semicolons off the end of each new line of code. This way the result of the calculation is printed to the console when you run it. Once you are sure the calculation is producing a valid value append the semicolon so you are not confused by cluttered output on the console window.

    • Many bugs in octave programming are a result of mismatched matrix sizes. If you encounter error messages like this:
      error: product: nonconformant arguments (op1 is 1x3, op2 is 1x4)
      
      error: evaluating binary operator `.*' near line 59, column
      print out the size of the vector just prior to the operation which generates the message. For example if the the code
      v0 + v1
      is producing the error. Change the code to:
      size(v0)
      
      size(v1)
      v0 + v1
      to print out the vector sizes. If the sizes still appear to be correctly matched then examine the documentation for the function or operation you are performing to be sure that you are clear about the data size requirements. Don't forget that the element by element multiply and divide operations on matrices require use of dot version of the multiply and divide operators (e.g. .* or ./ )

  8. Don't believe the line numbers reported in the error message too much. Often the reported line number is just after (or before) the line containing the error. You should treat the line numbers as suggestions regarding where to look for the error rather than as absolute fact. The same is true of the error messages themselves. Often the message will indicate a different problem than the one which actually exists. This shouldn't be too surprising; if octave knew the real problem it would fix it and not bother you about it. This is just another reason to use the incremental development approach. After solving a few bugs you will quickly start to recognize patterns in the way the program responds and reports trouble.
Contents

2 comments:

bloggingfellow said...

very helpful post. Thanks a lot.

MVP GROUP said...

I have this:x=x+ak(k+M+1)*exp(j*k*w0*t);
and there is an error. What is your suggestion? Thanks