FFT con un pic?

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
 
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.
 
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
 
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.
 
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.
 
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).
 
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
 
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
 
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?
 
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
 
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.
 
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
 
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!
 
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.
 

Adjuntos

  • FFT.txt
    12.1 KB · Visitas: 280
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:

Código:
#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:


Código:
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:


Código:
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:

Código:
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:

Código:
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!
 
Atrás
Arriba