GNU Radio 3.6.5 C++ API
|
00001 /* -*- c++ -*- */ 00002 /* 00003 * Copyright 2002,2012 Free Software Foundation, Inc. 00004 * 00005 * This file is part of GNU Radio 00006 * 00007 * GNU Radio is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 3, or (at your option) 00010 * any later version. 00011 * 00012 * GNU Radio is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with GNU Radio; see the file COPYING. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, 00020 * Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #ifndef INCLUDED_IIR_FILTER_H 00024 #define INCLUDED_IIR_FILTER_H 00025 00026 #include <filter/api.h> 00027 #include <vector> 00028 #include <stdexcept> 00029 00030 namespace gr { 00031 namespace filter { 00032 namespace kernel { 00033 00034 /*! 00035 * \brief base class template for Infinite Impulse Response filter (IIR) 00036 */ 00037 template<class i_type, class o_type, class tap_type> 00038 class iir_filter 00039 { 00040 public: 00041 /*! 00042 * \brief Construct an IIR with the given taps. 00043 * 00044 * This filter uses the Direct Form I implementation, where 00045 * \p fftaps contains the feed-forward taps, and \p fbtaps the feedback ones. 00046 * 00047 * \p fftaps and \p fbtaps must have equal numbers of taps 00048 * 00049 * The input and output satisfy a difference equation of the form 00050 00051 \f[ 00052 y[n] - \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k] 00053 \f] 00054 00055 * with the corresponding rational system function 00056 00057 \f[ 00058 H(z) = \frac{\sum_{k=0}^{N} b_k z^{-k}}{1 - \sum_{k=1}^{M} a_k z^{-k}} 00059 \f] 00060 00061 * Note that some texts define the system function with a + in 00062 * the denominator. If you're using that convention, you'll 00063 * need to negate the feedback taps. 00064 */ 00065 iir_filter(const std::vector<tap_type>& fftaps, 00066 const std::vector<tap_type>& fbtaps) throw (std::invalid_argument) 00067 { 00068 set_taps(fftaps, fbtaps); 00069 } 00070 00071 iir_filter() : d_latest_n(0),d_latest_m(0) { } 00072 00073 ~iir_filter() {} 00074 00075 /*! 00076 * \brief compute a single output value. 00077 * \returns the filtered input value. 00078 */ 00079 o_type filter(const i_type input); 00080 00081 /*! 00082 * \brief compute an array of N output values. 00083 * \p input must have N valid entries. 00084 */ 00085 void filter_n(o_type output[], const i_type input[], long n); 00086 00087 /*! 00088 * \return number of taps in filter. 00089 */ 00090 unsigned ntaps_ff() const { return d_fftaps.size(); } 00091 unsigned ntaps_fb() const { return d_fbtaps.size(); } 00092 00093 /*! 00094 * \brief install new taps. 00095 */ 00096 void set_taps(const std::vector<tap_type> &fftaps, 00097 const std::vector<tap_type> &fbtaps) throw (std::invalid_argument) 00098 { 00099 d_latest_n = 0; 00100 d_latest_m = 0; 00101 d_fftaps = fftaps; 00102 d_fbtaps = fbtaps; 00103 00104 int n = fftaps.size(); 00105 int m = fbtaps.size(); 00106 d_prev_input.resize(2 * n); 00107 d_prev_output.resize(2 * m); 00108 00109 for(int i = 0; i < 2 * n; i++) { 00110 d_prev_input[i] = 0; 00111 } 00112 for(int i = 0; i < 2 * m; i++) { 00113 d_prev_output[i] = 0; 00114 } 00115 } 00116 00117 protected: 00118 std::vector<tap_type> d_fftaps; 00119 std::vector<tap_type> d_fbtaps; 00120 int d_latest_n; 00121 int d_latest_m; 00122 std::vector<tap_type> d_prev_output; 00123 std::vector<i_type> d_prev_input; 00124 }; 00125 00126 // 00127 // general case. We may want to specialize this 00128 // 00129 template<class i_type, class o_type, class tap_type> 00130 o_type 00131 iir_filter<i_type, o_type, tap_type>::filter(const i_type input) 00132 { 00133 tap_type acc; 00134 unsigned i = 0; 00135 unsigned n = ntaps_ff(); 00136 unsigned m = ntaps_fb(); 00137 00138 if(n == 0) 00139 return (o_type)0; 00140 00141 int latest_n = d_latest_n; 00142 int latest_m = d_latest_m; 00143 00144 acc = d_fftaps[0] * input; 00145 for(i = 1; i < n; i ++) 00146 acc += (d_fftaps[i] * d_prev_input[latest_n + i]); 00147 for(i = 1; i < m; i ++) 00148 acc += (d_fbtaps[i] * d_prev_output[latest_m + i]); 00149 00150 // store the values twice to avoid having to handle wrap-around in the loop 00151 d_prev_output[latest_m] = acc; 00152 d_prev_output[latest_m+m] = acc; 00153 d_prev_input[latest_n] = input; 00154 d_prev_input[latest_n+n] = input; 00155 00156 latest_n--; 00157 latest_m--; 00158 if(latest_n < 0) 00159 latest_n += n; 00160 if(latest_m < 0) 00161 latest_m += m; 00162 00163 d_latest_m = latest_m; 00164 d_latest_n = latest_n; 00165 return (o_type)acc; 00166 } 00167 00168 template<class i_type, class o_type, class tap_type> 00169 void 00170 iir_filter<i_type, o_type, tap_type>::filter_n(o_type output[], 00171 const i_type input[], 00172 long n) 00173 { 00174 for(int i = 0; i < n; i++) 00175 output[i] = filter(input[i]); 00176 } 00177 00178 } /* namespace kernel */ 00179 } /* namespace filter */ 00180 } /* namespace gr */ 00181 00182 #endif /* INCLUDED_IIR_FILTER_H */ 00183