Matlab para Probabilísticos ¿Cómo trabaja Matlab? Matlab es un lenguaje intérprete que está basado esencialmente en el manejo numérico de la información. A diferencia de otros programas como Mathematica o MathCad, no permite trabajar con expresiones matemáticas simbólicas (salvo librerías que lo simulan). Esto que en un principio parece una desventaja, termina siendo una de las mayores virtudes de Matlab. Muchas veces que encaramos una situación problemática, tendemos a desarrollar modelos analíticos para entender la naturaleza del problema, y al resultar demasiado complejos de analizar, los reducimos a modelos lineales, que son fácilmente manipulables. Este enfoque puede funcionar muchas veces, pero a menudo carece de exactitud. El enfoque numérico nos permite justamente llegar a resolver problemas complejos analíticamente con una serie de tareas simples y repetitivas, siendo firmes candidatos a ser realizadas por computadora, logrando una precisión tan grande como el tiempo de procesamiento y la misma precisión de la máquina nos lo permitan. El entorno de Matlab No hay persona que al entrar a Matlab por primera vez se haya sentido desilusionada. Todo lo que se ve es una línea de entrada de comandos esperando. Matlab solo ejecuta órdenes. Es nuestro pequeño esclavo numérico. Estas órdenes pueden comunicarse de dos formas: Directamente en la línea de comandos Ud.: lústrame los zapatos Matlab: Sí Amo Ud.: ahora abanícame Matlab: Si, Amo Mediante una “receta” preestablecida llamada script Ud. le da a Matlab un papiro que dice: “Esclavo Matlab, estas son las tareas que le encargo en el día de la fecha: a) Lústrame los zapatos b) Abanícame De no cumplir con las tareas correctamente será degollado al amanecer“ Firmado, El Amo Es recomendable dar los primeros pasos dando órdenes directas ya que podemos ir apreciando la consecuencia de cada orden. A la hora de escribir un programa completo, la segunda forma es la más adecuada, ya que en el proceso de depurar el programa no es necesario escribirlo de nuevo cada vez que queramos ejecutarlo. Línea de comando La línea de comando de Matlab permite también realizar algunas operaciones del ya casi extinto DOS anteponiendo el símbolo de admiración (!) a la instrucción Por ejemplo >>!ren fulano.m mengano.m Cambia el nombre del archivo fulano.m a mengano.m El workspace (lugar de trabajo) El workspace es una metáfora del espacio de memoria que contiene a todas las variables con las que está trabajando. Al cerrarse Matlab toda esta preciosa información se pierde, por lo que es, nuevamente, recomendable el uso de programas preescritos (scripts) para volver a generar toda la información. De todas formas, Matlab permite grabar en un archivo el estado del workspace. Matlab Path Una de las primeras tareas a realizar cuando nos dispongamos a empezar a trabajar es crear un directorio o carpeta de trabajo para trabajar más cómodamente. Luego de crearlo, lo ponemos como directorio local (current directory). Cada vez que se ejecute un comando, este será el primer lugar donde lo busque y si no esta allí, Matlab buscara en su listado de paths. Las Librerías Una librería es una serie de funciones (archivos *.m) que permiten encarar determinados problemas. Existen librerías de procesamiento de señales, de manejo simbólico de datos (cosa que Matlab no debería por qué hacer pues es un simulador numérico), y de todo tipo de manejos esotéricos que no vienen al caso. Una de las ventajas de Matlab, es que su código es abierto. Esto quiere decir que cualquier función de las librerías, estándar o no, puede ser editada y modificada. Es decir que una función cualquiera que ya venga incluida en el paquete no difiere demasiado de una función que nosotros podamos escribir (esto fue cambiando un poco ya que cada vez mas se usan .dll pero el grueso sigue siendo .m) Matlab Editor/Debugger Matlab cuenta con un editor de texto, que también efectúa acciones de debugging, en donde pueden escribirse los scripts. El editor resalta en distintos colores las palabras reservadas, las cadenas de string, y no me acuerdo que otra cosa. Help! Este comando nos permite solicitar ayuda sobre cualquier comando o función que se encuentre instalada en Matlab. Escribiendo help en la línea de comando, el programa devuelve un listado de todas las librerías instaladas. Entonces: » help Para pedir mas detalles sobre las funciones que pertenecen a una librería dada, ingresamos help seguido del nombre de la librería. Por ejemplo: » help stats La librería stats agrupa diferentes rutinas útiles en probabilidad y estadística. Resulta muy instructivo echarle una mirada. Al final de la ayuda nos remite a algunos temas relacionados para que podamos continuar la búsqueda, si es que no terminamos de encontrar lo que buscábamos. Si quisiéramos ver con mas detalle algún ítem de la lista, basta con escribir help <ítem>. Ejemplo: » help normpdf NORMPDF Normal probability density function (pdf). Y = NORMPDF(X,MU,SIGMA) returns the pdf of the normal distribution with mean MU and standard deviation SIGMA, evaluated at the values in X. The size of Y is the common size of the input arguments. A scalar input functions as a constant matrix of the same size as the other inputs. Default values for MU and SIGMA are 0 and 1 respectively. Ante cualquier duda sobre el help tipeen: » help help Hay otro modo de ayuda, un poco mas cómodo, que se puede acceder desde el menú desplegable Help. El contenido es el mismo que el de la línea de comandos, solo que disponemos de un pequeño navegador. Matlab cuenta también (en sus versiones más recientes) con una enorme cantidad de archivos de ayuda en formato PDF o HTML. Son muy instructivos pero algo largos. Trabajando con vectores y matrices Vale la aclaración de que, para Matlab, los escalares son una matrices de 1x1. Por lo que las operaciones son válidas también para ellos. Creación de vectores y matrices Una particularidad de Matlab es que no es necesario declarar las variables. El espacio de memoria se ajusta dinámicamente en cada asignación. Por lo que podemos hacer lo siguiente: » a = 1 a = 1 y a continuación sobrescribirlo, » a = [1 2 3] a = 1 2 3 Para crear manualmente vectores y matrices se encierra los elementos entre corchetes, y se usan comas o espacios para separar elementos que estén en la misma fila, y punto y coma para separar las diferentes filas. Vector fila » a = [1 2 3] a = 1 2 3 Vector columna » a = [1 ; 2 ; 3] a = 1 2 3 Matriz » a = [1 2 3 ; 4 5 6; 7 8 9] a = 1 4 7 ! Nota: 2 5 8 3 6 9 zeros(), ones() - Estas funciones permiten crear matrices rellenas de ceros o de unos. Para conocer más sobre la sintaxis: >> help zeros >> help ones Operaciones matriciales básicas Suma y Resta Se usan los mismos operadores que en el caso de sumas y restas escalares (+ y -). La operación se realiza elemento a elemento, por lo que los vectores/matrices deben ser de dimensiones compatibles, con la excepción de que uno de ellos sea un escalar. Ejemplo: Definimos las matrices a y b: » a = [1 2 3 ; 4 5 6; 7 8 9] 5 4; 3 2 1] a = 1 4 7 » b = [9 2 5 8 8 3 6 9 7 ; 6 b = 9 6 3 8 5 2 7 4 1 Para efectuar la suma: » c = a+b c = 10 10 10 10 10 10 10 10 10 -6 0 6 -4 2 8 Para la resta: » d = a-b d = -8 -2 4 Producto matricial El operador producto es el asterisco (*). Nuevamente los operandos deben ser de dimensiones compatibles. Ejemplo Con las matrices del ejemplo anterior » e = a*b' e = 46 118 190 28 73 118 10 28 46 Transponer una matriz o un vector El operador de transposición es la comilla simple (‘). Transponer significa intercambiar filas por columnas. Una aplicación sería efectuar un producto interno. Siendo a y b vectores columna, se define el producto interno como: <a,b>=aT*b Donde T denota transposición. El resultado de <a,b> es un escalar. Ejemplo: » a = [1 ; 2 ; 3]; » b = [3 ; 2 ; 1]; » c = a'*b c = 10 ! Nota: Un punto y coma al final de una sentencia hace que no se vea el resultado de la operación. Esto es muy importante, porque Matlab tiene la molesta costumbre de ir mostrando todos los resultados obtenidos. El punto y coma nos permite filtrar los resultados parciales y en todo caso solo mostrar aquellos que sean de nuestro interés. Operaciones elemento a elemento Matlab define algunas operaciones que serán realizadas elemento a elemento. Ya vimos anteriormente que la operación A*B realizaba el producto matricial. Pero ¿que pasa si queremos que cada elemento de A quede multiplicado por cada elemento de B (suponiendo que tienen las mismas dimensiones)? Existe otro operador para tales fines: Definimos las matrices a y b: » a = [1 2 3 ; 4 5 6; 7 8 9] 5 4; 3 2 1] a = 1 4 7 2 5 8 » b = [9 8 3 6 9 7 ; 6 b = 9 6 3 8 5 2 7 4 1 16 25 16 21 24 9 » c =a.*b c = 9 24 21 Como se ve, si anteponemos un punto al operador, la operación se realiza elemento a elemento. La división (/) y la potencia (^) también permiten esta utilización. » c=a./b c = 0.1111 0.6667 2.3333 0.2500 1.0000 4.0000 0.4286 1.5000 9.0000 » c=b.^a c = 9 1296 2187 64 3125 256 343 4096 1 Otras operaciones pueden ser consultadas en la librería ops: Concatenación de vectores y matrices Supongamos que queremos formar una matriz con diferentes vectores y/o matrices de dimensiones compatibles, o queremos unir dos vectores para formar uno mas largo. Esto puede realizarse rápidamente de la siguiente manera: Comencemos generando dos vectores fila a y b: » a = [1 2 3]; » b = [4 5 6]; Podemos concatenarlos de varias maneras... Si los unimos uno a continuación del otro: » c = [a b] c = 1 2 3 4 5 6 Notar que al separar a y b por un espacio estamos diciendo que ambos pertenecen a la misma fila, por lo que es entendible el resultado obtenido. Si por el contrario, interponemos un punto y coma entre ambos: » c = [a ; b] c = 1 4 2 5 3 6 Matlab coloca cada vector en una fila diferente. Operador de rangos Para generar un vector cuyos elementos sean números crecientes o decrecientes en un intervalo regular existe el operador : (dos puntos). El uso más sencillo de este operador sería: <Mínimo>:<Máximo> Ejemplo: » a = 1:4 a = 1 2 3 4 Si queremos especificar un intervalo determinado, escribimos: <Mínimo>:<Intervalo>:<Máximo> Ejemplo: » a = 1:0.5:4 a = 1.0000 1.5000 2.0000 2.5000 3.0000 3.5000 4.0000 Y si queremos que el rango sea decreciente sólo escribimos el intervalo negativo. Ejemplo » a = 4:-0.5:1 a = 4.0000 3.5000 3.0000 2.5000 2.0000 1.5000 1.0000 Indexación Matlab permite acceder a un elemento o un conjunto de elementos de una matriz o un vector de una manera muy eficiente. Definamos la matriz a: » a=[1 2 3;4 5 6; 7 8 9]; Si queremos acceder al elemento a(1,2) (fila1 y columna 2 de a) y guardarlo en una variable nueva llamada a12: » a12=a(1,2) a12 = 2 Nota: Matlab no admite el cero como índice de vectores ni matrices !!!! ¿Pero que pasa si pretendo recuperar toda una fila o una columna, o hasta una submatriz contenida en a?. Veamos, para recuperar un conjunto de elementos debemos asignar rangos a las filas y columnas. Si busco la fila 1: » f1=a(1,1:3) f1 = 1 2 3 Esto se lee así: “Quiero todos los elementos que se encuentren en la fila 1 y en las columnas de 1 a 3 inclusive ”. Existe una manera mas compacta de escribir la misma sentencia. Se puede usar una suerte de comodín (:) que indica que quiero todas las filas o todas las columnas. » f1=a(1,:) f1 = 1 2 3 Esto se leería como: “Quiero los elementos de la fila 1 sin importar en que columna estén” De igual manera, para recuperar una columna cualquiera, la 2 por ejemplo: » c2=a(:,2) c2 = 2 5 8 Donde c2 es ahora un vector columna. Para indexar un vector, no importa si es fila o columna: » f1_1=f1(1) f1_1 = 1 Donde el primer elemento de f 1 queda guardado en la variable f 1_1 Por último se puede acceder a una submatriz de a: » sa=a(1:2,2:3) sa = 2 5 3 6 Donde rescatamos las primeras dos filas y las dos ultimas columnas. Funciones útiles de Matlab Comandos relacionados con el workspace. clear: borra todas las variables del entorno who: devuelve una lista de las variables que están en memoria load: carga el workspace desde un archivo. save: guarda el workspace en un archivo. Comandos relacionados con tamaño de datos length(): se aplica solo a vectores. Devuelve el largo del vector (es igual para filas y columnas). size(): se aplica tanto a vectores como matrices. Devuelve un vector de dos elementos: cantidad de filas y cantidad de columnas. Funciones matemáticas útiles sqrt(): Calcula la raíz cuadrada de un número, vector o matriz. (elemento a elemento) Comandos de control de flujo for: e if-elseif-else: son los clásicos de Pascal, C, Logo...? Comandos relacionados con la salida gráfica de datos figure(): abre una ventana gráfica close(): cierra una ventana gráfica plot(): grafica una serie de datos (x,y) sobre la figura activa. stem(): es igual que Plot() solo que no conecta los puntos entre sí. hold on: permite ir superponiendo diferentes graficas en una misma figura Funciones estadísticas mean(): calcula la media de un vector cov(): calcula la varianza de un vector normcdf(): evalúa en una serie x (vector) de valores la función de acumulación de una variable aleatoria normal de media u y varianza sigma. Nota: Todos los comandos deben estar siempre en minúscula. Para obtener una descripción detallada de la sintaxis utilicen el help... no me hagan escribir. Sentencias de control de flujo + Ejemplo Las sentencias for e if-elseif-else Supongamos que queremos recorrer un vector elemento a elemento y realizar una operación sobre cada uno. Por ejemplo, quiero suavizar una señal promediando el k-esimo valor con el (k+1)esimo y el (k-1)-esimo. Este tipo de operaciones son un poco mas complicadas de realizar operando matricialmente. Por lo que, por simplicidad se prefiere el for en este caso. Pero tenemos que ser conscientes de que un for insume mas tiempo de cómputo que una operación matricial !!. Por lo que, si trabajamos con un gran numero de datos, el for puede resultar demasiado lento (y peor aún cuando hay sentencias for anidadas), y puede que nos veamos en la necesidad de encarar el problema de otra forma. Vamos al problema... Como este código necesita varias líneas es preferible crear un archivo script (*.m) para guardar el programa completo. Asegurense de copiar el archivo al current directory o a un directorio que esté incluido en el MatLabPath para que puedan ejecutarlo. %%%%%%%%%%%%%%%% Promediador close all; clear all; % cierra todas las ventanas % Borra todas las variables N=50; % Numero de muestras v=randn(1,N); % Armo un vector de 10 muestras aleatorias independientes % distribuidas normalmente (media nula y varianza unitaria) u=zeros(1,N); % Por comodidad inicializo el vector donde voy a guardar % los resultados for k=1:N, % Para k variando en el rango 1..N if((k>1) & (k<10)), u(k)=1/3*(v(k-1)+v(k)+v(k+1)); % Si estoy en los elementos centrales % promedio normalmente elseif (k==1), u(k)=1/2*(v(k)+v(k+1)); % Si estoy en el primer elemento % promedio con el siguiente solamente else u(k)=1/2*(v(k-1)+v(k)); % Si estoy en el último (no queda otra) % promedio con el anterior solamente end % Fin del IF end % Fin del FOR figure(1); % Abro una ventana gráfica con el número (1) plot(v,'b'); % Dibujo el vector v en azul hold on % retengo el dibujo para que no se sobreescriba plot(u,'r'); % Dibujo el vector u en rojo title('Señal original (azul) - señal filtrada (rojo)'); La única salida del programa es este gráfico: Como se puede apreciar, la curva roja se saltea algunos picos de la original, por lo que parece anuvo nomás... Fine