eDSP  0.0.1
A cross-platform DSP library written in C++.
biquad.hpp
Go to the documentation of this file.
1 /*
2  * eDSP, A cross-platform Digital Signal Processing library written in modern C++.
3  * Copyright (C) 2018 Mohammed Boujemaoui Boulaghmoudi, All rights reserved.
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation, either version 3 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along width
16  * this program. If not, see <http://www.gnu.org/licenses/>
17  *
18  * File: biquad.hpp
19  * Date: 09/06/18
20  * Author: Mohammed Boujemaoui
21  */
22 
23 #ifndef EDSP_FILTER_BIQUAD_HPP
24 #define EDSP_FILTER_BIQUAD_HPP
25 
26 #include <edsp/math/numeric.hpp>
27 #include <edsp/meta/expects.hpp>
28 #include <algorithm>
29 #include <cmath>
30 #include <functional>
31 #include <complex>
32 
33 namespace edsp { namespace filter {
34 
38  enum class FilterType {
39  LowPass,
40  HighPass,
43  BandPass,
44  BandStop,
45  AllPass,
46  LowShelf,
47  HighShelf,
48  BandShelf,
49  Notch,
50  PeakingEQ
51  };
52 
70  template <typename T>
71  class biquad {
72  public:
73  using value_type = T;
74 
75  constexpr biquad() noexcept = default;
76  constexpr biquad(const biquad&) noexcept = default;
77  constexpr biquad(biquad&&) noexcept = default;
78  constexpr biquad& operator=(const biquad&) noexcept = default;
79  constexpr biquad& operator=(biquad&&) noexcept = default;
80 
86  constexpr biquad(const std::complex<T>& pole, const std::complex<T>& zero);
87 
95  constexpr biquad(const std::complex<T>& pole_first, const std::complex<T>& zero_first,
96  const std::complex<T>& pole_second, const std::complex<T>& zero_second);
97 
107  constexpr biquad(value_type a0, value_type a1, value_type a2, value_type b0, value_type b1,
108  value_type b2) noexcept;
112  ~biquad() = default;
113 
118  constexpr value_type a0() const noexcept;
119 
124  constexpr value_type a1() const noexcept;
125 
130  constexpr value_type a2() const noexcept;
131 
136  constexpr value_type b0() const noexcept;
137 
142  constexpr value_type b1() const noexcept;
143 
148  constexpr value_type b2() const noexcept;
149 
154  constexpr void set_a0(T value) noexcept;
159  constexpr void set_a1(T value) noexcept;
160 
165  constexpr void set_a2(T value) noexcept;
166 
171  constexpr void set_b0(T value) noexcept;
172 
177  constexpr void set_b1(T value) noexcept;
178 
183  constexpr void set_b2(T value) noexcept;
184 
192  template <typename InputIt, typename OutputIt>
193  constexpr void filter(InputIt first, InputIt last, OutputIt d_first);
194 
198  constexpr void reset() noexcept;
199 
206  constexpr bool stability() const noexcept;
207 
212  constexpr explicit operator bool() const noexcept;
213 
219  constexpr value_type tick(T value) noexcept;
220 
221  private:
222  value_type b2_{0};
223  value_type b1_{0};
224  value_type b0_{1};
225  value_type a2_{0};
226  value_type a1_{0};
227  value_type a0_{1};
228  value_type w0_{0};
229  value_type w1_{0};
230  };
231 
232  template <typename T>
234  value_type b2) noexcept :
235  b2_(b2 / a0),
236  b1_(b1 / a0),
237  b0_(b0 / a0),
238  a2_(a2 / a0),
239  a1_(a1 / a0),
240  a0_(1) {}
241 
242  template <typename T>
243  constexpr biquad<T>::biquad(const std::complex<T>& pole, const std::complex<T>& zero) :
244  b2_(0),
245  b1_(1),
246  b0_(-zero.real()),
247  a2_(0),
248  a1_(-pole.real()),
249  a0_(1) {
250  meta::expects(pole.imag() == 0, "Expecting real pole");
251  meta::expects(zero.imag() == 0, "Expecting real zero");
252  }
253 
254  template <typename T>
255  constexpr biquad<T>::biquad(const std::complex<T>& pole_first, const std::complex<T>& zero_first,
256  const std::complex<T>& pole_second, const std::complex<T>& zero_second) :
257  b0_(1),
258  a0_(1) {
259  if (pole_first.imag() != 0) {
260  meta::expects(pole_second == std::conj(pole_first), "Expecting complex conjugates");
261  a1_ = -2 * pole_first.real();
262  a2_ = std::norm(pole_first);
263  } else {
264  meta::expects(pole_second.imag() == 0, "Expecting a complex number");
265  a1_ = -(pole_first.real() + pole_second.real());
266  a2_ = pole_first.real() * pole_second.real();
267  }
268 
269  if (zero_first.imag() != 0) {
270  meta::expects(zero_second == std::conj(zero_first), "Expecting complex conjugates");
271  b1_ = -2 * zero_first.real();
272  b2_ = std::norm(zero_first);
273  } else {
274  meta::expects(zero_second.imag() == 0, "Expecting a complex number");
275  b1_ = -(zero_first.real() + zero_second.real());
276  b2_ = zero_first.real() * zero_second.real();
277  }
278  }
279 
280  template <typename T>
281  constexpr void biquad<T>::reset() noexcept {
282  w0_ = 0;
283  w1_ = 0;
284  }
285 
286  template <typename T>
287  constexpr bool biquad<T>::stability() const noexcept {
288  return std::abs(a2_) < 1 && (std::abs(a1_) < (1 + a2_));
289  }
290 
291  template <typename T>
292  constexpr void biquad<T>::set_a0(const value_type value) noexcept {
293  a0_ = value;
294  reset();
295  }
296 
297  template <typename T>
298  constexpr void biquad<T>::set_a1(const value_type value) noexcept {
299  a1_ = value;
300  reset();
301  }
302 
303  template <typename T>
304  constexpr void biquad<T>::set_a2(const value_type value) noexcept {
305  a2_ = value;
306  reset();
307  }
308 
309  template <typename T>
310  constexpr void biquad<T>::set_b0(const value_type value) noexcept {
311  b0_ = value;
312  reset();
313  }
314 
315  template <typename T>
316  constexpr void biquad<T>::set_b1(const value_type value) noexcept {
317  b1_ = value;
318  reset();
319  }
320 
321  template <typename T>
322  constexpr void biquad<T>::set_b2(const value_type value) noexcept {
323  b2_ = value;
324  reset();
325  }
326 
327  template <typename T>
328  template <typename InputIt, typename OutputIt>
329  constexpr void biquad<T>::filter(InputIt first, InputIt last, OutputIt d_first) {
330  for (; first != last; ++first, ++d_first) {
331  *d_first = tick(*first);
332  }
333  }
334 
335  template <typename T>
336  constexpr typename biquad<T>::value_type biquad<T>::tick(const value_type value) noexcept {
337  const auto out = b0_ * value + w0_;
338  w0_ = b1_ * value - a1_ * out + w1_;
339  w1_ = b2_ * value - a2_ * out;
340  return out;
341  }
342 
343  template <typename T>
344  constexpr biquad<T>::operator bool() const noexcept {
345  return stability();
346  }
347 
348  template <typename T>
349  constexpr typename biquad<T>::value_type biquad<T>::a0() const noexcept {
350  return a0_;
351  }
352 
353  template <typename T>
354  constexpr typename biquad<T>::value_type biquad<T>::a1() const noexcept {
355  return a1_;
356  }
357 
358  template <typename T>
359  constexpr typename biquad<T>::value_type biquad<T>::a2() const noexcept {
360  return a2_;
361  }
362 
363  template <typename T>
364  constexpr typename biquad<T>::value_type biquad<T>::b0() const noexcept {
365  return b0_;
366  }
367 
368  template <typename T>
369  constexpr typename biquad<T>::value_type biquad<T>::b1() const noexcept {
370  return b1_;
371  }
372 
373  template <typename T>
374  constexpr typename biquad<T>::value_type biquad<T>::b2() const noexcept {
375  return b2_;
376  }
377 }} // namespace edsp::filter
378 
379 #endif // EDSP_FILTER_BIQUAD_HPP
constexpr value_type tick(T value) noexcept
Computes the output of filtering one digital time-step.
Definition: biquad.hpp:336
constexpr void set_b2(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:322
FilterType
The FilterType enum defines the different available filters.
Definition: biquad.hpp:38
constexpr value_type b2() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:374
constexpr void set_a1(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:298
constexpr T real(const std::complex< T > &z)
Computes the real component of the complex number z.
Definition: complex.hpp:60
constexpr value_type a1() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:354
constexpr meta::value_type_t< InputIt > norm(InputIt first, InputIt last)
Compute the L2-norm of the signals in the range [first1, last1).
Definition: norm.hpp:48
This Biquad class implements a second-order recursive linear filter, containing two poles and two zer...
Definition: biquad.hpp:71
constexpr bool stability() const noexcept
Checks if the Biquad Filter is stable.
Definition: biquad.hpp:287
constexpr value_type a0() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:349
constexpr void set_a0(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:292
constexpr void set_b0(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:310
constexpr value_type b1() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:369
logger & reset(logger &stream)
Resets the logger to default configuration.
Definition: logger.hpp:416
constexpr std::complex< T > conj(const std::complex< T > &z)
Computes the complex conjugate of the complex number z.
Definition: complex.hpp:80
T value_type
Definition: biquad.hpp:73
constexpr value_type b0() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:364
constexpr void set_a2(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:304
constexpr void set_b1(T value) noexcept
Updates the value of the coefficient .
Definition: biquad.hpp:316
constexpr void reset() noexcept
Reset the filter to the original state.
Definition: biquad.hpp:281
Definition: amplifier.hpp:29
constexpr biquad() noexcept=default
constexpr value_type a2() const noexcept
Returns the value of the coefficient .
Definition: biquad.hpp:359
constexpr void filter(InputIt first, InputIt last, OutputIt d_first)
Filters the signal in the range [first, last) and stores the result in another range, beginning at d_first.
Definition: biquad.hpp:329