view src/BayesianArrayStructure.cpp @ 1:1a32ce016bb9

Changed bestEstimate timing to work via time sent from Max not the elapsed time. This had caused some problems, but this version now working surprisingly well on MIDI files with variable timing.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 18 Aug 2011 23:27:42 +0100
parents b299a65a3ad0
children 5581023e0de4
line wrap: on
line source
/*
 *  BayesianArrayStructure.cpp
 *  midiCannamReader
 *
 *  Created by Andrew on 17/07/2011.
 *  Copyright 2011 QMUL. All rights reserved.
 *
 */

#include "BayesianArrayStructure.h"

BayesianArrayStructure::BayesianArrayStructure(){
	printf("Bayesian structure: DeFault constructor called");
	
	prior.createVector(1);
	likelihood.createVector(1);
	posterior.createVector(1);

	
	tmpPrior.createVector(240);
	tmpPrior.addGaussianShape(100, 40, 1);
	tmpPrior.addGaussianShape(200, 10, 0.2);
	tmpPrior.translateDistribution(20);
	
	lastEventTime = ofGetElapsedTimeMillis();
	
	speedDecayWidth = 20;
	speedDecayAmount = 10;
}

BayesianArrayStructure::BayesianArrayStructure(int length){
	printf("BAYESIAN STURTUCRE CREATED LENGTH: %i\n", length);
	//this constructor isnt called  it seems
	prior.createVector(length);
	likelihood.createVector(length);
	posterior.createVector(length);

}



void BayesianArrayStructure::resetSize(int length){
	printf("BAYESIAN STRUCTURE size is : %i\n", length);
	
	prior.createVector(length);
	likelihood.createVector(length);
	posterior.createVector(length);
	
	acceleration.createVector(length);
	
}



void BayesianArrayStructure::resetSpeedToOne(){
	relativeSpeedPrior.zero();
	relativeSpeedPosterior.zero();
	relativeSpeedLikelihood.zero();
	
	relativeSpeedPosterior.addGaussianShape(40, 5, 0.6);
	
	relativeSpeedPosterior.addGaussianShape(100, 5, 0.8);
	relativeSpeedPosterior.renormalise();
	relativeSpeedPosterior.getMaximum();
	
	acceleration.addGaussianShape(2000, 20, 0.8);
	
}

void BayesianArrayStructure::resetSpeedSize(int length){
	printf("BAYESIAN SPEED size is : %i\n", length);
	
	relativeSpeedPrior.createVector(length);
	relativeSpeedLikelihood.createVector(length);
	relativeSpeedPosterior.createVector(length);
	
	

}
void BayesianArrayStructure::setRelativeSpeedScalar(double f){
	relativeSpeedPrior.scalar = f;
	relativeSpeedPosterior.scalar = f;
	relativeSpeedLikelihood.scalar = f;
}

void BayesianArrayStructure::simpleExample(){
	//simple example
	prior.addGaussianShape(50, 10, 1);
	prior.addGaussianShape(150, 30, 0.3);
	prior.addGaussianShape(250, 30, 0.2);
	
	likelihood.addGaussianShape(90, 20, 0.6);
	likelihood.addConstant(0.02);
	posterior.doProduct(prior, likelihood);
	
//	relativeSpeedPosterior.addToIndex(100, 1);
//	relativeSpeedPosterior.addToIndex(40, 0.7);	
	relativeSpeedPosterior.addGaussianShape(100, 20, 1);
//	relativeSpeedPosterior.addGaussianShape(10, 2, 0.5);
	relativeSpeedPosterior.getMaximum();
	
}

void BayesianArrayStructure::copyPriorToPosterior(){

	for (int i = 0;i < prior.arraySize;i++){
		posterior.array[i] = prior.array[i];
	}
}

void BayesianArrayStructure::resetArrays(){
	prior.zero();
	likelihood.zero();
	prior.addGaussianShape(0, 80, 1);
	likelihood.addConstant(1);
	posterior.zero();
	posterior.addGaussianShape(0, 60, 1);
	setNewDistributionOffsets(0);
	bestEstimate = 0;
//	lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
	
}

void BayesianArrayStructure::updateBestEstimate(){
	double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime;
	
	bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate);
	// 
	//lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
}

void BayesianArrayStructure::calculatePosterior(){
	posterior.doProduct(prior, likelihood);
	posterior.renormalise();
	
	/*
	int i;
	for (i = 0;i < prior.length;i++){
	//	printf("priori [%i] is %f\n", i, prior[i]);
		*(posterior+i) = *(prior+i);
	//	posterior[i] = likelihood[i] * prior[i];
	}
	 */

	 
}




void BayesianArrayStructure::setNewDistributionOffsets(const double& newOffset){
	prior.offset = newOffset;
	likelihood.offset = newOffset;
//	posterior.offset = newOffset;
}


void BayesianArrayStructure::crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference){
	//set the cutoff for offset of position first! XXX
	
//	printf("time difference %f, ", timeDifference);
	
	double timeDifferenceInPositionVectorUnits = timeDifference / prior.scalar;
	
	prior.zero();//kill prior
	calculateNewPriorOffset(timeDifference);//set new prior offset here
	
	for (int i = 0;i < speed.arraySize;i++){
//		printf("[%i] %f\n", i, speed.array[i]);
		//set speed
		double speedValue = speed.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5

		//so we have moved 
		int distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
		
		if (speed.array[i] != 0){
			
		//	printf("speed [%i] gives %f moved %i\n", i, speedValue, distanceMoved);
			
		for (int postIndex = 0;postIndex < position.arraySize;postIndex++){
		//old posterior contributing to new prior
			int newPriorIndex = postIndex + position.offset - prior.offset + distanceMoved;
			if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){
				prior.addToIndex(newPriorIndex, position.array[postIndex]*speed.array[i]);
			//	printf("adding [%i] : %f\n", newPriorIndex, posterior.array[postIndex]*speed.array[i]);
			}
		
		}
			
		}//if not zero
	}//end speed

	prior.renormalise();

}

void BayesianArrayStructure::calculateNewPriorOffset(const double& timeDifference){
	
	double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate);
	//	printf("Maxspeed is %f\n", maxSpeed);
	
	double priorMax = posterior.getMaximum();
	double distanceTravelled = maxSpeed * (timeDifference / prior.scalar);
	double newMaxLocation = posterior.MAPestimate + distanceTravelled;
	//	printf("MAP: %i, tim df %f, distance %f, new location %f\n", posterior.MAPestimate, timeDifference, distanceTravelled, newMaxLocation);
	
}


void BayesianArrayStructure::decaySpeedDistribution(double timeDifference){
	
	// commented for the moment
	 double relativeAmount = max(1.0, timeDifference/1000.);
//	printf("decay %f around %i \n", timeDifference, relativeSpeedPosterior.MAPestimate);
	relativeAmount *= speedDecayAmount;
	relativeSpeedPosterior.renormalise();
	relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, relativeAmount);
	
	relativeSpeedPosterior.renormalise();
	double newMax = relativeSpeedPosterior.getMaximum();
	
	//old code
//	relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, 10);
	//relativeSpeedPosterior.addConstant(1);
	
	/*
	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
	relativeSpeedLikelihood.zero();
	relativeSpeedLikelihood.addConstant(0.2);
	relativeSpeedLikelihood.addGaussianShape(relativeSpeedPosterior.maximumValue, speedDecayWidth, relativeAmount);
	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
	relativeSpeedPosterior.renormalise();
	 */
	

	
}

void BayesianArrayStructure::updateTempoDistribution(const double& speedRatio, const double& matchFactor){
	//speedratio is speed of played relative to the recording
	
	double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio);
//	printf("\nindex of likelihood would be %f\n", index);
	if (index >= 0 && index < relativeSpeedPrior.length){
		//then we can do update
		
		//set new likelihood
		relativeSpeedLikelihood.zero();
		relativeSpeedLikelihood.addConstant(0.05);
		
	relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5*matchFactor);
	

	//copy posterior to prior
	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);

	//update
	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);

	//normalise
	relativeSpeedPosterior.renormalise();
		
	relativeSpeedPosterior.getMaximum();	
	}//end if within range
	

}


void BayesianArrayStructure::setFlatTempoLikelihood(){	//set new likelihood
	relativeSpeedLikelihood.zero();
	relativeSpeedLikelihood.addConstant(0.3);
}

void BayesianArrayStructure::updateTempoLikelihood(const double& speedRatio, const double& matchFactor){
	
	double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio);

	if (index >= 0 && index < relativeSpeedPrior.length){
		relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5);//*matchFactor);
	}
}


void BayesianArrayStructure::calculateTempoUpdate(){
	//copy posterior to prior
	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
	
	//update
	relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood);
	
	//normalise
	relativeSpeedPosterior.renormalise();
	
	relativeSpeedPosterior.getMaximum();	
	
}


void BayesianArrayStructure::drawArrays(){
	
	//bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200);
	//bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200);
	
	int displaySize = prior.arraySize;
	ofSetColor(255,0,0);
	prior.drawVector(0, displaySize);
	ofSetColor(0,255,0);
	likelihood.drawVector(0, displaySize);
	ofSetColor(0,0,255);
	posterior.drawVector(0, displaySize);
	ofSetColor(255,255,0);
	relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize);
	
//	ofSetColor(255,255,255);
//	tmpPrior.drawVector(0,300);
	
}


void BayesianArrayStructure::drawTempoArrays(){
	ofSetColor(0,255,255);
	relativeSpeedPrior.drawVector(0, relativeSpeedPrior.arraySize);
	
	ofSetColor(255,0,255);
	relativeSpeedLikelihood.drawVector(0, relativeSpeedLikelihood.arraySize);
	
	ofSetColor(255,255,0);
	relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize);
	
	ofSetColor(255,255, 255);
	ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen
	
	ofSetColor(0, 255, 0);
	double fractionOfScreen = ((double)relativeSpeedPosterior.MAPestimate / relativeSpeedPosterior.length);
	ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight());
}


void BayesianArrayStructure::drawArraysRelativeToTimeframe(const double& startTimeMillis, const double& endTimeMillis){

	screenWidth = ofGetWidth();
	
	int startArrayIndex = 0;
	
	if (prior.getIndexInRealTerms(prior.arraySize-1) > startTimeMillis){
		//i.e. the array is on the page
	
	while (prior.getIndexInRealTerms(startArrayIndex) < startTimeMillis){
		startArrayIndex++;
	}
	int endArrayIndex = prior.arraySize-1;
	//could find constraints here
	if (prior.getIndexInRealTerms(prior.arraySize-1) > endTimeMillis)
		endArrayIndex = (floor)((endTimeMillis - prior.offset)/prior.scalar);
	
	//so we need to figure where start and end array are on screen
	int startScreenPosition, endScreenPosition;
	double screenWidthMillis = endTimeMillis - startTimeMillis;
		
	startScreenPosition = (prior.getIndexInRealTerms(startArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis;
	endScreenPosition = (double)(prior.getIndexInRealTerms(endArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis;
		
	ofSetColor(0,0,100);
	string relativeString = " offset "+ofToString(prior.offset, 1);//starttimes("+ofToString(startTimeMillis)+", "+ofToString(endTimeMillis);
	relativeString += ": index "+ofToString(startArrayIndex)+" , "+ofToString(endArrayIndex)+" [";
//	relativeString += ofToString(prior.getIndexInRealTerms(endArrayIndex), 3)+"] (sc-width:"+ofToString(screenWidthMillis, 1)+")  ";
	relativeString += " mapped to screen "+ofToString(startScreenPosition)+" , "+ofToString(endScreenPosition);
	ofDrawBitmapString(relativeString, 100, 180);
		
	ofSetColor(255, 255, 0);
	likelihood.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);

	ofSetColor(0,0,200);
	prior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
		
	ofSetColor(200, 0, 0);
	posterior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
		
		
//	ofSetColor(0, 200, 255);
//	acceleration.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);
		
		
	}

}