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 */
119
arm_iir_lattice_f32(const arm_iir_lattice_instance_f32 * S,const float32_t * pSrc,float32_t * pDst,uint32_t blockSize)120 void arm_iir_lattice_f32(
121 const arm_iir_lattice_instance_f32 * S,
122 const float32_t * pSrc,
123 float32_t * pDst,
124 uint32_t blockSize)
125 {
126 float32_t *pState = S->pState; /* State pointer */
127 float32_t *pStateCur; /* State current pointer */
128 float32_t acc; /* Accumlator */
129 float32_t fnext1, fnext2, gcurr1, gnext; /* Temporary variables for lattice stages */
130 float32_t *px1, *px2, *pk, *pv; /* Temporary pointers for state and coef */
131 uint32_t numStages = S->numStages; /* Number of stages */
132 uint32_t blkCnt, tapCnt; /* Temporary variables for counts */
133
134 #if defined (ARM_MATH_LOOPUNROLL)
135 float32_t gcurr2; /* Temporary variables for lattice stages */
136 float32_t k1, k2;
137 float32_t v1, v2, v3, v4;
138 #endif
139
140 /* initialise loop count */
141 blkCnt = blockSize;
142
143 /* Sample processing */
144 while (blkCnt > 0U)
145 {
146 /* Read Sample from input buffer */
147 /* fN(n) = x(n) */
148 fnext2 = *pSrc++;
149
150 /* Initialize Ladder coeff pointer */
151 pv = &S->pvCoeffs[0];
152
153 /* Initialize Reflection coeff pointer */
154 pk = &S->pkCoeffs[0];
155
156 /* Initialize state read pointer */
157 px1 = pState;
158
159 /* Initialize state write pointer */
160 px2 = pState;
161
162 /* Set accumulator to zero */
163 acc = 0.0;
164
165 #if defined (ARM_MATH_LOOPUNROLL)
166
167 /* Loop unrolling: Compute 4 taps at a time. */
168 tapCnt = (numStages) >> 2U;
169
170 while (tapCnt > 0U)
171 {
172 /* Read gN-1(n-1) from state buffer */
173 gcurr1 = *px1;
174
175 /* read reflection coefficient kN */
176 k1 = *pk;
177
178 /* fN-1(n) = fN(n) - kN * gN-1(n-1) */
179 fnext1 = fnext2 - (k1 * gcurr1);
180
181 /* read ladder coefficient vN */
182 v1 = *pv;
183
184 /* read next reflection coefficient kN-1 */
185 k2 = *(pk + 1U);
186
187 /* Read gN-2(n-1) from state buffer */
188 gcurr2 = *(px1 + 1U);
189
190 /* read next ladder coefficient vN-1 */
191 v2 = *(pv + 1U);
192
193 /* fN-2(n) = fN-1(n) - kN-1 * gN-2(n-1) */
194 fnext2 = fnext1 - (k2 * gcurr2);
195
196 /* gN(n) = kN * fN-1(n) + gN-1(n-1) */
197 gnext = gcurr1 + (k1 * fnext1);
198
199 /* read reflection coefficient kN-2 */
200 k1 = *(pk + 2U);
201
202 /* write gN(n) into state for next sample processing */
203 *px2++ = gnext;
204
205 /* Read gN-3(n-1) from state buffer */
206 gcurr1 = *(px1 + 2U);
207
208 /* y(n) += gN(n) * vN */
209 acc += (gnext * v1);
210
211 /* fN-3(n) = fN-2(n) - kN-2 * gN-3(n-1) */
212 fnext1 = fnext2 - (k1 * gcurr1);
213
214 /* gN-1(n) = kN-1 * fN-2(n) + gN-2(n-1) */
215 gnext = gcurr2 + (k2 * fnext2);
216
217 /* Read gN-4(n-1) from state buffer */
218 gcurr2 = *(px1 + 3U);
219
220 /* y(n) += gN-1(n) * vN-1 */
221 acc += (gnext * v2);
222
223 /* read reflection coefficient kN-3 */
224 k2 = *(pk + 3U);
225
226 /* write gN-1(n) into state for next sample processing */
227 *px2++ = gnext;
228
229 /* fN-4(n) = fN-3(n) - kN-3 * gN-4(n-1) */
230 fnext2 = fnext1 - (k2 * gcurr2);
231
232 /* gN-2(n) = kN-2 * fN-3(n) + gN-3(n-1) */
233 gnext = gcurr1 + (k1 * fnext1);
234
235 /* read ladder coefficient vN-2 */
236 v3 = *(pv + 2U);
237
238 /* y(n) += gN-2(n) * vN-2 */
239 acc += (gnext * v3);
240
241 /* write gN-2(n) into state for next sample processing */
242 *px2++ = gnext;
243
244 /* update pointer */
245 pk += 4U;
246
247 /* gN-3(n) = kN-3 * fN-4(n) + gN-4(n-1) */
248 gnext = (fnext2 * k2) + gcurr2;
249
250 /* read next ladder coefficient vN-3 */
251 v4 = *(pv + 3U);
252
253 /* y(n) += gN-4(n) * vN-4 */
254 acc += (gnext * v4);
255
256 /* write gN-3(n) into state for next sample processing */
257 *px2++ = gnext;
258
259 /* update pointers */
260 px1 += 4U;
261 pv += 4U;
262
263 /* Decrement loop counter */
264 tapCnt--;
265 }
266
267 /* Loop unrolling: Compute remaining taps */
268 tapCnt = numStages % 0x4U;
269
270 #else
271
272 /* Initialize tapCnt with number of samples */
273 tapCnt = numStages;
274
275 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
276
277 while (tapCnt > 0U)
278 {
279 gcurr1 = *px1++;
280 /* Process sample for last taps */
281 fnext1 = fnext2 - ((*pk) * gcurr1);
282 gnext = (fnext1 * (*pk++)) + gcurr1;
283 /* Output samples for last taps */
284 acc += (gnext * (*pv++));
285 *px2++ = gnext;
286 fnext2 = fnext1;
287
288 /* Decrement loop counter */
289 tapCnt--;
290 }
291
292 /* y(n) += g0(n) * v0 */
293 acc += (fnext2 * (*pv));
294
295 *px2++ = fnext2;
296
297 /* write out into pDst */
298 *pDst++ = acc;
299
300 /* Advance the state pointer by 4 to process the next group of 4 samples */
301 pState = pState + 1U;
302
303 /* Decrement loop counter */
304 blkCnt--;
305 }
306
307 /* Processing is complete. Now copy last S->numStages samples to start of the buffer
308 for the preperation of next frame process */
309
310 /* Points to the start of the state buffer */
311 pStateCur = &S->pState[0];
312 pState = &S->pState[blockSize];
313
314 /* Copy data */
315 #if defined (ARM_MATH_LOOPUNROLL)
316
317 /* Loop unrolling: Compute 4 taps at a time. */
318 tapCnt = numStages >> 2U;
319
320 while (tapCnt > 0U)
321 {
322 *pStateCur++ = *pState++;
323 *pStateCur++ = *pState++;
324 *pStateCur++ = *pState++;
325 *pStateCur++ = *pState++;
326
327 /* Decrement loop counter */
328 tapCnt--;
329 }
330
331 /* Loop unrolling: Compute remaining taps */
332 tapCnt = numStages % 0x4U;
333
334 #else
335
336 /* Initialize blkCnt with number of samples */
337 tapCnt = numStages;
338
339 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
340
341 while (tapCnt > 0U)
342 {
343 *pStateCur++ = *pState++;
344
345 /* Decrement loop counter */
346 tapCnt--;
347 }
348
349 }
350
351 /**
352 @} end of IIR_Lattice group
353 */
354