Audio Processing Framework (APF) version 0.5.0
biquad.h
Go to the documentation of this file.
1/******************************************************************************
2 Copyright (c) 2012-2016 Institut für Nachrichtentechnik, Universität Rostock
3 Copyright (c) 2006-2012 Quality & Usability Lab
4 Deutsche Telekom Laboratories, TU Berlin
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23*******************************************************************************/
24
25// https://AudioProcessingFramework.github.io/
26
29
30#ifndef APF_BIQUAD_H
31#define APF_BIQUAD_H
32
33#include <iosfwd> // for std::ostream
34#include <cmath> // for std::pow(), std::tan(), std::sqrt(), ...
35#include <complex>
36#include <vector>
37#include <cassert> // for assert()
38
40#include "apf/math.h"
41
42namespace apf
43{
44
45// TODO: make macros for trivial operators (see iterator.h)
46// TODO: combine SosCoefficients and LaplaceCoefficients in common class
47// template and use typedef with dummy template arguments.
48
51template<typename T>
53{
54 SosCoefficients(T b0_ = T(), T b1_ = T(), T b2_ = T()
55 , T a1_ = T(), T a2_ = T())
56 : b0(b0_), b1(b1_), b2(b2_)
57 , a1(a1_), a2(a2_)
58 {}
59
60 T b0, b1, b2;
61 T a1, a2;
62
63 SosCoefficients& operator+=(const SosCoefficients& rhs)
64 {
65 b0 += rhs.b0; b1 += rhs.b1; b2 += rhs.b2;
66 a1 += rhs.a1; a2 += rhs.a2;
67 return *this;
68 }
69
70 SosCoefficients operator+(const SosCoefficients& rhs) const
71 {
72 auto tmp = SosCoefficients(*this);
73 return tmp += rhs;
74 }
75
76 SosCoefficients& operator*=(T rhs)
77 {
78 b0 *= rhs; b1 *= rhs; b2 *= rhs;
79 a1 *= rhs; a2 *= rhs;
80 return *this;
81 }
82
83 SosCoefficients operator*(T rhs) const
84 {
85 auto tmp = SosCoefficients(*this);
86 return tmp *= rhs;
87 }
88
89 SosCoefficients& operator/=(T rhs)
90 {
91 b0 /= rhs; b1 /= rhs; b2 /= rhs;
92 a1 /= rhs; a2 /= rhs;
93 return *this;
94 }
95
96 SosCoefficients operator/(T rhs) const
97 {
98 auto tmp = SosCoefficients(*this);
99 return tmp /= rhs;
100 }
101
102 friend SosCoefficients operator*(T lhs, const SosCoefficients& rhs)
103 {
104 auto temp = SosCoefficients(rhs);
105 return temp *= lhs;
106 }
107
108 friend SosCoefficients
109 operator-(const SosCoefficients& lhs, const SosCoefficients& rhs)
110 {
111 return {lhs.b0 - rhs.b0, lhs.b1 - rhs.b1, lhs.b2 - rhs.b2
112 , lhs.a1 - rhs.a1, lhs.a2 - rhs.a2};
113 }
114
115 friend std::ostream&
116 operator<<(std::ostream& stream, const SosCoefficients& c)
117 {
118 stream << "b0: " << c.b0 << ", b1: " << c.b1 << ", b2: " << c.b2
119 << ", a1: " << c.a1 << ", a2: " << c.a2;
120 return stream;
121 }
122};
123
126template<typename T>
128{
129 LaplaceCoefficients(T b0_ = T(), T b1_ = T(), T b2_ = T()
130 , T a1_ = T(), T a2_ = T())
131 : b0(b0_), b1(b1_), b2(b2_)
132 , a1(a1_), a2(a2_)
133 {}
134
135 T b0, b1, b2;
136 T a1, a2;
137};
138
144template<typename T, template<typename> class DenormalPrevention = apf::dp::ac>
145class BiQuad : public SosCoefficients<T> , private DenormalPrevention<T>
146{
147 public:
148 using argument_type = T;
149 using result_type = T;
150
151 BiQuad() : w0(), w1(), w2() {}
152
158 {
160 return *this;
161 }
162
166 result_type operator()(argument_type in)
167 {
168 w0 = w1;
169 w1 = w2;
170 w2 = in - this->a1*w1 - this->a2*w0;
171
172 this->prevent_denormals(w2);
173
174 in = this->b0*w2 + this->b1*w1 + this->b2*w0;
175
176 return in;
177 }
178
179 T w0, w1, w2;
180};
181
184template<typename S, typename Container = std::vector<S>>
186{
187 public:
188 using argument_type = typename S::argument_type;
189 using result_type = typename S::result_type;
190 using size_type = typename Container::size_type;
191
193 explicit Cascade(size_type n) : _sections(n) {}
194
199 template<typename I>
200 void set(I first, I last)
201 {
202 assert(_sections.size() == size_type(std::distance(first, last)));
203
204 std::copy(first, last, _sections.begin());
205 }
206
210 result_type operator()(argument_type in)
211 {
212 for (auto& section: _sections)
213 {
214 in = section(in);
215 }
216 return in;
217 }
218
225 template<typename In, typename Out>
226 void execute(In first, In last, Out result)
227 {
228 using out_t = typename std::iterator_traits<Out>::value_type;
229
230 while (first != last)
231 {
232 *result++ = static_cast<out_t>(this->operator()(*first));
233 ++first;
234 }
235 }
236
237 size_type number_of_sections() const { return _sections.size(); }
238
239 private:
240 Container _sections;
241};
242
243namespace internal
244{
245
253template<typename T>
254void roots2poly(T Roots[2][2], T& poly1, T& poly2)
255{
256 T two = 2.0;
257
258 std::complex<T> eig[2];
259
260 T tmp_arg = std::pow((Roots[0][0]+Roots[1][1])/two, two)
261 + Roots[0][1]*Roots[1][0] - Roots[0][0]*Roots[1][1];
262
263 if (tmp_arg > 0)
264 {
265 eig[0] = (Roots[0][0]+Roots[1][1])/two + std::sqrt(tmp_arg);
266 eig[1] = (Roots[0][0]+Roots[1][1])/two - std::sqrt(tmp_arg);
267 }
268 else
269 {
270 eig[0] = std::complex<T>((Roots[0][0]+Roots[1][1])/two, std::sqrt(-tmp_arg));
271 eig[1] = std::complex<T>((Roots[0][0]+Roots[1][1])/two, -std::sqrt(-tmp_arg));
272 }
273
274 poly1 = real(-eig[0] - eig[1]);
275 poly2 = real(-eig[1] * -eig[0]);
276}
277
278} // namespace internal
279
288template<typename T>
290{
291 SosCoefficients<T> coeffs_out;
292
293 T one = 1.0;
294 T two = 2.0;
295
296 // prewarp
297 T fp_temp = static_cast<T>(fp) * (two * apf::math::pi<T>());
298 T lambda = fp_temp / std::tan(fp_temp / static_cast<T>(fs) / two) / two;
299
300 // calculate state space representation
301 T A[2][2] = { { -coeffs_in.a1, -coeffs_in.a2 }, { 1.0, 0.0 } };
302 T B[2] = { 1.0, 0.0 };
303 T C[2] = { coeffs_in.b1-coeffs_in.a1, coeffs_in.b2-coeffs_in.a2 };
304 T D = 1.0;
305
306 T t = one / lambda;
307 T r = std::sqrt(t);
308
309 T T1[2][2] = { { (t/two)*A[0][0] + one, (t/two)*A[0][1] },
310 { (t/two)*A[1][0], (t/two)*A[1][1] + one } };
311 T T2[2][2] = { { -(t/two)*A[0][0] + one, -(t/two)*A[0][1] },
312 { -(t/two)*A[1][0], -(t/two)*A[1][1] + one} };
313
314 // solve linear equation systems
315 T det = T2[0][0]*T2[1][1] - T2[0][1]*T2[1][0];
316 T Ad[2][2] = { { (T1[0][0]*T2[1][1] - T1[1][0]*T2[0][1]) / det,
317 (T1[0][1]*T2[1][1] - T1[1][1]*T2[0][1]) / det },
318 { (T1[1][0]*T2[0][0] - T1[0][0]*T2[1][0]) / det,
319 (T1[1][1]*T2[0][0] - T1[0][1]*T2[1][0]) / det } };
320 T Bd[2] = { (t/r) * (B[0]*T2[1][1] - B[1]*T2[0][1]) / det,
321 (t/r) * (B[1]*T2[0][0] - B[0]*T2[1][0]) / det };
322 T Cd[2] = { (C[0]*T2[1][1] - C[1]*T2[1][0]) / det,
323 (C[1]*T2[0][0] - C[0]*T2[0][1]) / det };
324 T Dd = (B[0]*Cd[0] + B[1]*Cd[1]) * (t/two) + D;
325
326 Cd[0] *= r;
327 Cd[1] *= r;
328
329 // convert roots to polynomial
330 internal::roots2poly(Ad, coeffs_out.a1, coeffs_out.a2);
331
332 T Tmp[2][2] = { { Ad[0][0]-Bd[0]*Cd[0], Ad[0][1]-Bd[0]*Cd[1] },
333 { Ad[1][0]-Bd[1]*Cd[0], Ad[1][1]-Bd[1]*Cd[1] } };
334
335 internal::roots2poly(Tmp, coeffs_out.b1, coeffs_out.b2);
336
337 coeffs_out.b0 = Dd;
338 coeffs_out.b1 += (Dd-one)*coeffs_out.a1;
339 coeffs_out.b2 += (Dd-one)*coeffs_out.a2;
340
341 return coeffs_out;
342}
343
344} // namespace apf
345
346#endif
void roots2poly(T Roots[2][2], T &poly1, T &poly2)
Roots-to-polynomial conversion.
Definition: biquad.h:254
Direct Form II recursive filter of second order.
Definition: biquad.h:146
result_type operator()(argument_type in)
Process filter on single sample.
Definition: biquad.h:166
BiQuad & operator=(const SosCoefficients< T > &c)
Assignment operator.
Definition: biquad.h:157
Cascade of filter sections.
Definition: biquad.h:186
void set(I first, I last)
Overwrite sections with new content.
Definition: biquad.h:200
result_type operator()(argument_type in)
Process all sections on single sample.
Definition: biquad.h:210
Cascade(size_type n)
Constructor.
Definition: biquad.h:193
void execute(In first, In last, Out result)
Process all sections on audio block.
Definition: biquad.h:226
Different methods to prevent denormal numbers.
Mathematical constants and helper functions.
Audio Processing Framework.
Definition: iterator.h:61
SosCoefficients< T > bilinear(LaplaceCoefficients< T > coeffs_in, int fs, int fp)
Bilinear transform.
Definition: biquad.h:289
Coefficients of analog recursive filter.
Definition: biquad.h:128
Coefficients of digital recursive filter (second order section).
Definition: biquad.h:53