annotate trunk/src/Modules/Features/ModuleGaussians.cc @ 275:ce2bab04f155

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