30 de abril de 2013 Introducción a GNU Octave Tercera parte Laboratorio Abierto de Electrónica - Ciclo de seminarios introductorios 1 Curso Octave 2013 - Tercera parte LABI Cursos Índice 1. Manejo de archivos 1.1. Guardado y carga de archivos . . La función save() . . . . . . . . La función load() . . . . . . . . 1.2. Formatos soportados . . . . . . default_save_options . . . . . . 1.3. Guardar imágenes como archivos 2. Funciones 2.1. Declaración . . . . . El comando nargin . El comando nargout 2.2. Invocación . . . . . . 2.3. Cómo documentarlas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Herramientas útiles para programar 3.1. Ingreso y control de datos . . . . . La función Input() . . . . . . . . . 3.2. Funciones de redondeo . . . . . . 3.3. Funciones generadoras de números 3.4. Validación de datos . . . . . . . . 3.5. Conversión de datos . . . . . . . . str2num y num2str . . . . . . . . lower y upper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. Referencias bibliográficas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 3 4 4 . . . . . 5 5 5 6 6 6 . . . . . . . . 7 7 7 7 7 8 8 8 9 9 Página 2 Curso Octave 2013 - Tercera parte 1. LABI Cursos Manejo de archivos Informalmente hemos tratado el manejo del archivo a lo largo del curso. Ahora formalizaremos algo más el tema. Escribir código en un archivo, para posteriormente ejecutar un programa en forma conjunta y no por medio de líneas en el intérprete de comandos, resulta algo muy cómodo cuando se trata de programas largos, con muchas líneas o bloques de código. Si este es el caso, Octave permite escribir código fuente en un archivo de texto o con alguna clase de editor que nos provea de funciones adicionales de edición. Luego hay que guardar el archivo con una extensión ".m". Para ejecutar los mismos, debemos luego invocar el nombre del archivo, sin incluir la extensión, en el intérprete de Octave. 1.1. Guardado y carga de archivos Octave nos da la posibilidad de generar un archivo a partir de los datos que hayamos procesado. A su vez, nos permite “cargar” esos datos a partir de un archivo de modo de poder procesar la información a partir de variables guardadas en el archivo, ya que no podemos operar directamente sobre los mismos. Para esto las funciones de las que disponemos son respectivamente save y load. A continuación detallamos su uso. La función save() Esta función admite dos maneras de invocación: >> save archivo VARIABLE # Guarda VARIABLE en archivo >> save (’archivo’, ’VARIABLE’) # Guarda VARIABLE en archivo Sino se pasa como argumento ninguna variable, Octave guarda en el archivo generado, todas las variables en el scope actual. La función load() Esta función, por su parte, también admite dos maneras de invocación, ambas cargan en memoria las variables originales guardadas: >> load archivo; >> load (’archivo’); Si queremos cargar el contenido del archivo en una variable nueva, declarada en nuestro código, podemos ejecutar: >> mi_variable = 1.2. load (’archivo’); Formatos soportados Según lo que se esté guardando, o la forma en que deseemos procesarlo posteriormente, existe una serie de formatos con los cuales podemos generar los archivos. La variedad de formatos es muy amplia pero en la práctica una porción reducida de ellos se utiliza. Aquí listamos solo los más comunes, para conocer el resto sugerimos referirse al help de save(). Página 3 Curso Octave 2013 - Tercera parte LABI Cursos En todos los casos siguientes, la extensión en sí misma es indicativa del formato en que generamos el archivo, pero no significa nada en términos de cómo se guarda o la forma en que se cargan esos datos posteriormente. Esa información está dada exclusivamente por la opción de formato con la que se invoca a save en cada caso. # Guarda en formato binario propio de Octave >> save -mat prueba1.mat A # Guarda en formato binario propio de Octave >> save -binary prueba.dat A # Genera un archivo de texto con una matriz en formato ascii # sin información adicional >> save -ascii prueba_ascii.txt A # Genera un archivo de texto de formato especial, con la matriz # y un ‘‘header’’ propio del Octave >> save -text prueba_texto.txt A # Como save() no tiene como opcion el formato csv, # existe una función que nos permite guadar en este formato >> csvwrite(’prueba.csv’, A) default_save_options Es importante remarcar que si save() se invoca sin especificar formato, por omisión asume formato de texto. Para asignar nosotros un formato por omisión, existe la función default_save_options(), que se invoca de la forma: # En este caso configuramos por omision el formato # binario estandar, compatible con Matlab >> default_save_options(’-mat’); 1.3. Guardar imágenes como archivos Muchas veces, más allá de ver el resultado de un gráfico, nos interesa poder salvarlo para incluirlo posteriormente en un informe o algún otro tipo de documento. Esto se puede realizar mediante la función print utilizada con la siguiente sintaxis: >> print(’-dFORMATO’, ’nombre_de_archivo.FORMATO’); Es importante mencionar que como “formato” debe indicarse la extensión del archivo que queremos generar; por ejemplo png, jpg, eps, pdf, entre otras. También, puede hacerse una declaración implícita mediante la extensión del nombre de archivo del siguiente modo: >> print(’nombre_de_archivo.FORMATO’); Página 4 Curso Octave 2013 - Tercera parte 2. LABI Cursos Funciones En cualquier lenguaje de programación disponer de funciones es útil para “modularizar” el código, es decir, permite hacer que el mismo sea más claro, ordenado, y reutilizable. Octave brinda la posibilidad de utilizar funciones, pero la forma de utilizarlas es algo diferente respecto de otros lenguajes. 2.1. Declaración Las funciones se declaran generalmente en archivos separados, y el nombre del archivo debe coincidir con el nombre de la función. Para que Octave interprete que estamos declarando una función debemos utilizar la siguiente sintaxis: function [X Y] = nombre_funcion(arg1, arg2, ...) ...; ...; ...; endfunction Si se retorna un solo valor, los corchetes no son necesarios. Por otra parte, también el endfunction es opcional, pero por estilo es recomendable agregarlo. Eventualmente puede utilizarse return dentro de la función, si se desea retornar de la misma ante algún evento en particular. Pero no funciona como comando de devolución de las variables de retorno, sino simplemente como un aviso de retorno anticipado. El comando nargin Una característica extra que podemos definir al declarar una función, es introducir una validación adicional sobre la cantidad de argumentos que se recibieron respecto de lo que deberían haberse recibido, y eventualmente introducir un comportamiento diferenciado en cada caso. Es decir, una posibilidad sería tomar un argumento por omisión en caso de que algún parámetro no haya sido suministrado por el usuario, por ejemplo si nuestra función recibiera un numero N que definiese el largo de un vector, y ese argumento no estuviera presente en la invocación, nuestro código podría asumir un valor cualquiera de N. function [X Y] = nombre_funcion(arg1, N) if nargin < 2 N = 10; endif ...; ...; ...; endfunction Página 5 Curso Octave 2013 - Tercera parte LABI Cursos El comando nargout Con la misma idea que para el comando de la sección anterior, se puede definir un comportamiento diferenciado en función de la cantidad de argumentos de retorno con los que se hizo la invocación de una función. Veamos un ejemplo ilustrativo: function [X Y] = nombre_funcion(arg1, N) if nargout == 2 X = 1:1:5; Y = length(vector); else X = 1:1:5; endif ...; ...; ...; endfunction 2.2. Invocación Para la invocación, se tienen que escribir primero los valores de retorno en el orden en que los define la función. Luego escribimos el nombre de la misma recordando que el archivo debe llevar el mismo nombre, y le pasamos los argumentos en el orden indicado por la ayuda de la función. >> [X Y] = nombre_funcion(arg1, arg2, ...) 2.3. Cómo documentarlas Vimos anteriormente en este curso que para poder acceder a la documentación de una función determinada, debíamos ejecutar en el intérprete la línea de código: help nombre_de_función. Esa información que se muestra al ejecutar help también puede ser generada para las funciones que declaramos nosotros al escribir nuestro código. Para esto lo que debemos hacer es escribir, antes de la declaración o prototipo de la función, el texto que queremos mostrar como parte de la ayuda, precediendo cada línea por alguno de los símbolos de comentado que soporta el lenguaje (# o %). A continuación escribimos el contenido de la función como lo habíamos hecho anteriormente. % Función que suma dos números. % Uso: % y = suma(x1, x2) function y = suma(x1, x2) y = x1 + x2; endfunction Página 6 Curso Octave 2013 - Tercera parte 3. 3.1. LABI Cursos Herramientas útiles para programar Ingreso y control de datos La función Input() Consideremos ahora que no queremos simplemente ejecutar un código fijado de antemano a partir de valores estáticos, sino que queremos “interactuar” con nuestro programa en tiempo de ejecución. Podríamos por ejemplo querer elegir si mostrar o no un conjunto de datos en pantalla en la ejecución del programa. O bien cambiar el valor inicial de alguna variable. La función input() espera un ingreso de datos por teclado, imprimiendo opcionalmente un mensaje al usuario, y una vez ingresado el dato libera el flujo de ejecución dejando al programa correr. Para que tenga sentido el dato ingresado, generalmente el resultado de input() se guarda en una variable sobre la cual luego se verifica alguna condición: vector = 5:-1:0; printf("¿Desea mostrar resultados en pantalla?\n") opcion = input("1 = SI | 2 = NO"); if opcion == 1 vector else break; endif 3.2. Funciones de redondeo Existe en Octave un conjunto de funciones que permite aproximar un número flotante a un entero, con algún criterio. Veamos ejemplos de uso de estas funciones: >> X = 9.87; >>floor(x) ans = 9 >>ceil(x) ans = 10 >> X = 6.4; >>round(x) ans = 6 >>fix(x) ans = 6 3.3. # Redondea hacia abajo. # Redondea hacia arriba. # Redondea hacia el entero más cercano. # Trunca los decimales del número. Funciones generadoras de números Vimos en la primer parte del curso la función rand(), sobre la que volvimos en varias oportunidades. En esta sección vamos a presentar todo un conjunto de funciones que tienen base probabilística, y que entregan su resultado en base a la distribución que representan, o a alguna propiedad matemática. Vamos a estudiar algunos ejemplos: Página 7 Curso Octave 2013 - Tercera parte LABI Cursos # Genera un elemento aleatorio, siguiendo una distribución exponencial. >>rande(N,M) # Genera un elemento aleatorio, siguiendo una distribución de Poisson. >>randp(N,M) # Genera un vector con los primeros N números naturales permutados de # manera aleatoria. >>randperm(N) # Devuelve la media estadística del argumento. >>mean() # Devuelve la varianza del argumento >>var() 3.4. Validación de datos Cuando se trabaja con ingreso de datos por parte del usuario, o bien cuando se leen datos de un archivo, es importante poder validar que los datos sean del tipo especificado para nuestro programa. Para eso existen una serie de funciones de las cuales solo ilustraremos algunas: >> a = 3; >> isdigit(a) ans = 0 >> vect = []; >> isempty(vec) ans = 1 >> exist(’a’, ’var’) # Verifica si existe una variable de nombre a. ans = 1 3.5. Conversión de datos En muchas ocasiones, es necesario modificar el tipo de una variable numérica para convertirla en cadena, o viceversa. O bien modificarle alguna propiedad. Presentamos acá algunas funciones que cumplen esa tarea, aunque existen otras que se comportan de manera similar. Ejecutando help de alguna de las funciones mencionadas en esta sección, el programa sugiere consultar help de otras funciones similares, str2num y num2str >> s = "3"; >> str2num(3) ans = 3 >> y = 2; >>disp([num2str(2)]); # Imprime el dato numérico, en forma de cadena Página 8 Curso Octave 2013 - Tercera parte LABI Cursos lower y upper Estas funciones toman una cadena de caracteres y la convierten toda a minúsculas o toda a mayúsculas respectivamente. La utilidad viene dada no solo porque pueda pretenderse guardar las cadenas con esta característica, sino que ayuda a la hora de realizar comparaciones si no queremos preocuparnos de que las mismas sean case sensitive: >> s = "hOlA MUNdo"; >> lower(s) ans = hola mundo >> s = "hOlA MUNdo"; >> upper(s) ans = HOLA MUNDO 4. Referencias bibliográficas http://www.gnu.org/software/octave/doc/interpreter/ http://octave.sourceforge.net/ Página 9