view bayesianArraySrc/BayesianArrayStructure.cpp @ 56:4394c9490716 tip

minor changes
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 24 Dec 2012 18:58:39 +0000
parents 5274e3b5479d
children
line wrap: on
line source
/*
 *  BayesianArrayStructure.cpp
 *  midiCannamReader
 *
 *  Created by Andrew on 17/07/2011.
 *  Copyright 2011 QMUL. All rights reserved.
 *
 */

//look at reset speed to one - what does this do? - get rid of?


#include "BayesianArrayStructure.h"

BayesianArrayStructure::BayesianArrayStructure(){
	printf("Bayesian structure: DeFault constructor called");

	usingIntegratedTempoEstimate = false;// use max index
	updatingSpeedDistribution = false;
	
	relativeSpeedLikelihoodStdDev = 5.0;
	
	prior.createVector(1);
	likelihood.createVector(1);
	posterior.createVector(1);

	speedPriorValue = 1.0;//default value for the speed prior
	speedEstimate = speedPriorValue;
	
	lastEventTime = 0;//ofGetElapsedTimeMillis();

	tmpBestEstimate = 0;
	crossUpdateTimeThreshold = 60;
	priorWidth = 0.1;
	

	
}

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

}



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);
	printf("scalar %f\n", posterior.scalar);
	
}

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

}

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

void BayesianArrayStructure::resetSpeedToOne(){
	relativeSpeedPrior.zero();
	relativeSpeedPosterior.zero();
	relativeSpeedLikelihood.zero();
	
	
//	relativeSpeedPosterior.addGaussianShape(100, 8, 0.1);
//	relativeSpeedPosterior.renormalise();
//	relativeSpeedPosterior.getMaximum();
	
	setSpeedPrior(speedPriorValue);
	speedEstimate = speedPriorValue;
	
	prior.zero();
	posterior.zero();
	
	posterior.addToIndex(0, 1);
	posterior.renormalise();
	
}

void BayesianArrayStructure::setSpeedPrior(double f){	
	speedPriorValue = f;
	int index = relativeSpeedPosterior.getRealTermsAsIndex(speedPriorValue);
	relativeSpeedPosterior.zero();
	
	//changed these a bit - still need to figure tempo process out properly
	relativeSpeedPosterior.addGaussianShapeFromRealTime(1, priorWidth, 4);
		
	//relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.getRealTermsAsIndex(1), 4, 1);
	
	printf("speed adding to index for 1 = %f\n", relativeSpeedPosterior.getRealTermsAsIndex(1));
//	relativeSpeedPosterior.addToIndex(relativeSpeedPosterior.getRealTermsAsIndex(1), 0.5);
	//relativeSpeedPosterior.addGaussianShapeFromRealTime(1, 3, 0.5);

	
	relativeSpeedPosterior.renormalise();
	relativeSpeedPosterior.getMaximum();
	
	
	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
	
	
	
	printf("BAYES STRUCTU ' SPEED PRIOR %f . index %i\n", speedPriorValue, index);
	
}


void BayesianArrayStructure::setPositionDistributionScalar(double f){
	if (f > 0){
	prior.scalar = f;
	posterior.scalar = f;
	likelihood.scalar = f;
	printf("SET POS DISTBN SCALAR %f\n", f);
	}
}

void BayesianArrayStructure::simpleExample(){
	relativeSpeedPosterior.getMaximum();
	relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior);
}

void BayesianArrayStructure::copyPriorToPosterior(){

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

void BayesianArrayStructure::setStartPlaying(){
	
	lastEventTime = 0;
	bestEstimate = 0;
	lastBestEstimateUpdateTime = 0;
	
	if (*realTimeMode)
		lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
	//cannot just be zero - offline bug
	//printf("start playing - best estimate %f\n", lastBestEstimateUpdateTime);
	
	resetArrays();
}

void BayesianArrayStructure::resetArrays(){
	//called when we start playing
	
	prior.zero();
	likelihood.zero();
	posterior.zero();
	
	updateCounter = 0;
	
	posterior.offset = -1 * matchWindowWidth / 2;//is set from the audioEventMatcher class
	setNewDistributionOffsets(0);
	
	int zeroIndex = posterior.getRealTermsAsIndex(0);
	printf("ZERO INDEX %i\n", zeroIndex);
	int offset = posterior.getIndexInRealTerms(0);
	printf("offset is %i\n", offset);
	
	posterior.addGaussianShapeFromRealTime(0, startingWindowWidth, 1);//one way to add at x msec
//	posterior.addGaussianShape(posterior.getRealTermsAsIndex(10), 50, 1);//alternative way
	
	likelihood.addConstant(1);
	
	updateCounter = 0;
	

	printf("bayes reset arrays - best estimate %f\n", lastBestEstimateUpdateTime);
	
	setSpeedPrior(speedPriorValue);//setting the prior speed
	relativeSpeedPosterior.copyFromDynamicVector(relativeSpeedPrior);
	
}


void BayesianArrayStructure::zeroArrays(){
	prior.zero();
	likelihood.zero();
	posterior.zero();
	
	relativeSpeedPrior.zero();
	relativeSpeedPosterior.zero();
	relativeSpeedLikelihood.zero();

}

/*
void BayesianArrayStructure::updateTmpBestEstimate(const double& timeDifference){
	//input is the time since the start of playing
//	double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime;
	double timeDiff = timeDifference;
	if (*realTimeMode)
		timeDiff = ofGetElapsedTimeMillis() - lastBestEstimateUpdateTime;

	double tmp = relativeSpeedPosterior.getIntegratedEstimate();
	tmpBestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
	// 
	//printf("tmp best %f and best %f time diff %f posterior MAP %f at speed %f\n", 0Estimate, bestEstimate, timeDifference, posterior.getIndexInRealTerms(posterior.MAPestimate), relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate));
	//lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
}
*/

void BayesianArrayStructure::updateBestEstimate(const double& timeDifference){
//	double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//
	double tmp = bestEstimate;
//	printf("best est routine: posterior offset %f\n", posterior.offset);
	
	double timeDiff = timeDifference;
	
	//Using timedifferencfe here will make it go wrong. Is time since beginning of playing
	
	if (*realTimeMode)
		timeDiff = ofGetElapsedTimeMillis() - lastBestEstimateUpdateTime;
	
	//lastbest is time we started playing
	/*
	if (usingIntegratedTempoEstimate)
		speedEstimateIndex = relativeSpeedPosterior.getIntegratedEstimate();
	else
		speedEstimateIndex = relativeSpeedPosterior.getMAPestimate();
	*/
	speedEstimateIndex = getSpeedEstimateIndex();
	
	speedEstimate = relativeSpeedPosterior.getIndexInRealTerms(speedEstimateIndex);
	bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*speedEstimate;
	
//	printf("best estimate update from %f to %f; time diff %f MAP %i = %f ms speed index %f est %f SpeedxTime %f\n", tmp, bestEstimate, timeDiff,
//		   posterior.MAPestimate, posterior.getIndexInRealTerms(posterior.MAPestimate), speedEstimateIndex, speedEstimate, timeDiff*speedEstimate);

		printf("BEST ESTIMATE %f\n", bestEstimate);
}


void BayesianArrayStructure::calculatePosterior(){
	//posterior.doProduct(prior, likelihood);
	assert(posterior.offset == prior.offset);
	
	int i;
	for (i = 0;i < posterior.length;i++){
		posterior.array[i] = likelihood.array[i] * prior.array[i];
	}
	
	posterior.renormalise();
	
	//	printf("After CALC");
	//	printPostOffset();	
	
}


double  BayesianArrayStructure::getSpeedEstimateIndex(){
	if (usingIntegratedTempoEstimate)
		return relativeSpeedPosterior.getIntegratedEstimate();
	else
		return relativeSpeedPosterior.getMAPestimate();
}


void BayesianArrayStructure::setNewDistributionOffsets(const double& newOffset){
	
	printf("prior offset was %f now %f\n", prior.offset, newOffset);
	
	prior.offset = newOffset;
	likelihood.offset = newOffset;
	//posterior.offset = newOffset;
}

void BayesianArrayStructure::zeroDistributionAtPosition(DynamicVector& distribution, const double& position){
	distribution.zero();
	setNewDistributionOffsets(max(0., position - (distribution.scalar*distribution.arraySize/2)));
}

void BayesianArrayStructure::updateBayesianDistributions(const double& newEventTime){
	
	//NEED TO CHECK HERE THAT THEY HAVE THE SAME OFFSETS
	prior.copyFromDynamicVector(posterior);//try the otehr way
	
	//bayesianStruct.copyPriorToPosterior();
	//need to get new MAP position and set the offset of the arrays
	//currently bestEstimate is the approx for the new MAP position
//	int tmpMap = bayesianStruct.posterior.getMAPestimate();
	
	double timeDifference = newEventTime - lastEventTime; 
//	printf("updating distributions at time %f diff %f offset %f\n", newEventTime, timeDifference, posterior.offset);
	
	//addnoise to the tempo distribution
	//bayesianStruct.decaySpeedDistribution(timeDifference);
	
	if (timeDifference > 50 && updatingSpeedDistribution){
		addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.);
	}

	printPostOffset();
	
	updateBestEstimate(timeDifference);
	lastBestEstimateUpdateTime = newEventTime;//getTimeNow(timePlayed);

	//set TARGETS - commented tenmporarily
	setNewDistributionOffsets(max(0., bestEstimate - (prior.scalar*prior.arraySize/2)));
	
	crossUpdateArrays(posterior, relativeSpeedPosterior, timeDifference);
	
	//i.e. using the same offset as prior
	posterior.offset = prior.offset;// NOW in SRT NEW DISTBN OFFSET
	
	//	float tmpPrior = max(0., bestEstimate - (prior.scalar*prior.arraySize/2));//	prior.offset = max(0., bestEstimate - (prior.scalar*prior.arraySize/2));
	//	printf("Using prior offset of %f not %f\n", tmpPrior, prior.offset);
	
	lastEventTime = newEventTime;//lastEventTime = ofGetElapsedTimeMillis();
	
}




void BayesianArrayStructure::crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference){

	//set the cutoff for offset of position first! XXX
	
	double timeDifferenceInPositionVectorUnits = timeDifference / prior.scalar;
	
	//printf("CROSS UPDATE time diff %f ms is %f units; ", timeDifference, timeDifferenceInPositionVectorUnits);
	prior.zero();//kill prior
	
//	calculateNewPriorOffset(timeDifference);//dioesnt do anything
	
//	printf("new prior offset %f and post offset %f\n", prior.offset, posterior.offset);
	
	if (timeDifferenceInPositionVectorUnits > crossUpdateTimeThreshold)
		complexCrossUpdate(timeDifferenceInPositionVectorUnits);
	else
		translateByMaximumSpeed(timeDifferenceInPositionVectorUnits);	
			

	updateCounter++;
	prior.renormalise();//not strictly necessary??

}

void BayesianArrayStructure::complexCrossUpdate(const double& timeDifferenceInPositionVectorUnits){

	
//	printf("before cross c : posterior map is %i = %f ms time diff pos vec %f\n", posterior.getMAPestimate(), posterior.getIndexInRealTerms(prior.getMAPestimate()), timeDifferenceInPositionVectorUnits);
	
	int distanceMoved, newPriorIndex;
	
	double speedValue = relativeSpeedPosterior.offset;
	
	for (int i = 0;i < relativeSpeedPosterior.arraySize;i++){
		
	//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5
		
		//so we have moved 
		distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
	//	printf("Speed value %f time %f gives distance %i\n", speedValue, timeDifferenceInPositionVectorUnits, distanceMoved);
		
		if (relativeSpeedPosterior.array[i] != 0){
			
			double speedContribution = relativeSpeedPosterior.array[i];
			
		//	printf("speed [%i](val[%f]) gives %f moved %i in %f units \n", i, relativeSpeedPosterior.array[i], speedValue, distanceMoved, timeDifferenceInPositionVectorUnits);
			
			//1/2/12 deleted line
			newPriorIndex = (int)posterior.millisToVectorUnits(posterior.offset - prior.offset) + distanceMoved;//i.e. where post[0] goes to in terms of prior at this speed
			int postIndex = 0;//index of posterior that will contribute
			
			while (postIndex < posterior.arraySize && newPriorIndex < prior.arraySize){

			//did use a for loop
			//	for (postIndex = 0;postIndex < posterior.arraySize;postIndex++){
				//old posterior contributing to new prior
			
				//would use this method
				//newPriorIndex = postIndex + posterior.offset - prior.offset + distanceMoved;
				
				if (newPriorIndex >= 0){
					prior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
			//		printf("speed index %i new prior index %i post val %f speed contrib %f dist %i\n", i, newPriorIndex, posterior.array[postIndex], speedContribution, distanceMoved);
				}
				//but we actually do this for simplicity
				newPriorIndex++;
				postIndex++;
			}//end for. now while
			
			
		}//if not zero
		
		speedValue += relativeSpeedPosterior.scalar;//optimised line
		//as we wanted:
		//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5
		
	}//end speed
	
	
//	printf("after cross c : prior map is %i = %f ms\n", prior.getMAPestimate(), prior.getIndexInRealTerms(prior.getMAPestimate()));
}



void BayesianArrayStructure::translateByMaximumSpeed(const double& timeDifferenceInPositionVectorUnits){

	
	int distanceMoved, newPriorIndex;
	double speedIndex = getSpeedEstimateIndex();
	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(speedIndex);
	
//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
	
	//so for scalar 0.01, 50 -> speed value of 0.5
	double speedContribution = relativeSpeedPosterior.array[(int)round(speedIndex)];
		//so we have moved 
		distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
				
	//	printf("speed [%i] gives %f moved %i in %f units \n", i, speedValue, distanceMoved, timeDifferenceInPositionVectorUnits);
			
			for (int postIndex = 0;postIndex < posterior.arraySize;postIndex++){
				//old posterior contributing to new prior
				newPriorIndex = (int)round(posterior.millisToVectorUnits(posterior.offset - prior.offset)) + postIndex  + distanceMoved;
				if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){
					prior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
				}
				
			}
	
}

void BayesianArrayStructure::addGaussianNoiseToSpeedPosterior(const double& std_dev){
	tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior);
	
	for (int i = 0;i < relativeSpeedPosterior.length;i++){
		tmpPosteriorForStorage.addGaussianShape(i, std_dev, relativeSpeedPosterior.array[i]);
		}
												
	tmpPosteriorForStorage.renormalise();
	
	relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage);											
}


void BayesianArrayStructure::addTriangularNoiseToSpeedPosterior(const double& std_dev){
	tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior);
	
	for (int i = 0;i < relativeSpeedPosterior.length;i++){
		//adding a linear amount depending on distance
		tmpPosteriorForStorage.addTriangularShape(i, std_dev*2.0, relativeSpeedPosterior.array[i]);
	}
	
	tmpPosteriorForStorage.renormalise();
	
	relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage);											
}

void BayesianArrayStructure::calculateNewPriorOffset(const double& timeDifference){
	
//	double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
	
	double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(getSpeedEstimateIndex());//either integrated or MAP
	//	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::setLikelihoodToConstant(){
	//set new likelihood
	relativeSpeedLikelihood.zero();
	relativeSpeedLikelihood.addConstant(speedLikelihoodNoise);
}


void BayesianArrayStructure::updateTempoLikelihood(const double& speedRatio, const double& matchFactor){
	
	//speedratio is speed of played relative to the recording
	
	double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio);
	//	printf("index of likelihood would be %f for ratio %f\n", index, speedRatio);
	if (index >= 0 && index < relativeSpeedPrior.length){	
		relativeSpeedLikelihood.addGaussianShape(index , relativeSpeedLikelihoodStdDev, matchFactor);
	}
}
	


void BayesianArrayStructure::updateTempoDistribution(){

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

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

	//normalise
	relativeSpeedPosterior.renormalise();
		
	relativeSpeedPosterior.getMaximum();	
	
	//relativeSpeedPosterior.updateIntegratedEstimate(); - could be swayed when off to side 
	//so now limited to where there is room sround the MAP estimate
	relativeSpeedPosterior.updateLimitedIntegratedEstimate();
	
	speedEstimate = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
}


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(0,0,255);
	prior.drawVector(0, displaySize);
	ofSetColor(0,255,0);
	likelihood.drawVector(0, displaySize);
	ofSetColor(255,0,255);
	posterior.drawVector(0, displaySize);
	
	
	
}


void BayesianArrayStructure::drawTempoArrays(){
	ofSetColor(0,0,255);
//	relativeSpeedPrior.drawVector(0, relativeSpeedPrior.arraySize);
	
	ofSetColor(0,150,255);
	relativeSpeedLikelihood.drawVector(0, relativeSpeedLikelihood.arraySize);
	
//	relativeSpeedLikelihood.drawConstrainedVector(0, 199, 0, 1000);// relativeSpeedLikelihood.arraySize);	
	ofSetColor(255,0,0);
	relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize);
	
//	ofSetColor(0,0,255);
//	tmpPosteriorForStorage.drawVector(0, tmpPosteriorForStorage.arraySize);
	
	ofSetColor(255,255, 255);
	ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen
	
	ofSetColor(25, 0, 250);
	double fractionOfScreen = ((double)relativeSpeedPosterior.integratedEstimate / relativeSpeedPosterior.length);
	ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight());
	
	ofSetColor(255, 0, 20);
	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(100,100,100);//255, 255, 0);
	likelihood.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition);

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

}


void BayesianArrayStructure::printPostOffset(){
	double tmp = posterior.getMAPestimate();
	printf(" MAP index %i post offset %f == %f ms\n", posterior.MAPestimate, posterior.offset, posterior.getIndexInRealTerms(posterior.MAPestimate));
}

//PROJECT PRIOR CODE

void BayesianArrayStructure::projectDistribution(const double& newEventTime, const double& newAlignmentPosition, DynamicVector& projectedPrior){
	
	projectedPrior.copyFromDynamicVector(posterior);

	double timeDifference = newEventTime - lastEventTime; 
	
//	if (timeDifference > 50 && updatingSpeedDistribution){
//		addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.);
//	}

	
//	updateBestEstimate(timeDifference);
//	lastBestEstimateUpdateTime = newEventTime;//getTimeNow(timePlayed);
	
	//set TARGETS - commented tenmporarily

	//setNewDistributionOffsets(max(0., bestEstimate  - (prior.scalar*prior.arraySize/2)));
	projectedPrior.offset = posterior.offset;//max(0., newAlignmentPosition - (projectedPrior.scalar*projectedPrior.arraySize/2));
							
//	int timeDifference = newEventTime - lastEventTime;
								
		double timeDifferenceInPositionVectorUnits = timeDifference / projectedPrior.scalar;
								
	//	printf("CROSS UPDATE time diff %f ms is %f units; ", timeDifference, timeDifferenceInPositionVectorUnits);
		projectedPrior.zero();//kill prior
								
								//	calculateNewPriorOffset(timeDifference);//dioesnt do anything
								
								//	printf("new prior offset %f and post offset %f\n", prior.offset, posterior.offset);
								
				if (timeDifferenceInPositionVectorUnits > crossUpdateTimeThreshold)
					complexCrossUpdateProjection(projectedPrior, timeDifferenceInPositionVectorUnits);
				else
					translatePosteriorByMaximumSpeed(projectedPrior, timeDifferenceInPositionVectorUnits);	
								
								
		//			updateCounter++;
		projectedPrior.renormalise();//not strictly necessary??
								
								
	//i.e. using the same offset as prior
//	posterior.offset = prior.offset;// 
	
	//	float tmpPrior = max(0., bestEstimate - (prior.scalar*prior.arraySize/2));//	prior.offset = max(0., bestEstimate - (prior.scalar*prior.arraySize/2));
	//	printf("Using prior offset of %f not %f\n", tmpPrior, prior.offset);
	
//	lastEventTime = newEventTime;//lastEventTime = ofGetElapsedTimeMillis();
	
}



void BayesianArrayStructure::complexCrossUpdateProjection(DynamicVector& projectedPrior, const double& timeDifferenceInPositionVectorUnits){
	
	int distanceMoved, newPriorIndex;

	double speedValue = relativeSpeedPosterior.offset;
	
	for (int i = 0;i < relativeSpeedPosterior.arraySize;i++){
		
		distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
		
		if (relativeSpeedPosterior.array[i] != 0){
			
			double speedContribution = relativeSpeedPosterior.array[i];
			
			newPriorIndex = posterior.offset - projectedPrior.offset + distanceMoved;//i.e. where post[0] goes to in terms of prior at this speed
			int postIndex = 0;//index of posterior that will contribute
			
			while (postIndex < posterior.arraySize && newPriorIndex < projectedPrior.arraySize){

				//would use this method
				//newPriorIndex = postIndex + posterior.offset - prior.offset + distanceMoved;
				
				if (newPriorIndex >= 0){
					projectedPrior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
					//		printf("speed index %i new prior index %i post val %f speed contrib %f dist %i\n", i, newPriorIndex, posterior.array[postIndex], speedContribution, distanceMoved);
				}
				//but we actually do this for simplicity
				newPriorIndex++;
				postIndex++;
			}//end for. now while
			
			
		}//if not zero
		
		speedValue += relativeSpeedPosterior.scalar;//optimised line
		//as we wanted:
		//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5
		
	}//end speed

}



void BayesianArrayStructure::translatePosteriorByMaximumSpeed(DynamicVector& translatedPosterior, const double& timeDifferenceInPositionVectorUnits){
	
	
	int distanceMoved, newPriorIndex;
	double speedIndex = getSpeedEstimateIndex();
	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(speedIndex);
	
	//	double speedValue = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.integratedEstimate);
	
	//so for scalar 0.01, 50 -> speed value of 0.5
	double speedContribution = relativeSpeedPosterior.array[(int)round(speedIndex)];
	//so we have moved 
	distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value
	
	//	printf("speed [%i] gives %f moved %i in %f units \n", i, speedValue, distanceMoved, timeDifferenceInPositionVectorUnits);
	
	for (int postIndex = 0;postIndex < posterior.arraySize;postIndex++){
		//old posterior contributing to new prior
		newPriorIndex = postIndex + posterior.offset - prior.offset + distanceMoved;
		if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){
			translatedPosterior.addToIndex(newPriorIndex, posterior.array[postIndex]*speedContribution);
		}
		
	}
	
}


//END PROJECT PRIOR CODE



/*
 
 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(speedLikelihoodNoise);
 
 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
 
 
 }
 
 */