dsPIC33E ADC a FFT ayuda

-2

Estoy muestreando una señal de rango de audio con un ancho de banda de 3100Hz y luego aplico una FFT utilizando el ejemplo de la biblioteca DSP de Microchip para determinar la frecuencia más dominante de la señal.

En el último paso en el que se supone que debo recuperar la frecuencia con la energía más alta, todo lo que obtengo son ceros.

El primer paso, que consiste en muestrear la señal analógica, está funcionando bien, ya que he exportado los valores de matriz a Excel y graficado el gráfico.

El código es el siguiente:

void alarmFreq (void) //Detect the dominant frequency of the audio picked by the microphone
    {    
    int i = 0;
    fractional *p_real = &sigCmpx[0].real;
    fractcomplex *p_cmpx = &sigCmpx[0];
    readMic();
    for (ix_MicADCbuff=0;ix_MicADCbuff<FFT_BLOCK_LENGTH;ix_MicADCbuff++)
    {
        sigCmpx[ix_MicADCbuff].real = Float2Fract(micADCbuff[ix_MicADCbuff]);   // replace real part with ADC value
        sigCmpx[ix_MicADCbuff].imag = 0;                                        // set imaginary part with 0
    }
    /*for (ix_MicADCbuff=0;ix_MicADCbuff<FFT_BLOCK_LENGTH;ix_MicADCbuff++)
    {
        *p_real = micADCbuff[ix_MicADCbuff];   // replace real part with ADC value
        *p_real++;                                        
    }*/
    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
        }                   
    p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real; //Set up pointers to convert real array to a complex array. The input array initially has all the real input samples followed by a series of zeros
    p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ;                     
    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 simply zero out the imaginary part of each data sample
            (*p_cmpx--).imag = 0x0000;  
        }
    FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));// Perform FFT operation
    BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);// Store output samples in bit-reversed order of their addresses   
    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 vector
    VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);//Find the frequency Bin ( = index into the SigCmpx[] array) that has the largest energy 
    peakFrequency = peakFrequencyBin*(AUDIO_FS/FFT_BLOCK_LENGTH); //Compute the frequency (in Hz) of the largest spectral component 
}
void readMic (void) //Sample microphone input
    {
    ADC1_ChannelSelectSet(ADC1_AI_MIC);
    ix_MicADCbuff=0;
    for(ix_MicADCbuff=0;ix_MicADCbuff<FFT_BLOCK_LENGTH;ix_MicADCbuff++)
        {
            //delay_ms(1);          //FS without waiting time 66790 Hz
            ADC1_SamplingStop();
            while(!ADC1_IsConversionComplete()){}
            micADCbuff[ix_MicADCbuff] = ADC1_Channel0ConversionResultGet();
        }
}

Variables externas

extern const fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2]    
__attribute__ ((space(auto_psv), aligned (FFT_BLOCK_LENGTH*2)));

fractcomplex sigCmpx[FFT_BLOCK_LENGTH] __attribute__ ((section (".ydata, data, ymemory"), 
    aligned (FFT_BLOCK_LENGTH * 2 *2))) ={0};

ACTUALIZACIÓN:

Ahora estoy obteniendo un valor, 16640 Hz para la frecuencia dominante.

Cuando exporto los datos generados a dsPICWorks, obtengo esto:

Parece que la función está devolviendo el valor correcto pero la FFT no está funcionando correctamente, ya que debería obtener otra cosa, ¿no?

    
pregunta RWeiser

2 respuestas

2

Todo el negocio relacionado con p_real y p_cmpx me parece extremadamente sospechoso.

El comentario dice "Configure los punteros para convertir una matriz real en una matriz compleja". Pero esto es completamente innecesario: la matriz compleja ya fue creada por el bucle for que sigue inmediatamente a la readMic(); llamada. Todo lo que estás haciendo aquí es mezclar tus datos (y poner a cero la mitad si es así).

Use su depurador para examinar la matriz compleja justo antes de llamar a la FFT. Si no ves tu forma de onda, hay algo mal.

Lo siento, pero tengo que decirlo: Esto tiene todas las características de programación de culto de la carga : la copiar y pegar bloques de código sin entender qué hacen y cuándo usarlos. Debe disminuir la velocidad, tomar las cosas paso a paso y asegurarse de entender lo que cada parte de código está haciendo por usted y por qué lo necesita antes de pasar a la siguiente.

    
respondido por el Dave Tweed
0

¡Así que lo tengo funcionando! Fue un problema de tipo de datos. Lo que hice fue cambiar los bits de tipo de datos de salida de ADC de decimal a fraccional y cargué las muestras directamente en la matriz que utiliza la función FFT. Sin embargo, todavía estoy teniendo comportamientos extraños.

Los intervalos de frecuencia son 66790/512 = 130Hz

A veces, cuando paso una señal cuya frecuencia dominante no es un múltiplo de 130Hz, obtengo como resultado la frecuencia dominante multiplicada por 3. Entonces, he agregado una instrucción de división por 3 en caso de que el resultado sea demasiado alto. Afortunadamente, solo tengo dos frecuencias esperadas que son 520Hz y 3100 Hz, así que puedo truncar los resultados, sin embargo, me gustaría saber cuál es el problema aquí.

Adjunto el código actualizado:

#define FFT_BLOCK_LENGTH    512      //Number of frequency points in the FFT
#define LOG2_BLOCK_LENGTH   9       //Number of "Butterfly" Stages in FFT processing should be related to FFT_BLOCK as in 2^9=512
#define AUDIO_FS            66790   //Sampling frequency of audio signal captured by the mic

int               ix_MicADCbuff;
unsigned long     alarmFrequency;
unsigned long     peakFrequency;

fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2]     /* Declare Twiddle Factor array in X-space*/
__attribute__ ((section (".xbss, bss, xmemory"), aligned (FFT_BLOCK_LENGTH*2)));

fractcomplex sigCmpx[FFT_BLOCK_LENGTH] __attribute__ ((section (".ydata, data, ymemory"), 
        aligned (FFT_BLOCK_LENGTH * 2 *2))) ={0};

void readMic(void)//Sample microphone input
{
        ADC1_ChannelSelectSet(ADC1_AI_MIC);
        ix_MicADCbuff=0;
        for(ix_MicADCbuff=0;ix_MicADCbuff<FFT_BLOCK_LENGTH;ix_MicADCbuff++)
            {
                //delay_us(162-116);          //FS without waiting time 66790 Hz
                ADC1_SamplingStop();
                while(!ADC1_IsConversionComplete()){}
                sigCmpx[ix_MicADCbuff].real = ADC1_Channel0ConversionResultGet();
            }
}
void alarmFreq(void)//Detect the dominant frequency of the audio picked by the microphone
{   
    int i = 0;
    fractional *p_real = &sigCmpx[0].real;
    fractcomplex *p_cmpx = &sigCmpx[0];
    readMic();
    for (ix_MicADCbuff=0;ix_MicADCbuff<FFT_BLOCK_LENGTH;ix_MicADCbuff++)
    {
        *p_real = sigCmpx[ix_MicADCbuff].real;   // load pointer with ADC values       
        *p_real++;      
    }
    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
        }               
    p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real; //Set up pointers to convert real array to a complex array. The input array initially has all the real input samples followed by a series of zeros
    p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ;                     
    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 simply zero out the imaginary part of each data sample
            (*p_cmpx--).imag = 0x0000;  
        }
    FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));// Perform FFT operation
    BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);// Store output samples in bit-reversed order of their addresses   
    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 vector
    VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);//Find the frequency Bin ( = index into the SigCmpx[] array) that has the largest energy 
    peakFrequency = peakFrequencyBin*(AUDIO_FS/FFT_BLOCK_LENGTH); //Compute the frequency (in Hz) of the largest spectral component
    if(peakFrequency>3200)
        {
            peakFrequency=peakFrequency/3;
        }
}
    
respondido por el RWeiser

Lea otras preguntas en las etiquetas