GNU Radio 3.4.2 C++ API
|
00001 /* -*- c++ -*- */ 00002 /* 00003 * Copyright 2002 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_GRI_IIR_H 00024 #define INCLUDED_GRI_IIR_H 00025 00026 #include <vector> 00027 #include <stdexcept> 00028 00029 /*! 00030 * \brief base class template for Infinite Impulse Response filter (IIR) 00031 */ 00032 template<class i_type, class o_type, class tap_type> 00033 class gri_iir { 00034 public: 00035 /*! 00036 * \brief Construct an IIR with the given taps. 00037 * 00038 * This filter uses the Direct Form I implementation, where 00039 * \p fftaps contains the feed-forward taps, and \p fbtaps the feedback ones. 00040 * 00041 * \p fftaps and \p fbtaps must have equal numbers of taps 00042 * 00043 * The input and output satisfy a difference equation of the form 00044 00045 \f[ 00046 y[n] - \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k] 00047 \f] 00048 00049 * with the corresponding rational system function 00050 00051 \f[ 00052 H(z) = \frac{\sum_{k=0}^{N} b_k z^{-k}}{1 - \sum_{k=1}^{M} a_k z^{-k}} 00053 \f] 00054 00055 * Note that some texts define the system function with a + in the denominator. 00056 * If you're using that convention, you'll need to negate the feedback taps. 00057 */ 00058 gri_iir (const std::vector<tap_type>& fftaps, 00059 const std::vector<tap_type>& fbtaps) throw (std::invalid_argument) 00060 { 00061 set_taps (fftaps, fbtaps); 00062 } 00063 00064 gri_iir () : d_latest_n(0),d_latest_m(0) { } 00065 00066 ~gri_iir () {} 00067 00068 /*! 00069 * \brief compute a single output value. 00070 * \returns the filtered input value. 00071 */ 00072 o_type filter (const i_type input); 00073 00074 /*! 00075 * \brief compute an array of N output values. 00076 * \p input must have N valid entries. 00077 */ 00078 void filter_n (o_type output[], const i_type input[], long n); 00079 00080 /*! 00081 * \return number of taps in filter. 00082 */ 00083 unsigned ntaps_ff () const { return d_fftaps.size (); } 00084 unsigned ntaps_fb () const { return d_fbtaps.size (); } 00085 00086 /*! 00087 * \brief install new taps. 00088 */ 00089 void set_taps (const std::vector<tap_type> &fftaps, 00090 const std::vector<tap_type> &fbtaps) throw (std::invalid_argument) 00091 { 00092 00093 00094 d_latest_n = 0; 00095 d_latest_m = 0; 00096 d_fftaps = fftaps; 00097 d_fbtaps = fbtaps; 00098 00099 int n = fftaps.size (); 00100 int m = fbtaps.size (); 00101 d_prev_input.resize (2 * n); 00102 d_prev_output.resize (2 * m); 00103 00104 for (int i = 0; i < 2 * n; i++){ 00105 d_prev_input[i] = 0; 00106 } 00107 for (int i = 0; i < 2 * m; i++){ 00108 d_prev_output[i] = 0; 00109 } 00110 } 00111 00112 protected: 00113 std::vector<tap_type> d_fftaps; 00114 std::vector<tap_type> d_fbtaps; 00115 int d_latest_n; 00116 int d_latest_m; 00117 std::vector<tap_type> d_prev_output; 00118 std::vector<i_type> d_prev_input; 00119 }; 00120 00121 00122 // 00123 // general case. We may want to specialize this 00124 // 00125 template<class i_type, class o_type, class tap_type> 00126 o_type 00127 gri_iir<i_type, o_type, tap_type>::filter (const i_type input) 00128 { 00129 tap_type acc; 00130 unsigned i = 0; 00131 unsigned n = ntaps_ff (); 00132 unsigned m = ntaps_fb (); 00133 00134 if (n == 0) 00135 return (o_type) 0; 00136 00137 int latest_n = d_latest_n; 00138 int latest_m = d_latest_m; 00139 00140 acc = d_fftaps[0] * input; 00141 for (i = 1; i < n; i ++) 00142 acc += (d_fftaps[i] * d_prev_input[latest_n + i]); 00143 for (i = 1; i < m; i ++) 00144 acc += (d_fbtaps[i] * d_prev_output[latest_m + i]); 00145 00146 // store the values twice to avoid having to handle wrap-around in the loop 00147 d_prev_output[latest_m] = acc; 00148 d_prev_output[latest_m+m] = acc; 00149 d_prev_input[latest_n] = input; 00150 d_prev_input[latest_n+n] = input; 00151 00152 latest_n--; 00153 latest_m--; 00154 if (latest_n < 0) 00155 latest_n += n; 00156 if (latest_m < 0) 00157 latest_m += m; 00158 00159 d_latest_m = latest_m; 00160 d_latest_n = latest_n; 00161 return (o_type) acc; 00162 } 00163 00164 00165 template<class i_type, class o_type, class tap_type> 00166 void 00167 gri_iir<i_type, o_type, tap_type>::filter_n (o_type output[], 00168 const i_type input[], 00169 long n) 00170 { 00171 for (int i = 0; i < n; i++) 00172 output[i] = filter (input[i]); 00173 } 00174 00175 #endif /* INCLUDED_GRI_IIR_H */ 00176