/* * fftutil.c * * Created on: Jan 5, 2018 * Author: deanm */ #include "Adafruit_ZeroFFT.h" /* * @brief In-place bit reversal function. * @param[in, out] *pSrc points to the in-place buffer of Q15 data type. * @param[in] fftLen length of the FFT. * @param[in] bitRevFactor bit reversal modifier that supports different * size FFTs with the same bit reversal table * @param[in] *pBitRevTab points to bit reversal table. * @return none. */ static q15_t ALIGN4 scratchData[ZERO_FFT_MAX]; void arm_bitreversal_q15(q15_t *pSrc16, uint32_t fftLen, uint16_t bitRevFactor, uint16_t *pBitRevTab) { q31_t *pSrc = (q31_t *)pSrc16; q31_t in; uint32_t fftLenBy2, fftLenBy2p1; uint32_t i, j; /* Initializations */ j = 0u; fftLenBy2 = fftLen / 2u; fftLenBy2p1 = (fftLen / 2u) + 1u; /* Bit Reversal Implementation */ for (i = 0u; i <= (fftLenBy2 - 2u); i += 2u) { if (i < j) { /* pSrc[i] <-> pSrc[j]; */ /* pSrc[i+1u] <-> pSrc[j+1u] */ in = pSrc[i]; pSrc[i] = pSrc[j]; pSrc[j] = in; /* pSrc[i + fftLenBy2p1] <-> pSrc[j + fftLenBy2p1]; */ /* pSrc[i + fftLenBy2p1+1u] <-> pSrc[j + fftLenBy2p1+1u] */ in = pSrc[i + fftLenBy2p1]; pSrc[i + fftLenBy2p1] = pSrc[j + fftLenBy2p1]; pSrc[j + fftLenBy2p1] = in; } /* pSrc[i+1u] <-> pSrc[j+fftLenBy2]; */ /* pSrc[i+2] <-> pSrc[j+fftLenBy2+1u] */ in = pSrc[i + 1u]; pSrc[i + 1u] = pSrc[j + fftLenBy2]; pSrc[j + fftLenBy2] = in; /* Reading the index for the bit reversal */ j = *pBitRevTab; /* Updating the bit reversal index depending on the fft length */ pBitRevTab += bitRevFactor; } } void arm_radix2_butterfly_q15(q15_t *pSrc, uint32_t fftLen, q15_t *pCoef, uint16_t twidCoefModifier) { int i, j, k, l; int n1, n2, ia; q15_t xt, yt, cosVal, sinVal; // N = fftLen; n2 = fftLen; 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] >> 2u) - (pSrc[2 * l] >> 2u); pSrc[2 * i] = ((pSrc[2 * i] >> 2u) + (pSrc[2 * l] >> 2u)) >> 1u; yt = (pSrc[2 * i + 1] >> 2u) - (pSrc[2 * l + 1] >> 2u); pSrc[2 * i + 1] = ((pSrc[2 * l + 1] >> 2u) + (pSrc[2 * i + 1] >> 2u)) >> 1u; pSrc[2u * l] = (((int16_t)(((q31_t)xt * cosVal) >> 16)) + ((int16_t)(((q31_t)yt * sinVal) >> 16))); pSrc[2u * l + 1u] = (((int16_t)(((q31_t)yt * cosVal) >> 16)) - ((int16_t)(((q31_t)xt * sinVal) >> 16))); } // butterfly loop end } // 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]) >> 1u; yt = pSrc[2 * i + 1] - pSrc[2 * l + 1]; pSrc[2 * i + 1] = (pSrc[2 * l + 1] + pSrc[2 * i + 1]) >> 1u; pSrc[2u * l] = (((int16_t)(((q31_t)xt * cosVal) >> 16)) + ((int16_t)(((q31_t)yt * sinVal) >> 16))); pSrc[2u * l + 1u] = (((int16_t)(((q31_t)yt * cosVal) >> 16)) - ((int16_t)(((q31_t)xt * sinVal) >> 16))); } // butterfly loop end } // groups loop end twidCoefModifier = twidCoefModifier << 1u; } // stages loop end 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; pSrc[2u * l + 1u] = yt; } // butterfly loop end } // groups loop end twidCoefModifier = twidCoefModifier << 1u; } static inline void applyWindow(q15_t *src, const q15_t *window, uint16_t len) { while (len--) { int32_t val = *src * *window++; *src++ = val >> 15; } } int ZeroFFT(q15_t *source, uint16_t length) { uint16_t twidCoefModifier; uint16_t bitRevFactor; uint16_t *pBitRevTable; q15_t *pSrc = source; switch (length) { #if ZERO_FFT_MAX == 8192 case 4096u: /* Initializations of structure parameters for 4096 point FFT */ /* Initialise the twiddle coef modifier value */ twidCoefModifier = 1u; /* Initialise the bit reversal table modifier */ bitRevFactor = 1u; /* Initialise the bit reversal table pointer */ pBitRevTable = (uint16_t *)armBitRevTable; applyWindow(source, window_hanning_4096, 4096); break; #endif #if ZERO_FFT_MAX >= 4096 case 2048u: /* Initializations of structure parameters for 2048 point FFT */ /* Initialise the twiddle coef modifier value */ twidCoefModifier = 2u; /* Initialise the bit reversal table modifier */ bitRevFactor = 2u; /* Initialise the bit reversal table pointer */ pBitRevTable = (uint16_t *)&armBitRevTable[1]; applyWindow(source, window_hanning_2048, 2048); break; #endif #if ZERO_FFT_MAX >= 2048 case 1024u: /* Initializations of structure parameters for 1024 point FFT */ twidCoefModifier = 4u; bitRevFactor = 4u; pBitRevTable = (uint16_t *)&armBitRevTable[3]; applyWindow(source, window_hanning_1024, 1024); break; #endif #if ZERO_FFT_MAX >= 1024 case 512u: /* Initializations of structure parameters for 512 point FFT */ twidCoefModifier = 8u; bitRevFactor = 8u; pBitRevTable = (uint16_t *)&armBitRevTable[7]; applyWindow(source, window_hanning_512, 512); break; #endif #if ZERO_FFT_MAX >= 512 case 256u: /* Initializations of structure parameters for 256 point FFT */ twidCoefModifier = 16u; bitRevFactor = 16u; pBitRevTable = (uint16_t *)&armBitRevTable[15]; applyWindow(source, window_hanning_256, 256); break; #endif case 128u: /* Initializations of structure parameters for 128 point FFT */ twidCoefModifier = 32u; bitRevFactor = 32u; pBitRevTable = (uint16_t *)&armBitRevTable[31]; applyWindow(source, window_hanning_128, 128); break; case 64u: /* Initializations of structure parameters for 64 point FFT */ twidCoefModifier = 64u; bitRevFactor = 64u; pBitRevTable = (uint16_t *)&armBitRevTable[63]; applyWindow(source, window_hanning_64, 64); break; case 32u: /* Initializations of structure parameters for 32 point FFT */ twidCoefModifier = 128u; bitRevFactor = 128u; pBitRevTable = (uint16_t *)&armBitRevTable[127]; applyWindow(source, window_hanning_32, 32); break; case 16u: /* Initializations of structure parameters for 16 point FFT */ twidCoefModifier = 256u; bitRevFactor = 256u; pBitRevTable = (uint16_t *)&armBitRevTable[255]; applyWindow(source, window_hanning_16, 16); break; default: /* Reporting argument error if fftSize is not valid value */ return -1; break; } // split the data q15_t *pOut = scratchData; for (int i = 0; i < length; i++) { *pOut++ = *pSrc++; // real *pOut++ = 0; // imaginary } arm_radix2_butterfly_q15(scratchData, length, (q15_t *)twiddleCoefQ15, twidCoefModifier); arm_bitreversal_q15(scratchData, length, bitRevFactor, pBitRevTable); pSrc = source; pOut = scratchData; for (int i = 0; i < length; i++) { q15_t val = *pOut++; uint32_t v = abs(val); *pSrc++ = v; pOut++; // discard imaginary phase val } return 0; }