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 */