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