GNU Radio 3.4.2 C++ API
gr_single_pole_iir.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2002,2006 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 #ifndef _GR_SINGLE_POLE_IIR_H_
00023 #define _GR_SINGLE_POLE_IIR_H_
00024 
00025 #include <stdexcept>
00026 #include <gr_complex.h>
00027 /*!
00028  * \brief class template for single pole IIR filter
00029  */
00030 template<class o_type, class i_type, class tap_type> 
00031 class gr_single_pole_iir {
00032 public:
00033   /*!
00034    * \brief construct new single pole IIR with given alpha
00035    *
00036    * computes y(i) = (1-alpha) * y(i-1) + alpha * x(i)
00037    */
00038   gr_single_pole_iir (tap_type alpha = 1.0)
00039   {
00040     d_prev_output = 0;
00041     set_taps (alpha);
00042   }
00043 
00044   /*!
00045    * \brief compute a single output value.
00046    * \returns the filtered input value.
00047    */
00048   o_type filter (const i_type input);
00049 
00050   /*!
00051    * \brief compute an array of N output values.
00052    * \p input must have n valid entries.
00053    */
00054   void filterN (o_type output[], const i_type input[], unsigned long n);
00055 
00056   /*!
00057    * \brief install \p alpha as the current taps.
00058    */
00059   void set_taps (tap_type alpha)
00060   { 
00061     if (alpha < 0 || alpha > 1)
00062       throw std::out_of_range ("Alpha must be in [0, 1]\n");
00063 
00064     d_alpha = alpha;
00065     d_one_minus_alpha = 1.0 - alpha;
00066   }
00067 
00068   //! reset state to zero
00069   void reset ()
00070   {
00071     d_prev_output = 0;
00072   }
00073 
00074   o_type prev_output () const { return d_prev_output; }
00075     
00076 protected:
00077   tap_type      d_alpha;
00078   tap_type      d_one_minus_alpha;
00079   o_type        d_prev_output;
00080 };
00081 
00082 
00083 //
00084 // general case.  We may want to specialize this
00085 //
00086 template<class o_type, class i_type, class tap_type> 
00087 o_type
00088 gr_single_pole_iir<o_type, i_type, tap_type>::filter (const i_type input)
00089 {
00090   o_type        output;
00091 
00092   output = d_alpha * input + d_one_minus_alpha * d_prev_output;
00093   d_prev_output = output;
00094 
00095   return (o_type) output;
00096 }
00097 
00098 
00099 template<class o_type, class i_type, class tap_type> 
00100 void 
00101 gr_single_pole_iir<o_type, i_type, tap_type>::filterN (o_type output[],
00102                                                        const i_type input[],
00103                                                        unsigned long n)
00104 {
00105   for (unsigned i = 0; i < n; i++)
00106     output[i] = filter (input[i]);
00107 }
00108 
00109 
00110 //
00111 // Specialized case for gr_complex output and double taps
00112 // We need to have a gr_complexd type for the calculations and prev_output variable (in stead of double)
00113 
00114 template<class i_type> 
00115 class gr_single_pole_iir<gr_complex, i_type, double>  {
00116 public:
00117   /*!
00118    * \brief construct new single pole IIR with given alpha
00119    *
00120    * computes y(i) = (1-alpha) * y(i-1) + alpha * x(i)
00121    */
00122   gr_single_pole_iir (double alpha = 1.0)
00123   {
00124     d_prev_output = 0;
00125     set_taps (alpha);
00126   }
00127 
00128   /*!
00129    * \brief compute a single output value.
00130    * \returns the filtered input value.
00131    */
00132  gr_complex filter (const i_type input);
00133 
00134   /*!
00135    * \brief compute an array of N output values.
00136    * \p input must have n valid entries.
00137    */
00138   void filterN (gr_complex output[], const i_type input[], unsigned long n);
00139 
00140   /*!
00141    * \brief install \p alpha as the current taps.
00142    */
00143   void set_taps (double alpha)
00144   { 
00145     if (alpha < 0 || alpha > 1)
00146       throw std::out_of_range ("Alpha must be in [0, 1]\n");
00147 
00148     d_alpha = alpha;
00149     d_one_minus_alpha = 1.0 - alpha;
00150   }
00151 
00152   //! reset state to zero
00153   void reset ()
00154   {
00155     d_prev_output = 0;
00156   }
00157 
00158   gr_complexd prev_output () const { return d_prev_output; }
00159     
00160 protected:
00161   double        d_alpha;
00162   double        d_one_minus_alpha;
00163   gr_complexd   d_prev_output;
00164 };
00165 
00166 template< class i_type> 
00167 gr_complex
00168 gr_single_pole_iir<gr_complex, i_type, double>::filter (const i_type input)
00169 {
00170   gr_complexd   output;
00171 
00172   output = d_alpha * (gr_complexd)input + d_one_minus_alpha * d_prev_output;
00173   d_prev_output = output;
00174 
00175   return (gr_complex) output;
00176 }
00177 
00178 //Do we need to specialize this, although it is the same as the general case?
00179 
00180 template<class i_type> 
00181 void 
00182 gr_single_pole_iir<gr_complex, i_type, double>::filterN (gr_complex output[],
00183                                                        const i_type input[],
00184                                                        unsigned long n)
00185 {
00186   for (unsigned i = 0; i < n; i++)
00187     output[i] = filter (input[i]);
00188 }
00189 
00190 #endif /* _GR_SINGLE_POLE_IIR_H_ */