GNU Radio 3.7.2 C++ API
iir_filter.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002,2012 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_IIR_FILTER_H
24 #define INCLUDED_IIR_FILTER_H
25 
26 #include <gnuradio/filter/api.h>
27 #include <vector>
28 #include <stdexcept>
29 
30 namespace gr {
31  namespace filter {
32  namespace kernel {
33 
34  /*!
35  * \brief base class template for Infinite Impulse Response filter (IIR)
36  */
37  template<class i_type, class o_type, class tap_type>
38  class iir_filter
39  {
40  public:
41  /*!
42  * \brief Construct an IIR with the given taps.
43  *
44  * This filter uses the Direct Form I implementation, where
45  * \p fftaps contains the feed-forward taps, and \p fbtaps the feedback ones.
46  *
47  * \p fftaps and \p fbtaps must have equal numbers of taps
48  *
49  * \p oldstyle: The old style of the IIR filter uses feedback
50  * taps that are negative of what most definitions use (scipy
51  * and Matlab among them). This parameter keeps using the old
52  * GNU Radio style and is set to TRUE by default. When taps
53  * generated from scipy, Matlab, or gr_filter_design, use the
54  * new style by setting this to FALSE.
55  *
56  * The input and output satisfy a difference equation of the form
57 
58  \f[
59  y[n] \pm \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k]
60  \f]
61 
62  * with the corresponding rational system function
63 
64  \f[
65  H(z) = \frac{\sum_{k=0}^{N} b_k z^{-k}}{1 \pm \sum_{k=1}^{M} a_k z^{-k}}
66  \f]
67  */
68  iir_filter(const std::vector<tap_type>& fftaps,
69  const std::vector<tap_type>& fbtaps,
70  bool oldstyle=true)
71  throw (std::invalid_argument)
72  {
73  d_oldstyle = oldstyle;
74  set_taps(fftaps, fbtaps);
75  }
76 
78 
80 
81  /*!
82  * \brief compute a single output value.
83  * \returns the filtered input value.
84  */
85  o_type filter(const i_type input);
86 
87  /*!
88  * \brief compute an array of N output values.
89  * \p input must have N valid entries.
90  */
91  void filter_n(o_type output[], const i_type input[], long n);
92 
93  /*!
94  * \return number of taps in filter.
95  */
96  unsigned ntaps_ff() const { return d_fftaps.size(); }
97  unsigned ntaps_fb() const { return d_fbtaps.size(); }
98 
99  /*!
100  * \brief install new taps.
101  */
102  void set_taps(const std::vector<tap_type> &fftaps,
103  const std::vector<tap_type> &fbtaps)
104  throw (std::invalid_argument)
105  {
106  d_latest_n = 0;
107  d_latest_m = 0;
108  d_fftaps = fftaps;
109 
110  if(d_oldstyle) {
111  d_fbtaps = fbtaps;
112  }
113  else {
114  // New style negates taps a[1:N-1] to fit with most IIR
115  // tap generating programs.
116  d_fbtaps.resize(fbtaps.size());
117  d_fbtaps[0] = fbtaps[0];
118  for(size_t i = 1; i < fbtaps.size(); i++) {
119  d_fbtaps[i] = -fbtaps[i];
120  }
121  }
122 
123  int n = fftaps.size();
124  int m = fbtaps.size();
125  d_prev_input.clear();
126  d_prev_output.clear();
127  d_prev_input.resize(2 * n, 0);
128  d_prev_output.resize(2 * m, 0);
129  }
130 
131  protected:
133  std::vector<tap_type> d_fftaps;
134  std::vector<tap_type> d_fbtaps;
137  std::vector<tap_type> d_prev_output;
138  std::vector<i_type> d_prev_input;
139  };
140 
141  //
142  // general case. We may want to specialize this
143  //
144  template<class i_type, class o_type, class tap_type>
145  o_type
147  {
148  tap_type acc;
149  unsigned i = 0;
150  unsigned n = ntaps_ff();
151  unsigned m = ntaps_fb();
152 
153  if(n == 0)
154  return (o_type)0;
155 
156  int latest_n = d_latest_n;
157  int latest_m = d_latest_m;
158 
159  acc = d_fftaps[0] * input;
160  for(i = 1; i < n; i ++)
161  acc += (d_fftaps[i] * d_prev_input[latest_n + i]);
162  for(i = 1; i < m; i ++)
163  acc += (d_fbtaps[i] * d_prev_output[latest_m + i]);
164 
165  // store the values twice to avoid having to handle wrap-around in the loop
166  d_prev_output[latest_m] = acc;
167  d_prev_output[latest_m+m] = acc;
168  d_prev_input[latest_n] = input;
169  d_prev_input[latest_n+n] = input;
170 
171  latest_n--;
172  latest_m--;
173  if(latest_n < 0)
174  latest_n += n;
175  if(latest_m < 0)
176  latest_m += m;
177 
178  d_latest_m = latest_m;
179  d_latest_n = latest_n;
180  return (o_type)acc;
181  }
182 
183  template<class i_type, class o_type, class tap_type>
184  void
186  const i_type input[],
187  long n)
188  {
189  for(int i = 0; i < n; i++)
190  output[i] = filter(input[i]);
191  }
192 
193  } /* namespace kernel */
194  } /* namespace filter */
195 } /* namespace gr */
196 
197 #endif /* INCLUDED_IIR_FILTER_H */
198 
int d_latest_m
Definition: iir_filter.h:136
o_type filter(const i_type input)
compute a single output value.
Definition: iir_filter.h:146
std::vector< i_type > d_prev_input
Definition: iir_filter.h:138
bool d_oldstyle
Definition: iir_filter.h:132
base class template for Infinite Impulse Response filter (IIR)
Definition: iir_filter.h:38
iir_filter(const std::vector< tap_type > &fftaps, const std::vector< tap_type > &fbtaps, bool oldstyle=true)
Construct an IIR with the given taps.
Definition: iir_filter.h:68
std::vector< tap_type > d_fftaps
Definition: iir_filter.h:133
void set_taps(const std::vector< tap_type > &fftaps, const std::vector< tap_type > &fbtaps)
install new taps.
Definition: iir_filter.h:102
~iir_filter()
Definition: iir_filter.h:79
void filter_n(o_type output[], const i_type input[], long n)
compute an array of N output values. input must have N valid entries.
Definition: iir_filter.h:185
std::vector< tap_type > d_fbtaps
Definition: iir_filter.h:134
unsigned ntaps_ff() const
Definition: iir_filter.h:96
int d_latest_n
Definition: iir_filter.h:135
unsigned ntaps_fb() const
Definition: iir_filter.h:97
iir_filter()
Definition: iir_filter.h:77
std::vector< tap_type > d_prev_output
Definition: iir_filter.h:137