Mercurial > hg > qm-dsp
comparison dsp/rateconversion/DecimatorB.cpp @ 155:529f42b50d81
Add DecimatorB (Butterworth filter, arbitrary powers of two)
author | Chris Cannam |
---|---|
date | Tue, 22 Oct 2013 08:58:28 +0100 |
parents | dsp/rateconversion/Decimator.cpp@e5907ae6de17 |
children | e4a57215ddee |
comparison
equal
deleted
inserted
replaced
154:f47182362b51 | 155:529f42b50d81 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 QM DSP Library | |
5 | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 */ | |
14 | |
15 #include "DecimatorB.h" | |
16 | |
17 #include "maths/MathUtilities.h" | |
18 | |
19 #include <iostream> | |
20 | |
21 using std::vector; | |
22 | |
23 DecimatorB::DecimatorB(int inLength, int decFactor) | |
24 { | |
25 m_inputLength = 0; | |
26 m_outputLength = 0; | |
27 m_decFactor = 1; | |
28 m_aaBuffer = 0; | |
29 m_tmpBuffer = 0; | |
30 | |
31 initialise(inLength, decFactor); | |
32 } | |
33 | |
34 DecimatorB::~DecimatorB() | |
35 { | |
36 deInitialise(); | |
37 } | |
38 | |
39 void DecimatorB::initialise(int inLength, int decFactor) | |
40 { | |
41 m_inputLength = inLength; | |
42 m_decFactor = decFactor; | |
43 m_outputLength = m_inputLength / m_decFactor; | |
44 | |
45 if (m_decFactor < 2 || !MathUtilities::isPowerOfTwo(m_decFactor)) { | |
46 std::cerr << "ERROR: DecimatorB::initialise: Decimation factor must be a power of 2 and at least 2 (was: " << m_decFactor << ")" << std::endl; | |
47 m_decFactor = 0; | |
48 return; | |
49 } | |
50 | |
51 if (m_inputLength % m_decFactor != 0) { | |
52 std::cerr << "ERROR: DecimatorB::initialise: inLength must be a multiple of decimation factor (was: " << m_inputLength << ", factor is " << m_decFactor << ")" << std::endl; | |
53 m_decFactor = 0; | |
54 return; | |
55 } | |
56 | |
57 m_aaBuffer = new double[m_inputLength]; | |
58 m_tmpBuffer = new double[m_inputLength]; | |
59 | |
60 // Order 6 Butterworth lowpass filter | |
61 // Calculated using e.g. MATLAB butter(6, 0.5, 'low') | |
62 | |
63 m_b[0] = 0.029588223638661; | |
64 m_b[1] = 0.177529341831965; | |
65 m_b[2] = 0.443823354579912; | |
66 m_b[3] = 0.591764472773216; | |
67 m_b[4] = 0.443823354579912; | |
68 m_b[5] = 0.177529341831965; | |
69 m_b[6] = 0.029588223638661; | |
70 | |
71 m_a[0] = 1.000000000000000; | |
72 m_a[1] = 0.000000000000000; | |
73 m_a[2] = 0.777695961855673; | |
74 m_a[3] = 0.000000000000000; | |
75 m_a[4] = 0.114199425062434; | |
76 m_a[5] = 0.000000000000000; | |
77 m_a[6] = 0.001750925956183; | |
78 | |
79 for (int factor = m_decFactor; factor > 1; factor /= 2) { | |
80 m_o.push_back(vector<double>(6, 0.0)); | |
81 } | |
82 } | |
83 | |
84 void DecimatorB::deInitialise() | |
85 { | |
86 delete [] m_aaBuffer; | |
87 delete [] m_tmpBuffer; | |
88 } | |
89 | |
90 void DecimatorB::doAntiAlias(const double *src, double *dst, int length, | |
91 int filteridx) | |
92 { | |
93 vector<double> &o = m_o[filteridx]; | |
94 | |
95 for (int i = 0; i < length; i++) { | |
96 | |
97 double input = src[i]; | |
98 double output = input * m_b[0] + o[0]; | |
99 | |
100 o[0] = input * m_b[1] - output * m_a[1] + o[1]; | |
101 o[1] = input * m_b[2] - output * m_a[2] + o[2]; | |
102 o[2] = input * m_b[3] - output * m_a[3] + o[3]; | |
103 o[3] = input * m_b[4] - output * m_a[4] + o[4]; | |
104 o[4] = input * m_b[5] - output * m_a[5] + o[5]; | |
105 o[5] = input * m_b[6] - output * m_a[6]; | |
106 | |
107 dst[i] = output; | |
108 } | |
109 } | |
110 | |
111 void DecimatorB::doProcess() | |
112 { | |
113 int filteridx = 0; | |
114 int factorDone = 1; | |
115 int factorRemaining = m_decFactor; | |
116 | |
117 while (factorDone < m_decFactor) { | |
118 | |
119 doAntiAlias(m_tmpBuffer, m_aaBuffer, | |
120 m_inputLength / factorDone, | |
121 filteridx); | |
122 | |
123 filteridx ++; | |
124 factorDone *= 2; | |
125 | |
126 for (int i = 0; i < m_inputLength / factorDone; ++i) { | |
127 m_tmpBuffer[i] = m_aaBuffer[i * 2]; | |
128 } | |
129 } | |
130 } | |
131 | |
132 void DecimatorB::process(const double *src, double *dst) | |
133 { | |
134 if (m_decFactor == 0) return; | |
135 | |
136 for (int i = 0; i < m_inputLength; ++i) { | |
137 m_tmpBuffer[i] = src[i]; | |
138 } | |
139 | |
140 doProcess(); | |
141 | |
142 for (int i = 0; i < m_outputLength; ++i) { | |
143 dst[i] = m_tmpBuffer[i]; | |
144 } | |
145 } | |
146 | |
147 void DecimatorB::process(const float *src, float *dst) | |
148 { | |
149 if (m_decFactor == 0) return; | |
150 | |
151 for (int i = 0; i < m_inputLength; ++i) { | |
152 m_tmpBuffer[i] = src[i]; | |
153 } | |
154 | |
155 doProcess(); | |
156 | |
157 for (int i = 0; i < m_outputLength; ++i) { | |
158 dst[i] = m_tmpBuffer[i]; | |
159 } | |
160 } |