avior:
* Care must be taken when using the Q15 and Q31 versions of the LMS filter.
* The following issues must be considered:
* - Scaling of coefficients
* - Overflow and saturation
*
* \par Scaling of Coefficients:
* Filter coefficients are represented as fractional values and
* coefficients are restricted to lie in the range [-1 +1).
* The fixed-point functions have an additional scaling parameter postShift.
* At the output of the filter's accumulator is a shift register which shifts the result by postShift bits.
* This essentially scales the filter coefficients by 2^postShift and
* allows the filter coefficients to exceed the range [+1 -1).
* The value of postShift is set by the user based on the expected gain through the system being modeled.
*
* \par Overflow and Saturation:
* Overflow and saturation behavior of the fixed-point Q15 and Q31 versions are
* described separately as part of the function specific documentation below.
*/
/**
* @addtogroup LMS
* @{
*/
/**
* @details
* This function operates on floating-point data types.
*
* @brief Processing function for floating-point LMS filter.
* @param[in] *S points to an instance of the floating-point LMS filter structure.
* @param[in] *pSrc points to the block of input data.
* @param[in] *pRef points to the block of reference data.
* @param[out] *pOut points to the block of output data.
* @param[out] *pErr points to the block of error data.
* @param[in] blockSize number of samples to process.
* @return none.
*/
void arm_lms_f32(
const arm_lms_instance_f32 * S,
float32_t * pSrc,
float32_t * pRef,
float32_t * pOut,
float32_t * pErr,
uint32_t blockSize)
{
float32_t *pState = S->pState; /* State pointer */
float32_t *pCoeffs = S->pCoeffs; /* Coefficient pointer */
float32_t *pStateCurnt; /* Points to the current sample of the state */
float32_t *px, *pb; /* Temporary pointers for state and coefficient buffers */
float32_t mu = S->mu; /* Adaptive factor */
uint32_t numTaps = S->numTaps; /* Number of filter coefficients in the filter */
uint32_t tapCnt, blkCnt; /* Loop counters */
float32_t sum, e, d; /* accumulator, error, reference data sample */
float32_t w = 0.0f; /* weight factor */
e = 0.0f;
d = 0.0f;
/* S->pState points to state array which contains previous frame (numTaps - 1) samples */
/* pStateCurnt points to the location where the new input data should be written */
pStateCurnt = &(S->pState[(numTaps - 1u)]);
blkCnt = blockSize;
#ifndef ARM_MATH_CM0_FAMILY
/* Run the below code for Cortex-M4 and Cortex-M3 */
while(blkCnt > 0u)
{
/* Copy the new input sample into the state buffer */
*pStateCurnt++ = *pSrc++;
/* Initialize pState pointer */
px = pState;
/* Initialize coeff pointer */
pb = (pCoeffs);
/* Set the accumulator to zero */
sum = 0.0f;
/* Loop unrolling. Process 4 taps at a time. */
tapCnt = numTaps >> 2;
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
sum += (*px++) * (*pb++);
sum += (*px++) * (*pb++);
sum += (*px++) * (*pb++);
sum += (*px++) * (*pb++);
/* Decrement the loop counter */
tapCnt--;
}
/* If the filter length is not a multiple of 4, compute the remaining filter taps */
tapCnt = numTaps % 0x4u;
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
sum += (*px++) * (*pb++);
/* Decrement the loop counter */
tapCnt--;
}
/* The result in the accumulator, store in the destination buffer. */
*pOut++ = sum;
/* Compute and store error */
d = (float32_t) (*pRef++);
e = d - sum;
*pErr++ = e;
/* Calculation of Weighting factor for the updating filter coefficients */
w = e * mu;
/* Initialize pState pointer */
px = pState;
/* Initialize coeff pointer */
pb = (pCoeffs);
/* Loop unrolling. Process 4 taps at a time. */
tapCnt = numTaps >> 2;
/* Update filter coefficients */
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
*pb = *pb + (w * (*px++));
pb++;
*pb = *pb + (w * (*px++));
pb++;
*pb = *pb + (w * (*px++));
pb++;
*pb = *pb + (w * (*px++));
pb++;
/* Decrement the loop counter */
tapCnt--;
}
/* If the filter length is not a multiple of 4, compute the remaining filter taps */
tapCnt = numTaps % 0x4u;
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
*pb = *pb + (w * (*px++));
pb++;
/* Decrement the loop counter */
tapCnt--;
}
/* Advance state pointer by 1 for the next sample */
pState = pState + 1;
/* Decrement the loop counter */
blkCnt--;
}
/* Processing is complete. Now copy the last numTaps - 1 samples to the
satrt of the state buffer. This prepares the state buffer for the
next function call. */
/* Points to the start of the pState buffer */
pStateCurnt = S->pState;
/* Loop unrolling for (numTaps - 1u) samples copy */
tapCnt = (numTaps - 1u) >> 2u;
/* copy data */
while(tapCnt > 0u)
{
*pStateCurnt++ = *pState++;
*pStateCurnt++ = *pState++;
*pStateCurnt++ = *pState++;
*pStateCurnt++ = *pState++;
/* Decrement the loop counter */
tapCnt--;
}
/* Calculate remaining number of copies */
tapCnt = (numTaps - 1u) % 0x4u;
/* Copy the remaining q31_t data */
while(tapCnt > 0u)
{
*pStateCurnt++ = *pState++;
/* Decrement the loop counter */
tapCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(blkCnt > 0u)
{
/* Copy the new input sample into the state buffer */
*pStateCurnt++ = *pSrc++;
/* Initialize pState pointer */
px = pState;
/* Initialize pCoeffs pointer */
pb = pCoeffs;
/* Set the accumulator to zero */
sum = 0.0f;
/* Loop over numTaps number of values */
tapCnt = numTaps;
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
sum += (*px++) * (*pb++);
/* Decrement the loop counter */
tapCnt--;
}
/* The result is stored in the destination buffer. */
*pOut++ = sum;
/* Compute and store error */
d = (float32_t) (*pRef++);
e = d - sum;
*pErr++ = e;
/* Weighting factor for the LMS version */
w = e * mu;
/* Initialize pState pointer */
px = pState;
/* Initialize pCoeffs pointer */
pb = pCoeffs;
/* Loop over numTaps number of values */
tapCnt = numTaps;
while(tapCnt > 0u)
{
/* Perform the multiply-accumulate */
*pb = *pb + (w * (*px++));
pb++;
/* Decrement the loop counter */
tapCnt--;
}
/* Advance state pointer by 1 for the next sample */
pState = pState + 1;
/* Decrement the loop counter */
blkCnt--;
}
/* Processing is complete. Now copy the last numTaps - 1 samples to the
* start of the state buffer. This prepares the state buffer for the
* next function call. */
/* Points to the start of the pState buffer */
pStateCurnt = S->pState;
/* Copy (numTaps - 1u) samples */
tapCnt = (numTaps - 1u);
/* Copy the data */
while(tapCnt > 0u)
{
*pStateCurnt++ = *pState++;
/* Decrement the loop counter */
tapCnt--;
}
#endif /* #ifndef ARM_MATH_CM0_FAMILY */
}
/**
* @} end of LMS group
*/