Subversion Repositories DashDisplay

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* ----------------------------------------------------------------------    
  2. * Copyright (C) 2010-2014 ARM Limited. All rights reserved.    
  3. *    
  4. * $Date:        19. March 2015
  5. * $Revision:    V.1.4.5  
  6. *    
  7. * Project:          CMSIS DSP Library    
  8. * Title:            arm_cfft_q15.c  
  9. *    
  10. * Description:  Combined Radix Decimation in Q15 Frequency CFFT processing function
  11. *    
  12. * Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
  13. *  
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. *   - Redistributions of source code must retain the above copyright
  18. *     notice, this list of conditions and the following disclaimer.
  19. *   - Redistributions in binary form must reproduce the above copyright
  20. *     notice, this list of conditions and the following disclaimer in
  21. *     the documentation and/or other materials provided with the
  22. *     distribution.
  23. *   - Neither the name of ARM LIMITED nor the names of its contributors
  24. *     may be used to endorse or promote products derived from this
  25. *     software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  33. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  35. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.  
  39. * -------------------------------------------------------------------- */
  40.  
  41. #include "arm_math.h"
  42.  
  43. extern void arm_radix4_butterfly_q15(
  44.     q15_t * pSrc,
  45.     uint32_t fftLen,
  46.     q15_t * pCoef,
  47.     uint32_t twidCoefModifier);
  48.  
  49. extern void arm_radix4_butterfly_inverse_q15(
  50.     q15_t * pSrc,
  51.     uint32_t fftLen,
  52.     q15_t * pCoef,
  53.     uint32_t twidCoefModifier);
  54.  
  55. extern void arm_bitreversal_16(
  56.     uint16_t * pSrc,
  57.     const uint16_t bitRevLen,
  58.     const uint16_t * pBitRevTable);
  59.    
  60. void arm_cfft_radix4by2_q15(
  61.     q15_t * pSrc,
  62.     uint32_t fftLen,
  63.     const q15_t * pCoef);
  64.    
  65. void arm_cfft_radix4by2_inverse_q15(
  66.     q15_t * pSrc,
  67.     uint32_t fftLen,
  68.     const q15_t * pCoef);
  69.  
  70. /**  
  71. * @ingroup groupTransforms  
  72. */
  73.  
  74. /**
  75. * @addtogroup ComplexFFT  
  76. * @{  
  77. */
  78.  
  79. /**  
  80. * @details  
  81. * @brief       Processing function for the Q15 complex FFT.
  82. * @param[in]      *S    points to an instance of the Q15 CFFT structure.  
  83. * @param[in, out] *p1   points to the complex data buffer of size <code>2*fftLen</code>. Processing occurs in-place.  
  84. * @param[in]     ifftFlag       flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform.  
  85. * @param[in]     bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output.  
  86. * @return none.  
  87. */
  88.  
  89. void arm_cfft_q15(
  90.     const arm_cfft_instance_q15 * S,
  91.     q15_t * p1,
  92.     uint8_t ifftFlag,
  93.     uint8_t bitReverseFlag)
  94. {
  95.     uint32_t L = S->fftLen;
  96.  
  97.     if(ifftFlag == 1u)
  98.     {
  99.         switch (L)
  100.         {
  101.         case 16:
  102.         case 64:
  103.         case 256:
  104.         case 1024:
  105.         case 4096:
  106.             arm_radix4_butterfly_inverse_q15  ( p1, L, (q15_t*)S->pTwiddle, 1 );
  107.             break;
  108.            
  109.         case 32:
  110.         case 128:
  111.         case 512:
  112.         case 2048:
  113.             arm_cfft_radix4by2_inverse_q15  ( p1, L, S->pTwiddle );
  114.             break;
  115.         }  
  116.     }
  117.     else
  118.     {
  119.         switch (L)
  120.         {
  121.         case 16:
  122.         case 64:
  123.         case 256:
  124.         case 1024:
  125.         case 4096:
  126.             arm_radix4_butterfly_q15  ( p1, L, (q15_t*)S->pTwiddle, 1 );
  127.             break;
  128.            
  129.         case 32:
  130.         case 128:
  131.         case 512:
  132.         case 2048:
  133.             arm_cfft_radix4by2_q15  ( p1, L, S->pTwiddle );
  134.             break;
  135.         }  
  136.     }
  137.    
  138.     if( bitReverseFlag )
  139.         arm_bitreversal_16((uint16_t*)p1,S->bitRevLength,S->pBitRevTable);    
  140. }
  141.  
  142. /**    
  143. * @} end of ComplexFFT group    
  144. */
  145.  
  146. void arm_cfft_radix4by2_q15(
  147.     q15_t * pSrc,
  148.     uint32_t fftLen,
  149.     const q15_t * pCoef)
  150. {    
  151.     uint32_t i;
  152.     uint32_t n2;
  153.     q15_t p0, p1, p2, p3;
  154. #ifndef ARM_MATH_CM0_FAMILY
  155.     q31_t T, S, R;
  156.     q31_t coeff, out1, out2;
  157.     const q15_t *pC = pCoef;
  158.     q15_t *pSi = pSrc;
  159.     q15_t *pSl = pSrc + fftLen;
  160. #else
  161.     uint32_t ia, l;
  162.     q15_t xt, yt, cosVal, sinVal;
  163. #endif
  164.    
  165.     n2 = fftLen >> 1;
  166.  
  167. #ifndef ARM_MATH_CM0_FAMILY
  168.  
  169.     for (i = n2; i > 0; i--)
  170.     {
  171.         coeff = _SIMD32_OFFSET(pC);
  172.         pC += 2;
  173.  
  174.         T = _SIMD32_OFFSET(pSi);
  175.         T = __SHADD16(T, 0); // this is just a SIMD arithmetic shift right by 1
  176.  
  177.         S = _SIMD32_OFFSET(pSl);
  178.         S = __SHADD16(S, 0); // this is just a SIMD arithmetic shift right by 1
  179.  
  180.         R = __QSUB16(T, S);
  181.  
  182.         _SIMD32_OFFSET(pSi) = __SHADD16(T, S);
  183.         pSi += 2;
  184.  
  185.     #ifndef ARM_MATH_BIG_ENDIAN
  186.  
  187.         out1 = __SMUAD(coeff, R) >> 16;
  188.         out2 = __SMUSDX(coeff, R);
  189.  
  190.     #else
  191.  
  192.         out1 = __SMUSDX(R, coeff) >> 16u;
  193.         out2 = __SMUAD(coeff, R);
  194.  
  195.     #endif //     #ifndef ARM_MATH_BIG_ENDIAN
  196.  
  197.         _SIMD32_OFFSET(pSl) =
  198.         (q31_t) ((out2) & 0xFFFF0000) | (out1 & 0x0000FFFF);
  199.         pSl += 2;
  200.     }
  201.    
  202. #else //    #ifndef ARM_MATH_CM0_FAMILY
  203.    
  204.     ia = 0;
  205.     for (i = 0; i < n2; i++)
  206.     {
  207.         cosVal = pCoef[ia * 2];
  208.         sinVal = pCoef[(ia * 2) + 1];
  209.         ia++;
  210.        
  211.         l = i + n2;        
  212.        
  213.         xt = (pSrc[2 * i] >> 1u) - (pSrc[2 * l] >> 1u);
  214.         pSrc[2 * i] = ((pSrc[2 * i] >> 1u) + (pSrc[2 * l] >> 1u)) >> 1u;
  215.        
  216.         yt = (pSrc[2 * i + 1] >> 1u) - (pSrc[2 * l + 1] >> 1u);
  217.         pSrc[2 * i + 1] =
  218.         ((pSrc[2 * l + 1] >> 1u) + (pSrc[2 * i + 1] >> 1u)) >> 1u;
  219.  
  220.         pSrc[2u * l] = (((int16_t) (((q31_t) xt * cosVal) >> 16)) +
  221.                   ((int16_t) (((q31_t) yt * sinVal) >> 16)));
  222.  
  223.         pSrc[2u * l + 1u] = (((int16_t) (((q31_t) yt * cosVal) >> 16)) -
  224.                        ((int16_t) (((q31_t) xt * sinVal) >> 16)));
  225.     }
  226.    
  227. #endif //    #ifndef ARM_MATH_CM0_FAMILY
  228.    
  229.     // first col
  230.     arm_radix4_butterfly_q15( pSrc, n2, (q15_t*)pCoef, 2u);
  231.     // second col
  232.     arm_radix4_butterfly_q15( pSrc + fftLen, n2, (q15_t*)pCoef, 2u);
  233.                        
  234.     for (i = 0; i < fftLen >> 1; i++)
  235.     {
  236.         p0 = pSrc[4*i+0];
  237.         p1 = pSrc[4*i+1];
  238.         p2 = pSrc[4*i+2];
  239.         p3 = pSrc[4*i+3];
  240.        
  241.         p0 <<= 1;
  242.         p1 <<= 1;
  243.         p2 <<= 1;
  244.         p3 <<= 1;
  245.        
  246.         pSrc[4*i+0] = p0;
  247.         pSrc[4*i+1] = p1;
  248.         pSrc[4*i+2] = p2;
  249.         pSrc[4*i+3] = p3;
  250.     }
  251. }
  252.  
  253. void arm_cfft_radix4by2_inverse_q15(
  254.     q15_t * pSrc,
  255.     uint32_t fftLen,
  256.     const q15_t * pCoef)
  257. {    
  258.     uint32_t i;
  259.     uint32_t n2;
  260.     q15_t p0, p1, p2, p3;
  261. #ifndef ARM_MATH_CM0_FAMILY
  262.     q31_t T, S, R;
  263.     q31_t coeff, out1, out2;
  264.     const q15_t *pC = pCoef;
  265.     q15_t *pSi = pSrc;
  266.     q15_t *pSl = pSrc + fftLen;
  267. #else
  268.     uint32_t ia, l;
  269.     q15_t xt, yt, cosVal, sinVal;
  270. #endif
  271.    
  272.     n2 = fftLen >> 1;
  273.  
  274. #ifndef ARM_MATH_CM0_FAMILY
  275.  
  276.     for (i = n2; i > 0; i--)
  277.     {
  278.         coeff = _SIMD32_OFFSET(pC);
  279.         pC += 2;
  280.  
  281.         T = _SIMD32_OFFSET(pSi);
  282.         T = __SHADD16(T, 0); // this is just a SIMD arithmetic shift right by 1
  283.  
  284.         S = _SIMD32_OFFSET(pSl);
  285.         S = __SHADD16(S, 0); // this is just a SIMD arithmetic shift right by 1
  286.  
  287.         R = __QSUB16(T, S);
  288.  
  289.         _SIMD32_OFFSET(pSi) = __SHADD16(T, S);
  290.         pSi += 2;
  291.  
  292.     #ifndef ARM_MATH_BIG_ENDIAN
  293.  
  294.         out1 = __SMUSD(coeff, R) >> 16;
  295.         out2 = __SMUADX(coeff, R);
  296.     #else
  297.  
  298.         out1 = __SMUADX(R, coeff) >> 16u;
  299.         out2 = __SMUSD(__QSUB(0, coeff), R);
  300.  
  301.     #endif //     #ifndef ARM_MATH_BIG_ENDIAN
  302.  
  303.         _SIMD32_OFFSET(pSl) =
  304.         (q31_t) ((out2) & 0xFFFF0000) | (out1 & 0x0000FFFF);        
  305.         pSl += 2;
  306.     }
  307.    
  308. #else //    #ifndef ARM_MATH_CM0_FAMILY
  309.  
  310.     ia = 0;
  311.     for (i = 0; i < n2; i++)
  312.     {
  313.         cosVal = pCoef[ia * 2];
  314.         sinVal = pCoef[(ia * 2) + 1];
  315.         ia++;
  316.        
  317.         l = i + n2;
  318.         xt = (pSrc[2 * i] >> 1u) - (pSrc[2 * l] >> 1u);
  319.         pSrc[2 * i] = ((pSrc[2 * i] >> 1u) + (pSrc[2 * l] >> 1u)) >> 1u;
  320.        
  321.         yt = (pSrc[2 * i + 1] >> 1u) - (pSrc[2 * l + 1] >> 1u);
  322.         pSrc[2 * i + 1] =
  323.           ((pSrc[2 * l + 1] >> 1u) + (pSrc[2 * i + 1] >> 1u)) >> 1u;
  324.        
  325.         pSrc[2u * l] = (((int16_t) (((q31_t) xt * cosVal) >> 16)) -
  326.                         ((int16_t) (((q31_t) yt * sinVal) >> 16)));
  327.        
  328.         pSrc[2u * l + 1u] = (((int16_t) (((q31_t) yt * cosVal) >> 16)) +
  329.                            ((int16_t) (((q31_t) xt * sinVal) >> 16)));
  330.     }
  331.    
  332. #endif //    #ifndef ARM_MATH_CM0_FAMILY
  333.  
  334.     // first col
  335.     arm_radix4_butterfly_inverse_q15( pSrc, n2, (q15_t*)pCoef, 2u);
  336.     // second col
  337.     arm_radix4_butterfly_inverse_q15( pSrc + fftLen, n2, (q15_t*)pCoef, 2u);
  338.                        
  339.     for (i = 0; i < fftLen >> 1; i++)
  340.     {
  341.         p0 = pSrc[4*i+0];
  342.         p1 = pSrc[4*i+1];
  343.         p2 = pSrc[4*i+2];
  344.         p3 = pSrc[4*i+3];
  345.        
  346.         p0 <<= 1;
  347.         p1 <<= 1;
  348.         p2 <<= 1;
  349.         p3 <<= 1;
  350.        
  351.         pSrc[4*i+0] = p0;
  352.         pSrc[4*i+1] = p1;
  353.         pSrc[4*i+2] = p2;
  354.         pSrc[4*i+3] = p3;
  355.     }
  356. }
  357.  
  358.