1 /* ----------------------------------------------------------------------
2 * Project: CMSIS DSP Library
3 * Title: arm_iir_lattice_f32.c
4 * Description: Floating-point IIR Lattice filter processing function
5 *
6 * $Date: 23 April 2021
7 * $Revision: V1.9.0
8 *
9 * Target Processor: Cortex-M and Cortex-A cores
10 * -------------------------------------------------------------------- */
11 /*
12 * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13 *
14 * SPDX-License-Identifier: Apache-2.0
15 *
16 * Licensed under the Apache License, Version 2.0 (the License); you may
17 * not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19 *
20 * www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28
29 #include "dsp/filtering_functions.h"
30
31 /**
32 @ingroup groupFilters
33 */
34
35 /**
36 @defgroup IIR_Lattice Infinite Impulse Response (IIR) Lattice Filters
37
38 This set of functions implements lattice filters
39 for Q15, Q31 and floating-point data types. Lattice filters are used in a
40 variety of adaptive filter applications. The filter structure has feedforward and
41 feedback components and the net impulse response is infinite length.
42 The functions operate on blocks
43 of input and output data and each call to the function processes
44 <code>blockSize</code> samples through the filter. <code>pSrc</code> and
45 <code>pDst</code> point to input and output arrays containing <code>blockSize</code> values.
46
47 @par Algorithm
48 \image html IIRLattice.gif "Infinite Impulse Response Lattice filter"
49 @par
50 <pre>
51 fN(n) = x(n)
52 fm-1(n) = fm(n) - km * gm-1(n-1) for m = N, N-1, ..., 1
53 gm(n) = km * fm-1(n) + gm-1(n-1) for m = N, N-1, ..., 1
54 y(n) = vN * gN(n) + vN-1 * gN-1(n) + ...+ v0 * g0(n)
55 </pre>
56 @par
57 <code>pkCoeffs</code> points to array of reflection coefficients of size <code>numStages</code>.
58 Reflection Coefficients are stored in time-reversed order.
59 @par
60 <pre>
61 {kN, kN-1, ..., k1}
62 </pre>
63 @par
64 <code>pvCoeffs</code> points to the array of ladder coefficients of size <code>(numStages+1)</code>.
65 Ladder coefficients are stored in time-reversed order.
66 <pre>
67 {vN, vN-1, ..., v0}
68 </pre>
69 @par
70 <code>pState</code> points to a state array of size <code>numStages + blockSize</code>.
71 The state variables shown in the figure above (the g values) are stored in the <code>pState</code> array.
72 The state variables are updated after each block of data is processed; the coefficients are untouched.
73
74 @par Instance Structure
75 The coefficients and state variables for a filter are stored together in an instance data structure.
76 A separate instance structure must be defined for each filter.
77 Coefficient arrays may be shared among several instances while state variable arrays cannot be shared.
78 There are separate instance structure declarations for each of the 3 supported data types.
79
80 @par Initialization Functions
81 There is also an associated initialization function for each data type.
82 The initialization function performs the following operations:
83 - Sets the values of the internal structure fields.
84 - Zeros out the values in the state buffer.
85 To do this manually without calling the init function, assign the follow subfields of the instance structure:
86 numStages, pkCoeffs, pvCoeffs, pState. Also set all of the values in pState to zero.
87 @par
88 Use of the initialization function is optional.
89 However, if the initialization function is used, then the instance structure cannot be placed into a const data section.
90 To place an instance structure into a const data section, the instance structure must be manually initialized.
91 Set the values in the state buffer to zeros and then manually initialize the instance structure as follows:
92 <pre>
93 arm_iir_lattice_instance_f32 S = {numStages, pState, pkCoeffs, pvCoeffs};
94 arm_iir_lattice_instance_q31 S = {numStages, pState, pkCoeffs, pvCoeffs};
95 arm_iir_lattice_instance_q15 S = {numStages, pState, pkCoeffs, pvCoeffs};
96 </pre>
97 @par
98 where <code>numStages</code> is the number of stages in the filter; <code>pState</code> points to the state buffer array;
99 <code>pkCoeffs</code> points to array of the reflection coefficients; <code>pvCoeffs</code> points to the array of ladder coefficients.
100
101 @par Fixed-Point Behavior
102 Care must be taken when using the fixed-point versions of the IIR lattice filter functions.
103 In particular, the overflow and saturation behavior of the accumulator used in each function must be considered.
104 Refer to the function specific documentation below for usage guidelines.
105 */
106
107 /**
108 @addtogroup IIR_Lattice
109 @{
110 */
111
112 /**
113 @brief Processing function for the floating-point IIR lattice filter.
114 @param[in] S points to an instance of the floating-point IIR lattice structure
115 @param[in] pSrc points to the block of input data
116 @param[out] pDst points to the block of output data
117 @param[in] blockSize number of samples to process
118 @return none
119 */
120
arm_iir_lattice_f32(const arm_iir_lattice_instance_f32 * S,const float32_t * pSrc,float32_t * pDst,uint32_t blockSize)121 void arm_iir_lattice_f32(
122 const arm_iir_lattice_instance_f32 * S,
123 const float32_t * pSrc,
124 float32_t * pDst,
125 uint32_t blockSize)
126 {
127 float32_t *pState = S->pState; /* State pointer */
128 float32_t *pStateCur; /* State current pointer */
129 float32_t acc; /* Accumlator */
130 float32_t fnext1, fnext2, gcurr1, gnext; /* Temporary variables for lattice stages */
131 float32_t *px1, *px2, *pk, *pv; /* Temporary pointers for state and coef */
132 uint32_t numStages = S->numStages; /* Number of stages */
133 uint32_t blkCnt, tapCnt; /* Temporary variables for counts */
134
135 #if defined (ARM_MATH_LOOPUNROLL)
136 float32_t gcurr2; /* Temporary variables for lattice stages */
137 float32_t k1, k2;
138 float32_t v1, v2, v3, v4;
139 #endif
140
141 /* initialise loop count */
142 blkCnt = blockSize;
143
144 /* Sample processing */
145 while (blkCnt > 0U)
146 {
147 /* Read Sample from input buffer */
148 /* fN(n) = x(n) */
149 fnext2 = *pSrc++;
150
151 /* Initialize Ladder coeff pointer */
152 pv = &S->pvCoeffs[0];
153
154 /* Initialize Reflection coeff pointer */
155 pk = &S->pkCoeffs[0];
156
157 /* Initialize state read pointer */
158 px1 = pState;
159
160 /* Initialize state write pointer */
161 px2 = pState;
162
163 /* Set accumulator to zero */
164 acc = 0.0;
165
166 #if defined (ARM_MATH_LOOPUNROLL)
167
168 /* Loop unrolling: Compute 4 taps at a time. */
169 tapCnt = (numStages) >> 2U;
170
171 while (tapCnt > 0U)
172 {
173 /* Read gN-1(n-1) from state buffer */
174 gcurr1 = *px1;
175
176 /* read reflection coefficient kN */
177 k1 = *pk;
178
179 /* fN-1(n) = fN(n) - kN * gN-1(n-1) */
180 fnext1 = fnext2 - (k1 * gcurr1);
181
182 /* read ladder coefficient vN */
183 v1 = *pv;
184
185 /* read next reflection coefficient kN-1 */
186 k2 = *(pk + 1U);
187
188 /* Read gN-2(n-1) from state buffer */
189 gcurr2 = *(px1 + 1U);
190
191 /* read next ladder coefficient vN-1 */
192 v2 = *(pv + 1U);
193
194 /* fN-2(n) = fN-1(n) - kN-1 * gN-2(n-1) */
195 fnext2 = fnext1 - (k2 * gcurr2);
196
197 /* gN(n) = kN * fN-1(n) + gN-1(n-1) */
198 gnext = gcurr1 + (k1 * fnext1);
199
200 /* read reflection coefficient kN-2 */
201 k1 = *(pk + 2U);
202
203 /* write gN(n) into state for next sample processing */
204 *px2++ = gnext;
205
206 /* Read gN-3(n-1) from state buffer */
207 gcurr1 = *(px1 + 2U);
208
209 /* y(n) += gN(n) * vN */
210 acc += (gnext * v1);
211
212 /* fN-3(n) = fN-2(n) - kN-2 * gN-3(n-1) */
213 fnext1 = fnext2 - (k1 * gcurr1);
214
215 /* gN-1(n) = kN-1 * fN-2(n) + gN-2(n-1) */
216 gnext = gcurr2 + (k2 * fnext2);
217
218 /* Read gN-4(n-1) from state buffer */
219 gcurr2 = *(px1 + 3U);
220
221 /* y(n) += gN-1(n) * vN-1 */
222 acc += (gnext * v2);
223
224 /* read reflection coefficient kN-3 */
225 k2 = *(pk + 3U);
226
227 /* write gN-1(n) into state for next sample processing */
228 *px2++ = gnext;
229
230 /* fN-4(n) = fN-3(n) - kN-3 * gN-4(n-1) */
231 fnext2 = fnext1 - (k2 * gcurr2);
232
233 /* gN-2(n) = kN-2 * fN-3(n) + gN-3(n-1) */
234 gnext = gcurr1 + (k1 * fnext1);
235
236 /* read ladder coefficient vN-2 */
237 v3 = *(pv + 2U);
238
239 /* y(n) += gN-2(n) * vN-2 */
240 acc += (gnext * v3);
241
242 /* write gN-2(n) into state for next sample processing */
243 *px2++ = gnext;
244
245 /* update pointer */
246 pk += 4U;
247
248 /* gN-3(n) = kN-3 * fN-4(n) + gN-4(n-1) */
249 gnext = (fnext2 * k2) + gcurr2;
250
251 /* read next ladder coefficient vN-3 */
252 v4 = *(pv + 3U);
253
254 /* y(n) += gN-4(n) * vN-4 */
255 acc += (gnext * v4);
256
257 /* write gN-3(n) into state for next sample processing */
258 *px2++ = gnext;
259
260 /* update pointers */
261 px1 += 4U;
262 pv += 4U;
263
264 /* Decrement loop counter */
265 tapCnt--;
266 }
267
268 /* Loop unrolling: Compute remaining taps */
269 tapCnt = numStages % 0x4U;
270
271 #else
272
273 /* Initialize tapCnt with number of samples */
274 tapCnt = numStages;
275
276 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
277
278 while (tapCnt > 0U)
279 {
280 gcurr1 = *px1++;
281 /* Process sample for last taps */
282 fnext1 = fnext2 - ((*pk) * gcurr1);
283 gnext = (fnext1 * (*pk++)) + gcurr1;
284 /* Output samples for last taps */
285 acc += (gnext * (*pv++));
286 *px2++ = gnext;
287 fnext2 = fnext1;
288
289 /* Decrement loop counter */
290 tapCnt--;
291 }
292
293 /* y(n) += g0(n) * v0 */
294 acc += (fnext2 * (*pv));
295
296 *px2++ = fnext2;
297
298 /* write out into pDst */
299 *pDst++ = acc;
300
301 /* Advance the state pointer by 4 to process the next group of 4 samples */
302 pState = pState + 1U;
303
304 /* Decrement loop counter */
305 blkCnt--;
306 }
307
308 /* Processing is complete. Now copy last S->numStages samples to start of the buffer
309 for the preperation of next frame process */
310
311 /* Points to the start of the state buffer */
312 pStateCur = &S->pState[0];
313 pState = &S->pState[blockSize];
314
315 /* Copy data */
316 #if defined (ARM_MATH_LOOPUNROLL)
317
318 /* Loop unrolling: Compute 4 taps at a time. */
319 tapCnt = numStages >> 2U;
320
321 while (tapCnt > 0U)
322 {
323 *pStateCur++ = *pState++;
324 *pStateCur++ = *pState++;
325 *pStateCur++ = *pState++;
326 *pStateCur++ = *pState++;
327
328 /* Decrement loop counter */
329 tapCnt--;
330 }
331
332 /* Loop unrolling: Compute remaining taps */
333 tapCnt = numStages % 0x4U;
334
335 #else
336
337 /* Initialize blkCnt with number of samples */
338 tapCnt = numStages;
339
340 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
341
342 while (tapCnt > 0U)
343 {
344 *pStateCur++ = *pState++;
345
346 /* Decrement loop counter */
347 tapCnt--;
348 }
349
350 }
351
352 /**
353 @} end of IIR_Lattice group
354 */
355