void TempoTapDegara::createViterbiTransitionMatrix() {
  // Prepare a transition matrix for Viterbi algorithm: it is a _hopSizeODF x
  // _hopSizeODF matrix, where each column i consists of a gaussian centered
  // at i, with stddev=8 by default (i.e., when _hopSizeODF=128), and leave
  // columns before 28th and after 108th zeroed, as well as the lines before
  // 28th and after 108th. Paper: informal tests revealed that stddev parameter
  // can vary by a factor of 2 without altering the overall performance of beat
  // tracker.

  // Generalize values to any ODF sample rate.

  _transitionsViterbi.resize(_hopSizeODF);
  for (int i=0; i<_hopSizeODF; ++i) {
    _transitionsViterbi[i].resize(_hopSizeODF);
  }

  Real scale = _sampleRateODF / (44100./512);

  // each sequent column contains a gaussian shifted by 1 line
  vector<Real> gaussian;
  gaussianPDF(gaussian, 8*scale, 1.);

  int minIndex = floor(28 * scale) - 1;  // because 0-th index is 1st column/line
  int maxIndex = ceil(108 * scale) - 1;
  int gaussianMean = gaussian.size() / 2;

  for (int i=minIndex; i<=maxIndex; ++i) {
    // gaussian with mean=i, std=8*scale;
    for (int j=i-gaussianMean; j<=i+gaussianMean; ++j) {
      if (j>=minIndex && j <= maxIndex) {
        _transitionsViterbi[i][j] = gaussian[j - (i-gaussianMean)];
      }
    }
  }
}
void TempoTapDegara::computeBeatsDegara(vector <Real>& detections,
                        const vector<Real>& beatPeriods,
                        const vector<Real>& beatEndPositions,
                        vector<Real>& ticks) {

  // Implementation of Degara's beat tracking using a probabilitic framework
  // (Hidden Markov Model). Tempo estimations throughout the track are assumed
  // to be computed from the algorithm by M. Davies.

  // avoid zeros to avoid log(0) error in future
  for(size_t i=0; i<detections.size(); ++i) {
    if (detections[i]==0) {
      detections[i] = numeric_limits<Real>::epsilon();
    }
  }

  // Minimum tempo (i.e., maximum period) to be considered
  Real periodMax = beatPeriods[argmax(beatPeriods)];
  // The number of states of the HMM is determined bt the largest time between
  // beats allowed (periodMax + 3 standard deviations). Compute a list of
  // inter-beat time intervals corresponding to each state (ignore zero period):
  vector<Real> ibi;
  Real ibiMax = periodMax + 3 *_sigma_ibi;

  ibi.reserve(ceil(ibiMax / _resolutionODF));
  for (Real t=_resolutionODF; t<=ibiMax; t+=_resolutionODF) {
    ibi.push_back(t);
  }
  _numberStates = (int) ibi.size();

  // Compute transition matrix from the inter-beat-interval distribution
  // according to the tempo estimates. Transition matrix is unique for each beat
  // period.
  map<Real, vector<vector<Real> > > transitionMatrix;
  vector<Real> gaussian;
  vector<Real> ibiPDF(_numberStates);

  gaussianPDF(gaussian, _sigma_ibi, _resolutionODF, 0.01 / _resample);
  // Scale down to avoid computational errors,
  // * _resolutionODF, as in matlab code, works worse

  for (size_t i=0; i<beatPeriods.size(); ++i) {
    // no need to recompute if we have seen this beat period before
    if (transitionMatrix.count(beatPeriods[i])==0) {
      // Shift gaussian vector to be centered at beatPeriods[i] secs which is
      // equivalent to round(beatPeriods[i] / _resolutionODF) samples.
      int shift = (int) gaussian.size()/2 - round(beatPeriods[i]/_resolutionODF - 1);
      for (int j=0; j<_numberStates; ++j) {
        int j_new = j + shift;
        ibiPDF[j] = j_new < 0 || j_new >= (int) gaussian.size() ? 0 : gaussian[j_new];
      }
      computeHMMTransitionMatrix(ibiPDF, transitionMatrix[beatPeriods[i]]);
    }
  }

  // Compute observation likelihoods for each HMM state
  vector<vector<Real> > biy;   // _numberStates x _numberFramesODF
  biy.reserve(_numberStates);

  // treat ODF as probability, normalize to 0.99 to avoid numerical problems
  _numberFrames = detections.size();
  vector<Real> beatProbability(_numberFrames);
  vector<Real> noBeatProbability(_numberFrames);
  for (size_t i=0; i<_numberFrames; ++i) {
    beatProbability[i] = 0.99 * detections[i];
    noBeatProbability[i] = 1. - beatProbability[i];
    // NB: work in log space to avoid numerical issues
    beatProbability[i] = (1-_alpha) * log(beatProbability[i]);
    noBeatProbability[i] = (1-_alpha) * log(noBeatProbability[i]);
  }

  biy.push_back(beatProbability);
  biy.insert(biy.end(), _numberStates-1, noBeatProbability);

  // Decoding
  vector<int> stateSequence;
  decodeBeats(transitionMatrix, beatPeriods, beatEndPositions, biy, stateSequence);
  for (size_t i=0; i<stateSequence.size(); ++i) {
    if (stateSequence[i] == 0) { // beat detected
      ticks.push_back(i * _resolutionODF);
    }
  }
}
// sample a new pose from a given command and previous pose
// see Table 5.3 - Probabilistic Robotics
void SampleVelocityModel::samplePose2D(Pose2D *p) {

    // auxiliar variables
    double v, w, y, v2, w2, dt, vw, *pose;

    // get the current pose
    pose = p->v;

    // iterate over the Velocity Commands
    for (int j = 0; j < commands.size() - 1; j++) {

        // just to be easy to write and reduce repetitive multiplication
        v2 = std::fabs(commands[j].linear);
        w2 = std::fabs(commands[j].angular);

        // the time betwen the current and the next command
        // the last command in this command vector is a hack
        // just to obtain the time from the laser and set the last command as
        // the first one in the next MCL call (next LaserScan)
        dt = (commands[j+1].stamp - commands[j].stamp).toSec();

        if (real_world) {

            // get the linear velocity
            v = commands[j].linear + gaussianPDF(a1*v2 + a2*w2);

            // get the angular velocity
            w = commands[j].angular + gaussianPDF(a3*v2 + a4*w2);

        } else {

            // get the linear velocity
            v = commands[j].linear*1.2 + gaussianPDF(a1*v2 + a2*w2);

            // get the angular velocity
            w = commands[j].angular*1.5 + gaussianPDF(a3*v2 + a4*w2);

        }

        // get the final angle extra noisy angular velocity
        y = gaussianPDF(a5*v2 + a6*w2);

        // updates the pose based on this current command
        // verify if the angular is zero or very close to zero

        if (0.0 != commands[j].angular) {

            // here we can use the given algorithm directly
            vw = v/w;

            // get the x distance
            pose[0] += - vw*sin(pose[2]) + vw*sin(pose[2] + w*dt);

            // get the y distance
            pose[1] += (vw*cos(pose[2]) - vw*cos(pose[2] + w*dt));

            // get the new angle
            pose[2] += w*dt + y*dt;


        } else if (0.0 != commands[j].linear) {

            // get the x distance
            pose[0] += v*cos(pose[2])*dt;

            // get the y distance
            pose[1] += v*sin(pose[2])*dt;

            // get the new angle, just adding some noise
            pose[2] += y*dt;


        } else {

            // just return
            return;

        }

        // angular velocity
        // maintain the orientation between -PI/2 and PI/2
        pose[2] = mrpt::math::wrapToPi(pose[2]);

    }

}