andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 IIRFilter.cpp: template class handling an Nth-order IIR filter on data
|
andrewm@0
|
21 in a given Node.
|
andrewm@0
|
22 */
|
andrewm@0
|
23
|
andrewm@20
|
24 #ifdef _MSC_VER
|
andrewm@20
|
25 #define _USE_MATH_DEFINES
|
andrewm@20
|
26 #endif
|
andrewm@20
|
27 #include <cmath>
|
andrewm@0
|
28 #include "IIRFilter.h"
|
andrewm@0
|
29
|
andrewm@0
|
30 // These are static functions to design IIR filters specifically for floating-point datatypes.
|
andrewm@0
|
31 // vector<double> and be converted to another type at the end if needed.
|
andrewm@0
|
32
|
andrewm@0
|
33 void designFirstOrderLowpass(std::vector<double>& bCoeffs, std::vector<double>& aCoeffs,
|
andrewm@0
|
34 double cutoffFrequency, double sampleFrequency) {
|
andrewm@0
|
35 bCoeffs.clear();
|
andrewm@0
|
36 aCoeffs.clear();
|
andrewm@0
|
37
|
andrewm@0
|
38 double omega = tan(M_PI * cutoffFrequency / sampleFrequency);
|
andrewm@0
|
39 double n = 1.0 / (1.0 + omega);
|
andrewm@0
|
40
|
andrewm@0
|
41 bCoeffs.push_back(omega * n); // B0
|
andrewm@0
|
42 bCoeffs.push_back(omega * n); // B1
|
andrewm@0
|
43 aCoeffs.push_back((omega - 1) * n); // A1
|
andrewm@0
|
44 }
|
andrewm@0
|
45
|
andrewm@0
|
46 void designFirstOrderHighpass(std::vector<double>& bCoeffs, std::vector<double>& aCoeffs,
|
andrewm@0
|
47 double cutoffFrequency, double sampleFrequency) {
|
andrewm@0
|
48 bCoeffs.clear();
|
andrewm@0
|
49 aCoeffs.clear();
|
andrewm@0
|
50
|
andrewm@0
|
51 double omega = tan(M_PI * cutoffFrequency / sampleFrequency);
|
andrewm@0
|
52 double n = 1.0 / (1.0 + omega);
|
andrewm@0
|
53
|
andrewm@0
|
54 bCoeffs.push_back(n); // B0
|
andrewm@0
|
55 bCoeffs.push_back(-n); // B1
|
andrewm@0
|
56 aCoeffs.push_back((omega - 1) * n); // A1
|
andrewm@0
|
57 }
|
andrewm@0
|
58
|
andrewm@0
|
59 void designSecondOrderLowpass(std::vector<double>& bCoeffs, std::vector<double>& aCoeffs,
|
andrewm@0
|
60 double cutoffFrequency, double q, double sampleFrequency) {
|
andrewm@0
|
61 bCoeffs.clear();
|
andrewm@0
|
62 aCoeffs.clear();
|
andrewm@0
|
63
|
andrewm@0
|
64 double omega = tan(M_PI * cutoffFrequency / sampleFrequency);
|
andrewm@0
|
65 double n = 1.0 / (omega*omega + omega/q + 1.0);
|
andrewm@0
|
66 double b0 = n * omega * omega;
|
andrewm@0
|
67
|
andrewm@0
|
68 bCoeffs.push_back(b0); // B0
|
andrewm@0
|
69 bCoeffs.push_back(2.0 * b0); // B1
|
andrewm@0
|
70 bCoeffs.push_back(b0); // B2
|
andrewm@0
|
71 aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1
|
andrewm@0
|
72 aCoeffs.push_back(n * (omega * omega - omega / q + 1.0));
|
andrewm@0
|
73 }
|
andrewm@0
|
74
|
andrewm@0
|
75 void designSecondOrderHighpass(std::vector<double>& bCoeffs, std::vector<double>& aCoeffs,
|
andrewm@0
|
76 double cutoffFrequency, double q, double sampleFrequency) {
|
andrewm@0
|
77 bCoeffs.clear();
|
andrewm@0
|
78 aCoeffs.clear();
|
andrewm@0
|
79
|
andrewm@0
|
80 double omega = tan(M_PI * cutoffFrequency / sampleFrequency);
|
andrewm@0
|
81 double n = 1.0 / (omega*omega + omega/q + 1.0);
|
andrewm@0
|
82
|
andrewm@0
|
83 bCoeffs.push_back(n); // B0
|
andrewm@0
|
84 bCoeffs.push_back(-2.0 * n); // B1
|
andrewm@0
|
85 bCoeffs.push_back(n); // B2
|
andrewm@0
|
86 aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1
|
andrewm@0
|
87 aCoeffs.push_back(n * (omega * omega - omega / q + 1.0));
|
andrewm@0
|
88 }
|
andrewm@0
|
89
|
andrewm@0
|
90 void designSecondOrderBandpass(std::vector<double>& bCoeffs, std::vector<double>& aCoeffs,
|
andrewm@0
|
91 double cutoffFrequency, double q, double sampleFrequency) {
|
andrewm@0
|
92 bCoeffs.clear();
|
andrewm@0
|
93 aCoeffs.clear();
|
andrewm@0
|
94
|
andrewm@0
|
95 double omega = tan(M_PI * cutoffFrequency / sampleFrequency);
|
andrewm@0
|
96 double n = 1.0 / (omega*omega + omega/q + 1.0);
|
andrewm@0
|
97 double b0 = n * omega / q;
|
andrewm@0
|
98 bCoeffs.push_back(b0); // B0
|
andrewm@0
|
99 bCoeffs.push_back(0.0); // B1
|
andrewm@0
|
100 bCoeffs.push_back(-b0); // B2
|
andrewm@0
|
101 aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1
|
andrewm@0
|
102 aCoeffs.push_back(n * (omega * omega - omega / q + 1.0));
|
andrewm@0
|
103 } |