martes, mayo 15, 2012

Reconocimiento de voz con AVR de 8 bits


Desde hace unas semanas estoy trabajando en un experimento que espero se convierta en proyecto.

El objetivo es dotar del poder del entendimiento del habla a un robot que estoy armando, muy lentamente, con microcontroladores AVR de gama baja (ATMega8/16/128).

Estos micros poseen entre 0.5KB a 4KB de Memoria SRAM y entre 8KB a 128KB de Flash corriendo de unos pocos Mhz, el reconocimiento del habla típico en PCs requiere de una cantidad de memoria considerable y de una velocidad de proceso de varios GHz.

Debido a estas restricciones me limitaré a reconocer una x cantidad de comandos de voz, como podrían ser "Avanzar", "Retroceder", etc, o bien dígitos, "1", "2", etc.

Bien, comienzo esta locura de experimento y espero llegar a algo.. :D

La voz humana


La voz de una persona se emite en un rango de frecuencias entre 60Hz a 7000Hz, sin embargo podemos considerar que las frecuencias más usuales están entre los 120Hz a 2000Hz. Para capturar este  espectro de frecuencia por la teoría de Nyquist se debe hacer muestras a por lo menos el doble de rápido que la frecuencia más alta de la señal, por lo que nos da unos 4000 muestras por segundo.

El éxito de este experimento estará en lograr esas 4000 muestras/segundo con un uC a, digamos, 16Mhz.

Bueno lo primero que hice fue abordar el problema por partes, he aquí la primera parte, la analógica.

Filtro de frecuencias
Implementé esto en la protoboard, digamos que se trata de un amplificador operacional cuádruple (LM324N) con un filtro pasa alta a la entrada y un pasa bajos a la salida.


Alimenté el circuito con 5v y me puse a disfrutar como bailaba la gráfica en el osciloscopio mientras pensaba como digitalizar esa importante cantidad de información analógica, entonces activé la función Math del osciloscopio, puse FFT y salió esto:

Aquí digo "UNO"

Y aquí "DOS"

En la web encontré una implementación de la FFT (Transformada Rápida de Fourier) escrita por ChaN.

Y hasta aquí llegué por ahora, voy a probar la biblioteca de FFT e intentaré capturar/procesar los valores del ADC, si lo logro el paso siguiente será determinar el comando dictado, ahí el truco estará en hacerlo por correlación (estadística), alguna red neuronal, o ... ya se verá..

18/05/2012 - Captura y procesamiento de ADC

Realicé una prueba sencilla conectando la salida de audio a la entrada ADC0 de un ATmega8A ejecutandose a 16Mhz, con una referencia de voltaje de 5v y enviando datos de captura por puerto serie a la pc.
La velocidad del AVR es más que suficiente para cubrir con la tarea del sampleado, la biblioteca FFT en uso a 64 puntos(muestras) permite un throughput de hasta 19kbps con un tiempo de procesamiento de 3.4ms.
Estos 64 puntos los sumé en un vector de 32 bytes (la mitad útil del resultado de la FFT), la suma la realizo 20 veces y envío el vector de sumas por puerto serie.
Desde la PC tiré los valores a una planilla de cálculo con un gráfico simple que muestra el espectro de audio (de las sumas en realidad).
Capturé los valores de diferentes palabras y estos son los gráficos resultantes, los colores que corresponden a cada uno de los conjuntos obtenidos son:

UNO

DOS

ADELANTE

RETROCEDER



Nota: Aunque la línea azul (dato 1) parezca similar en algunas gráficas, es muy diferente (ver la escala del eje y).

Para hacer el código de la correlación usando tipos de datos flotantes el ATmega8 me queda corto de memoria, voy a tener que armar una plaquita para un ATmega16/32 o 128.

Como pensaba el reconocimiento es totalmente factible utilizando una correlación estadística o una red neuronal.


23/05/2012 - Prueba 001 - Clasificación por distancia

La prueba fue relativamente exitosa (~70% de acierto), como se puede ver en este video:
Lo que está funcionando es un muestreo a 7800Hz, recolectando 16 muestras del espectro (salida del FFT) y su respectiva comparación por distancia con respecto a un patrón almacenado en la flash (atributo PROGMEM en AVR). Como se puede ver depende mucho del tono, duración de la palabra, ruido, etc, estos factores son los que espero mejorar con el algoritmo de redes neuronales del modelo oculto de Markov.


Continuará...

10 comentarios:

  1. Hola,
    Que proyecto más interesante, casi parece imposible hacer eso con un micro de 8 bits.
    Una pregunta, ¿con el doble de la frecuencia de la onda tendrias suficiente para captar toda la información?
    Según tengo entendido el teorema de Nyquist está muy bien en la teoría y es posible utilizarlo como requisito mínimo, pero en la práctica es necesario frecuencias mas altas, 10f me han recomendado siempre.
    Te lo pregunto por saber si eso podría dar problemas.
    Un saludo.

    ResponderEliminar
    Respuestas
    1. Hola litox9, puede parecer imposible pero estoy completamente seguro que si se puede, es cuestión de intentarlo hasta lograrlo.
      La verdad que a estas bajas frecuencias capturar dos veces la frecuencia máxima está ok, los músculos de la boca son lentos y el registro de cada fonema dura un lapso importante.

      Además, si la música con todo el rango de 0 a 22kHz se puede samplear a 44.000 ciclos por segundo no veo porque para una frecuencia mucho menor no se válido usar el mismo método.

      El reconocimiento debería andar, va a andar, tiene que andar! :)

      saludos

      Eliminar
  2. Felixls excelente investigación estás llevando adelante... Sigo los avances!

    ResponderEliminar
    Respuestas
    1. Este es un experimento bastante curioso, el hardware es simple, pero el software se está complicando a un nivel avanzado, al punto de tener que codificarlo primero en la PC en C# (por lo de la red neuronal) y luego llevar la ejecución de la red al micro junto con todas las limitaciones de memoria y velocidad.
      Intenté con correlación estadística y no parece ayudar mucho ya que una persona no siempre habla en el mismo tono (sumado al rudio de ambiente), esto cual cambia los patrones del espectro de audio y no es posible correlacionar sin tener en cuenta corrimientos.
      Por estos problemas es que ahora estoy experimentando con redes de HMM NN(Hidden Markov Model Neural Network), y otras.

      saludos Lucas!

      Eliminar
  3. Hola Felixls, excelente proyecto el que has encarado, y no dudo en absoluto que llegarás a buen término.
    No he visto el circuito que utilizas, me tomo el atrevimiento de hacerte una sugerencia, que tal vez ya la tengas implementada, deberías filtrar las frecuencias bajas, entre 300 y 3000 Hz como mucho, aunque si recortas mas, digamos, entre 500 y 1800, podrías simplificar el análisis.

    saludos
    Héctor

    ResponderEliminar
    Respuestas
    1. Hola Hector, gracias por el apoyo. El circuito como muestro en el video ahora es mucho más simple (un solo operacional) con un filtro pasa bajos a la salida con un corte en 4000Hz, intenté cambiar un poco el RC y me filtraba algunas partes importantes de la voz.

      saludos!

      Eliminar
  4. ¡Que buena pinta tiene esto! Ya se ven cositas.
    Si me lo permites te hago unas sugerencias:

    -Lo primero filtrar también las bajas frecuencias, como dice Héctor Javier, pero no tanto, con pocos componentes mas puedes hacer un filtro pasabanda que tenga una frecuencia de corte inferior en 120Hz, eliminarias gran parte del ruido ambiente que se te cuele por el microfono.
    -Normalizar los valores de entrada, si haces comparaciones entre dos señales por lo menos que éstas sean comparables, no puedes depender de la distancia al microfono o de lo fuerte que estés hablando, con normalizar me refiero a dividir cada valor por la suma de todos los valores, así cada valor estará siempre acotado entre 0 y 1.

    Una vez hecho esto seguramente la diferencia entre las FFT seguramente será muy pequeña y ahí será donde viene el trabajo de reconocimiento de voz de verdad.

    Un saludo y animo!

    ResponderEliminar
  5. brother de casualidad no tienes el codigo en ensamblador para capturar notas musicales con atmega 8??

    ResponderEliminar
  6. hola que tal.. pues bueno yo te recomendaria usar un Xmega.. que es lo mismo que el atmega (basicamente) pero con mejoras como las de velocidad tanto de procesamiento como de muestreo.. eso ayuda muchisimo para un mejor procesamiento de señales.. y a la final el codigo es muy compatible con ese otro micro ya que es de la misma gama!!

    ResponderEliminar
  7. Hola Félix. Talvez un poco tarde este comentario, pero yo estuve experimentando con lo mismo hace unos años, y el resultado que obtuve es este: https://www.youtube.com/watch?v=IpRbdIheUlc . El algoritmo que usé es el siguiente: obtengo la información frecuencial con 4 filtros fijos (por software). Los filtros están mal implementados, me dí cuenta más tarde, pero igual funciona. Luego obtengo una especie de "fingerprint" dividiendo el audio en bloques temporales y anotando la frecuencia predominante de las 4 en cada bloque. De alguna manera codifico el orden de los bloques en el fingerprint, eso no me acuerdo cómo lo hice, pero es importante. Finalmente proceso los fingerprints con una red neuronal. Lo hice sin saber mucho, incluso el preamplificador de micrófono que usé es pésimo. Pero pienso que este mismo algoritmo, bien ejecutado, puede dar excelentes resultados. Hoy me puse a buscar info sobre lo mismo "reconocimiento de voz con AVR 8bit" para encontrar mi propio proyecto, y encontré el tuyo. También encontré este otro que hizo lo mismo, con un algoritmo completamente distinto, tanto al tuyo como al mío: https://www.youtube.com/watch?t=13&v=xpJXD2z8eWs. Saludos.

    ResponderEliminar