|
|
|
|
@ -32,108 +32,6 @@
|
|
|
|
|
@ingroup groupFilters
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@defgroup FIR Finite Impulse Response (FIR) Filters
|
|
|
|
|
|
|
|
|
|
This set of functions implements Finite Impulse Response (FIR) filters
|
|
|
|
|
for Q7, Q15, Q31, and floating-point data types. Fast versions of Q15 and Q31 are also provided.
|
|
|
|
|
The functions operate on blocks of input and output data and each call to the function processes
|
|
|
|
|
<code>blockSize</code> samples through the filter. <code>pSrc</code> and
|
|
|
|
|
<code>pDst</code> points to input and output arrays containing <code>blockSize</code> values.
|
|
|
|
|
|
|
|
|
|
@par Algorithm
|
|
|
|
|
The FIR filter algorithm is based upon a sequence of multiply-accumulate (MAC) operations.
|
|
|
|
|
Each filter coefficient <code>b[n]</code> is multiplied by a state variable which equals a previous input sample <code>x[n]</code>.
|
|
|
|
|
<pre>
|
|
|
|
|
y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[numTaps-1] * x[n-numTaps+1]
|
|
|
|
|
</pre>
|
|
|
|
|
@par
|
|
|
|
|
\image html FIR.GIF "Finite Impulse Response filter"
|
|
|
|
|
@par
|
|
|
|
|
<code>pCoeffs</code> points to a coefficient array of size <code>numTaps</code>.
|
|
|
|
|
Coefficients are stored in time reversed order.
|
|
|
|
|
@par
|
|
|
|
|
<pre>
|
|
|
|
|
{b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
|
|
|
|
|
</pre>
|
|
|
|
|
@par
|
|
|
|
|
<code>pState</code> points to a state array of size <code>numTaps + blockSize - 1</code>.
|
|
|
|
|
Samples in the state buffer are stored in the following order.
|
|
|
|
|
@par
|
|
|
|
|
<pre>
|
|
|
|
|
{x[n-numTaps+1], x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2]....x[n](==pSrc[0]), x[n+1](==pSrc[1]), ..., x[n+blockSize-1](==pSrc[blockSize-1])}
|
|
|
|
|
</pre>
|
|
|
|
|
@par
|
|
|
|
|
Note that the length of the state buffer exceeds the length of the coefficient array by <code>blockSize-1</code>.
|
|
|
|
|
The increased state buffer length allows circular addressing, which is traditionally used in the FIR filters,
|
|
|
|
|
to be avoided and yields a significant speed improvement.
|
|
|
|
|
The state variables are updated after each block of data is processed; the coefficients are untouched.
|
|
|
|
|
|
|
|
|
|
@par Instance Structure
|
|
|
|
|
The coefficients and state variables for a filter are stored together in an instance data structure.
|
|
|
|
|
A separate instance structure must be defined for each filter.
|
|
|
|
|
Coefficient arrays may be shared among several instances while state variable arrays cannot be shared.
|
|
|
|
|
There are separate instance structure declarations for each of the 4 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.
|
|
|
|
|
- Zeros out the values in the state buffer.
|
|
|
|
|
To do this manually without calling the init function, assign the follow subfields of the instance structure:
|
|
|
|
|
numTaps, pCoeffs, pState. Also set all of the values in pState to zero.
|
|
|
|
|
@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.
|
|
|
|
|
Set the values in the state buffer to zeros before static initialization.
|
|
|
|
|
The code below statically initializes each of the 4 different data type filter instance structures
|
|
|
|
|
<pre>
|
|
|
|
|
arm_fir_instance_f32 S = {numTaps, pState, pCoeffs};
|
|
|
|
|
arm_fir_instance_q31 S = {numTaps, pState, pCoeffs};
|
|
|
|
|
arm_fir_instance_q15 S = {numTaps, pState, pCoeffs};
|
|
|
|
|
arm_fir_instance_q7 S = {numTaps, pState, pCoeffs};
|
|
|
|
|
</pre>
|
|
|
|
|
where <code>numTaps</code> is the number of filter coefficients in the filter; <code>pState</code> is the address of the state buffer;
|
|
|
|
|
<code>pCoeffs</code> is the address of the coefficient buffer.
|
|
|
|
|
@par Initialization of Helium version
|
|
|
|
|
For Helium version the array of coefficients must be padded with zero to contain
|
|
|
|
|
a full number of lanes.
|
|
|
|
|
|
|
|
|
|
The array length L must be a multiple of x. L = x * a :
|
|
|
|
|
- x is 4 for f32
|
|
|
|
|
- x is 4 for q31
|
|
|
|
|
- x is 4 for f16 (so managed like the f32 version and not like the q15 one)
|
|
|
|
|
- x is 8 for q15
|
|
|
|
|
- x is 16 for q7
|
|
|
|
|
|
|
|
|
|
The additional coefficients
|
|
|
|
|
(x * a - numTaps) must be set to 0.
|
|
|
|
|
numTaps is still set to its right value in the init function. It means that
|
|
|
|
|
the implementation may require to read more coefficients due to the vectorization and
|
|
|
|
|
to avoid having to manage too many different cases in the code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@par Helium state buffer
|
|
|
|
|
The state buffer must contain some additional temporary data
|
|
|
|
|
used during the computation but which is not the state of the FIR.
|
|
|
|
|
The first A samples are temporary data.
|
|
|
|
|
The remaining samples are the state of the FIR filter.
|
|
|
|
|
@par
|
|
|
|
|
So the state buffer has size <code> numTaps + A + blockSize - 1 </code> :
|
|
|
|
|
- A is blockSize for f32
|
|
|
|
|
- A is 8*ceil(blockSize/8) for f16
|
|
|
|
|
- A is 8*ceil(blockSize/4) for q31
|
|
|
|
|
- A is 0 for other datatypes (q15 and q7)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@par Fixed-Point Behavior
|
|
|
|
|
Care must be taken when using the fixed-point versions of the FIR filter functions.
|
|
|
|
|
In particular, the overflow and saturation behavior of the accumulator used in each function must be considered.
|
|
|
|
|
Refer to the function specific documentation below for usage guidelines.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@addtogroup FIR
|
|
|
|
|
@{
|
|
|
|
|
|