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