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