This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

12 bit from ADC to Q15 for a FFT

I have a project on a STM32F103 using the ADC.

I'm trying to make simple VU meter. I made a litle circuit (a resistor divisor and a decoupling capacitor) to put the audio signal into de uC. Becouse of the resistor I get 2048 counts for no audio input.

So, when I put audio to the systems I get my ADC sampling it around 2048. Now I want to convert 16 bits unsigned (but centered at 2048) to Q15 to use CMSIS FFT_Q15

Is there any CMSIS function to do that? Is there a simple way to do that?

Thank!

  • This is part of my code:

     

    	for(i=0;i<128;i+=2)
    	{
    		FFT_ADCvalues[i]=(q15_t)((int16_t)(DMA_ADCvalues[i/2]-2048)<<3);
    		FFT_ADCvalues[i+1]=(q15_t)0;
    	}
    	arm_cfft_q15(&arm_cfft_sR_q15_len64, FFT_ADCvalues, 0, 1);
    	arm_cmplx_mag_q15(FFT_ADCvalues, MAG_of_fft, 64);

    As I have 12 bits binary offset stored in an unsigned int16_t I'm trying to convert to q15 but it seems that don't work ok, becouse the result of arm_cmplx_mag_q15 is 255,0,0,0,0,0,0,.....

     

    So, what am I doing wrong?

  • I made this code test:

    	float fltSinWave[64];
    	q15_t q15SinWave[64];
    	q15_t q15FFT[128];
    	q15_t q15MAG[64];
    	uint32_t F=1562;
    	uint32_t Fs = 10000;
    	uint8_t i;
    	for(i=0;i<64;i++)
    	{
    		// Seno discreto FLOTANTE
    		fltSinWave[i] = (sin(2*M_PI*i*F/Fs));
    		// Seno discreto en Q15
    		q15SinWave[i] = (q15_t)(fltSinWave[i] * (1<<15));
    	}
    	// Preparo el array de la FFT
    	for(i=0;i<128;i+=2)
    	{
    		q15FFT[i] = q15SinWave[i/2];
    		q15FFT[i+1] = 0;
    	}
    	// Calculo la FFT
    	arm_cfft_q15(&arm_cfft_sR_q15_len64, q15FFT, 0, 1);
    	// Calculo la magnitud de cada punto
    	arm_cmplx_mag_q15(q15FFT, q15MAG, 64);

    This way the fft and mag is working ok. Except for the mag output. I get 8191 in the bin number 10. 8191 is 0001 1111 1111 1111 in q2.14 format (arm_cmplx_mag_q15 change 1.15 to 2.14). So left shiting 1 bit I get 0011 1111 1111 1110 that is almost 0.5. But I should get 1. So there is another scale factor...

    Idea?

  • Hi,

    This is a common characteristic of complex FFT on real signals, just have a look at the bin number (64 - 10), you should have the same magnitude.

    Real signals have a symmetric spectrum at output of Complex FFT, you can try to search or read this.

  • FFT has a nice effect : it "splits" your signal in frequencies !
    First bin of FFT output represents DC part of your signal.
    You can consider all your samples to be of the form (2048 + s[k]), directly perform FFT on it. If s(t) is a centered signal (average value of 0), you would end with FFT output:
    0 : 2048
    1 : ...
  • I know what you are saying.
    But it don&#x27;t answer my question wich is:
    What other scale factor exist, becouse my output on bin 10 is 0.5 and should be 1.
    I know that in cfft_f32 function, de value on the bin should be divided by Nfft and the multiply by 2. In q15 version seems that I have to just multiply the bin value by 2. But I want some proof of that.

    Thank!
  • Your signal "energy" is split on positive half of spectrum (bins 1 to 31) and negative half (bins -1 to -31 which are in position 63 to 33).
    Therefore in your case, half of expected magnitude is found on bin 10, the other half is on bin 64 - 10 !

    So either you know that your signal was real as input and you can simply multiply first half of spectrum by 2, or you take whole spectrum into account and perform the complex addition X(10) = FFT(10) + FFT*(64-10) (where the star "*" stands for complex conjugate).