h(i,0)*z^2 + h(i,1)*z + h(i,2) H(i,z) = ------------------------------ . z^2 + h(i,3)*z + h(i,4)
Each filter section needs an input sample, two past input samples and two past output samples to calculate each output sample. In the cascade connection, the output of one section is the input to next section. This means that past output samples for one section are also the past input samples for the next section. For Nsec sections, the total filter "memory" required is mem=2*(Nsec+1) values. In this routine, the input array has 2 extra elements at the beginning to store the two past inputs. The output array must be primed with 2 past outputs for each of the Nsec sections.
On input, the first two elements of the input array (x[0] and x[1]) are the two previous inputs to the filter; the next Nout elements are new input values. The first 2*Nsec elements of the output array y[] prime the calculation. Elements y[0] and y[1] are the previous outputs of the filter. The next two elements are the outputs of the previous to last filter section, and so on up to y[2*Nsec-2] and y[2*Nsec-1] which are previous outputs of the first section.
The filter is processed one section at a time. For the first section, the input array is the input. For the second section, the output from the first section is the input and so on. The output of these sections overlay each other. The computation is arranged such that the overall output of the filter appears as Nout samples starting with y[2]. On return, the last 2*Nsec elements of this array are suitable for priming the array for the next invocation. This priming can be accomplished by moving the top 2*Nsec elements of the output array to the bottom of the array. The input array can be handled similarly; the top two elements of x[] serve as the needed memory values for the next invocation of this routine.
The input and output arrays can also be shared. As output values are computed, they can overlay the input values that are no longer needed. Consider an array A[] with mem+Nout elements, where mem=2*(Nsec+1). The first 2 elements are previous outputs of the overall filter, the next two elements are previous outputs of the penultimate section, and so on up to elements A[mem-2] and A[mem-1] which are previous inputs. The remaining Nout values are new input values. Invoke this routine as
FIfiltIIR (&A[mem-2], A, Nout, h, Nsec)On return, the Nout new output values start at A[2]. The top mem elements of A[] are suitable for priming the array for the next invocation. These mem elements should be moved to the bottom of array A[].
A[0] A[1] ... A[mem-1] A[mem] A[mem+1] ... A[N+mem-1] |<-- filter memory -->| |<--- N input values --->|
A[0] A[1] A[2] A[3] ... A[N] A[N+1] A[N+2] ... A[N+mem-1] |<-- N output values -->| |<--- filter memory --->|