Mercurial > hg > nnls-chroma
diff viterbi.cpp @ 43:131801714118 matthiasm-plugin
* HMM implementation for chord recognition
author | matthiasm |
---|---|
date | Mon, 25 Oct 2010 00:52:39 +0900 |
parents | |
children | 109d3b2c7105 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/viterbi.cpp Mon Oct 25 00:52:39 2010 +0900 @@ -0,0 +1,85 @@ + +#include "viterbi.h" +#include <iostream> + +std::vector<int> ViterbiPath(std::vector<double> init, std::vector<vector<double> > trans, std::vector<vector<double> > obs) { + + int nState = init.size(); + int nFrame = obs.size(); + // cerr << nState << " " << nFrame << endl; + + // check for consistency + if (trans[0].size() != nState || trans.size() != nState || obs[0].size() != nState) { + cerr << "ERROR: matrix sizes inconsistent." << endl; + } + + vector<vector<double> > delta; // "matrix" of conditional probabilities + vector<vector<int> > psi; // "matrix" of remembered indices of the best transitions + vector<int> path = vector<int>(nFrame, nState-1); // the final output path (current assignment arbitrary, makes sense only for Chordino, where nChord-1 is the "no chord" label) + vector<double> scale = vector<double>(nFrame, 0); // remembers by how much the vectors in delta are scaled. + + double deltasum = 0; + + /* initialise first frame */ + delta.push_back(init); + for (int iState = 0; iState < nState; ++iState) { + delta[0][iState] *= obs[0][iState]; + deltasum += delta[0][iState]; + } + for (int iState = 0; iState < nState; ++iState) delta[0][iState] /= deltasum; // normalise (scale) + scale.push_back(1.0/deltasum); + psi.push_back(vector<int>(nState,0)); + + /* rest of the forward step */ + for (int iFrame = 1; iFrame < nFrame; ++iFrame) { + delta.push_back(vector<double>(nState,0)); + deltasum = 0; + psi.push_back(vector<int>(nState,0)); + /* every state wants to know which previous state suits him best */ + for (int jState = 0; jState < nState; ++jState) { + int bestState = nState - 1; + double bestValue = 0; + for (int iState = 0; iState < nState; ++iState) { + double currentValue = delta[iFrame-1][iState] * trans[iState][jState]; + if (currentValue > bestValue) { + bestValue = currentValue; + bestState = iState; + } + } + // cerr << bestState <<" ::: " << bestValue << endl ; + delta[iFrame][jState] = bestValue * obs[iFrame][jState]; + deltasum += delta[iFrame][jState]; + psi[iFrame][jState] = bestState; + } + if (deltasum > 0) { + for (int iState = 0; iState < nState; ++iState) { + delta[iFrame][iState] /= deltasum; // normalise (scale) + } + scale.push_back(1.0/deltasum); + } else { + for (int iState = 0; iState < nState; ++iState) { + delta[iFrame][iState] = 1.0/nState; + } + scale.push_back(1.0); + } + + } + + /* initialise backward step */ + int bestValue = 0; + for (int iState = 0; iState < nState; ++iState) { + double currentValue = delta[nFrame-1][iState]; + if (currentValue > path[nFrame-1]) { + bestValue = currentValue; + path[nFrame-1] = iState; + } + } + + /* rest of backward step */ + for (int iFrame = nFrame-2; iFrame > -1; --iFrame) { + path[iFrame] = psi[iFrame+1][path[iFrame+1]]; + // cerr << path[iFrame] << endl; + } + + return path; +}