<< Organo de luces (I) - Introducción Organo de luces (III) - Etapa de potencia >>

Obtención de la señal

Como comentaba en el post anterior, en mi caso voy a  a utilizar un micrófono como fuente de señal, esto evita tener que conectar la fuente directamente y proporciona más libertad de movimiento.
Yo he utilizado un módulo de Dealextreme (como no), el SKU: 135533, que es un módulo detector de sonido con una salida digital y una analógica. Aquí utilizaremos esta última.
Como el nivel de la señal que entrega es muy pequeño, he utilizado un vetusto u741 (pero funcional) que había por un cajón, para adecuar la señal a la entrada del Arduino.
También es posible utilizar directamente un micrófono electret , pero habrá que amplificarlo adecuadamente (podéis encontrar infinidad de esquemas en internet), o bien utilizar un módulo ya amplificado como este 

El esquema de montaje es este (clik en las imágenes para ampliar):

Esquema del organo de luces con Arduino
Y el montaje este:

Montaje del organo de luces con Arduino



Algunos detalles:

  • La resistencia de 1k para alimentar el módulo reduce en gran manera el ruido en la alimentación producido por el Arduino, que se traslada luego a la salida. 
  • El u714 está en una configuración básica de amplificador, a su salida se obtiene una señal de aproximadamente 1Vpp con un offset de 5V/2  ~ 2.5V.
  • Como la entradas analógicas de Arduino necesitan señales de 0 a 5V,  el divisor de tensión formado por R1/R2 crean un offset de aprox 0.5V para que la señal tenga un rango del 0 a 1 V aprox.
  • Para poder medir con mayor precisión, programaremos la referencia del conversor analógico del Arduino como INTERNAL, que tiene un valor de 1,1V en vez de los 5V de defecto.
Necesitaréis la librería fix_fft que podéis descargar de aquí :  fix_fft

El código

El código está comentado para poderlo seguir fácilmente, pero veamos básicamente su funcionamiento.
Esta parte contiene una dosis de matemática que puede ser algo aburrida para algunos, si no te interesa simplemente pasa de ella :-). 

Inicialización
Se configura como antes hemos dicho la referencia analógica como INTERNAL, para medir tensiones del orden de 1V. También se configura el prescaler a 32 (el prescaler divide la frecuencia de reloj del micro para realizar las conversiones A/D entre otras cosas), para conseguir un a frecuencia de muestreo de unos 38 KHz, lo cual es más que suficiente para este proyecto. Luego se configuran los pines de salida.

Bucle
Se realiza un muestreo de 128 muestras, se pasa pon una función de ventana (Hann), para minimizar los efectos de las discontinuidades al principio y al final del muestreo y luego se aplica la transformada rápida de Fourier con la llamada a fix_fft.
Después de esto en data tenemos los valores de las 64 bandas (Nmuestras/2) .
Como nos interesan en valor absoluto y no las partes reales e imaginarias por separado, calculamos el módulo, y puesto que el valor es algo pequeño lo dejamos al cuadrado.

A continuación sólo queda agrupar los valores en tres bandas (graves, medios y agudos) y en función de si superan un límite activar las salidas.
El límite varía en función de la cantidad de veces que cada canal se enciende, lo que proporciona una cierta realimentación y evita que con los cambios de volumen un canal se sature o no se encienda.
La agrupación de las bandas y los límites los he obtenido probando, podéis realizar vuestras pruebas para obtener otros resultados.

Si te ha gustado no te pierdas el próximo post para ver como conectarlo a bombillas de verdad :




Si te ha gustado, recuerda compartirlo en tu red social favorita. Gracias

48 comments

16 de diciembre de 2012, 1:04

hola mucho gusto muy bueno tu proyecto estoy buscando ayuda con el codigo de el paso por cero lo necesito muy urg lo intentado varias veces y no me funciona porfavor si me puedes ayudar mi correo es davidleonardo91@gmail.com para que expliques como se programa el paso por cero gracias de antemano

6 de marzo de 2013, 21:51

ggracias por el proyecto espero ponerlo en practica

13 de marzo de 2013, 21:05

Muchas gracias por subir tu proyecto. no me quedo muy claro,¿como variaste la frecuencia de muestreo en el IDE ? ¿hay algún modo exacto de calcular la frecuencia de muestreo?, digo como para detectar componentes en una banda de frecuencias en especifico. muchas gracias denuevo, saludos!

26 de marzo de 2013, 13:22

he intentado hacer tu proyecto, pero se necesita el archivo "fix_fft" el enlace no deja descargarse

26 de marzo de 2013, 13:37

Vale. He averiguado que del enlace en ingles funciona.

13 de abril de 2013, 3:33

@Santiago Navarro
Perdón ya está arreglado el enlace.
Gracias.

13 de abril de 2013, 3:51

@Ignacio Daniel Tomasov Silva
Está comentado en el código.
No se cambia desde el IDE, lo que se hace es modificar el valor del prescaler (que se encarga de dividir la frecuencia del reloj para atacar al timer).
Puedes encontrar mucha información en esta página www.arduinoos.com busca lo referente a FFT.

23 de junio de 2013, 15:22

hola queria consultarte si funciona con un microfono de dos patas ( + y - ) y como lo conecto ?

25 de junio de 2013, 1:20

@alexander pastene
Supongo que te refieres a un micrófono 'electret'.
Se puede utilizar con un preamplificador , como este: Preamplificador electret
La salida "out" puedes conectarla directamente a la patilla A0 del arduino manteniendo el divisor de tension con las resistencias R1/R2.
Lo que no se es que sensibilidad tendrá ... cuestión de probar.

3 de julio de 2013, 4:28

ciao, ho dei problemi con il progetto, ho caricato il codice sull'arduino, ma non funziona. Aiuto grazie.

3 de julio de 2013, 4:29

hola, tengo problemas con el proyecto, que he subido del sull'arduino código, pero no funciona. Ayuda gracias.

26 de noviembre de 2013, 9:12

¿Qué se tiene en cuenta para seleccionar los valores de C1, C2 yR3 ?

john
27 de diciembre de 2013, 23:48

Awesome dude, I wish my Spanish were better.

29 de diciembre de 2013, 5:18

@johnThank you. There is an English version here

28 de junio de 2014, 15:35

hola, tengo problemas con el proyecto, me dice que "ADCSRA was not declared in this scope" ¿Podría dar una mano. Gracias.
bitWrite(ADCSRA,ADPS2,1);
bitWrite(ADCSRA,ADPS1,0);
bitWrite(ADCSRA,ADPS0,1);

30 de junio de 2014, 5:45

@Iulio Naida
¿Qué arduino estás utilizando: Uno, Due, Leonardo, Mega ...?
¿Qué versión del entorno 1.0.5 o anterior?

2 de julio de 2014, 6:14

Arduino Due! 1.5.6 - r2

inside.game.labs@gmail.com
3 de julio de 2014, 13:45

Hola! Primeramente felicitarte por la web! es estupenda y muy interesante... Tengo un problemilla, intento entender el código pero todavia estoy muy pez!! Yo estoy intentando que, a partir de un microfono, poder sacar las frecuencias... y de ellas solamente utilizar 3 (que serian proximas a 20000Hz , por ejemplo 19800, 20300 y 20500 , por ejemplo) de tal manera que cuando aparezcan esas frecuencias, se ejecute un código... es posible hacerlo a traves de tu ejemplo?

7 de julio de 2014, 4:12

@Iulio Naida
Upss!
El Arduino DUE utiliza un micro distintinto, y no es compatible a nivel de registros con el ATMega.
La buena noticia es que es mucho más rápido y no es necesario cambiar el preescaler, simplemente elimina esas tres lineas.

7 de julio de 2014, 5:29

@inside.game.labs@gmail.com
Gracias por tu comentario!
En realidad tienes que calcular a que banda tienes que prestar atención, en teoría la frecuencia de muestreo es de aprox 38.4Khz y hay 64 bandas, así que 38400/2/64 = 300Hz, es decir que las bandas van 0-300Hz, 301-600Hz, ..., xx-19.200Hz
Para llegar a las frecuencias que necesitas ... tendrías que bajar aún mas el preescaler (a 16 por ejemplo) para llegar a 38400Hz, a costa de perder precisión ...
Te recomiendo esta página Arduinoos que habla ampliamente del tema.

15 de octubre de 2014, 15:47

es necesario el arduino uno?? o se puede hacer sin el, de otra forma?

16 de octubre de 2014, 14:12

@kevin johann
Siempre lo puedes hacer con electrónica analógica ...
Busca light organ" en google y encontrarás muchos esquemas.

16 de octubre de 2014, 15:15

voy a tratar de hacerlo de tu forma, con el arduino.. pero tengo algunas dudas ya que soy nuevo en esto:
--cual es el voltaje de los condensadores?
--cual es el modelo de arduino uno que me sirve para hacer esto?? porque he visto en internet que hay muchos modelos, el r8, etc...
--una vez que se le puso el código en el arduino uno es necesario mantenerlo enchufado a la computadora para su funcionamiento? ya que preferiría una vez que le ponga los códigos poder usarlo sin que este enchufado.
--por ultimo, en la etapa "3", donde se le sube el Voltaje para lamparas de 220V, las resistencias (220; 360; 330) son en "K" o en "OHMS" porque no dice y no me doy cuenta.
desde ya muchas gracias y disculpa las molestias

17 de octubre de 2014, 9:09

@kevin johann
Ok, te respondo
1) Ten en cuenta que el circuito trabaja con 5v, así que con que sean a partir de 10V te valen.
2) Te sirve cualquier modelo de los que usan un AVR atmega: Arduino uno, Arduino leonardo, Arduino Mega, Arduino Nano, Arduino Micro, Arduino pro mini, Arduino Mini. Los más sencillos para empezar: Arduino Uno o el Leonardo, si los quieres mas pequeños el Micro o el Nano.
3) No, una vez que programas el Arduino no necesita el ordenador, sólo una fuente de alimentación.
4) Los valores de las resistencias están en omhs es decir son de 220, 330 y 360 oms.
Saludos.

17 de marzo de 2015, 2:13

hola... muy bueno el proyecto... pero al compilar en el arduino uno (1.5.7) me aparece el siguiente error:

fix_fft.cpp:209:28: error: 'Sinewave' was not declared in this scope
wi = -pgm_read_word_near(Sinewave + j);

Me podrías ayudar por favor gracias...

31 de marzo de 2015, 10:23

hola! muchas gracias para muestra este trabajo por tu blog! creo que mi micrófono esta demasiado sensible...pienso que necesito cambiar el prescalar, pero no se como es posible de hacer esto en el código. me puedes avisar por favor?

31 de marzo de 2015, 23:36

@Kerem
Puedes bajar la ganancia del operacional bajando la resistencia de 270K (puedes poner una variable) .
Otra opción es subir los límites de cada canal:
limXXX = 20 + acumXXX*5;
Puedes probar a subir el 20 como valor inicial

Anónimo
18 de mayo de 2015, 12:00

hola, gracias por el post ya tengo toda la electronica montada pero me sale este error de compilacion, antes me salia el de mas arriba pero lo arregle con el post sobre el yun.

Fix_fft\fix_fft.cpp.o: In function `fix_fft(char*, char*, int, int)':
C:\Users\MIsabelCarde\Documents\Arduino\libraries\Fix_fft/fix_fft.cpp:130: multiple definition of `fix_fft(char*, char*, int, int)'

si pudieras ayudarme estaria muy agradecido mi arduino es un duemilanove.
un saludo.

24 de mayo de 2015, 9:19

@Anónimo
Por lo que pone en el error parece que la librería (fix_fft.cpp) está más de una vez.
Comprueba que que sólo esté como librería y no en la carpeta del proyecto.

Anónimo
6 de julio de 2015, 11:26

¿Me podrías decir para que sirven ambos condensadores? Llevo un rato pensándolo y no se me ocurre.

20 de octubre de 2015, 0:09

@Anónimo
Para bloquear la componente continua

24 de octubre de 2015, 17:57

Hola, qué tal? Espero que todo bien. También quería felicitarte por el proyecto, está muy genial. Gracias.
He intentado probarlo, ver el código y descifrarlo, y aún voy en eso; sin embargo, cuando le di en "verificar", me salió un error, que terminé corrigiéndolo después de una ardua lucha en google, para luego darme cuenta que la solución estaba en los comentarios :v En fin, lo copilé y otra vez y me apareció este mensaje:
"
Global variables use 341 bytes (16%) of dynamic memory, leaving 1.707 bytes for local variables. Maximum is 2.048 bytes.
"
No entiendo mucho qué significa, salvo por la ligera sospecha de que la memoria no es suficiente en mi Arduino UNO atmega328p. y google no me da referencia alguna. Aún así, subido y todo, no me funcionó. No creo que las resistencias influyan tanto en su ohmmeaje, y en vez de un 4,7uf le puse uno de 10uf.
Agradecería una respuesta, ya que de verdad quiero montar mi discoteca ochentera en mi cuarto :D Gracias otra vez.

25 de octubre de 2015, 21:42

@Joanvahu

Hoola, otra vez, te cuento que en prueba y prueba me di cuenta que ese mensaje que aparecía no era nada, así que me preguntaba por qué no funcionaba el circuito, revisé y revisé el circuito y todo estaba bien, sin embargo las luces seguían sin responder. Por tanto, aquello me llevó a preguntarme por qué, y en un desespero grité cerca del módulo dealextreme y vi que los leds respondieron ante aquel suceso, y ¡TODO ESTABA BIEN! Solo que no era tan sensible como debe, funciona con frecuencias altas. La nueva interrogante es, ¿cómo lo haría más sensible? Gracias de antemano.

26 de octubre de 2015, 13:11

@Joanvahu
Hay varias opciones ..
1) Cambiar de módulo de sonido ... la verdad es que este módulo como analógico es realmente malo, pero era el que tenía, ahora he probado con un modulo que incluye un Max9812 (lo puedes encontrar en ebay) y no hace falta ni el operacional.

2) Aumentar la ganancia del u741, para ello aumenta la resistencia R3 por ejemplo a 560K o a 1Momh, pero ojo aumentará el ruido.

3) Prueba a cambiar la linea
data[i] = analogRead(0)/4 - 128; // 0..1024 a -128..127
por
data[i] = analogRead(0)/2 - 256; // 0..1024 a -256..256

4) Comentar las lineas en las que se dividen por 2 los acumulados
bajos = bajos/2; ... medio = medios/ 2 ....

5) jugar con los límites
limBajos = 20 + acumBajos*5; // Puedes bajar el 20 o el 5

Todo es probar ....

5 de febrero de 2016, 14:27

Me pasa lo mismo. Pero el enlace está roto. Ayuda por favor.

8 de febrero de 2016, 23:50

@Unknown
¿Qué enlace?

jgarp64
19 de febrero de 2016, 11:00

ERROR DE COMPILACION:
fix_fft.cpp:50: error: 'prog_uint8_Sinewave' does not name a type

const prog_uint8_Sinewave[N_WAVE-N_WAVE/4] PROGMEM = {

^

In file included from sketch\fix_fft.cpp:1:0:

sketch\fix_fft.cpp: In function 'int fix_fft(char*, char*, int, int)':

fix_fft.cpp:199: error: 'Sinewave' was not declared in this scope

wr = pgm_read_word_near(Sinewave + j+N_WAVE/4);

^

fix_fft.cpp:209: error: 'Sinewave' was not declared in this scope

wi = -pgm_read_word_near(Sinewave + j);

^

exit status 1
'prog_uint8_Sinewave' does not name a type

Me puedes ayudar? Muchas gracias

jgarp64
19 de febrero de 2016, 11:09

Solucionado error de compilación, la solución fue:
const uint8_t Sinewave[N_WAVE-N_WAVE/4] PROGMEM = {
muchas gracias por tu blog.

27 de abril de 2016, 7:35

Excelente trabajo, voy a intentar hacerlo, pero tengo unas dudas. Me gustaría hacerlo midiendo directamente el valor de tensión en la salida de los altavoces haciendo un divisor de tensión pero, ¿de qué manera me afectaría al código arduino si lo hiciera así?
Otra cosa que quiero preguntarte es si hay algún problema en poner en lugar de 3 LEDs, 3 relés que me controlen 3 bombillas conectadas a 220v, supongo que será igual uno y otro caso.
Un saludo y felicitaciones por la página

27 de abril de 2016, 13:06

@cristian
1) Si utilizas una resistencia variable para poder ajustar el nivel de la señal, el código no debería cambiar (cuidado si atacas directamente la entrada del Arduino no sobrepase los 5V).
2) En el post siguiente se describe la etapa de potencia para controlar 3 bombillas de 220V aunque con TRIACS no con relés.

27 de abril de 2016, 15:18

@Arduino Guay Muchas gracias por las aclaraciones, he estado mirando y es cierto que con TRIACS es mejor. A la hora de probar el código, me ha salido el mismo error que ha @jgarp64, y lo he corregido de la misma manera que él, pero ahora me da otro error que no se como arreglar:



fix_fft\fix_fft.cpp.o: In function `fix_fft(char*, char*, int, int)':
C:\Users\Cristian\Documents\Arduino\libraries\fix_fft/fix_fft.cpp:129: multiple definition of `fix_fft(char*, char*, int, int)'
fix_fft.cpp.o:C:\Users\Cristian\AppData\Local\Temp\build8683375630035343489.tmp/fix_fft.cpp:129: first defined here
fix_fft\fix_fft.cpp.o: In function `fix_fft(char*, char*, int, int)':
C:\Users\Cristian\Documents\Arduino\libraries\fix_fft/fix_fft.cpp:129: multiple definition of `fix_fftr(char*, int, int)'
fix_fft.cpp.o:C:\Users\Cristian\AppData\Local\Temp\build8683375630035343489.tmp/fix_fft.cpp:129: first defined here
collect2.exe: error: ld returned 1 exit status


¿Sabes a qué puede deberse?

28 de abril de 2016, 23:41

@cristian
No estoy seguro, pero según el error "multiple definition of `fix_fftr(char*, int, int)'" parece que esta encontrando esta función duplicada ..
Comprueba que no tengas duplicado en el proyecto (en la carpeta) algún archivo (fix_fft.h o fix_fft.cpp) por ejemplo al haberlo modificado (si has dejado alguna copia como el original)

1 de mayo de 2016, 11:50

@Arduino Guay correcto, eso era lo que pasaba, mil gracias, ahora solo queda montar el harware y ponerlo en marcha a ver que tal.

Publicar un comentario en la entrada

Buscar en el blog

Cargando...

¡Lo más visto!

English Version

English Version
Arduino is Cool!!

También en Facebook