00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
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
00209
00210
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
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
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
00243
00244
00245
00246
00247
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
00259
00260
00261
00262
00263
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
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
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
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
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
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
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
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
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
00381
00382
00383
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
00396
00397
00398
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
00411
00412
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
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
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