Vamos a usar nuestra computadora y unos cascos de audio para determinar nuestro umbral de audición.1 El procedimiento va a ser el siguiente:
Existen diferentes drivers de audio para Linux y con distintas posibilidades. Uno de ellos es ALSA (Advanced Linux Sound Architecture) y es el que nosotros vamos a usar en esta práctica.
Ejecutar:
si el fichero existe es que ALSA está ejecutándose y está bien configurado.
Dependiendo del hardware de sonido de nuestra computadora, es posible que el archivo anterior no exista o tenga otro nombre. También podemos comprobar si nos funciona ALSA ejecutando:
Si nos escuchamos a nosotros mismos cuando hablamos por el micro, entonces todo está correcto.
Como administrador instalamos los paquetes correspondientes:
Vamos a generar tonos puros (sonidos que tienen sólo una componente de frecuencia). Para ellos usaremos dos programas llamados modulator y dc. Un modulador es un elemento que realiza la modulación de una señal. El otro programa simplemente genera una señal constante (dc = direct current). Veámos cómo se relacionan ambos programas para generar un tono puro.
Un modulador posee dos entradas y una salida. Una de las entradas es la señal modulante (señal de datos) y la otra es un parámetro que controla la frecuencia de la señal portadora. A la salida encontramos la señal modulada:
Una forma sencilla de modular una señal es desplazar (hacia frecuencias superiores) el espectro de frecuencias de dicha señal. Para desmodular simplemente movemos de nuevo el espectro de la señal de forma que quede en su posición inicial.
El programa modulator.c que puede descargarse de http://www.ace.ual.es/\~vruiz/imyso/modulator.tar.gz es un modulador de señales digitales y su código fuente es:
Como se puede apreciar en el código, modulator utiliza por defecto una portadora de 440 Hz. Para cambiar dicha frecuencia en tiempo de ejecución vamos a utilizar el programa ModulatorControl.java cuyo código fuente es:
ModulatorControl utiliza dos clases externas llamadas InFromServer y OutToServer cuyos códigos fuente son:
y
Para manegar con mayor comodidad los parámetros de ModulatorControl.java se adjunta un script escrito en Python:
Finalmente, para facilitar la tarea de la compilación de todos estos programas vamos a utilizar el programa make. Este programa utiliza como configuración un fichero Makefile, que no es otra cosa que una colección de reglas con la estructura:
donde un “objetivo” puede ser tanto un fichero a generar como un objetivo de objetivos.
El fichero Makefile para el proyecto modulator es:
Finalmente, en el directorio modulator ejectutar:
Si todo ha ido bien, debería poder listar los ficheros modulator, ModulatorControl.class, InFromServer.class y OutToServer.class.
Como para realizar esta práctica vamos a invocar a estos programas (y otros más) desde un directorio diferente, nos va a ser útil especificar el camino a cada uno de ellos en la variable de entorno que contiene todos los directorios donde el shell busca un comando que se escribe sin especificar su camino completo. Para ello sitúese en el directorio modulator y ejecute:
En esta práctica vamos a modular a diferentes frecuencias una señal constante.2 Dicha señal puede generarse con el programa dc.c (http://www.ace.ual.es/\~vruiz/imyso/dc.tar.gz):
El programa DcControl.java sirve para controlar a dc.c. Su código fuente es:
Para manegar con mayor comodidad los parámetros de DcControl.java se adjunta un script escrito en Phython:
El Makefile:
Finalmente en dc ejecute:
para obtener el ejecutable dc y el fichero DcControl.class. Nótese que al igual que ModulatorControl, DcControl utiliza las clases InFromServer y OutToServer. Estas clases son accesibles en tiempo de ejecución por DcControl al estar incluida en la variable de entorno CLASSPATH el camino completo al directorio modulator. Sin embargo, todavía es necesario escribir:
para que podamos invocar al programa DcControl desde cualquier directorio.
La DFT (Discrete Fourier Transform) o Transformada Discreta de Fourier es la herramienta matemática que permite representar un sonido digitalizado en función de sus componentes de frecuencia. Algorítmicamente hablando, la rutina DFT calcula a partir de un conjunto de muestras de audio digitalizadas otro conjunto de coeficientes de Fourier. Por definición, cada coeficiente de Fourier es un número complejo. La forma natural de representación de estos números es mediante su notación fase-magnitud, donde la magnitud expresa la amplitud del sonido que da lugar a dicha componente de frecuencia y la fase, su fase. Sin embargo, es común representar dichos números complejos también como un número real y otro imaginario.
Generalmente, la rutina DFT necesita que tanto el conjunto de entrada como el de salida de muestras complejas se almacenen en un array. En el array de entrada la posición dentro del array depende del instante de tiempo en el que la muestra allí almacenada se generó. En el array de salida la posición dentro del array indica la banda de frecuencia a la que corresponde dicho coeficiente de Fourier.
En esta práctica vamos a utilizar un algoritmo de cálculo rápido de la DFT conocido como FFT (Fast Fourier Transform). El número de operaciones de la DFT es proporcional a N2 donde N es el número de muestras procesadas. Por el contrario, la FFT tiene una complejidad de N log 2(N).
Ya que vamos a trabajar con sonidos, el tamaño del array (el número de muestras del array) junto con la frecuencia de muestreo nos va a determinar el tamaño temporal de la ventana de análisis que estamos utilizando en nuestro analizador de espectro de audio. Por ejemplo, si la frecuencia de muestreo utilizada es 8.000 Hz y el tamaño de la ventana medido en muestras es de 1.000 muestras, entonces cada uno de los 500 coeficientes de Fourier calculados por la rutina DFT hablaría de un ancho de banda igual a
El primer coeficiente (primer número complejo) se refiere a la banda [0,8) Hz, el segundo a la banda [8,16) y así sucesivamente. Nótese que el Teorema del Muestreo Uniforme indica que si f es la frecuencia de muestreo utilizada, entonces f∕2 es la máxima componente de frecuencia registrada. Por esta razón, aunque pasamos 1.000 muestras a la rutina DFT, obtenemos sólo 500 coeficientes.
Por tanto, el tamaño de la ventana de análisis controla la resolución del espectro en el dominio de la frecuencia y la frecuencia de muestreo el rango de frecuencias capturado.
Antes de calcular la FFT de la ventana de análisis las muestras son multiplicadas por una función que minimiza la distorsión espectral. Dicha distorsión está provocada por la duración no-infinita (por motivos prácticos) de la ventana de análisis.
Si analizamos desde el punto de vista de la frecuencia qué estamos haciendo cuando calculamos la FFT de un cojunto finito de muestras de una señal, veremos que en realidad estamos calculando el espectro de la señal resultante de multiplicar las muestras por una función cuadrada (la ventana de análisis) que vale distinto de 0 (en concreto, 1) justamente en el intervalo de tiempo que se toman las muestras.
Si aplicamos el Teorema de Convolución, el espectro resultante de la anterior operación es la convolución en el dominio de la frecuencia de los espectros de la señal de audio y de la función cuadrada. Como el espectro de la función cuadrada es una Sinc (la Función Muestreo) y no una función impulso (Delta de Dirac), el espectro de la señal de audio se presenta distorsionado por dicha Sinc.
Para minimizar esta distorsión podemos hacer dos cosas:
RTASA (Real Time Audio Spectrum Analyzer) es una aplicación escrita en Java que permite calcular en tiempo real el espectro de frecuencias de Fourier de una señal de audio que entra a través de la entrada de datos estándar.
Por definición, el espectro de frecuencias de Fourier de una señal es el módulo de los coeficientes complejos de Fourier de dicha señal. Los sonidos naturales están constituidos por una sumatoria de sonidos puros o sinusoidales con diferentes fases, amplitudes y frecuencias. Los seres humanos somos especialmente sensibles a la frecuencia de los sonidos cuando vamos a reconocerlos. Por lo tanto, una forma conveniente de caracterizar los sonidos es describir las amplitudes de las componentes puras (frecencias) de los mismos.
Un analizador de espectro en tiempo real es un sistema que es capaz de visualizar y dar información acerca del espectro de una señal, con poco retardo. Para el caso de una señal unidimensional (como es el caso de una señal de audio), el espectro es una gráfica cartesiana donde en el eje X se indica la frecuencia (generalmente en Hz) y en el eje Y la amplitud de dicha frecuencia (generalmente sin dimensiones).
RTASA acepta una secuencia RAW (sin cabecera) de muestras a través de entrada estándar. Debe tratarse de una secuencia de muestras de 16 bits, con signo, en formato little endian (el usado en las máquinas Intel). Se esperan dos canales.
RTASA acepta parámetros iniciales desde la línea de comandos e interactivamente (durante la ejecución), a través de diferentes elementos de entrada.
Los parámetros iniciales son:
Los otros controles interactivos son:
La única salida del programa es una copia de los datos de audio de entrada, sin procesar. Por supuesto, se muestra la gráfica del espectro (ventana Spectrum). En la parte superior aparece el espectro del canal izquierdo y abajo, el del canal derecho. La ventana es redimensionable.
El programa RTASA.java (descargue el fichero http://www.ace.ual.es/\~vruiz/imyso/RTASA.tar.gz) tiene como código fuente:
Esta clase necesita además de:
Para ejecutar correctamente esta aplicacion debemos lanzar los programas modulator y dc en el host que posee la tarjeta de sonido y por lo tanto, donde se va a realizar la audición. El/los cliente/s que controla/n la frecuencia de la portandora puede/n ejecutarse también es ese host o en cualquier otro host de Internet (siempre que el tráfico multicast entre los clientes y el servidor esté permitido). En la práctica, sólo en la red local el tráfico multicast suele estar permitido.
Como se puede ver en el código de modulator, el socket que hemos creado para controlar la frecuencia acepta una cadena de caracteres que representan un número entero.3 Puesto que dicha cadena está en formato ASCII, podemos usar el programa estándar telnet para controlar la frecuencia de la portadora. Para hacer esto escribiremos:
donde PORT es el puerto de escucha, definido en el fichero modulator.c. Tras establecer la conexión podremos cambiar la frecuencia tecleando una nueva (y pulsando la tecla ¡Enter¿). La otra forma de controlar la frecuencia consiste en usar ModulatorControl. Para ejecutar este programa escribieremos:
en el directorio que contiene las clases compiladas (los ficheros .class).
Por supuesto, es necesariauna máquina virtual de Java instalada en cada host cliente. Estos son algunos ejemplos interesantes:
Finalmente, ya poseemos todos los comocimientos y herramientas necesarias para llevar a cabo nuestro experimento. Ejecutar4 :
Por comodidad, se ha creado un tar.gz con todo el código necesario en http://www.ace.ual.es/\~vruiz/imyso/umbral.tar.gz).
Y para diferentes frecuencias (tantas como sea posible) comience a incrementar el valor de la señal producida por dc. En cuanto perciba el tono de la sinusoide, anote el valor que indica dc o DcControl. Este valor será su umbral de audición para la correspondiente frecuencia.