Hola.
Después de trastear un poco con varios programas y librerías, consigo con una que me saque valores de fft de una señal que meto. La cosa es que no tengo muy claro el ancho en Hz de cada "bin" o columna.
Mi señal es una adaptación de la señal de red eléctrica, por lo que el armónico fundamenta (el "bin" o columna 1) debe ser 50Hz, o muy aproximado a esto, y el resto deben ser multiplos de 50Hz. Osea que mi fft debe sacar "bins" o columnas de la forma...
1 -> 0-50Hz
2 -> 50-100Hz
3 -> 100-150Hz
....etc
No se muy bien como hacerlo. Pido si alguien sabe o ya lo ha hecho antes, que me ayude a modificar el siguiente programa para conseguir lo que quiero. Ya sea cambiando las muestras, la velocidad del oscilador ADC de arduino o como sea. (solo me interesa la parte de fft no la de las bandas para las luces)
P.D: Cuando subo las muestras de 256 el programa no saca valores. Creo que este fallo está en la función de la ventana de Hann pero no localizo como solucionarlo.
Gracias.
/*
* Organo de luces psicodelicas
* Organo de luces de tres canales , utilizando la FFT
* Autor: Jose Daniel Herrera
* Fecha: 05/09/2012
* http://arduino-guay.blogspot.com.es
*/
#include "fix_fft.h"
#define MUESTRAS 128 // Numero de muestras para el cálculo de la FFT
#define LOGM 7 // Logaritmo en base 2 del número de muestras
#define BAJOS_MEDIOS 7 // Nº de banda para el corte entre Bajos y Medios
#define MEDIOS_AGUDOS 35 // Nº de banda para el corte entre Medios y Agudos
#define BPIN 9 // Pin de salida Bajos
#define MPIN 10 // Pin de salida Medios
#define APIN 11 // Pin de salida Agudos
#define MAX_PASADAS 10 // Nº de pasadas para el cálculo de los límites
char data[MUESTRAS]; // Array con los valores muestreados (parte real)
char im[MUESTRAS]; // Array con los valores muestreados (parte imaginaria)
unsigned char salida[MUESTRAS/2]; // Valores obtenidos de la FFT (espectro de 64 bandas)
unsigned char bajos,medios,agudos; // Valores calculados para cada canal
byte pasada, // nº de pasada para el cáculo de los límites
acumBajos,acumMedios,acumAgudos, // acumuladores de veces que se supera el límite
limBajos,limMedios,limAgudos; // límites calculados para cada canal
/*
* Funcion que aplica una ventana de Hann a los datos muestreados para reducir el
* efecto de las discontinuidades en los extremos
*/
void aplicaVentana (char *vData) {
double muestrasMenosUno = (double(MUESTRAS) - 1.0);
// Como la ventana es simétrica , se calcula para la mitad y se aplica el factor por los dos extremos
for (uint8_t i = 0; i < MUESTRAS/2 ; i++) {
double indiceMenosUno = double(i);
double ratio = (indiceMenosUno / muestrasMenosUno);
double factorPeso = 0.5 * (1.0 - cos(6.28 * ratio));
vData[i] *= factorPeso;
vData[MUESTRAS - (i + 1)] *= factorPeso;
}
}
void setup() {
Serial.begin (9600);
// Configuramos el prescaler a 32 -> 16Mhz/32 = 500 KHz
// como cada conversion son 13 ciclos 500/13 ~ 38.4KHz
// Es decir podemos medir en teoria hasta unos 19KHz,
// que para este proyecto sobra.
bitWrite(ADCSRA,ADPS2,1);
bitWrite(ADCSRA,ADPS1,0);
bitWrite(ADCSRA,ADPS0,1);
// Como la señal es muy baja,utilizamos la referencia interna
// de 1.1 V en vez de la de defecto de 5 V.
// analogReference(INTERNAL);
// Salidas para los canales de Bajos,Medios y Agudos
pinMode(BPIN,OUTPUT);
pinMode(MPIN,OUTPUT);
pinMode(APIN,OUTPUT);
// Variables para el cálculo de los límites
pasada = 0;
acumBajos = acumMedios = acumAgudos = 0;
limBajos = limMedios = limAgudos = 50;
}
void loop() {
// Realizamos el muestreo
for( int i=0; i < MUESTRAS; i++) {
data[i] = analogRead(0)/4 -128; //Convertimos de 0..1024 a -128..127
im[i] = 0; // parte imaginaria = 0
}
// Aplicamos la ventana de Hann
aplicaVentana (data);
// Calculamos la FFT
fix_fft(data,im,LOGM,0);
// Sólo nos interesan los valores absolutos, no las fases, asi que
// calculamos el módulos de los vectores re*re + im*im.
for (int i=0; i < MUESTRAS/2; i++){
salida[i] = sqrt (data[i] * data[i] + im[i] * im[i]);
}
for (int i=0; i < (MUESTRAS/2); i++){
Serial.print (i+1);
Serial.print (" : ");
Serial.println (salida[i]);
}
delay (2000);
}