This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Complex FFT for F2809

Other Parts Discussed in Thread: CONTROLSUITE

Hi all

We have quadrature-type hardware and both Re and Im data are available. The question is how to input them both in FFT module? All examples and module descriptions refer to pure real type data, but ours are true complex

Thanks in advance

 

  • Hi!

    How about calculating two FFTs (one with the real part of the input vector, the other one with the imaginary part)?

    FFT(Re+i*Im) = FFT(Re)+i*FFT(Im)

    Best regards,
    Edwin Krasser

  • What FFT module computes  is magnitude of FFT, so

    mag(FFT(Re+i*Im)) is not the same as mag(FFT(Re))+mag(FFT(Im))

  • You have to calculate the magnitudes later, after you calculate FFT(Re)+i*FFT(Im). =>

    you need: mag( FFT(Re)+i*FFT(Im) )

    Best regards and good luck
    Edwin Krasser

  • Hi Tigran,

    Are you using the fixed point library in  controlSUITE?. IF using the CFFT routine, all you have to do is interleave the real and imaginary data in the input buffer, bit reverse real data followed by the imaginary data and then run the fft.

    If you look at the 2833x_FixedPoint_CFFT example, that is exactly what it does. Same concept can be applied to the FPU library as well.

  • thanks for your posting

    the problem of complex FFT calculation is fully solved

    I'd like to present it

    for(p=0;p<1024;p++){

      ipcb[2*p] = (unsigned long) A[p] << 16 ; // Input samples in Real Part
      ipcb[2*p+1] = (unsigned long) B[p] << 16 ; // Input samples in Imaginary Part
    }

    CFFT32_brev2(&ipcb[0],&ipcb[0],N); // Bit-reverse real part
    CFFT32_brev2(&ipcb[1],&ipcb[1],N); // Bit-reverse imaginary part
    // fft.win(&fft);
    fft.calc(&fft);
    fft.mag(&fft);

    Without windowing all works fine !

    Unfortunately, window function deals only with real part, and imaginary part in ipcb remains unchanged 

    Is there any idea how to do?

  • hi

    how to modify cfft_winc.asm (cfft32w.asm) in order to apply to imaginary part, but not to real as it is now ?

    Thank you

    c28\dsp_tbox\fft\clib\src\cfft32w.asm

    ;============================================================================
    ;
    ; File Name : cfft_winc.asm
    ;
    ; Originator : Advanced Embeeded Control
    ; Texas Instruments
    ;
    ; Description : This file contains source code to window the input data sequence in the case of
    ; complex FFT modules
    ;
    ; Date : 26/4/2001 (dd/mm/yyyy)
    ;===========================================================================
    ; Routine Type : C Callable
    ;
    ; Description :
    ; void FFTC_win(FFTxxxC_handle)
    ; This function windows N-point real data sequence stored in bit-reversed order
    ; in alternate memory location.(used with Complex FFT modules)
    ;
    ;======================================================================
    ; COMPLEX FFT MODULES
    ;----------------------------------------------------------------------
    ;typedef struct {
    ; long *ipcbptr;
    ; long *tfptr
    ; int size;
    ; int nrstage;
    ; int *magptr;
    ; int *winptr;
    ; int peakmag;
    ; int peakfrq;
    ; int normflag;
    ; void (*init)(void);
    ; void (*izero)(void *);
    ; void (*calc)(void *);
    ; void (*mag)(void *);
    ; void (*win)(void *);
    ; }CFFT32;
    ;======================================================================

    .def _CFFT32_win

    _CFFT32_win:
    MOVL XAR5,*XAR4++ ; XAR5=ipcbptr
    MOVL XAR6,*+XAR4[6] ; XAR6=winptr
    MOV ACC,*+XAR4[2]<<15 ; AH=size/2
    MOVH AR0,ACC<<2 ; AR0=2*size
    MOVZ AR7,AH ; AR7=(size/2)
    SUBB XAR7,#1 ; AR7=(size/2)-1
    MOVL XAR4,XAR7 ; AR4=(size/2)-1

    nextsamp1:
    MOVL XT,*XAR6++
    QMPYL ACC,XT,*XAR5
    LSL ACC,#1
    MOVL *BR0++,ACC
    BANZ nextsamp1,AR7--

    nextsamp2:
    MOVL XT,*--XAR6
    QMPYL ACC,XT,*XAR5
    LSL ACC,#1
    MOVL *BR0++,ACC
    BANZ nextsamp2,AR4--
    LRETR

  • Hi Tigran,

    You can use the following code for windowing

    _FFT32_win:   
                MOVL    XAR5,*XAR4++    ; XAR5=ipcbptr(src)
                MOVL    XAR6,*+XAR4[6]  ; XAR6=winptr
                MOV     ACC,*+XAR4[2]<<15 ; AH=size/2
                MOVH    AR0,ACC<<2      ; AR0=2*size (AH*4)
                MOVZ    AR7,AH          ; AR7=(size/2)                                  
                SUBB    XAR7,#1         ; AR7=(size/2)-1
                SPM        1                ;Bump up product by 1
    nextsamp1:  
                MOVL    XT,*XAR6++
                QMPYL   ACC,XT,*+XAR5[0]
                QMPYL   P,XT,*+XAR5[2]
                MOVL    *XAR5++,ACC
                MOVL    *XAR5++,P
                BANZ    nextsamp1,AR7--
                
    nextsamp2:  
                MOVL    XT,*--XAR6
                QMPYL   ACC,XT,*+XAR5[0]
                QMPYL   P,XT,*+XAR5[2]
                MOVL    *XAR5++,ACC
                MOVL    *XAR5++,P
                BANZ    nextsamp2,AR4--

                LRETR

    This function does not bit-reverse the input so you would have to window the raw input, bit reverse and then run the fft as follows:

            fft.ipcbptr=ipcbsrc;        /* Source input                  */
            fft.winptr=(long *)win;     /* Window coefficient array                 */
            fft.win(&fft);                    /* window the real part, store bit reversed */
            
            fft.ipcbptr=ipcb;            /* FFT computation buffer                    */
            fft.magptr=ipcbsrc;       /* Magnitude output buffer                    */
            fft.init(&fft);                   /* Twiddle factor pointer initialization       */
            
            CFFT32_brev(ipcbsrc, ipcb, N);              // Real part bit-reversing
            CFFT32_brev(&ipcbsrc[1], &ipcb[1], N);      // Imaginary part bit-reversing

            
            fft.calc(&fft);                /* Compute the FFT                            */
            
            fft.mag(&fft);                /* Q30 format (abs(ipcbsrc)/2^16).^2         */

  • Hi Vishal

    thanks! all work fine!

    only a minor note

    the results of windowing on both Re and Im parts are twice less then expected, i.e. if you place in ipcb all constants, let's say 127, after windowing we will have windowing function profile, but twice less, with maximum at 63

  • We need help in understanding this comment in your library code examples for mag(&fft):

         /* Q30 format (abs(ipcbsrc)/2^16).^2         */

    If the mag(&fft) is in Q30 format, and it is magnitude squared for the frequency, isn't the result in each ipcbsrc frequency bin after the mag(&fft) operation equal to:

       ([abs(ipcbsrc)]^2)/(2^30)?

    Why is 2^16 in your equation?  Also, does this take into account the 2/N multiplier for each frequency and its conjucate in the spectrum?  We need help establishing how your mag(&ffft) operation back converts into a number between -1 and 1 representing the zero-to-peak amplitude of the constituent sinusiod at that frequency.  Assume FFT sample inputs are real valued.

  • The magnitude function uses the QMACL instruction to do the squaring and summing

    QMACL P,loc32,*XAR7++ ; ACC = ACC + P << PM;
                          ; P = (signed T * signed Prog[*XAR7 or *XAR7++]) >> 32;

    So essentially you are doing a Q31*Q31 >> 32

    2^31*2^31*2^-32 = 2^30 (Q30)

    the comment is correct, you are squaring and then right shifting by 32 bits. 

    Dylan Pfeifer said:
    Also, does this take into account the 2/N multiplier for each frequency and its conjucate in the spectrum? 

    No it doesn't. Aside from scaling the product by 32 bits to get a Q30 format there is no other scaling.

  • Thank you Vishal.  Two other questions:

    We are assuming that a simple sqrt() operation on the each array element of icbsrc after the mag(&fft) operation will result in the amplitude of the constituent sinusoid for that frequency.  Is that correct?  Or is there another step?

    Also, is it correct that in the v101 release of the FixedPointLib for f2803x devices that the REAL_FFT32_512 operation should not be used, but rather the N/2 Complex FFT?

    We are using the REAL_FFT_512 and taking a simple integer square root through IQMath on the result of icbsrc after the mag(&fft) operation.  This seems "close enough" for our results if we scale the 12-bit ADC input to the real FFT by 2^17 rather than 2^19.  But this doesn't seem the correct usage of the library...

    Thanks again.

  • Dylan Pfeifer said:
    Also, is it correct that in the v101 release of the FixedPointLib for f2803x devices that the REAL_FFT32_512 operation should not be used, but rather the N/2 Complex FFT?

    You can use the RFFT routines in the library - the RFFT routine itself uses an N/2 pt CFFT to do the computation and then some post fft operations to get the correct spectrum. In fact, the details of it are probably better explained here:

    http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521

    If you were referring to my comments in some of the other posts on the topics, i was referring to the use of the RFFT32_xxxP_DEFAULTS when initializing the structure object. The "size", "nrstage" and "ratio" elements in those macros are incorrect

    #define RFFT32_32P_DEFAULTS { (long *)NULL,\
    (long *)NULL,\
    32,\ //16 - since we use a 16pt CFFT to do a 32pt RFFT
    5,\  //4  - 4 stages in a 16 pt CFFT
    (long *)NULL,\
    (long *)NULL,\
    0,\
    0,\
    128,\ // 256 - you need to every 256th twiddle in the TF table for a 16-pt CFFT
    (void (*)(void *))FFT32_init,\
    (void (*)(void *))FFT32_calc,\
    (void (*)(void *))FFT32_mag,\
    (void (*)(void *))FFT32_win}

    This is being fixed. I will be releasing a revision of this library that will go out on controlSUITE next month.

    Dylan Pfeifer said:
    We are using the REAL_FFT_512 and taking a simple integer square root through IQMath on the result of icbsrc after the mag(&fft) operation.  This seems "close enough" for our results if we scale the 12-bit ADC input to the real FFT by 2^17 rather than 2^19.  But this doesn't seem the correct usage of the library...

    Im not that knowledgeable on how the input scaling affects the output of the sqrt(). Are you seeing saturation, truncation when you scale up by 19 bits or is the result more accurate at 17 bits vs 19 bits

  • When using the sqrt() operation on the result of each icbsrc array element after the mag(&fft) operation, when the input is scaled by 2^17, the result agrees with our function-generated input (a known sinusoid), with 2% error of measurement attenuation.  When we scale by 2^19, the amplitude of the sinusoid after the sqrt() operation seems 4x large (a divide by four missing somewhere).

    This either means we are interpreting our ADC input scaling wrong, or that using the IQMath sqrt() operation on the elements of mag(&fft) requires another step or shifting to account for a value that is mag^2 in Q30.

  • What also would be the correct header corrections for the REAL_FFT_512P_DEFAULTS....  thanks again.

  • It should be 

    #define RFFT32_512P_DEFAULTS    { (long *)NULL,\
            (long *)NULL,\
            256,\
            8,\
            (long *)NULL,\
            (long *)NULL,\
            0,\
            0,\
            16,\
            (void (*)(void *))FFT32_init,\
            (void (*)(void *))FFT32_calc,\
            (void (*)(void *))FFT32_mag,\
            (void (*)(void *))FFT32_win}