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