/* -*- c++ -*- */
/*
 * Copyright 2007 Free Software Foundation, Inc.
 * 
 * This file is part of GNU Radio
 * 
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * GNU Radio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifndef INCLUDED_GR_IIR_RESONATOR_BANDPASS_FFF_H
#define	INCLUDED_GR_IIR_RESONATOR_BANDPASS_FFF_H

#include <gr_sync_block.h>
//include <gri_iir_resonator_bandpass.h>
#include <stdexcept>

class gr_iir_resonator_bandpass_fff;
typedef boost::shared_ptr<gr_iir_resonator_bandpass_fff> gr_iir_resonator_bandpass_fff_sptr;
gr_iir_resonator_bandpass_fff_sptr 
gr_make_iir_resonator_bandpass_fff (const float gain, const float fbtap0,const float fbtap1,const float intrinsic_gain)
                                    throw (std::invalid_argument);

/*!
 * \brief  IIR filter with float input, float output and float taps
 * \ingroup filter
 *
 * This filter is a resonating IIR bandpass filter
 * it is an optimized version of gr_iir_filter for the case of a resonating bandpass filter
 * Since two af the taps can be replaced with addition/subtracting and one tap is zero.
 * Get the filter taps and intrinsic gain with fishers iir filter tool mkfiler:
 * ./mkfilter -Re Q-factor -Bp -a fcentre/samplerate [-l]
 * 
 * for example a filter with Q=10  samplerate=1000 and fcentre=200 Hz
 * ./mkfilter -Re 10 -Bp -a 0.2 -l
 * G  = 1.6936432750e+01 <--intrinsic_gain
 * NZ = 2
 *  -1.0000000000e+00  <-- this tap is hardcoded to -1 in this filter
 *   0.0000000000e+00  <-- this tap is hardcoded to 0 in this filter
 *   1.0000000000e+00  <-- this tap is hardcoded to +1 in this filter
 * NP = 2
 *  -8.8191137830e-01  <--fbtap0
 *   5.8154259780e-01  <--fbtap1
 *  -1.0000000000e+00  <--ignore this value
 
 * \p fbtap0 is the first feedback tap
 * \p fbtap0 is the second feedback tap
 * \p intrinsic gain is the gain the filter naturally would have (without compensation). This is dependent on the filter taps. The intrinsic gain is compensated in this filter 
 * \p gain is the wanted actual gain of the filter
 * 
 * The input and output satisfy a difference equation of the form

 \f[
 y[n] - \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k]
 \f]

 * with the corresponding rational system function

 \f[
 H(z) = \frac{\sum_{k=0}^{M} b_k z^{-k}}{1 - \sum_{k=1}^{N} a_k z^{-k}}
 \f]

 * Note that some texts define the system function with a + in the denominator.
 * If you're using that convention, you'll need to negate the feedback taps.
 */
class gr_iir_resonator_bandpass_fff : public gr_sync_block
{
 private:
  friend gr_iir_resonator_bandpass_fff_sptr 
  gr_make_iir_resonator_bandpass_fff  (const float gain, const float fbtap0,const float fbtap1,const float intrinsic_gain=1.0) 
                                      throw (std::invalid_argument);

  float 				d_v0;
  float 				d_v1;
  float 				d_v2;

  float 				d_fb0;
  float 				d_fb1;
  float					d_gain;
  float					d_intrinsic_gain;
  float					d_inv_gain;
  bool					d_updated;

  float filter_one(float input);

  void filter_n (float output[], const float input[], long n);

  /*!
   * Construct an IIR filter with the given taps
   */
  gr_iir_resonator_bandpass_fff  (const float gain, const float fbtap0,const float fbtap1,const float intrinsic_gain)
                                  throw (std::invalid_argument);

 public:
  ~gr_iir_resonator_bandpass_fff ();

  /*!
   * Reset the internal state of the IIR filter (clear the feedback variables)
   */
  void reset();
  /*!
   * Set the wanted gain
   */
  void set_gain (const float gain) throw (std::invalid_argument);

  /*!
   * Set the feedbacktaps and optional the intrinsic gain
   */
  void set_taps (const float fbtap0, const float fbtap1,const float intrinsic_gain=1.0, bool do_reset=true) throw (std::invalid_argument);


  int work (int noutput_items,
	    gr_vector_const_void_star &input_items,
	    gr_vector_void_star &output_items);
};

#endif

