annotate src/Modules/Features/ModuleGaussians.cc @ 6:8c859ef1fb75

- Added a basic main function to test that all the can be fitted together - Fixed an initialisation bug in ModuleFileInput that left the buffer size at zero - Added proper description strings to the input and output modules - Fixed an out-by-a-factor-of-1000 bug in the SAI memory allocation (oops) - Added LOG_INFO_NN fucnction to log without a newline. Useful for the ASCII art module chain in aimc.cc.
author tomwalters
date Thu, 18 Feb 2010 19:35:07 +0000
parents decdac21cfc2
children fcbf85ce59fb
rev   line source
tomwalters@0 1 // Copyright 2008-2010, Thomas Walters
tomwalters@0 2 //
tomwalters@0 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@0 4 // http://www.acousticscale.org/AIMC
tomwalters@0 5 //
tomwalters@0 6 // This program is free software: you can redistribute it and/or modify
tomwalters@0 7 // it under the terms of the GNU General Public License as published by
tomwalters@0 8 // the Free Software Foundation, either version 3 of the License, or
tomwalters@0 9 // (at your option) any later version.
tomwalters@0 10 //
tomwalters@0 11 // This program is distributed in the hope that it will be useful,
tomwalters@0 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
tomwalters@0 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
tomwalters@0 14 // GNU General Public License for more details.
tomwalters@0 15 //
tomwalters@0 16 // You should have received a copy of the GNU General Public License
tomwalters@0 17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
tomwalters@0 18
tomwalters@0 19 /*! \file
tomwalters@0 20 * \brief Gaussian features - based on MATLAB code by Christian Feldbauer
tomwalters@0 21 */
tomwalters@0 22
tomwalters@0 23 /*!
tomwalters@1 24 * \author Thomas Walters <tom@acousticscale.org>
tomwalters@0 25 * \date created 2008/06/23
tomwalters@0 26 * \version \$Id: ModuleGaussians.cc 2 2010-02-02 12:59:50Z tcw $
tomwalters@0 27 */
tomwalters@0 28
tomwalters@0 29 #include <math.h>
tomwalters@0 30
tomwalters@0 31 #include "Modules/Features/ModuleGaussians.h"
tomwalters@0 32 #include "Support/Common.h"
tomwalters@0 33
tomwalters@0 34 namespace aimc {
tomwalters@6 35 ModuleGaussians::ModuleGaussians(Parameters *params) : Module(params) {
tomwalters@0 36 // Set module metadata
tomwalters@0 37 module_description_ = "Gaussian Fitting to SSI profile";
tomwalters@1 38 module_identifier_ = "gaussians";
tomwalters@0 39 module_type_ = "features";
tomwalters@0 40 module_version_ = "$Id: ModuleGaussians.cc 2 2010-02-02 12:59:50Z tcw $";
tomwalters@0 41
tomwalters@1 42 m_iParamNComp = parameters_->DefaultInt("features.gaussians.ncomp", 4);
tomwalters@1 43 m_fParamVar = parameters_->DefaultFloat("features.gaussians.var", 115.0);
tomwalters@1 44 m_fParamPosteriorExp =
tomwalters@1 45 parameters_->DefaultFloat("features.gaussians.posterior_exp", 6.0);
tomwalters@1 46 m_iParamMaxIt = parameters_->DefaultInt("features.gaussians.maxit", 250);
tomwalters@0 47
tomwalters@1 48 // The parameters system doesn't support tiny numbers well, to define this
tomwalters@1 49 // variable as a string, then convert it to a float afterwards
tomwalters@1 50 parameters_->DefaultString("features.gaussians.priors_converged", "1e-7");
tomwalters@0 51 m_fParamPriorsConverged =
tomwalters@1 52 parameters_->GetFloat("features.gaussians.priors_converged");
tomwalters@0 53 }
tomwalters@0 54
tomwalters@0 55 ModuleGaussians::~ModuleGaussians() {
tomwalters@0 56 }
tomwalters@0 57
tomwalters@0 58 bool ModuleGaussians::InitializeInternal(const SignalBank &input) {
tomwalters@0 59 m_pA.resize(m_iParamNComp, 0.0f);
tomwalters@0 60 m_pMu.resize(m_iParamNComp, 0.0f);
tomwalters@0 61
tomwalters@0 62 // Assuming the number of channels is greater than twice the number of
tomwalters@0 63 // Gaussian components, this is ok
tomwalters@0 64 if (input.channel_count() >= 2 * m_iParamNComp) {
tomwalters@1 65 output_.Initialize(m_iParamNComp, 1, input.sample_rate());
tomwalters@0 66 } else {
tomwalters@0 67 LOG_ERROR(_T("Too few channels in filterbank to produce sensible "
tomwalters@0 68 "Gaussian features. Either increase the number of filterbank"
tomwalters@0 69 " channels, or decrease the number of Gaussian components"));
tomwalters@0 70 return false;
tomwalters@0 71 }
tomwalters@0 72
tomwalters@0 73 m_iNumChannels = input.channel_count();
tomwalters@0 74 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
tomwalters@0 75
tomwalters@0 76 return true;
tomwalters@0 77 }
tomwalters@0 78
tomwalters@3 79 void ModuleGaussians::ResetInternal() {
tomwalters@0 80 m_pSpectralProfile.clear();
tomwalters@0 81 m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
tomwalters@0 82 }
tomwalters@0 83
tomwalters@0 84 void ModuleGaussians::Process(const SignalBank &input) {
tomwalters@1 85 if (!initialized_) {
tomwalters@1 86 LOG_ERROR(_T("Module ModuleGaussians not initialized."));
tomwalters@1 87 return;
tomwalters@1 88 }
tomwalters@0 89 // Calculate spectral profile
tomwalters@0 90 for (int iChannel = 0;
tomwalters@0 91 iChannel < input.channel_count();
tomwalters@0 92 ++iChannel) {
tomwalters@0 93 m_pSpectralProfile[iChannel] = 0.0f;
tomwalters@0 94 for (int iSample = 0;
tomwalters@0 95 iSample < input.buffer_length();
tomwalters@0 96 ++iSample) {
tomwalters@0 97 m_pSpectralProfile[iChannel] += input[iChannel][iSample];
tomwalters@0 98 }
tomwalters@2 99 m_pSpectralProfile[iChannel] /= static_cast<double>(input.buffer_length());
tomwalters@1 100 }
tomwalters@1 101
tomwalters@2 102 double spectral_profile_sum = 0.0f;
tomwalters@1 103 for (int i = 0; i < input.channel_count(); ++i) {
tomwalters@1 104 spectral_profile_sum += m_pSpectralProfile[i];
tomwalters@1 105 }
tomwalters@1 106
tomwalters@1 107 double logsum = log(spectral_profile_sum);
tomwalters@1 108 if (!isinf(logsum)) {
tomwalters@1 109 output_.set_sample(m_iParamNComp - 1, 0, logsum);
tomwalters@1 110 } else {
tomwalters@1 111 output_.set_sample(m_iParamNComp - 1, 0, -1000.0);
tomwalters@0 112 }
tomwalters@0 113
tomwalters@0 114 for (int iChannel = 0;
tomwalters@0 115 iChannel < input.channel_count();
tomwalters@0 116 ++iChannel) {
tomwalters@0 117 m_pSpectralProfile[iChannel] = pow(m_pSpectralProfile[iChannel], 0.8);
tomwalters@0 118 }
tomwalters@0 119
tomwalters@0 120 RubberGMMCore(2, true);
tomwalters@0 121
tomwalters@2 122 double fMean1 = m_pMu[0];
tomwalters@2 123 double fMean2 = m_pMu[1];
tomwalters@2 124 //LOG_INFO(_T("Orig. mean 0 = %f"), m_pMu[0]);
tomwalters@2 125 //LOG_INFO(_T("Orig. mean 1 = %f"), m_pMu[1]);
tomwalters@2 126 //LOG_INFO(_T("Orig. prob 0 = %f"), m_pA[0]);
tomwalters@2 127 //LOG_INFO(_T("Orig. prob 1 = %f"), m_pA[1]);
tomwalters@0 128
tomwalters@2 129 double fA1 = 0.05 * m_pA[0];
tomwalters@2 130 double fA2 = 1.0 - 0.25 * m_pA[1];
tomwalters@0 131
tomwalters@2 132 //LOG_INFO(_T("fA1 = %f"), fA1);
tomwalters@2 133 //LOG_INFO(_T("fA2 = %f"), fA2);
tomwalters@2 134
tomwalters@2 135 double fGradient = (fMean2 - fMean1) / (fA2 - fA1);
tomwalters@2 136 double fIntercept = fMean2 - fGradient * fA2;
tomwalters@2 137
tomwalters@2 138 //LOG_INFO(_T("fGradient = %f"), fGradient);
tomwalters@2 139 //LOG_INFO(_T("fIntercept = %f"), fIntercept);
tomwalters@0 140
tomwalters@0 141 for (int i = 0; i < m_iParamNComp; ++i) {
tomwalters@2 142 m_pMu[i] = ((double)i / ((double)m_iParamNComp - 1.0f))
tomwalters@2 143 * fGradient + fIntercept;
tomwalters@2 144 //LOG_INFO(_T("mean %d = %f"), i, m_pMu[i]);
tomwalters@0 145 }
tomwalters@0 146
tomwalters@0 147 for (int i = 0; i < m_iParamNComp; ++i) {
tomwalters@2 148 m_pA[i] = 1.0f / (double)m_iParamNComp;
tomwalters@0 149 }
tomwalters@0 150
tomwalters@0 151 RubberGMMCore(m_iParamNComp, false);
tomwalters@0 152
tomwalters@0 153 for (int i = 0; i < m_iParamNComp - 1; ++i) {
tomwalters@0 154 if (!isnan(m_pA[i])) {
tomwalters@0 155 output_.set_sample(i, 0, m_pA[i]);
tomwalters@0 156 } else {
tomwalters@0 157 output_.set_sample(i, 0, 0.0f);
tomwalters@0 158 }
tomwalters@0 159 }
tomwalters@1 160
tomwalters@0 161 PushOutput();
tomwalters@0 162 }
tomwalters@0 163
tomwalters@0 164 bool ModuleGaussians::RubberGMMCore(int iNComponents, bool bDoInit) {
tomwalters@0 165 int iSizeX = m_iNumChannels;
tomwalters@0 166
tomwalters@0 167 // Normalise the spectral profile
tomwalters@2 168 double fSpectralProfileTotal = 0.0f;
tomwalters@0 169 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@0 170 fSpectralProfileTotal += m_pSpectralProfile[iCount];
tomwalters@0 171 }
tomwalters@0 172 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@0 173 m_pSpectralProfile[iCount] /= fSpectralProfileTotal;
tomwalters@0 174 }
tomwalters@0 175
tomwalters@0 176 if (bDoInit) {
tomwalters@0 177 // Uniformly spaced components
tomwalters@2 178 double dd = (iSizeX - 1.0f) / iNComponents;
tomwalters@0 179 for (int i = 0; i < iNComponents; i++) {
tomwalters@0 180 m_pMu[i] = dd / 2.0f + (i * dd);
tomwalters@0 181 m_pA[i] = 1.0f / iNComponents;
tomwalters@0 182 }
tomwalters@0 183 }
tomwalters@0 184
tomwalters@2 185 vector<double> pA_old;
tomwalters@0 186 pA_old.resize(iNComponents);
tomwalters@2 187 vector<double> pP_mod_X;
tomwalters@0 188 pP_mod_X.resize(iSizeX);
tomwalters@2 189 vector<double> pP_comp;
tomwalters@0 190 pP_comp.resize(iSizeX * iNComponents);
tomwalters@0 191
tomwalters@0 192 for (int iIteration = 0; iIteration < m_iParamMaxIt; iIteration++) {
tomwalters@0 193 // (re)calculate posteriors (component probability given observation)
tomwalters@0 194 // denominator: the model density at all observation points X
tomwalters@0 195 for (int i = 0; i < iSizeX; ++i) {
tomwalters@0 196 pP_mod_X[i] = 0.0f;
tomwalters@0 197 }
tomwalters@0 198
tomwalters@0 199 for (int i = 0; i < iNComponents; i++) {
tomwalters@0 200 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@0 201 pP_mod_X[iCount] += 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
tomwalters@2 202 * exp((-0.5f) * pow(((double)(iCount + 1)-m_pMu[i]), 2)
tomwalters@0 203 / m_fParamVar) * m_pA[i];
tomwalters@0 204 }
tomwalters@0 205 }
tomwalters@0 206
tomwalters@0 207 for (int i = 0; i < iSizeX * iNComponents; ++i) {
tomwalters@0 208 pP_comp[i] = 0.0f;
tomwalters@0 209 }
tomwalters@0 210
tomwalters@0 211 for (int i = 0; i < iNComponents; i++) {
tomwalters@0 212 for (int iCount = 0; iCount < iSizeX; iCount++) {
tomwalters@0 213 pP_comp[iCount + i * iSizeX] =
tomwalters@0 214 1.0f / sqrt(2.0f * M_PI * m_fParamVar)
tomwalters@2 215 * exp((-0.5f) * pow(((double)(iCount + 1) - m_pMu[i]), 2) / m_fParamVar);
tomwalters@0 216 pP_comp[iCount + i * iSizeX] =
tomwalters@0 217 pP_comp[iCount + i * iSizeX] * m_pA[i] / pP_mod_X[iCount];
tomwalters@0 218 }
tomwalters@0 219 }
tomwalters@0 220
tomwalters@0 221 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@2 222 double fSum = 0.0f;
tomwalters@0 223 for (int i = 0; i < iNComponents; ++i) {
tomwalters@0 224 pP_comp[iCount+i*iSizeX] = pow(pP_comp[iCount + i * iSizeX],
tomwalters@0 225 m_fParamPosteriorExp); // expansion
tomwalters@0 226 fSum += pP_comp[iCount+i*iSizeX];
tomwalters@0 227 }
tomwalters@0 228 for (int i = 0; i < iNComponents; ++i)
tomwalters@0 229 pP_comp[iCount+i*iSizeX] = pP_comp[iCount + i * iSizeX] / fSum;
tomwalters@0 230 // renormalisation
tomwalters@0 231 }
tomwalters@0 232
tomwalters@0 233 for (int i = 0; i < iNComponents; ++i) {
tomwalters@0 234 pA_old[i] = m_pA[i];
tomwalters@0 235 m_pA[i] = 0.0f;
tomwalters@0 236 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@0 237 m_pA[i] += pP_comp[iCount + i * iSizeX] * m_pSpectralProfile[iCount];
tomwalters@0 238 }
tomwalters@0 239 }
tomwalters@0 240
tomwalters@0 241 // finish when already converged
tomwalters@2 242 double fPrdist = 0.0f;
tomwalters@0 243 for (int i = 0; i < iNComponents; ++i) {
tomwalters@0 244 fPrdist += pow((m_pA[i] - pA_old[i]), 2);
tomwalters@0 245 }
tomwalters@0 246 fPrdist /= iNComponents;
tomwalters@0 247
tomwalters@0 248 if (fPrdist < m_fParamPriorsConverged) {
tomwalters@2 249 //LOG_INFO("Converged!");
tomwalters@0 250 break;
tomwalters@0 251 }
tomwalters@2 252 //LOG_INFO("Didn't converge!");
tomwalters@2 253
tomwalters@0 254
tomwalters@0 255 // update means (positions)
tomwalters@0 256 for (int i = 0 ; i < iNComponents; ++i) {
tomwalters@2 257 double mu_old = m_pMu[i];
tomwalters@0 258 if (m_pA[i] > 0.0f) {
tomwalters@0 259 m_pMu[i] = 0.0f;
tomwalters@0 260 for (int iCount = 0; iCount < iSizeX; ++iCount) {
tomwalters@0 261 m_pMu[i] += m_pSpectralProfile[iCount]
tomwalters@2 262 * pP_comp[iCount + i * iSizeX] * (double)(iCount + 1);
tomwalters@0 263 }
tomwalters@0 264 m_pMu[i] /= m_pA[i];
tomwalters@0 265 if (isnan(m_pMu[i])) {
tomwalters@0 266 m_pMu[i] = mu_old;
tomwalters@0 267 }
tomwalters@0 268 }
tomwalters@0 269 }
tomwalters@0 270 } // loop over iterations
tomwalters@0 271
tomwalters@0 272 // Ensure they are sorted, using a really simple bubblesort
tomwalters@0 273 bool bSorted = false;
tomwalters@0 274 while (!bSorted) {
tomwalters@0 275 bSorted = true;
tomwalters@0 276 for (int i = 0; i < iNComponents - 1; ++i) {
tomwalters@0 277 if (m_pMu[i] > m_pMu[i + 1]) {
tomwalters@2 278 double fTemp = m_pMu[i];
tomwalters@0 279 m_pMu[i] = m_pMu[i + 1];
tomwalters@0 280 m_pMu[i + 1] = fTemp;
tomwalters@0 281 fTemp = m_pA[i];
tomwalters@0 282 m_pA[i] = m_pA[i + 1];
tomwalters@0 283 m_pA[i + 1] = fTemp;
tomwalters@0 284 bSorted = false;
tomwalters@0 285 }
tomwalters@0 286 }
tomwalters@0 287 }
tomwalters@0 288 return true;
tomwalters@0 289 }
tomwalters@0 290 } //namespace aimc
tomwalters@0 291