26#ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_FILTERS_INL
27#define LASS_GUARDIAN_OF_INCLUSION_NUM_FILTERS_INL
40 template <
typename T,
typename ForwardIterator>
41 num::Polynomial<T> laplaceToZHelper(ForwardIterator first, ForwardIterator last,
const T& samplingFrequency)
43 typedef num::NumTraits<T> TNumTraits;
44 typedef num::Polynomial<T> TPolynomial;
46 TPolynomial oneMinZ = 2 * samplingFrequency * (TNumTraits::one - TPolynomial::x());
47 TPolynomial onePlusZ = TNumTraits::one + TPolynomial::x();
49 const size_t n =
static_cast<size_t>(std::distance(first, last));
50 for (
size_t i = 0; i < n; ++i)
52 result += *first++ * oneMinZ.pow(i) * onePlusZ.pow(n - i - 1);
57 template <
typename T,
typename ForwardIterator1,
typename ForwardIterator2>
58 std::pair< std::vector<T>, std::vector<T> >
59 laplaceToZ(ForwardIterator1 numeratorFirst, ForwardIterator1 numeratorLast,
60 ForwardIterator2 denominatorFirst, ForwardIterator2 denominatorLast,
61 const T& samplingFrequency)
63 typedef num::NumTraits<T> TNumTraits;
64 typedef num::Polynomial<T> TPolynomial;
66 TPolynomial num = laplaceToZHelper(numeratorFirst, numeratorLast, samplingFrequency);
67 TPolynomial den = laplaceToZHelper(denominatorFirst, denominatorLast, samplingFrequency);
68 TPolynomial onePlusZ = TNumTraits::one + TPolynomial::x();
69 const size_t m = num.size();
70 const size_t n = den.size();
73 num *= onePlusZ.pow(
static_cast<unsigned>(n - m));
77 den *= onePlusZ.pow(
static_cast<unsigned>(m - n));
79 return std::make_pair(num.coefficients(), den.coefficients());
83 std::pair< std::vector<T>, std::vector<T> >
84 laplaceButterworthLowPass(
unsigned n,
const T& cutoff,
const T& gain)
86 typedef num::NumTraits<T> TNumTraits;
87 typedef num::Polynomial<T> TPolynomial;
89 const TPolynomial s = TPolynomial::x() / cutoff;
90 const TPolynomial s2 = s * s;
92 TPolynomial nom(gain);
93 TPolynomial den(TNumTraits::one);
96 for (
unsigned k = 0; k < n / 2; ++k)
98 const T theta = (TNumTraits::pi * (2 * k + n + 1)) / (2 * n);
99 den *= s2 - 2 * num::cos(theta) * s + TNumTraits::one;
102 return std::make_pair(nom.coefficients(), den.coefficients());
105 template <
typename T>
106 std::pair< std::vector<T>, std::vector<T> >
107 laplaceButterworthHighPass(
unsigned n,
const T& cutoff,
const T& gain)
109 typedef num::NumTraits<T> TNumTraits;
110 typedef std::pair< std::vector<T>, std::vector<T> > TValuesPair;
112 TValuesPair result = laplaceButterworthLowPass<T>(n, TNumTraits::one, TNumTraits::one);
114 std::reverse(result.second.begin(), result.second.end());
115 for (
size_t k = 0; k < result.second.size(); ++k)
117 result.second[k] /=
num::pow(cutoff, T(k));
120 result.first.resize(n + 1);
121 std::fill(result.first.begin(), result.first.end(), TNumTraits::zero);
122 result.first[n] = gain /
num::pow(cutoff, T(n));
130template <
typename T,
typename InIt,
typename OutIt>
131FirFilter<T, InIt, OutIt>::FirFilter(
const TValues& impulseResponse):
132 taps_(impulseResponse),
133 buffer_(2 * impulseResponse.size()),
134 nextIndex_(impulseResponse.size()),
135 tapSize_(impulseResponse.size()),
138 if (impulseResponse.empty())
140 LASS_THROW(
"Cannot use an empty vector as impulse response");
143 for (
size_t i = 0; i < tapSize_; ++i)
145 nextIndex_[i] = (i - 1 + tapSize_) % tapSize_;
152template <
typename T,
typename InIt,
typename OutIt>
153typename FirFilter<T, InIt, OutIt>::TOutputIterator
154FirFilter<T, InIt, OutIt>::doFilter(TInputIterator first, TInputIterator last, TOutputIterator output)
156 const T*
const taps = &taps_[0];
157 while (first != last)
159 buffer_[tapSize_ + bufferIndex_] = buffer_[bufferIndex_] = *first++;
160 const T*
const buf = &buffer_[bufferIndex_];
161 TValue accumulator = TNumTraits::zero;
162 for (
size_t i = 0; i < tapSize_; ++i)
164 accumulator += taps[i] * buf[i];
166 bufferIndex_ = nextIndex_[bufferIndex_];
167 *output++ = accumulator;
174template <
typename T,
typename InIt,
typename OutIt>
175void FirFilter<T, InIt, OutIt>::doReset()
177 std::fill(buffer_.begin(), buffer_.end(), TNumTraits::zero);
195template <
typename T,
typename InIt,
typename OutIt>
198 this->init(numerator, denominator);
208template <
typename T,
typename InIt,
typename OutIt>
211 this->init(coefficients.first, coefficients.second);
229template <
typename T,
typename InIt,
typename OutIt>
231 const TValues& numerator,
const TValues& denominator,
TParam samplingFrequency)
233 return doMakeLaplace(numerator.begin(), numerator.end(), denominator.begin(), denominator.end(), samplingFrequency);
245template <
typename T,
typename InIt,
typename OutIt>
247 unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
249 return doMakeLaplace(impl::laplaceButterworthLowPass(order, cutoffAngularFrequency, gain), samplingFrequency);
261template <
typename T,
typename InIt,
typename OutIt>
263 unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
265 return doMakeLaplace(impl::laplaceButterworthHighPass(order, cutoffAngularFrequency, gain), samplingFrequency);
285template <
typename T,
typename InIt,
typename OutIt>
287 TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
289 const TValue
num[] = { gain };
290 const TValue den[] = { TNumTraits::one,
num::inv(cutoffAngularFrequency * qFactor),
num::inv(
num::sqr(cutoffAngularFrequency)) };
291 return doMakeLaplace(
num,
num + 1, den, den + 3, samplingFrequency);
311template <
typename T,
typename InIt,
typename OutIt>
313 TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
315 const TValue
num[] = { 0, 0, gain /
num::sqr(cutoffAngularFrequency) };
316 const TValue den[] = { TNumTraits::one,
num::inv(cutoffAngularFrequency * qFactor),
num::inv(
num::sqr(cutoffAngularFrequency)) };
317 return doMakeLaplace(
num,
num + 3, den, den + 3, samplingFrequency);
337template <
typename T,
typename InIt,
typename OutIt>
339 TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
341 const TValue
num[] = { TNumTraits::zero, gain / (centerAngularFrequency * qFactor) };
342 const TValue den[] = { TNumTraits::one,
num::inv(centerAngularFrequency * qFactor),
num::inv(
num::sqr(centerAngularFrequency)) };
343 return doMakeLaplace(
num,
num + 2, den, den + 3, samplingFrequency);
365template <
typename T,
typename InIt,
typename OutIt>
367 TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
369 const TValue
num[] = { gain, TNumTraits::zero, gain /
num::sqr(centerAngularFrequency) };
370 const TValue den[] = { TNumTraits::one,
num::inv(centerAngularFrequency * qFactor),
num::inv(
num::sqr(centerAngularFrequency)) };
371 return doMakeLaplace(
num,
num + 3, den, den + 3, samplingFrequency);
381template <
typename T,
typename InIt,
typename OutIt>
384 TValue
num[] = { gain };
385 TValue den[] = { TNumTraits::zero, TNumTraits::one, };
386 return doMakeLaplace(
num,
num + 1, den, den + 2, samplingFrequency);
396template <
typename T,
typename InIt,
typename OutIt>
399 TValue
num[] = { TNumTraits::zero, gain, };
400 TValue den[] = { TNumTraits::one, };
401 return doMakeLaplace(
num,
num + 2, den, den + 1, samplingFrequency);
410template <
typename T,
typename InIt,
typename OutIt>
413 TValue
num[] = { 0, 0, 0, 0, 7.39705e9 };
414 TValue den[] = { .3086662405e21, .5301498365e19, .2674964995e17, .3343329206e14, 6734684542., 158881.5, 1 };
415 return doMakeLaplace(
417 den, den +
sizeof(den)/
sizeof(TValue),
423template <
typename T,
typename InIt,
typename OutIt>
424typename IirFilter<T, InIt, OutIt>::TOutputIterator
427 const T*
const xTaps = &xTaps_[0];
428 const T*
const yTaps = yTaps_.empty() ? 0 : &yTaps_[0];
429 while (first != last)
431 xBuffer_[xTapSize_ + xBufferIndex_] = xBuffer_[xBufferIndex_] = *first++;
432 const T*
const xBuf = &xBuffer_[xBufferIndex_];
433 const T*
const yBuf = &yBuffer_[yBufferIndex_];
434 TValue accumulator = TNumTraits::zero;
435 for (
size_t i = 0; i < xTapSize_; ++i)
437 accumulator += xTaps[i] * xBuf[i];
439 for (
size_t i = 0; i < yTapSize_; ++i)
441 accumulator -= yTaps[i] * yBuf[i];
443 xBufferIndex_ = xNextIndex_[xBufferIndex_];
444 yBufferIndex_ = yNextIndex_[yBufferIndex_];
445 yBuffer_[yTapSize_ + yBufferIndex_] = yBuffer_[yBufferIndex_] = accumulator;
446 *output++ = accumulator;
453template <
typename T,
typename InIt,
typename OutIt>
454void IirFilter<T, InIt, OutIt>::doReset()
456 std::fill(xBuffer_.begin(), xBuffer_.end(), TNumTraits::zero);
457 std::fill(yBuffer_.begin(), yBuffer_.end(), TNumTraits::zero);
462template <
typename T,
typename InIt,
typename OutIt>
463void IirFilter<T, InIt, OutIt>::init(
const TValues& numerator,
const TValues& denominator)
465 if (numerator.empty() || denominator.empty())
467 LASS_THROW(
"Cannot use an empty vector as numerator or denominator");
469 if (denominator[0] == TNumTraits::zero)
471 LASS_THROW(
"Cannot use a zero as first element in the denominator");
475 yTaps_.assign(stde::next(denominator.begin()), denominator.end());
476 xTapSize_ = xTaps_.size();
477 yTapSize_ = yTaps_.size();
478 const TValue scaler = num::inv(denominator[0]);
479 for (
size_t i = 0; i < xTapSize_; ++i)
483 for (
size_t i = 0; i < yTapSize_; ++i)
488 const size_t xBufferSize = xTapSize_;
489 const size_t yBufferSize = std::max<size_t>(yTapSize_, 1);
490 xBuffer_.resize(2 * xBufferSize);
491 yBuffer_.resize(2 * yBufferSize);
492 xNextIndex_.resize(xBufferSize);
493 yNextIndex_.resize(yBufferSize);
494 for (
size_t i = 0; i < xBufferSize; ++i)
496 xNextIndex_[i] = (i + xBufferSize - 1) % xBufferSize;
498 for (
size_t i = 0; i < yBufferSize; ++i)
500 yNextIndex_[i] = (i + yBufferSize - 1) % yBufferSize;
511template <
typename T,
typename InIt,
typename OutIt>
512template <
typename FwdIt1,
typename FwdIt2>
514 FwdIt1 numFirst, FwdIt1 numLast, FwdIt2 denFirst, FwdIt2 denLast, TParam samplingFrequency)
523template <
typename T,
typename InIt,
typename OutIt>
525 const TValuesPair& coefficients,
TParam samplingFrequency)
527 return doMakeLaplace(coefficients.first.begin(), coefficients.first.end(),
528 coefficients.second.begin(), coefficients.second.end(),
Infinite Impulse Response filter.
static IirFilter makeButterworthHighPass(unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing a high-pass butterworth filter.
IirFilter(const TValues &numerator, const TValues &denominator)
construct IIR filter
static IirFilter makeRlcNotch(TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing an notch RLC circuit.
static IirFilter makeRlcHighPass(TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing an high-pass RLC circuit.
static IirFilter makeDifferentiator(TParam gain, TParam samplingFrequency)
make an IIR filter implementing a perfect differentiator
static IirFilter makeButterworthLowPass(unsigned order, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing a low-pass butterworth filter.
static IirFilter makeRlcBandPass(TParam qFactor, TParam centerAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing an band-pass RLC circuit.
static IirFilter makeIntegrator(TParam gain, TParam samplingFrequency)
make an IIR filter implementing a perfect integrator
static IirFilter makeRlcLowPass(TParam qFactor, TParam cutoffAngularFrequency, TParam gain, TParam samplingFrequency)
make an IIR filter implementing an low-pass RLC circuit.
static IirFilter makeAWeighting(TParam samplingFrequency)
make an A weighting filter
T sqr(const T &x)
return x * x
T inv(const T &x)
return x ^ -1
T pow(const T &x, const T &p)
return exp(p * log(x));
numeric types and traits.
Library for Assembled Shared Sources.