/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cfft_radix2_f32.c
*
* Description: Radix-2 Decimation in Frequency CFFT & CIFFT Floating point processing function
*
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.3 2010/11/29
* Initial version
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupTransforms
*/
/**
* @defgroup Radix2_CFFT_CIFFT Radix-2 Complex FFT Functions
*
* \par
* Complex Fast Fourier Transform(CFFT) and Complex Inverse Fast Fourier Transform(CIFFT) is an efficient algorithm to compute Discrete Fourier Transform(DFT) and Inverse Discrete Fourier Transform(IDFT).
* Computational complexity of CFFT reduces drastically when compared to DFT.
* \par
* This set of functions implements CFFT/CIFFT
* for Q15, Q31, and floating-point data types. The functions operates on in-place buffer which uses same buffer for input and output.
* Complex input is stored in input buffer in an interleaved fashion.
*
* \par
* The functions operate on blocks of input and output data and each call to the function processes
* 2*fftLen
samples through the transform. pSrc
points to In-place arrays containing 2*fftLen
values.
* \par
* The pSrc
points to the array of in-place buffer of size 2*fftLen
and inputs and outputs are stored in an interleaved fashion as shown below.
*
{real[0], imag[0], real[1], imag[1],..}* * \par Lengths supported by the transform: * \par * Internally, the function utilize a radix-2 decimation in frequency(DIF) algorithm * and the size of the FFT supported are of the lengths [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]. * * * \par Algorithm: * * Complex Fast Fourier Transform: * \par * Input real and imaginary data: *
* x(n) = xa + j * ya * x(n+N/2 ) = xb + j * yb ** where N is length of FFT * \par * Output real and imaginary data: *
* X(2r) = xa'+ j * ya' * X(2r+1) = xb'+ j * yb' ** \par * Twiddle factors for radix-2 FFT: *
* Wn = cosVal + j * (- sinVal) ** * \par * \image html CFFT_Radix2.gif "Radix-2 Decimation-in Frequency Complex Fast Fourier Transform" * * \par * Output from Radix-2 CFFT Results in Digit reversal order. Interchange middle two branches of every butterfly results in Bit reversed output. * \par * Butterfly CFFT equations: *
* xa' = xa + xb * ya' = ya + yb * xb' = (xa-xb)* cosVal + (ya-yb) * sinVal * yb' = (ya-yb)* cosVal - (xa-xb) * sinVal ** * * Complex Inverse Fast Fourier Transform: * \par * CIFFT uses same twiddle factor table as CFFT with modifications in the design equation as shown below. * * \par * Modified Butterfly CIFFT equations: *
* xa' = xa + xb * ya' = ya + yb * xb' = (xa-xb)* cosVal - (ya-yb) * sinVal * yb' = (ya-yb)* cosVal + (xa-xb) * sinVal ** * \par Instance Structure * A separate instance structure must be defined for each Instance but the twiddle factors and bit reversal tables can be reused. * There are separate instance structure declarations for each of the 3 supported data types. * * \par Initialization Functions * There is also an associated initialization function for each data type. * The initialization function performs the following operations: * - Sets the values of the internal structure fields. * - Initializes twiddle factor table and bit reversal table pointers * \par * Use of the initialization function is optional. * However, if the initialization function is used, then the instance structure cannot be placed into a const data section. * To place an instance structure into a const data section, the instance structure must be manually initialized. * Manually initialize the instance structure as follows: *
*arm_cfft_radix2_instance_f32 S = {fftLen, ifftFlag, bitReverseFlag, pTwiddle, pBitRevTable, twidCoefModifier, bitRevFactor, onebyfftLen}; *arm_cfft_radix2_instance_q31 S = {fftLen, ifftFlag, bitReverseFlag, pTwiddle, pBitRevTable, twidCoefModifier, bitRevFactor}; *arm_cfft_radix2_instance_q15 S = {fftLen, ifftFlag, bitReverseFlag, pTwiddle, pBitRevTable, twidCoefModifier, bitRevFactor}; ** \par * where
fftLen
length of CFFT/CIFFT; ifftFlag
Flag for selection of CFFT or CIFFT(Set ifftFlag to calculate CIFFT otherwise calculates CFFT);
* bitReverseFlag
Flag for selection of output order(Set bitReverseFlag to output in normal order otherwise output in bit reversed order);
* pTwiddle
points to array of twiddle coefficients; pBitRevTable
points to the array of bit reversal table.
* twidCoefModifier
modifier for twiddle factor table which supports all FFT lengths with same table;
* pBitRevTable
modifier for bit reversal table which supports all FFT lengths with same table.
* onebyfftLen
value of 1/fftLen to calculate CIFFT;
*
* \par Fixed-Point Behavior
* Care must be taken when using the fixed-point versions of the CFFT/CIFFT function.
* Refer to the function specific documentation below for usage guidelines.
*/
/**
* @addtogroup Radix2_CFFT_CIFFT
* @{
*/
/**
* @details
* @brief Processing function for the floating-point Radix-2 CFFT/CIFFT.
* @param[in] *S points to an instance of the floating-point Radix-2 CFFT/CIFFT structure.
* @param[in, out] *pSrc points to the complex data buffer of size 2*fftLen
. Processing occurs in-place.
* @return none.
*/
void arm_cfft_radix2_f32(
const arm_cfft_radix2_instance_f32 * S,
float32_t * pSrc)
{
if(S->ifftFlag == 1u)
{
/* Complex IFFT radix-2 */
arm_radix2_butterfly_inverse_f32(pSrc, S->fftLen, S->pTwiddle,
S->twidCoefModifier, S->onebyfftLen);
}
else
{
/* Complex FFT radix-2 */
arm_radix2_butterfly_f32(pSrc, S->fftLen, S->pTwiddle,
S->twidCoefModifier);
}
if(S->bitReverseFlag == 1u)
{
/* Bit Reversal */
arm_bitreversal_f32(pSrc, S->fftLen, S->bitRevFactor, S->pBitRevTable);
}
}
/**
* @} end of Radix2_CFFT_CIFFT group
*/
/* ----------------------------------------------------------------------
** Internal helper function used by the FFTs
** ------------------------------------------------------------------- */
/*
* @brief Core function for the floating-point CFFT butterfly process.
* @param[in, out] *pSrc points to the in-place buffer of floating-point data type.
* @param[in] fftLen length of the FFT.
* @param[in] *pCoef points to the twiddle coefficient buffer.
* @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table.
* @return none.
*/
void arm_radix2_butterfly_f32(
float32_t * pSrc,
uint32_t fftLen,
float32_t * pCoef,
uint16_t twidCoefModifier)
{
int i, j, k, l;
int n1, n2, ia;
float32_t xt, yt, cosVal, sinVal;
#ifndef ARM_MATH_CM0
/* Initializations for the first stage */
n2 = fftLen;
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (i = 0; i < n2; i++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
/* Twiddle coefficients index modifier */
ia = ia + twidCoefModifier;
/* index calculation for the input as, */
/* pSrc[i + 0], pSrc[i + fftLen/1] */
l = i + n2;
/* Butterfly implementation */
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2u * l] = xt * cosVal + yt * sinVal;
pSrc[2u * l + 1u] = yt * cosVal - xt * sinVal;
} // groups loop end
twidCoefModifier = twidCoefModifier << 1u;
// loop for stage
for (k = fftLen / 2; k > 2; k = k >> 1)
{
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (j = 0; j < n2; j++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = j; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2u * l] = xt * cosVal + yt * sinVal;
pSrc[2u * l + 1u] = yt * cosVal - xt * sinVal;
} // butterfly loop end
} // groups loop end
twidCoefModifier = twidCoefModifier << 1u;
} // stages loop end
n1 = n2;
n2 = n2 >> 1;
ia = 0;
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = 0; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = (pSrc[2 * i] + pSrc[2 * l]);
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = (pSrc[2 * l + 1] + pSrc[2 * i + 1]);
pSrc[2u * l] = xt;
pSrc[2u * l + 1u] = yt;
} // groups loop end
#else
//N = fftLen;
n2 = fftLen;
// loop for stage
for (k = fftLen; k > 1; k = k >> 1)
{
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (j = 0; j < n2; j++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = j; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2 * l] = (cosVal * xt + sinVal * yt); // >> 15;
pSrc[2 * l + 1] = (cosVal * yt - sinVal * xt); // >> 15;
}
}
twidCoefModifier = twidCoefModifier << 1u;
}
#endif // #ifndef ARM_MATH_CM0
}
void arm_radix2_butterfly_inverse_f32(
float32_t * pSrc,
uint32_t fftLen,
float32_t * pCoef,
uint16_t twidCoefModifier,
float32_t onebyfftLen)
{
int i, j, k, l;
int n1, n2, ia;
float32_t xt, yt, cosVal, sinVal;
#ifndef ARM_MATH_CM0
//N = fftLen;
n2 = fftLen;
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (i = 0; i < n2; i++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2u * l] = xt * cosVal - yt * sinVal;
pSrc[2u * l + 1u] = yt * cosVal + xt * sinVal;
} // groups loop end
twidCoefModifier = twidCoefModifier << 1u;
// loop for stage
for (k = fftLen / 2; k > 2; k = k >> 1)
{
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (j = 0; j < n2; j++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = j; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2u * l] = xt * cosVal - yt * sinVal;
pSrc[2u * l + 1u] = yt * cosVal + xt * sinVal;
} // butterfly loop end
} // groups loop end
twidCoefModifier = twidCoefModifier << 1u;
} // stages loop end
n1 = n2;
n2 = n2 >> 1;
ia = 0;
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = 0; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = (pSrc[2 * i] + pSrc[2 * l]) * onebyfftLen;
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = (pSrc[2 * l + 1] + pSrc[2 * i + 1]) * onebyfftLen;
pSrc[2u * l] = xt * onebyfftLen;
pSrc[2u * l + 1u] = yt * onebyfftLen;
} // butterfly loop end
#else
//N = fftLen;
n2 = fftLen;
// loop for stage
for (k = fftLen; k > 2; k = k >> 1)
{
n1 = n2;
n2 = n2 >> 1;
ia = 0;
// loop for groups
for (j = 0; j < n2; j++)
{
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = j; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = pSrc[2 * i] + pSrc[2 * l];
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = pSrc[2 * l + 1] + pSrc[2 * i + 1];
pSrc[2u * l] = xt * cosVal - yt * sinVal;
pSrc[2u * l + 1u] = yt * cosVal + xt * sinVal;
} // butterfly loop end
} // groups loop end
twidCoefModifier = twidCoefModifier << 1u;
} // stages loop end
n1 = n2;
n2 = n2 >> 1;
ia = 0;
cosVal = pCoef[ia * 2];
sinVal = pCoef[(ia * 2) + 1];
ia = ia + twidCoefModifier;
// loop for butterfly
for (i = 0; i < fftLen; i += n1)
{
l = i + n2;
xt = pSrc[2 * i] - pSrc[2 * l];
pSrc[2 * i] = (pSrc[2 * i] + pSrc[2 * l]) * onebyfftLen;
yt = pSrc[2 * i + 1] - pSrc[2 * l + 1];
pSrc[2 * i + 1] = (pSrc[2 * l + 1] + pSrc[2 * i + 1]) * onebyfftLen;
pSrc[2u * l] = xt * onebyfftLen;
pSrc[2u * l + 1u] = yt * onebyfftLen;
} // butterfly loop end
#endif // #ifndef ARM_MATH_CM0
}