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