library of assembled shared sources

http://lass.cocamware.com

filters.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  Distributed under the terms of the GPL (GNU Public License)
00006  *
00007  *  The LASS License:
00008  *
00009  *  Copyright 2004-2006 Bram de Greve and Tom De Muer
00010  *
00011  *  LASS is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  */
00025 
00026 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_FILTERS_INL
00027 #define LASS_GUARDIAN_OF_INCLUSION_NUM_FILTERS_INL
00028 
00029 #include "num_common.h"
00030 #include "filters.h"
00031 #include "polynomial.h"
00032 #include "../stde/extended_iterator.h"
00033 
00034 namespace lass
00035 {
00036 namespace num
00037 {
00038 namespace impl
00039 {
00040     template <typename T, typename ForwardIterator>
00041     num::Polynomial<T> laplaceToZHelper(ForwardIterator first, ForwardIterator last, const T& samplingFrequency)
00042     {
00043         typedef num::NumTraits<T> TNumTraits;
00044         typedef num::Polynomial<T> TPolynomial;
00045 
00046         const T twoFs = 2 * samplingFrequency;
00047 
00048         TPolynomial oneMinZ = 2 * samplingFrequency * (TNumTraits::one - TPolynomial::x());
00049         TPolynomial onePlusZ = TNumTraits::one + TPolynomial::x();
00050         TPolynomial result;
00051         const int n = static_cast<int>(std::distance(first, last));
00052         int i = 0;
00053         while (first != last)
00054         {
00055             result += *first * oneMinZ.pow(i) * onePlusZ.pow(n - i - 1);
00056             ++first;
00057             ++i;
00058         }
00059         return result;
00060     }
00061 
00062     template <typename T, typename ForwardIterator1, typename ForwardIterator2>
00063     std::pair< std::vector<T>, std::vector<T> >
00064     laplaceToZ(ForwardIterator1 numeratorFirst, ForwardIterator1 numeratorLast, 
00065             ForwardIterator2 denominatorFirst, ForwardIterator2 denominatorLast, 
00066             const T& samplingFrequency)
00067     {
00068         typedef num::NumTraits<T> TNumTraits;
00069         typedef num::Polynomial<T> TPolynomial;
00070 
00071         TPolynomial num = laplaceToZHelper(numeratorFirst, numeratorLast, samplingFrequency);
00072         TPolynomial den = laplaceToZHelper(denominatorFirst, denominatorLast, samplingFrequency);
00073         TPolynomial onePlusZ = TNumTraits::one + TPolynomial::x();
00074         const size_t m = num.size();
00075         const size_t n = den.size();
00076         if (n > m)
00077         {
00078             num *= onePlusZ.pow(static_cast<unsigned>(n - m));
00079         }
00080         else
00081         {
00082             den *= onePlusZ.pow(static_cast<unsigned>(m - n));
00083         }
00084         return std::make_pair(num.coefficients(), den.coefficients());
00085     }
00086 
00087     template <typename T>
00088     std::pair< std::vector<T>, std::vector<T> > 
00089     laplaceButterworthLowPass(unsigned n, const T& cutoff, const T& gain)
00090     {
00091         typedef num::NumTraits<T> TNumTraits;
00092         typedef num::Polynomial<T> TPolynomial;
00093         
00094         const TPolynomial s = TPolynomial::x() / cutoff;
00095         const TPolynomial s2 = s * s;
00096 
00097         TPolynomial den(TNumTraits::one);
00098         if (n % 2 == 1)
00099             den += s;
00100         for (unsigned k = 0; k < n / 2; ++k)
00101         {
00102             const T theta = (TNumTraits::pi * (2 * k + n + 1)) / (2 * n);
00103             den *= s2 - 2 * num::cos(theta) * s + TNumTraits::one;
00104         }
00105 
00106         return std::make_pair(TPolynomial::one().coefficients(), den.coefficients());
00107     }
00108 
00109     template <typename T>
00110     std::pair< std::vector<T>, std::vector<T> > 
00111     laplaceButterworthHighPass(unsigned n, const T& cutoff, const T& gain)
00112     {
00113         typedef num::NumTraits<T> TNumTraits;
00114         typedef std::pair< std::vector<T>, std::vector<T> > TValuesPair;
00115 
00116         TValuesPair result = laplaceButterworthLowPass<T>(n, TNumTraits::one, TNumTraits::one);
00117 
00118         std::reverse(result.second.begin(), result.second.end());
00119         for (size_t k = 0; k < result.second.size(); ++k)
00120         {
00121             result.second[k] /= num::pow(cutoff, T(k));
00122         }
00123 
00124         result.first.resize(n + 1);
00125         std::fill(result.first.begin(), result.first.end(), TNumTraits::zero);
00126         result.first[n] = gain / num::pow(cutoff, T(n));
00127 
00128         return result;
00129     }
00130 }
00131 
00132 // --- FirFilter -----------------------------------------------------------------------------------
00133 
00134 template <typename T, typename InIt, typename OutIt>
00135 FirFilter<T, InIt, OutIt>::FirFilter(const TValues& impulseResponse):
00136     taps_(impulseResponse),
00137     buffer_(2 * impulseResponse.size()),
00138     nextIndex_(impulseResponse.size()),
00139     tapSize_(impulseResponse.size()),
00140     bufferIndex_(0)
00141 {
00142     if (impulseResponse.empty())
00143     {
00144         LASS_THROW("Cannot use an empty vector as impulse response");
00145     }
00146 
00147     for (size_t i = 0; i < tapSize_; ++i)
00148     {
00149         nextIndex_[i] = (i - 1 + tapSize_) % tapSize_;
00150     }
00151     this->reset();
00152 }
00153 
00154 
00155 
00156 template <typename T, typename InIt, typename OutIt>
00157 typename FirFilter<T, InIt, OutIt>::TOutputIterator
00158 FirFilter<T, InIt, OutIt>::doFilter(TInputIterator first, TInputIterator last, TOutputIterator output)
00159 {
00160     const T* const taps = &taps_[0];
00161     while (first != last)
00162     {
00163         buffer_[tapSize_ + bufferIndex_] = buffer_[bufferIndex_] = *first++;
00164         const T* const buf = &buffer_[bufferIndex_];
00165         TValue accumulator = TNumTraits::zero;
00166         for (size_t i = 0; i < tapSize_; ++i)
00167         {
00168             accumulator += taps[i] * buf[i];
00169         }
00170         bufferIndex_ = nextIndex_[bufferIndex_];
00171         *output++ = accumulator;
00172     }
00173     return output;
00174 }
00175 
00176 
00177 
00178 template <typename T, typename InIt, typename OutIt>
00179 void FirFilter<T, InIt, OutIt>::doReset()
00180 {
00181     std::fill(buffer_.begin(), buffer_.end(), TNumTraits::zero);
00182 }
00183 
00184 
00185 
00186 // --- IirFilter -----------------------------------------------------------------------------------
00187 
00188 /** construct IIR filter
00189  *
00190  * @code
00191  *        a[0] + a[1] * z^-1 + a[2] * z^-2 + ... + a[m-1] * z^-(m-1)
00192  * H(z) = ----------------------------------------------------------
00193  *        b[0] + b[1] * z^-1 + b[2] * z^-2 + ... + b[m-1] * z^-(m-1)
00194  * @endcode
00195  *
00196  * @param numerator [in] coefficients a[i] of transfer function H(z).
00197  * @param denominator [in] coefficients b[i] of transfer function H(z).
00198  */
00199 template <typename T, typename InIt, typename OutIt>
00200 IirFilter<T, InIt, OutIt>::IirFilter(const TValues& numerator, const TValues& denominator)
00201 {
00202     this->init(numerator, denominator);
00203     this->reset();
00204 }
00205 
00206 
00207 
00208 /** construct IIR filter
00209  *
00210  * @param coefficients [in] numerator (=first) and denominator (=second) of transfer function H(z).
00211  */
00212 template <typename T, typename InIt, typename OutIt>
00213 IirFilter<T, InIt, OutIt>::IirFilter(const TValuesPair& coefficients)
00214 {
00215     this->init(coefficients.first, coefficients.second);
00216     this->reset();
00217 }
00218 
00219 
00220 
00221 /* make an IIR filter from a transfer function H(s) in Laplace domain.
00222  *
00223  * @code
00224  *        a[0] + a[1] * s + a[2] * s^2 + ... + a[m-1] * s^m-1
00225  * H(s) = ---------------------------------------------------
00226  *        b[0] + b[1] * s + b[2] * s^2 + ... + b[n-1] * s^n-1
00227  * @endcode
00228  *
00229  * @param numerator [in] coefficients a[i] of Laplace transfer function H(s).
00230  * @param denominator [in] coefficients b[i] of Laplace transfer function H(s).
00231  * @param samplingFrequency [in] sampling frequency of the digital signal.
00232  */
00233 template <typename T, typename InIt, typename OutIt>
00234 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeLaplace(
00235         const TValues& numerator, const TValues& denominator, TParam samplingFrequency)
00236 {
00237     return doMakeLaplace(numerator.begin(), numerator.end(), denominator.begin(), denominator.end(), samplingFrequency);
00238 }
00239 
00240 
00241 
00242 /** make an IIR filter implementing a low-pass butterworth filter.
00243  *
00244  *  @param order [in] order of filter.  filter rolls of at (order * 6) dB per decade.
00245  *  @param cutoffAngularFrequency [in] cutoff frequency measured in radians per sec (w = 2 pi f).
00246  *  @param gain [in] DC gain
00247  *  @param samplingFrequency [in] sampling frequency of digital signal
00248  */
00249 template <typename T, typename InIt, typename OutIt>
00250 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeButterworthLowPass(
00251         unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
00252 {
00253     return doMakeLaplace(impl::laplaceButterworthLowPass(order, cutoffAngularFrequency, gain), samplingFrequency);
00254 }
00255 
00256 
00257 
00258 /** make an IIR filter implementing a high-pass butterworth filter.
00259  *
00260  *  @param order [in] order of filter.  filter rolls of at (order * 6) dB per decade.
00261  *  @param cutoffAngularFrequency [in] cutoff frequency measured in radians per sec (w = 2 pi f).
00262  *  @param gain [in] DC gain
00263  *  @param samplingFrequency [in] sampling frequency of digital signal
00264  */
00265 template <typename T, typename InIt, typename OutIt>
00266 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeButterworthHighPass(
00267         unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
00268 {
00269     return doMakeLaplace(impl::laplaceButterworthHighPass(order, cutoffAngularFrequency, gain), samplingFrequency);
00270 }
00271 
00272 
00273 
00274 /** make an IIR filter implementing an low-pass RLC circuit.
00275  *
00276  *  @code
00277  *   o---[R]---[sL]---*-----o
00278  *                    |
00279  *  Vin            [1/sC]  Vout
00280  *                    |
00281  *   o----------------*-----o
00282  *  @endcode
00283  *
00284  *  @param qFactor [in] quality factor Q = sqrt(L/C)/R (Q > 1 for resonance peak, Q = 1/sqrt(2) for 2nd order butterworth).
00285  *  @param cutoffAngularFrequency [in] cutoff frequency measured in radians per sec (w = 2 pi f = 1 / sqrt(LC))
00286  *  @param gain [in] DC gain
00287  *  @param samplingFrequency [in] sampling frequency of digital signal
00288  */
00289 template <typename T, typename InIt, typename OutIt>
00290 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeRlcLowPass(
00291         TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
00292 {
00293     const TValue num[] = { gain };
00294     const TValue den[] = { TNumTraits::one, num::inv(cutoffAngularFrequency * qFactor), num::inv(num::sqr(cutoffAngularFrequency)) };
00295     return doMakeLaplace(num, num + 1, den, den + 3, samplingFrequency);
00296 }
00297 
00298 
00299 
00300 /** make an IIR filter implementing an high-pass RLC circuit.
00301  *
00302  *  @code
00303  *   o---[R]---[1/sC]---*----o
00304  *                      |
00305  *  Vin               [sL]  Vout
00306  *                      |
00307  *   o------------------*----o
00308  *  @endcode
00309  *
00310  *  @param qFactor [in] quality factor Q = sqrt(L/C)/R (Q > 1 for resonance peak, Q = 1/sqrt(2) for 2nd order butterworth).
00311  *  @param cutoffAngularFrequency [in] cutoff frequency measured in radians per sec (w = 2 pi f = 1 / sqrt(LC))
00312  *  @param gain [in] DC gain
00313  *  @param samplingFrequency [in] sampling frequency of digital signal
00314  */
00315 template <typename T, typename InIt, typename OutIt>
00316 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeRlcHighPass(
00317         TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
00318 {
00319     const TValue num[] = { 0, 0, gain / num::sqr(cutoffAngularFrequency) };
00320     const TValue den[] = { TNumTraits::one, num::inv(cutoffAngularFrequency * qFactor), num::inv(num::sqr(cutoffAngularFrequency)) };
00321     return doMakeLaplace(num, num + 3, den, den + 3, samplingFrequency);
00322 }
00323 
00324 
00325 
00326 /** make an IIR filter implementing an band-pass RLC circuit.
00327  *
00328  *  @code
00329  *   o---[sL]---[1/sC]---*----o
00330  *                       |
00331  *  Vin                 [R]  Vout
00332  *                       |
00333  *   o-------------------*----o
00334  *  @endcode
00335  *
00336  *  @param qFactor [in] quality factor Q = sqrt(L/C)/R (greater Q is more narrow stop band).
00337  *  @param centerAngularFrequency [in] frequency to be filter out, measured in radians per sec (w = 2 pi f = 1 / sqrt(LC))
00338  *  @param gain [in] DC gain
00339  *  @param samplingFrequency [in] sampling frequency of digital signal
00340  */
00341 template <typename T, typename InIt, typename OutIt>
00342 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeRlcBandPass(
00343         TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
00344 {
00345     const TValue num[] = { TNumTraits::zero, gain / (centerAngularFrequency * qFactor) };
00346     const TValue den[] = { TNumTraits::one, num::inv(centerAngularFrequency * qFactor), num::inv(num::sqr(centerAngularFrequency)) };
00347     return doMakeLaplace(num, num + 2, den, den + 3, samplingFrequency);
00348 }
00349 
00350 
00351 
00352 /** make an IIR filter implementing an notch RLC circuit.
00353  *
00354  *  @code
00355  *   o---[R]---*----o
00356  *             |
00357  *           [sL]
00358  *  Vin        |   Vout
00359  *          [1/sC]
00360  *             |
00361  *   o---------*----o
00362  *  @endcode
00363  *
00364  *  @param qFactor [in] quality factor Q = sqrt(L/C)/R (greater Q is more narrow stop band).
00365  *  @param centerAngularFrequency [in] frequency to be filter out, measured in radians per sec (w = 2 pi f = 1 / sqrt(LC))
00366  *  @param gain [in] DC gain
00367  *  @param samplingFrequency [in] sampling frequency of digital signal
00368  */
00369 template <typename T, typename InIt, typename OutIt>
00370 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeRlcNotch(
00371         TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
00372 {
00373     const TValue num[] = { gain, TNumTraits::zero, gain / num::sqr(centerAngularFrequency) };
00374     const TValue den[] = { TNumTraits::one, num::inv(centerAngularFrequency * qFactor), num::inv(num::sqr(centerAngularFrequency)) };
00375     return doMakeLaplace(num, num + 3, den, den + 3, samplingFrequency);
00376 }
00377 
00378 
00379 
00380 /** make an IIR filter implementing a perfect integrator
00381  *
00382  *  @param gain [in] DC gain
00383  *  @param samplingFrequency [in] sampling frequency of digital signal
00384  */
00385 template <typename T, typename InIt, typename OutIt>
00386 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeIntegrator(TParam gain, TParam samplingFrequency)
00387 {
00388     TValue num[] = { gain };
00389     TValue den[] = { TNumTraits::zero, TNumTraits::one, };
00390     return doMakeLaplace(num, num + 1, den, den + 2, samplingFrequency);
00391 }
00392 
00393 
00394 
00395 /** make an IIR filter implementing a perfect differentiator
00396  *
00397  *  @param gain [in] DC gain
00398  *  @param samplingFrequency [in] sampling frequency of digital signal
00399  */
00400 template <typename T, typename InIt, typename OutIt>
00401 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeDifferentiator(TParam gain, TParam samplingFrequency)
00402 {
00403     TValue num[] = { TNumTraits::zero, gain, };
00404     TValue den[] = { TNumTraits::one, };
00405     return doMakeLaplace(num, num + 2, den, den + 1, samplingFrequency);
00406 }
00407 
00408 
00409 
00410 /** make an A weighting filter
00411  *
00412  *  @param samplingFrequency [in] sampling frequency of digital signal
00413  */
00414 template <typename T, typename InIt, typename OutIt>
00415 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::makeAWeighting(TParam samplingFrequency)
00416 {
00417     TValue num[] = { 0, 0, 0, 0, 7.39705e9 };
00418     TValue den[] = { .3086662405e21, .5301498365e19, .2674964995e17, .3343329206e14, 6734684542., 158881.5, 1 };
00419     return doMakeLaplace(
00420         num, num + sizeof(num)/sizeof(TValue), 
00421         den, den + sizeof(den)/sizeof(TValue), 
00422         samplingFrequency);
00423 }
00424 
00425 
00426 
00427 template <typename T, typename InIt, typename OutIt>
00428 typename IirFilter<T, InIt, OutIt>::TOutputIterator
00429 IirFilter<T, InIt, OutIt>::doFilter(TInputIterator first, TInputIterator last, TOutputIterator output)
00430 {
00431     const T* const xTaps = &xTaps_[0];
00432     const T* const yTaps = yTaps_.empty() ? 0 : &yTaps_[0];
00433     while (first != last)
00434     {
00435         xBuffer_[xTapSize_ + xBufferIndex_] = xBuffer_[xBufferIndex_] = *first++;
00436         const T* const xBuf = &xBuffer_[xBufferIndex_];
00437         const T* const yBuf = &yBuffer_[yBufferIndex_];
00438         TValue accumulator = TNumTraits::zero;
00439         for (size_t i = 0; i < xTapSize_; ++i)
00440         {
00441             accumulator += xTaps[i] * xBuf[i];
00442         }
00443         for (size_t i = 0; i < yTapSize_; ++i)
00444         {
00445             accumulator -= yTaps[i] * yBuf[i];
00446         }
00447         xBufferIndex_ = xNextIndex_[xBufferIndex_];
00448         yBufferIndex_ = yNextIndex_[yBufferIndex_];
00449         yBuffer_[yTapSize_ + yBufferIndex_] = yBuffer_[yBufferIndex_] = accumulator;
00450         *output++ = accumulator;
00451     }
00452     return output;
00453 }
00454 
00455 
00456 
00457 template <typename T, typename InIt, typename OutIt>
00458 void IirFilter<T, InIt, OutIt>::doReset()
00459 {
00460     std::fill(xBuffer_.begin(), xBuffer_.end(), TNumTraits::zero);
00461     std::fill(yBuffer_.begin(), yBuffer_.end(), TNumTraits::zero);
00462 }
00463 
00464 
00465 
00466 template <typename T, typename InIt, typename OutIt>
00467 void IirFilter<T, InIt, OutIt>::init(const TValues& numerator, const TValues& denominator)
00468 {
00469     if (numerator.empty() || denominator.empty())
00470     {
00471         LASS_THROW("Cannot use an empty vector as numerator or denominator");
00472     }
00473     if (denominator[0] == TNumTraits::zero)
00474     {
00475         LASS_THROW("Cannot use a zero as first element in the denominator");
00476     }
00477 
00478     xTaps_ = numerator;
00479     yTaps_.assign(stde::next(denominator.begin()), denominator.end());
00480     xTapSize_ = xTaps_.size();
00481     yTapSize_ = yTaps_.size();
00482     const TValue scaler = num::inv(denominator[0]);
00483     for (size_t i = 0; i < xTapSize_; ++i)
00484     {
00485         xTaps_[i] *= scaler;
00486     }
00487     for (size_t i = 0; i < yTapSize_; ++i)
00488     {
00489         yTaps_[i] *= scaler;
00490     }
00491     
00492     const size_t xBufferSize = xTapSize_;
00493     const size_t yBufferSize = std::max<size_t>(yTapSize_, 1);
00494     xBuffer_.resize(2 * xBufferSize);
00495     yBuffer_.resize(2 * yBufferSize);
00496     xNextIndex_.resize(xBufferSize);
00497     yNextIndex_.resize(yBufferSize);
00498     for (size_t i = 0; i < xBufferSize; ++i)
00499     {
00500         xNextIndex_[i] = (i + xBufferSize - 1) % xBufferSize;
00501     }
00502     for (size_t i = 0; i < yBufferSize; ++i)
00503     {
00504         yNextIndex_[i] = (i + yBufferSize - 1) % yBufferSize;
00505     }
00506 
00507     xBufferIndex_ = 0;
00508     yBufferIndex_ = 0;
00509 }
00510 
00511 
00512 
00513 /** little private helper
00514  */
00515 template <typename T, typename InIt, typename OutIt>
00516 template <typename FwdIt1, typename FwdIt2>
00517 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::doMakeLaplace(
00518         FwdIt1 numFirst, FwdIt1 numLast, FwdIt2 denFirst, FwdIt2 denLast, TParam samplingFrequency)
00519 {
00520     return IirFilter<T, InIt, OutIt>(impl::laplaceToZ(numFirst, numLast, denFirst, denLast, samplingFrequency));
00521 }
00522 
00523 
00524 
00525 /** little private helper
00526  */
00527 template <typename T, typename InIt, typename OutIt>
00528 IirFilter<T, InIt, OutIt> IirFilter<T, InIt, OutIt>::doMakeLaplace(
00529         const TValuesPair& coefficients, TParam samplingFrequency)
00530 {
00531     return doMakeLaplace(coefficients.first.begin(), coefficients.first.end(),
00532         coefficients.second.begin(), coefficients.second.end(), 
00533         samplingFrequency);
00534 }
00535 
00536 }
00537 
00538 }
00539 
00540 #endif
00541 
00542 // EOF

Generated on Mon Nov 10 14:20:04 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo