andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: IIRFilter.cpp: template class handling an Nth-order IIR filter on data andrewm@0: in a given Node. andrewm@0: */ andrewm@0: andrewm@20: #ifdef _MSC_VER andrewm@20: #define _USE_MATH_DEFINES andrewm@20: #endif andrewm@20: #include andrewm@0: #include "IIRFilter.h" andrewm@0: andrewm@0: // These are static functions to design IIR filters specifically for floating-point datatypes. andrewm@0: // vector and be converted to another type at the end if needed. andrewm@0: andrewm@0: void designFirstOrderLowpass(std::vector& bCoeffs, std::vector& aCoeffs, andrewm@0: double cutoffFrequency, double sampleFrequency) { andrewm@0: bCoeffs.clear(); andrewm@0: aCoeffs.clear(); andrewm@0: andrewm@0: double omega = tan(M_PI * cutoffFrequency / sampleFrequency); andrewm@0: double n = 1.0 / (1.0 + omega); andrewm@0: andrewm@0: bCoeffs.push_back(omega * n); // B0 andrewm@0: bCoeffs.push_back(omega * n); // B1 andrewm@0: aCoeffs.push_back((omega - 1) * n); // A1 andrewm@0: } andrewm@0: andrewm@0: void designFirstOrderHighpass(std::vector& bCoeffs, std::vector& aCoeffs, andrewm@0: double cutoffFrequency, double sampleFrequency) { andrewm@0: bCoeffs.clear(); andrewm@0: aCoeffs.clear(); andrewm@0: andrewm@0: double omega = tan(M_PI * cutoffFrequency / sampleFrequency); andrewm@0: double n = 1.0 / (1.0 + omega); andrewm@0: andrewm@0: bCoeffs.push_back(n); // B0 andrewm@0: bCoeffs.push_back(-n); // B1 andrewm@0: aCoeffs.push_back((omega - 1) * n); // A1 andrewm@0: } andrewm@0: andrewm@0: void designSecondOrderLowpass(std::vector& bCoeffs, std::vector& aCoeffs, andrewm@0: double cutoffFrequency, double q, double sampleFrequency) { andrewm@0: bCoeffs.clear(); andrewm@0: aCoeffs.clear(); andrewm@0: andrewm@0: double omega = tan(M_PI * cutoffFrequency / sampleFrequency); andrewm@0: double n = 1.0 / (omega*omega + omega/q + 1.0); andrewm@0: double b0 = n * omega * omega; andrewm@0: andrewm@0: bCoeffs.push_back(b0); // B0 andrewm@0: bCoeffs.push_back(2.0 * b0); // B1 andrewm@0: bCoeffs.push_back(b0); // B2 andrewm@0: aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1 andrewm@0: aCoeffs.push_back(n * (omega * omega - omega / q + 1.0)); andrewm@0: } andrewm@0: andrewm@0: void designSecondOrderHighpass(std::vector& bCoeffs, std::vector& aCoeffs, andrewm@0: double cutoffFrequency, double q, double sampleFrequency) { andrewm@0: bCoeffs.clear(); andrewm@0: aCoeffs.clear(); andrewm@0: andrewm@0: double omega = tan(M_PI * cutoffFrequency / sampleFrequency); andrewm@0: double n = 1.0 / (omega*omega + omega/q + 1.0); andrewm@0: andrewm@0: bCoeffs.push_back(n); // B0 andrewm@0: bCoeffs.push_back(-2.0 * n); // B1 andrewm@0: bCoeffs.push_back(n); // B2 andrewm@0: aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1 andrewm@0: aCoeffs.push_back(n * (omega * omega - omega / q + 1.0)); andrewm@0: } andrewm@0: andrewm@0: void designSecondOrderBandpass(std::vector& bCoeffs, std::vector& aCoeffs, andrewm@0: double cutoffFrequency, double q, double sampleFrequency) { andrewm@0: bCoeffs.clear(); andrewm@0: aCoeffs.clear(); andrewm@0: andrewm@0: double omega = tan(M_PI * cutoffFrequency / sampleFrequency); andrewm@0: double n = 1.0 / (omega*omega + omega/q + 1.0); andrewm@0: double b0 = n * omega / q; andrewm@0: bCoeffs.push_back(b0); // B0 andrewm@0: bCoeffs.push_back(0.0); // B1 andrewm@0: bCoeffs.push_back(-b0); // B2 andrewm@0: aCoeffs.push_back(2.0 * n * (omega * omega - 1.0)); // A1 andrewm@0: aCoeffs.push_back(n * (omega * omega - omega / q + 1.0)); andrewm@0: }