GNU Radio 3.6.4 C++ API
gri_iir.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifndef INCLUDED_GRI_IIR_H
24 #define INCLUDED_GRI_IIR_H
25 
26 #include <gr_core_api.h>
27 #include <vector>
28 #include <stdexcept>
29 
30 /*!
31  * \brief base class template for Infinite Impulse Response filter (IIR)
32  */
33 template<class i_type, class o_type, class tap_type>
34 class gri_iir {
35 public:
36  /*!
37  * \brief Construct an IIR with the given taps.
38  *
39  * This filter uses the Direct Form I implementation, where
40  * \p fftaps contains the feed-forward taps, and \p fbtaps the feedback ones.
41  *
42  * \p fftaps and \p fbtaps must have equal numbers of taps
43  *
44  * The input and output satisfy a difference equation of the form
45 
46  \f[
47  y[n] - \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k]
48  \f]
49 
50  * with the corresponding rational system function
51 
52  \f[
53  H(z) = \frac{\sum_{k=0}^{N} b_k z^{-k}}{1 - \sum_{k=1}^{M} a_k z^{-k}}
54  \f]
55 
56  * Note that some texts define the system function with a + in the denominator.
57  * If you're using that convention, you'll need to negate the feedback taps.
58  */
59  gri_iir (const std::vector<tap_type>& fftaps,
60  const std::vector<tap_type>& fbtaps) throw (std::invalid_argument)
61  {
62  set_taps (fftaps, fbtaps);
63  }
64 
65  gri_iir () : d_latest_n(0),d_latest_m(0) { }
66 
67  ~gri_iir () {}
68 
69  /*!
70  * \brief compute a single output value.
71  * \returns the filtered input value.
72  */
73  o_type filter (const i_type input);
74 
75  /*!
76  * \brief compute an array of N output values.
77  * \p input must have N valid entries.
78  */
79  void filter_n (o_type output[], const i_type input[], long n);
80 
81  /*!
82  * \return number of taps in filter.
83  */
84  unsigned ntaps_ff () const { return d_fftaps.size (); }
85  unsigned ntaps_fb () const { return d_fbtaps.size (); }
86 
87  /*!
88  * \brief install new taps.
89  */
90  void set_taps (const std::vector<tap_type> &fftaps,
91  const std::vector<tap_type> &fbtaps) throw (std::invalid_argument)
92  {
93 
94 
95  d_latest_n = 0;
96  d_latest_m = 0;
97  d_fftaps = fftaps;
98  d_fbtaps = fbtaps;
99 
100  int n = fftaps.size ();
101  int m = fbtaps.size ();
102  d_prev_input.resize (2 * n);
103  d_prev_output.resize (2 * m);
104 
105  for (int i = 0; i < 2 * n; i++){
106  d_prev_input[i] = 0;
107  }
108  for (int i = 0; i < 2 * m; i++){
109  d_prev_output[i] = 0;
110  }
111  }
112 
113 protected:
114  std::vector<tap_type> d_fftaps;
115  std::vector<tap_type> d_fbtaps;
118  std::vector<tap_type> d_prev_output;
119  std::vector<i_type> d_prev_input;
120 };
121 
122 
123 //
124 // general case. We may want to specialize this
125 //
126 template<class i_type, class o_type, class tap_type>
127 o_type
129 {
130  tap_type acc;
131  unsigned i = 0;
132  unsigned n = ntaps_ff ();
133  unsigned m = ntaps_fb ();
134 
135  if (n == 0)
136  return (o_type) 0;
137 
138  int latest_n = d_latest_n;
139  int latest_m = d_latest_m;
140 
141  acc = d_fftaps[0] * input;
142  for (i = 1; i < n; i ++)
143  acc += (d_fftaps[i] * d_prev_input[latest_n + i]);
144  for (i = 1; i < m; i ++)
145  acc += (d_fbtaps[i] * d_prev_output[latest_m + i]);
146 
147  // store the values twice to avoid having to handle wrap-around in the loop
148  d_prev_output[latest_m] = acc;
149  d_prev_output[latest_m+m] = acc;
150  d_prev_input[latest_n] = input;
151  d_prev_input[latest_n+n] = input;
152 
153  latest_n--;
154  latest_m--;
155  if (latest_n < 0)
156  latest_n += n;
157  if (latest_m < 0)
158  latest_m += m;
159 
160  d_latest_m = latest_m;
161  d_latest_n = latest_n;
162  return (o_type) acc;
163 }
164 
165 
166 template<class i_type, class o_type, class tap_type>
167 void
169  const i_type input[],
170  long n)
171 {
172  for (int i = 0; i < n; i++)
173  output[i] = filter (input[i]);
174 }
175 
176 #endif /* INCLUDED_GRI_IIR_H */
177