annotate SparseHMM.cpp @ 131:b877df85ad9e fixedlag

mono pitch works now with the refactored HMM implementation
author Matthias Mauch <mail@matthiasmauch.net>
date Fri, 03 Jul 2015 14:09:05 +0100
parents 080fe18f5ebf
children 926c292fa3ff
rev   line source
Chris@9 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@9 2
Chris@9 3 /*
Chris@9 4 pYIN - A fundamental frequency estimator for monophonic audio
Chris@9 5 Centre for Digital Music, Queen Mary, University of London.
Chris@9 6
Chris@9 7 This program is free software; you can redistribute it and/or
Chris@9 8 modify it under the terms of the GNU General Public License as
Chris@9 9 published by the Free Software Foundation; either version 2 of the
Chris@9 10 License, or (at your option) any later version. See the file
Chris@9 11 COPYING included with this distribution for more information.
Chris@9 12 */
Chris@9 13
matthiasm@0 14 #include "SparseHMM.h"
matthiasm@0 15 #include <vector>
matthiasm@0 16 #include <cstdio>
matthiasm@0 17 #include <iostream>
matthiasm@0 18
matthiasm@0 19 using std::vector;
matthiasm@0 20 using std::pair;
matthiasm@0 21
mail@130 22 SparseHMM::SparseHMM() :
mail@130 23 m_nState(0),
mail@130 24 m_nTrans(0),
mail@130 25 m_init(0),
mail@130 26 m_from(0),
mail@130 27 m_to(0),
mail@130 28 m_transProb(0),
mail@130 29 m_scale(0),
mail@130 30 m_psi(0),
mail@130 31 m_delta(0),
mail@130 32 m_oldDelta(0)
mail@130 33 {
mail@130 34
mail@130 35 }
mail@130 36
matthiasm@0 37 const vector<double>
matthiasm@0 38 SparseHMM::calculateObsProb(const vector<pair<double, double> > data)
matthiasm@0 39 {
matthiasm@0 40 // dummy (virtual?) implementation to be overloaded
matthiasm@0 41 return(vector<double>());
matthiasm@0 42 }
matthiasm@0 43
mail@130 44 void
mail@130 45 SparseHMM::build()
mail@130 46 { }
mail@130 47
matthiasm@0 48 const std::vector<int>
mail@130 49 SparseHMM::decodeViterbi(std::vector<vector<double> > obsProb)
matthiasm@0 50 {
mail@130 51 size_t nFrame = obsProb.size();
mail@130 52 if (nFrame < 1) {
Chris@38 53 return vector<int>();
Chris@38 54 }
mail@131 55
mail@130 56 initialise(obsProb[0]);
matthiasm@0 57
matthiasm@0 58 // rest of forward step
matthiasm@0 59 for (size_t iFrame = 1; iFrame < nFrame; ++iFrame)
matthiasm@0 60 {
mail@130 61 process(obsProb[iFrame]);
mail@130 62 }
matthiasm@0 63
mail@130 64 vector<int> path = finalise();
mail@130 65 return(path);
mail@130 66 }
mail@130 67
mail@131 68 void
mail@131 69 SparseHMM::reset()
mail@131 70 {
mail@131 71 m_scale.clear();
mail@131 72 m_psi.clear();
mail@131 73 for (size_t i = 0; i < m_delta.size(); ++i) m_delta[i] = 0;
mail@131 74 for (size_t i = 0; i < m_oldDelta.size(); ++i) m_oldDelta[i] = 0;
mail@131 75 }
mail@130 76
mail@130 77 void
mail@130 78 SparseHMM::initialise(vector<double> firstObs)
mail@130 79 {
mail@131 80 reset();
mail@131 81
mail@130 82 double deltasum = 0;
mail@130 83
mail@130 84 // initialise first frame
mail@130 85 for (size_t iState = 0; iState < m_nState; ++iState)
mail@130 86 {
mail@130 87 m_oldDelta[iState] = m_init[iState] * firstObs[iState];
mail@130 88 deltasum += m_oldDelta[iState];
mail@130 89 }
mail@130 90
mail@130 91 for (size_t iState = 0; iState < m_nState; ++iState)
mail@130 92 {
mail@130 93 m_oldDelta[iState] /= deltasum; // normalise (scale)
mail@130 94 }
mail@130 95
mail@130 96 m_scale.push_back(1.0/deltasum);
mail@130 97 m_psi.push_back(vector<int>(m_nState,0));
mail@130 98 }
mail@130 99
mail@130 100 int
mail@130 101 SparseHMM::process(vector<double> newObs)
mail@130 102 {
mail@130 103 vector<int> tempPsi = vector<int>(m_nState,0);
mail@130 104
mail@130 105 // calculate best previous state for every current state
mail@130 106 size_t fromState;
mail@130 107 size_t toState;
mail@130 108 double currentTransProb;
mail@130 109 double currentValue;
mail@130 110
mail@130 111 // this is the "sparse" loop
mail@130 112 for (size_t iTrans = 0; iTrans < m_nTrans; ++iTrans)
mail@130 113 {
mail@130 114 fromState = m_from[iTrans];
mail@130 115 toState = m_to[iTrans];
mail@130 116 currentTransProb = m_transProb[iTrans];
matthiasm@0 117
mail@130 118 currentValue = m_oldDelta[fromState] * currentTransProb;
mail@130 119 if (currentValue > m_delta[toState])
matthiasm@0 120 {
mail@130 121 // will be multiplied by the right obs later!
mail@130 122 m_delta[toState] = currentValue;
mail@130 123 tempPsi[toState] = fromState;
matthiasm@0 124 }
matthiasm@0 125 }
mail@130 126 m_psi.push_back(tempPsi);
matthiasm@0 127
mail@130 128
mail@130 129 double deltasum = 0;
mail@130 130 for (size_t jState = 0; jState < m_nState; ++jState)
mail@130 131 {
mail@130 132 m_delta[jState] *= newObs[jState];
mail@130 133 deltasum += m_delta[jState];
mail@130 134 }
mail@130 135
mail@130 136 if (deltasum > 0)
mail@130 137 {
mail@130 138 for (size_t iState = 0; iState < m_nState; ++iState)
mail@130 139 {
mail@130 140 m_oldDelta[iState] = m_delta[iState] / deltasum;// normalise (scale)
mail@130 141 m_delta[iState] = 0;
mail@130 142 }
mail@130 143 m_scale.push_back(1.0/deltasum);
mail@130 144 } else
mail@130 145 {
mail@130 146 std::cerr << "WARNING: Viterbi has been fed some zero "
mail@130 147 "probabilities, at least they become zero "
mail@130 148 "in combination with the model." << std::endl;
mail@130 149 for (size_t iState = 0; iState < m_nState; ++iState)
mail@130 150 {
mail@130 151 m_oldDelta[iState] = 1.0/m_nState;
mail@130 152 m_delta[iState] = 0;
mail@130 153 }
mail@130 154 m_scale.push_back(1.0);
mail@130 155 }
mail@130 156 return 0;
mail@130 157 }
mail@130 158
mail@130 159 vector<int>
mail@130 160 SparseHMM::finalise()
mail@130 161 {
matthiasm@0 162 // initialise backward step
mail@130 163 size_t nFrame = m_psi.size();
mail@130 164
mail@130 165 // The final output path (current assignment arbitrary, makes sense only for
mail@130 166 // Chordino, where nChord-1 is the "no chord" label)
mail@130 167 vector<int> path = vector<int>(nFrame, m_nState-1);
mail@130 168
matthiasm@0 169 double bestValue = 0;
mail@130 170 for (size_t iState = 0; iState < m_nState; ++iState)
matthiasm@0 171 {
mail@130 172 double currentValue = m_oldDelta[iState];
matthiasm@0 173 if (currentValue > bestValue)
matthiasm@0 174 {
matthiasm@0 175 bestValue = currentValue;
matthiasm@0 176 path[nFrame-1] = iState;
matthiasm@0 177 }
matthiasm@0 178 }
matthiasm@0 179
mail@130 180 // Rest of backward step
matthiasm@0 181 for (int iFrame = nFrame-2; iFrame != -1; --iFrame)
matthiasm@0 182 {
mail@130 183 path[iFrame] = m_psi[iFrame+1][path[iFrame+1]];
matthiasm@0 184 }
mail@130 185
matthiasm@0 186 return path;
mail@130 187 }