# FFT con un pic?



## Alberth (Abr 23, 2008)

Es posible hacer un calculo de FFT con un PIC de Microchip?


----------



## Eduardo (Abr 23, 2008)

Mira la nota de aplicacion de microchip AN542.


----------



## fragmir (Jul 22, 2008)

Yo tambien tengo duda de eso, si deseo muestrear una señal de 1khz debo hacer interrupcion cada 1/2000hz para cumplir on teorema de nyquist no?
mi duda surge cuando lleno mi buffer de 16 muestras y le quiero aplicar la fft cada 200ms,
es buena idea? no he encontrado mucho de esto en los foros .
gracias


----------



## Eduardo (Jul 23, 2008)

> Yo tambien tengo duda de eso, si deseo muestrear una señal de 1khz debo hacer interrupcion cada 1/2000hz para cumplir on teorema de nyquist no?


- Si se trata de una señal de baja frecuencia cuyo espectro llega como maximo a 1kHz *si*.
- Si es una señal periodica de frecuencia fundamental 1kHz *no*.



> mi duda surge cuando lleno mi buffer de 16 muestras y le quiero aplicar la fft cada 200ms,es buena idea?


Son muy pocas muestras, aunque todo depende de para queres usarlas.


----------



## fragmir (Jul 23, 2008)

A que te refieres con eso de que si es una señal periodica con fundamental de 1khz no, que puede generar aliasing si ocupo esa frec. de muestreo?

Mi objetivo es obtener un espectro frecuencial de 8 intervalos de frecuencia; desde 0 hasta 1khz, y despues se revisara cada intervalo y si rebasa un umbral "x" activo un circuito "x".
Gracias por la ayuda


----------



## Eduardo (Jul 23, 2008)

Si tenes una señal periodica con frecuencia de 1kHz o cercana, muestreando 2 kHz lo unico que podes reconstruir es una senoide, porque todas sus armonicas estan arriba del kHz, deben ser eliminadas con un filtro antialias porque si no reconstruis cualquier cosa.


Por otro lado, la frecuencia de Nyquist es un limite, en la practica no conviene estar tan cerca porque te complica inutilmente el filtro ademas de que necesitas muestrear durante una cantidad grande de ciclos para que la reconstruccion sea confiable.

Pensa simplemente lo que pasa si muestreas una senoide de 1kHz a 2kHz. Si el instante de muestreo coincide con el maximo/minimo de la señal esta todo bien, pero si te coincide con el pasaje por cero vas a muestrear puros ceros.

Como criterio practico, conviene que la frecuencia maxima de la señal no sea mayor que 0.75 la frecuencia limite.  
Es decir, si tu frecuencia maxima de interes es de 1kHz, entonces muestrea a 2/.75 =  2.7 kHz o mas. 

No te olvides que como interesar adquirir la señal con poca deformacion, el filtro antialias no solo debe eliminar todos los armonicos superiores sino que tambien debe ser lineal en fase, eso significa que si estas muy cerca de la frecuencia limite el filtro va a tener que ser de un orden grande --> poco practico.
Cuanto mas lejos estes --> menos requisitos del filtro y mas confiable la reconstruccion.


----------



## fragmir (Jul 23, 2008)

Jaja  yo me rompi la cabeza con esa situacion cuando la graficaba en matlab, ya que si no desfaso el  inicio del muestreo, si aplico como la fs=2fmax, el matlab sacaba puro cero y eso me hizo mucho ruido por lo que tu idea me parece muy buena aplicar .75, trataré eso en matlab y despues seguire con lo de la fft. para pasarlo al pic.
mil gracias.


----------



## Eduardo (Jul 23, 2008)

Otro comentario.
Cual es tu frecuencia minima de interes?   Porque en la FFT con 16 muestras solamente vas a sacar solamente 8 frecuencias submultiplos de la de muestreo mas la componente continua de ese fragmento.

Por lo general la FFT se hace con 128 o mas valores y la ventana no es bueno que sea rectangular sino una ventana de Hamming o la que venga mejor (Coseno levantado,Von Hann,Blackman,etc).


----------



## tiopepe123 (Jul 23, 2008)

Depende de la aplicacion, pero tambien hay la serie 18 que lleva multiplicador o la ds que se parece mas a un dsp con una MAC.

Si lo que deseas detectar "tonos" mira 
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en024294

Dentro hay una aplicacion para evaluar el dtmf y fsk y un pdf donde se explica como hacer una dft de 1 solo bit con una XOR como multiplicador


----------



## fragmir (Jul 23, 2008)

asi es requiero 8 multiplos de la señal de 1khz y no deseo detectar tonos sino que necesito separar la señal en 8 rangos de frecuencia para determinar su amplitud, algo parecido a un analizador de espectros pero con 8 bandas.
 y buen dato respecto a lo de microchip, lo checare.
Investigare eso de la ventana de hamming, triangular etc. porque no puedo comentar nada al respecto, pues no se de que se trata eso.
Gracias


----------



## fragmir (Jul 23, 2008)

Hola
Ya lo realice en matlab y efectivamente si realizo el stem a 2750 khz, obtengo mejores muestras, ahora creo que comenzaré a realizar mi proyecto.
agradezco y  espero me ayuden con las dudas que se me presenten en el camino.
de igual manera si puedo ayudarles en algo me avisan
un saludo


----------



## fragmir (Jul 28, 2008)

Hola, me surge una duda, porque N=2^N como puedo determinar N si mi fmax=1khz?


----------



## fragmir (Ago 9, 2008)

Hola, ya pude implementar casi todo el codigo d ela fft en el pic, pero alguien sabe como reordeno el vector donde guardo la fft  para obtener mi espectro frecuencial ordenado?


----------



## Alberth (Ago 13, 2008)

hola! fragmir, estoy haciendo un programa parecido al tuyo de fft, pero como lo compruebas? es decir yo tengo un vector de entrada que corresponde a una señal analogica de cierto voltaje, cuando aplico la funcion fft se supone que es el vector de salida, pero como lo compruebas? es decir que valores te da? o como puedo saber que efectivamente la fft se esta realizando correctamente? tienes algun vector de prueba ?
saludos


----------



## fragmir (Ago 13, 2008)

Hola:
si mira te recomiendo que apliques lo siguiente:

en tu codigo fft  simula un vector de 16 elementos y puedes poner cualquier valor [1 2 3 2 2 3 2 2 2 2 2] por decir algo, aplicas fft y despues comparas con matlab, tienes matlab?
si es así la sintaxis es la siguiente:

vector=[1 2 1 2 1 2 1 2 21 2 1 2 22 12 2 1 ......];
vectorfft=fft(vector,128);
vectorfft, así podras ver lo que arroja la fft de matlab y podras comparar con la tuya.
si no tienes matlab te dejo el siguiente vector:
1,2,1,0 su fft = [4,-j2,0,j2]
suerte.


----------



## Alberth (Ago 13, 2008)

hola que tal! gracias por responder fragmir, me habian comentado que tenia que llenar de algunos ceros el vector antes de calcular la fft es decir para el vetor de entrada: vector=1,2,1,0
una vez llenado de ceros quedaria asi: 1,0,2,0,1,0,0,0 que asi lo tenia que introducir al micro?
por otro lado donde mencionabas que el vector 1,2,1,0 su fft=4,j2,0,j2, eso es su correspondiente vector en fft, pero como puedo representarlo en amplitud contra frecuencia?, es decir como un espectro....
saludos


----------



## fragmir (Sep 3, 2008)

Disculpa que no haya escrito, no me di cuenta del mensaje.
eso de usar ceros entre los digitos no se porque lo dijeron, no me atrevo a decir que es falso porque no lo se. lo que yo te puedo decir es que mis simulaciones han funcionado prefectamente y lo ultimo que me falta es un pequeño problema en el dspic para implementarlo, todo está simulado en borland y en matlab y veras que coincide.
contactame y te puedo enviar mis códigos para que lo cheques.
Lo que te puedo decir es que si quieres graficar amplitud contra frecuencia, pouedes tomar la mitad del espectro total. (epsectro positivo) y utilizar la funcion fftshift de matlab para intercambiar las mitades de tu biffer fft. el valor absoluto del buffer fft son las amplitudes del espectro y para coincidirlo en frecuencia con amplitud, deberás declarar un vector donde el tamaño sea de N/2:
frec=[0:63]*2500/128; aqui mi fft es de 128 elementos, mi frecuencia de muestreo es de 2500 y  el vector es de 64 elementos porque solo ocupo una parte del espectro.
saludos!


----------



## dsklast (Oct 4, 2011)

Bueno he estado trabajando en un analizador de espectro. Hasta ahora tengo la FFT para N puntos completa y funcionando. Actalmente la uso con 32 y 64 muestras y ejecuta 10 FFT de 64 puntos por segundo y 28 de 32 puntos por segundo. Esta hecha en CCS trate de emplear un codigo optimizado.

Quiero compartir con ustedes este avance pues e recivido mucho informacion de este foro para mis proyectos y quiero compartir este tema como muestra de gratitud con el foro. el codigo es completamente libre si lo quieren cambiar mejorar etc.

Adjunto la rutina FFT cualquier duda, sugerencia, opinion y demas bien recividas son.


----------



## cristian_elect (Oct 4, 2011)

Poner un numero decimal tan largo en una variable de tipo float de 32bits. No sea tan exagerados.


----------



## hibiscusblau (Dic 3, 2012)

Hola a todos, 

Estoy trabajando con el codigo FFT de Microchip y tengo un problema con los valores de la FFT, porqué pongo un senos fijo a la entrada del ADC (por ejemplo de 500Hz) y muestro en el hyperterminal los BIN y la frecuencia correspondiente, y cada vez que hago una adquisición de señal, me muestra BINs y frecuencia de peak diferente (con la misma entrada analogica). Por eso no sé qué estoy haciendo mal. 

Parametros de la FFT:


```
#define               FOSC     10000000
#define               PLL         8
//#define           FCY        FOSC*PLL/4
 
#define NUMSAMP         256
#define SAMPLINGRATE    8000
#define SAMPCOUNT       (20000000/SAMPLINGRATE)+1
```

Leo el señal sinusoidal desde del canal AN3 y muestreo con el TMR3 por eso configuro el ADC de la siguiente forma:



```
void ADCInit (){
 
        //ADCON1 Register
         //Set up A/D conversrion results to be read in 1.15 fractional number format.
        //All other bits to their default state
        ADCON1bits.FORM = 2;  // 11 Signal fractional, 10 Fractional, 01 Signed integer, 00 Integer  
 
ADCON1bits.SSRC = 2; //Use Timer3 to provide sampling time
                ADCON1bits.ASAM = 1;  // Auto-Sample Start Mode. Allows the ADC to schedule sample/conversion sequences with no intervention by the user or other devices resources
 
        //ADCON2 Register
        ADCON2bits.SMPI = 0;// interrupció x cada mostra/conversio
                               //ADCON3 = 0x1F02; // SAMC  = 11111 (31Tad) i ADCS = 2 => Tad = Tcy*(2+1)/2
 
                               // Dades per una Fs = 8KHz
                               ADCON3bits.ADCS = 63; // Tad = Tcy(ADCS+1)/2 = 1.6usec
 
                    TMR3 = 0x0000;
        PR3 = SAMPCOUNT;  // Load Period value SAMPCOUNT = (Fcy/Fs)+1 (ho he vist algun lloc amb -1)
 
//IFS0bits.T3IF: Timer3 Interrupt Flag Status bit
//1 = Interrupt request has occurred
//0 = Interrupt request has not occurred
        IFS0bits.T3IF = 0;
 
//IEC0bits.T3IE: Timer3 Interrupt Enable bit
//1 = Interrupt request enabled
//0 = Interrupt request not enabled
        IEC0bits.T3IE = 0;
 
 
        //Set up A/D Channel Select Register to convert AN3 on Mux A input
        ADCHS = 0x0003;
 
        //ADCSSL Register
        //Channel Scanning is disabled. All bits left to their default state
        ADCSSL = 0x0000;
 
        //ADPCFG Register
        //Set up channels AN3 as analog input and configure rest as digital
        ADPCFG = 0xFFFF;
        ADPCFGbits.PCFG3 = 0;
 
                               //Clear the A/D interrupt flag bit
        IFS0bits.ADIF = 0;
 
        //Set the A/D interrupt enable bit
        IEC0bits.ADIE = 1;
 
        //Turn on the A/D converter
        //This is typically done after configuring other registers
        ADCON1bits.ADON = 1;
 
        //Start Timer 3
                               //T3CONbits.TON: Timer On Control bit
                               //1 = Starts the timer
                               //0 = Stops the timer
        T3CONbits.TON = 1;
 
                               CountSamples = 0;
}
```

Después, espero los datos en la interrupción del ADC:



```
void __attribute__ ((__interrupt__, no_auto_psv)) _ADCInterrupt(void)
{
                //            int i;
                fractional aux;
 
    //Clear the Timer3 Interrupt Flag
    IFS0bits.T3IF = 0;
 
    //Clear the A/D Interrupt flag bit or else the CPU will
    //keep vectoring back to the ISR
    IFS0bits.ADIF = 0;
 
                inputSignal[CountSamples] = ADCBUF0; // mentrestant...
                //sigCmpx[CountSamples].real = ADCBUF0; // mentrestant...
                CountSamples++;
 
                if (CountSamples >= FFT_BLOCK_LENGTH){      
                               ADCFFTMoveSamples(); // moc les mostres del buffer aux al buffer sigCmpx.
                               doFilterFlag = 1; // CountSamples >= 256, ja ho tinc tot
                               CountSamples = 0;        
                }
}
```


En ADCFFTMoveSamples, copio las muestras dentro de SigCmpx para no reescribir las muestras y que me calcule mal la FFT (actualmente paro la interrupción del ADC cuando entro a calcular la FFT pero en un futuro la idea es que se pueda trabajar en paralelo). Esta función hace lo siguiente:


```
void ADCFFTMoveSamples(){
                int i;
                for (i = 0; i < FFT_BLOCK_LENGTH; i++){
                               sigCmpx[i].real = inputSignal[i]; //inicialitzo a 0
                               sigCmpx[i].imag = 0; //inicialitzo a 0       
                }
}
```

Then, when flag doFilterFlag =1, the main calls FFTMotor(), and it does:


```
char FFTMotor(){
                int i = 0;
                fractional *p_real = &sigCmpx[0].real ; // posa al punter p_real l'@de memòria on es troba sigCmpx[0].real
                fractcomplex *p_cmpx = &sigCmpx[0] ; // posa al punter p_cmpx l'@de memòria on es troba sigCmpx[0]
                char flagAuxCaiguda =0;
//******* paro la interrupció
                IEC0bits.ADIE = 0;                           //paro la interrupció per fer la FFT
//*****baixo flags
                ThereIsARockFlag = 0;
                doFilterFlag = 0;
 
                sprintf(uTxt, "\r\n 1 Inici FFT  \r\n");
                putsUART1((unsigned int *)uTxt);
 
                for ( i = 0; i < FFT_BLOCK_LENGTH; i++ )/* The FFT function requires input data */
                {                                                                             /* to be in the fractional fixed-point range [-0.5, +0.5]*/
                               *p_real = *p_real >>1 ;                               /* So, we shift all data samples by 1 bit to the right. */
//En teoria això divieix per 2? el valor de la variable que apunta p_real. Perquè la variable va de [+1, -1], l'ADC ja l'agafa tipus fractional, per tant divideix x 2.
                               *p_real++;                                        /* Should you desire to optimize this process, perform */
                }                                                                             /* data scaling when first obtaining the time samples */
                                                                                              /* Or within the BitReverseComplex function source code */
 
                // p_real = &sigCmpx[127].real posa a p_real l'@ de memòria de sigCmpx[127].real
                p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real ;   /* Set up pointers to convert real array */
 
                // p_cmpx = &sigCmpx[255] posa a p_cmpx l'@ de memòria de sigCmpx[255]
                p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ; /* to a complex array. The input array initially has all */
                                                                                              /* the real input samples followed by a series of zeros */
 
                for ( i = FFT_BLOCK_LENGTH; i > 0; i-- ) /* Convert the Real input sample array */
                {                                                                             /* to a Complex input sample array  */
                               (*p_cmpx).real = (*p_real--);   /* We will simpy zero out the imaginary  */
                               (*p_cmpx--).imag = 0x0000;      /* part of each data sample */
                }
 
                FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
 
                // Store output samples in bit-reversed order of their addresses
                BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);
 
                // Compute the square magnitude of the complex FFT output array so we have a Real output vetor
                SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real);
 
                // Find the frequency Bin ( = index into the sigCmpx[] array) that has the largest energy
                // i.e., the largest spectral component
                VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);
 
                sprintf(uTxt, "\r\n BIN: %d \r\n",peakFrequencyBin );
                putsUART1((unsigned int *)uTxt);
                // Compute the frequency (in Hz) of the largest spectral component
                peakFrequency = peakFrequencyBin*(SAMPLING_RATE/FFT_BLOCK_LENGTH);
 
                sprintf(uTxt, "\r\n Frequencia de Pic: %ld \r\n", peakFrequency);
                putsUART1((unsigned int *)uTxt);
                sprintf(uTxt, "\r\n Fi FFT \r\n");
                putsUART1((unsigned int *)uTxt);
//
                flagAuxCaiguda = FFTDecide();
 
                ADCEnableConversion ();
                IEC0bits.ADIE = 1;
                return flagAuxCaiguda;
}
```

Alguien sabe qué estoy haciendo mal? 

Muchas gracias a todos!


----------



## hibiscusblau (Ene 30, 2013)

Buenas notícias!

Ya he encontrado el fallo, o los fallos! Aquí os los pongo por si alguien le pasa lo mismo que yo:

Correción 1: guardar las muestras en parte real y parte imaginaria

Código:

```
void __attribute__ ((__interrupt__, no_auto_psv)) _ADCInterrupt(void)
{
    IFS0bits.T3IF = 0;    //Clear the Timer3 Interrupt Flag    
    IFS0bits.ADIF = 0; //Clear the A/D Interrupt flag bit or else the CPU will keep vectoring back to the ISR

	if(tics%2 == 0 ){
		sigCmpx[CountSamples].real = ADCBUF0; 
	}else{
		sigCmpx[CountSamples].imag = ADCBUF0; 
		CountSamples++;
	}
	tics++;
	if (CountSamples >= FFT_BLOCK_LENGTH){	
		doFilterFlag = 1; 
		CountSamples = 0;
		tics = 0;
	}
}
```

Corrección 2:


```
Código:
#define FFT_BLOCK_LENGTH	512    /* = Number of frequency points in the FFT */
#define LOG2_BLOCK_LENGTH 	9	/* = Number of "Butterfly" Stages in FFT processing */  2^9 = 512

#define SAMPLING_RATE		8000 	/* = Rate at which input signal was sampled */
                                        /* SAMPLING_RATE is used to calculate the frequency*/
                                        /* of the largest element in the FFT output vector*/
```

La fft se realiza asi:


```
char FFTMotor(){
	int i = 0;

	double aux = 0;

	fractional *p_real = &sigCmpx[0].real ; // posa al punter p_real l'@de memòria on es troba sigCmpx[0].real
	fractcomplex *p_cmpx = &sigCmpx[0] ; // posa al punter p_cmpx l'@de memòria on es troba sigCmpx[0]

	IEC0bits.ADIE = 0;		 //paro la interrupció per fer la FFT

	sprintf(uTxt, "\r\n entro  a la FFTMOTOR \r\n" );
	putsUART1((unsigned int *)uTxt);
	ThereIsARockFlag = 0;
	doFilterFlag = 0;

	p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real ;	/* Set up pointers to convert real array */  // p_real = &sigCmpx[127].real posa a p_real l'@ de memòria de sigCmpx[127].real	
	p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1]; /* to a complex array. The input array initially has all */ // p_cmpx = &sigCmpx[255] posa a p_cmpx l'@ de memòria de sigCmpx[255]
						/* the real input samples followed by a series of zeros */

	for ( i = FFT_BLOCK_LENGTH; i > 0; i-- )
	{	
 		/* Convert the Real input sample array to a Complex input sample array  */			
		(*p_cmpx).real = (*p_real--);
	/* We will simpy zero out the imaginary   part of each data sample */
		(*p_cmpx--).imag = 0x0000;	
	}

	
#ifndef FFTTWIDCOEFFS_IN_PROGMEM
	FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA);
#else
	FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
#endif

	sigCmpx[0].real = 0; // remove signal continue

	// Store output samples in bit-reversed order of their addresses 
	BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);
	// Compute the square magnitude of the complex FFT output array so we have a Real output vetor 
	SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real);
	// Find the frequency Bin ( = index into the sigCmpx[] array) that has the largest energy
	// i.e., the largest spectral component 
	VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);

	// Compute the frequency (in Hz) of the largest spectral component
	aux = 15.63; //((8000)/FFT_BLOCK_LENGTH);
	peakFrequency = peakFrequencyBin*15.63; //(SAMPLING_RATE/FFT_BLOCK_LENGTH); //aux;

	sprintf(uTxt, "\r\n Frequencia de Pic: %ld \r\n", peakFrequency);
	putsUART1((unsigned int *)uTxt);

	IEC0bits.ADIE = 0;
	return 0;
}
```

Saludos!


----------



## jhefren (Jul 10, 2013)

Saludos @dsklast podrias explicar paso a paso como trabaja, en realidad quiero hacer una, pero en assembler, ya que es mi fuerte y no manejo  muy bien el lenguaje c. Muchas Gracias


----------



## hibiscusblau (Jul 18, 2013)

Supongo que quieres que saber el paso a paso de la fft, no? 

Si te fijas es un codigo que viene proporcionado por las librerías de microchip, y uso sus funciones. 

De hecho, actualmente modifiqué el código y es más simple. Y es el siguiente:


```
void __attribute__ ((__interrupt__, no_auto_psv)) _ADCInterrupt(void)
{
    //Clear the Timer3 Interrupt Flag
    IFS0bits.T3IF = 0;
    //Clear the A/D Interrupt flag bit or else the CPU will     //keep vectoring back to the ISR
    IFS0bits.ADIF = 0;
sigCmpx[CountSamples].real = ADCBUF0; //>>1;
	sigCmpx[CountSamples].imag = 0; //>>1;
	CountSamples++;

	if( ADCBUF0 > AdData){
		AdData = ADCBUF0;
	} 
	tics++;
	if (CountSamples >= FFT_BLOCK_LENGTH){
		doFFTflag = 1; // CountSamples >= 256, ja ho tinc tot
		CountSamples = 0;
		t++;
		tics = 0;
	}
//	LEDblau = 1;
}
```


----------



## hibiscusblau (Jul 23, 2013)

Hola jhefren, 

El otro día no pude terminar mi post. El código que te puse es la adquisición de los datos, que si te fijas, guardo los datos en la parte real de sigCmpx, y en la parte imaginaria 0. 


```
sigCmpx[CountSamples].real = ADCBUF0; //>>1;
sigCmpx[CountSamples].imag = 0; //>>1;
```

Ya que si coges los típicos ejemplos de Microchip, al final mueve las muestras de la parte imaginaria a la mitad para arriba (de FFT_BLOCK_LENGTH/2 a FFT_BLOCK_LENGTH) y en mi caso, la parte de la FFT he sacado esta parte para que el código sea más rendible. 


Código de la FFT:


```
if(doFFTflag == 1){ //si tengo todas las muestras

	        IEC0bits.ADIE = 0;  //paro la interrupción para hacer la FFT	
		doFFTflag = 0;

		                VectorWindow(FFT_BLOCK_LENGTH,&sigCmpx[0].real,&sigCmpx[0].real,ham_window); 
		fractional *p_real = &sigCmpx[0].real ; // pongo el puntero p_real la @ de memoria donde se encuentra sigCmpx[0].real
		// redimensiono la señal para que no sobrepase el margen que la función FFT necesita para operar correctamente
		for ( i = 0; i < FFT_BLOCK_LENGTH; i++ ){/* The FFT function requires input data *//* to be in the fractional fixed-point range [-0.5, +0.5]*/
			*p_real = *p_real >>1 ;		/* So, we shift all data samples by 1 bit to the right. */ 
			*p_real++;			/* Should you desire to optimize this process, perform data scaling when first obtaining the time samples */
					/* Or within the BitReverseComplex function source code */
		}	

                //hago la FFT
		#ifndef FFTTWIDCOEFFS_IN_PROGMEM
			FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA);
		#else
			FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
		#endif

		sigCmpx[0].real = 0; // pongo el primer "BIN" a 0 porque no quiero la tensión continua que tiene a la entrada, (esto no se hasta qué punto es necesario pero por si acaso...)
		
		BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]); // Store output samples in bit-reversed order of their addresses. 
                //gira el array 
		SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real); // Compute the square magnitude of the complex FFT output array so we have a Real output vetor
                //calcula la magnitud a real, haciendo la raiz de la parte real^2 y la parte imaginaria^2 de cada vector. O sea, pasa de una función compleja a imaginaria. 
		VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);	// Compute the frequency (in Hz) of the largest spectral component 		// Find the frequency Bin ( = index into the sigCmpx[] array) that has the largest energy 	// i.e., the largest spectral component
                  //calcula que "BIN" tiene la potencia más alta.


		peakFrequency = peakFrequencyBin*Freq_for_BIN; 
          //calcula qué frecuencia tiene la potencia más alta. 
       }
```


Cada BIN es cada casilla del array. O sea, si nuestra frecuencia de muestreo es de 4000muestras/segundo y el número de muestras es 512, la unidad del BIN sera:

*BIN = Fs/N = 4000/512 = 7.8125Hz. *

O sea, si la frequencia de entrada vale 10Hz, la función *Vector_Max*, devolvera que *peakFrequencyBin* es 2, ya que se encuentra en la 2a casilla del array. Cada casilla son 7.8125Hz.

BIN 1 = 1a casilla de 0Hz a 7.8125Hz
BIN 2 = 2a casilla de 7.8125Hz a 15.625Hz
BIn 3 = 3a casilla de 15.625Hz a 23.4375Hz

Por eso, para saber que frequencia corresponde el BIN que devuelve *peakFrecuencyBin* lo multiplico por Freq_for_BIN que está definido como:


```
#define Freq_for_BIN ((double) SAMPLINGRATE) / FFT_BLOCK_LENGTH;
```

Espero que te sirva de ayuda.


----------

