File indexing completed on 2025-01-05 04:12:54

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2010 The University of Toronto                        *
0004  *                   sbenton@phsyics.utoronto.ca                           *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 
0014 #include <deque>
0015 #include <vector>
0016 #include <complex>
0017 
0018 #include "math_kst.h"
0019 
0020 #ifndef IIRFILTER_H
0021 #define IIRFILTER_H
0022 
0023 using std::deque;
0024 using std::vector;
0025 
0026 typedef std::complex<double> complex;
0027 
0028 /* 
0029  * allows for definition of general recursive/IIR filters
0030  *
0031  * Probably doesn't need to be a template, but I was experimenting
0032  * now you can filter a series of vectors! (or rather float/long double/complex)
0033  *
0034  */
0035 template<class T> class IIRFilter {
0036   public:
0037     IIRFilter(unsigned int order);
0038 
0039     //do fitlering by calling your instance with most recent input
0040     T operator() (T x);
0041 
0042     //clear the filter history
0043     void clear();
0044 
0045     //evaluate transfer function at complex point z
0046     complex transfer(complex z);
0047 
0048     //function generates data stream containing impulse and frequency response
0049     //clears filter both before and after
0050     int FilterResponse(const char* out, double max_f=0.5, unsigned int n=100);
0051 
0052   protected:
0053     //to be used in derived class constructors
0054     void setCoefficients(vector<double> na, vector<double> nb);
0055 
0056   private:
0057     deque<T> x0;    //last filter input
0058     deque<T> y0;    //last filter output
0059     vector<double> a;   //coefficients to multiply y0
0060     vector<double> b;   //coefficients to multiply x, x0
0061     unsigned int order; //order of the filter
0062 };
0063 
0064 /* 
0065  * A few sample filter types. Analytic forms for a few low-order Bessel filters
0066  *
0067  * TODO: it would be great to use numerically designed filters
0068  *
0069  */
0070 
0071 //1st order bessel low-pass, with knee frequency f (in sample rate units)
0072 template <class T> class BesselLP1 : public IIRFilter<T> {
0073   public:
0074     BesselLP1(double f);
0075 };
0076 
0077 //1st order bessel high-pass, with knee frequency f (in sample rate units)
0078 template <class T> class BesselHP1 : public IIRFilter<T> {
0079   public:
0080     BesselHP1(double f);
0081 };
0082 
0083 //4th order bessel low-pass, with knee frequency f (in sample rate units)
0084 template <class T> class BesselLP4 : public IIRFilter<T> {
0085   public:
0086     BesselLP4(double f);
0087 };
0088 
0089 
0090 /*******************************************************************************
0091  * IMPLEMENTATION
0092  * g++ doesn't support 'export' for template implementations in another file
0093  * so, all the implementations are here
0094  ******************************************************************************/
0095 
0096 #include <iostream>
0097 #include <fstream>
0098 #include <numeric>
0099 #include <cmath>
0100 
0101 using std::cerr;
0102 using std::endl;
0103 
0104 template<class T> IIRFilter<T>::IIRFilter(unsigned int order)
0105 {
0106   this->order = order;
0107   x0.resize(order, 0.0);
0108   y0.resize(order, 0.0);
0109   a.resize(order, 0.0);
0110   b.resize(order+1, 0.0);  //includes coefficient for new inupt x
0111 }
0112 
0113 template<class T> T IIRFilter<T>::operator() (T x)
0114 {
0115   T y = b[0]*x;
0116   //cerr << "y = (" << b[0] << ")*x[n]" << endl;
0117   for (unsigned int i=0; i<order; i++) {
0118     y += b[i+1] * x0[i];
0119     y -= a[i]   * y0[i];
0120     //cerr << "    + (" << b[i+1] << ")*x[n-" << i+1 << "]";
0121     //cerr << " - (" << a[i] << ")*y[n-" << i+1 << "]" << endl;
0122   }
0123 
0124   x0.pop_back();
0125   x0.push_front(x);
0126   y0.pop_back();
0127   y0.push_front(y);
0128 
0129   return y;
0130 }
0131 
0132 template<class T> void IIRFilter<T>::clear() {
0133   x0.resize(order, T());
0134   y0.resize(order, T());
0135 }
0136 
0137 template<class T> complex IIRFilter<T>::transfer(complex z)
0138 {
0139   complex numer = pow(z,4)*b[0];
0140   complex denom = pow(z,4);
0141   for (unsigned int i=0; i<order; i++) {
0142     numer += b[i+1]*pow(z,order-1-i);
0143     denom += a[i]*pow(z,order-1-i);
0144   }
0145 
0146   return numer/denom;
0147 }
0148 
0149 template<class T> int IIRFilter<T>::FilterResponse(const char* out,  double max_f, unsigned int n)
0150 {
0151   std::ofstream oo(out);
0152   if (!oo) {
0153     cerr << "Couldn't open FilterResponse output file" << endl;
0154     return 1;
0155   }
0156   this->clear();
0157 
0158   oo << "INDEX\timpulse\tfreq\tgain\tphase" << endl;
0159   for (unsigned int i=0; i<n; i++) {
0160     oo << i+1 << "\t";              //INDEX
0161     oo << (*this)((i==0)?1.0:0.0) << "\t";  //impulse response
0162     //frequency goes up to Nyquist (0.5 in sample frequency units)
0163     double freq = (double)i*max_f/(double)n;
0164     oo << freq << "\t";             //frequency (in sample units)
0165     complex resp = transfer(complex(cos(2*M_PI*freq),sin(2*M_PI*freq)));
0166     oo << abs(resp) << "\t";            //gain
0167     oo << arg(resp) << "\n";            //phase
0168   }
0169 
0170   this->clear();
0171   return 0;
0172 }
0173 
0174 template<class T> 
0175 void IIRFilter<T>::setCoefficients(vector<double> na, vector<double> nb)
0176 {
0177   if (na.size() != order || nb.size() != order+1) {
0178     cerr << "Invalid size of coefficient vector\n" << endl;
0179     return;
0180   }
0181   a = na;
0182   b = nb;
0183 }
0184 
0185 
0186 
0187 //The filter forms below were solved analytically using a bilinear transform
0188 
0189 //bessel scale factors
0190 //convert normalization from unit delay at f=0 to 3dB attenutation at 1rad/s
0191 const double norm_bessel_O1  = 1.0;
0192 const double norm_bessel_O2  = 1.36165412871613;
0193 const double norm_bessel_O3  = 1.75567236868121;
0194 const double norm_bessel_O4  = 2.11391767490422;
0195 const double norm_bessel_O5  = 2.42741070215263;
0196 const double norm_bessel_O6  = 2.70339506120292;
0197 const double norm_bessel_O7  = 2.95172214703872;
0198 const double norm_bessel_O8  = 3.17961723751065;
0199 const double norm_bessel_O9  = 3.39169313891166;
0200 const double norm_bessel_O10 = 3.59098059456916;
0201 
0202 template<class T> BesselLP1<T>::BesselLP1(double f) : IIRFilter<T>(1)
0203 {
0204   vector<double> a(1), b(2);
0205   double alpha = M_PI*f/norm_bessel_O1;
0206   alpha = tan(alpha);   //pre-warp
0207   a[0] = (alpha-1.0)/(1.0+alpha);
0208   b[0] = alpha/(1.0+alpha);
0209   b[1] = alpha/(1.0+alpha);
0210   this->setCoefficients(a, b);
0211 }
0212 
0213 template<class T> BesselHP1<T>::BesselHP1(double f) : IIRFilter<T>(1)
0214 {
0215   vector<double> a(1), b(2);
0216   double alpha = M_PI*f/norm_bessel_O1;
0217   alpha = tan(alpha);   //pre-warp
0218   a[0] = (alpha-1.0)/(1.0+alpha);
0219   b[0] = 1.0/(1.0+alpha);
0220   b[1] = -1.0/(1.0+alpha);
0221   this->setCoefficients(a, b);
0222 }
0223 
0224 template<class T> BesselLP4<T>::BesselLP4(double f) : IIRFilter<T>(4)
0225 {
0226   vector<double> a(4), b(5);
0227   double alpha = M_PI*f/norm_bessel_O4;
0228   alpha = tan(alpha);   //pre-warp
0229   double denom = (1.0 + 1.0/alpha + 45.0/105.0/pow(alpha,2) 
0230       + 10.0/105.0/pow(alpha,3) + 1.0/105.0/pow(alpha,4));
0231 
0232   a[0] = (4.0 + 2.0/alpha 
0233       - 20.0/105.0/pow(alpha,3) - 4.0/105.0/pow(alpha,4))/denom;
0234   a[1] = (6.0 - 90.0/105.0/pow(alpha,2) + 6.0/105.0/pow(alpha,4))/denom;
0235   a[2] = (4.0 - 2.0/alpha 
0236       + 20.0/105.0/pow(alpha,3) - 4.0/105.0/pow(alpha,4))/denom;
0237   a[3] = (1.0 - 1.0/alpha + 45.0/105.0/pow(alpha,2) 
0238       - 10.0/105.0/pow(alpha,3) + 1.0/105.0/pow(alpha,4))/denom;
0239 
0240   b[0] = 1.0/denom;
0241   b[1] = 4.0/denom;
0242   b[2] = 6.0/denom;
0243   b[3] = 4.0/denom;
0244   b[4] = 1.0/denom;
0245 
0246   /*
0247   cerr << "y = (" << b[0] << ")*x[n]" << endl;
0248   for (unsigned int i=0; i<4; i++) {
0249     cerr << "    + (" << b[i+1] << ")*x[n-" << i+1 << "]";
0250     cerr << " - (" << a[i] << ")*y[n-" << i+1 << "]" << endl;
0251   }
0252   */
0253 
0254   this->setCoefficients(a, b);
0255 }
0256 
0257 #endif