/*******************************************************************************
 *	SigGen.cpp	Signal Generator classes
 *			T.Barnaby,	BEAM Ltd,	2006-09-12
 *	updated by	D.Korchagin,	CERN AB-BI-SW,	2007-08-31
 *******************************************************************************
 */

#include <SigGen.h>
#include <math.h>
#include <time.h>

#ifndef __Lynx__
#else
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#endif

#define	DEBUG	0

#if DEBUG
#define	dprintf(fmt, a...)       printf(fmt, ##a);
#else
#define	dprintf(fmt, a...)
#endif

BSignal::BSignal(int id, int numSamples, int numRepeat, int nextId){
	int	i;
	
	this->id = id;
	this->numSamples = numSamples;
	this->numRepeat = numRepeat;
	this->nextId = nextId;
	
	for(i = 0; i < NumChannels; i++){
		data[i] = new Sample[this->numSamples];
		memset(data[i], 0, this->numSamples * sizeof(Sample));
	}
}

BSignal::BSignal(const BSignal& sig){
	int	i;
	
	id = sig.id;
	numSamples = sig.numSamples;
	numRepeat = sig.numRepeat;
	nextId = sig.nextId;

	for(i = 0; i < NumChannels; i++){
		data[i] = new Sample[this->numSamples];
		memcpy(data[i], sig.data[i], this->numSamples * sizeof(Sample));
	}
}

BSignal::~BSignal(){
	int	i;
	
	for(i = 0; i < NumChannels; i++){
		delete [] data[i];
	}
}

BSignal& BSignal::operator=(const BSignal& sig){
	int	i;
	
	id = sig.id;
	numSamples = sig.numSamples;
	numRepeat = sig.numRepeat;
	nextId = sig.nextId;

	for(i = 0; i < NumChannels; i++){
		delete [] data[i];
	}

	for(i = 0; i < NumChannels; i++){
		data[i] = new Sample[this->numSamples];
		memcpy(data[i], sig.data[i], this->numSamples * sizeof(Sample));
	}
	return *this;
}

SigGen::SigGen(){
	osampleRate = 48000;
	ox = 0;
}

SigGen::~SigGen(){
}

BError SigGen::config(double sampleRate){
	BError	err;

	osampleRate = sampleRate;
	ox = 0;
	
	return err;
}

BError SigGen::generate(Sample* data, int numSamples){
	BError	err;
	
	return err;
}


SigGenSine::SigGenSine(){
}

SigGenSine::~SigGenSine(){
}

BError SigGenSine::config(double sampleRate, double freq, double amplitude){
	BError	err;
	
	SigGen::config(sampleRate);
	ofreq = freq;
	oamplitude = amplitude;
	
	return err;
}

BError SigGenSine::generate(Sample* data, int numSamples){
	BError	err;
	int	i;
	
	for(i = 0; i < numSamples; i++, ox++){
		data[i] = oamplitude * sin(ox * 2.0 * M_PI * ofreq / osampleRate);
	}

	return err;
}


SigGenSquare::SigGenSquare(){
}

SigGenSquare::~SigGenSquare(){
}

BError SigGenSquare::config(double sampleRate, double freq, double amplitude, double offset){
	BError	err;
	
	SigGen::config(sampleRate);
	ofreq = freq;
	oamplitude = amplitude;
	ooffset = offset;

	return err;
}

BError SigGenSquare::generate(Sample* data, int numSamples){
	BError	err;
	int	i;
	
	for(i = 0; i < numSamples; i++, ox++){
		if(sin(ox * 2.0 * M_PI * ofreq / osampleRate) > 0.1)
			data[i] = ooffset + oamplitude;
		else
			data[i] = ooffset - oamplitude;
	}

	return err;
}


SigGenNoise::SigGenNoise(){
}

SigGenNoise::~SigGenNoise(){
}

BError SigGenNoise::config(double sampleRate, double amplitude){
	BError	err;
	
	SigGen::config(sampleRate);
	oamplitude = amplitude;
	
	return err;
}

BError SigGenNoise::generate(Sample* data, int numSamples){
	BError	err;
	int	i;
	
	for(i = 0; i < numSamples; i++, ox++){
		data[i] = oamplitude * double(rand() - (RAND_MAX / 2)) / (RAND_MAX / 2);
	}

	return err;
}


SigGenPulse::SigGenPulse(){
}

SigGenPulse::~SigGenPulse(){
}

BError SigGenPulse::config(double sampleRate, double freq, double amplitude, double onTime, double startTime){
	BError	err;
	
	SigGen::config(sampleRate);
	ofreq = freq;
	oamplitude = amplitude;
	oonTime = onTime;
	ostartTime = startTime;
	
	return err;
}

BError SigGenPulse::generate(Sample* data, int numSamples){
	BError	err;
	int	i;
	int	x;
	int	xRepeat;
	int	xStart;
	int	xEnd;
	
	xRepeat = int(round(osampleRate / ofreq));
	x = ox % xRepeat;
	xStart = int(ostartTime * osampleRate);
	xEnd = xStart + int(oonTime * osampleRate);
	
	for(i = 0; i < numSamples; i++, ox++, x++){
		if(((x % xRepeat) >= xStart) && ((x % xRepeat) < xEnd))
			data[i] = oamplitude;
		else
			data[i] = 0;
	}

	return err;
}



SigGenBeam::SigGenBeam(){
	oharmonic = 0;
	oblr = 0;
	oreduce = 0;
}

SigGenBeam::~SigGenBeam(){
}

BError SigGenBeam::config(double sampleRate, double fref, int harmonic, int bunchSet, double reduce, int blr, double amplitude){
	BError	err;
	
	SigGen::config(sampleRate);
	oharmonic = harmonic;
	oamplitude = amplitude;
	ofref = fref;
	oblr = blr;
	obunchSet = bunchSet;
	oreduce = reduce;
	
	return err;
}

BError SigGenBeam::generate(Sample* data, int numSamples){
	BError	err;
	int	i;
	double	sigma;
	double	d,t,y,b=0;
	int	bunch;
	double	m = 1.0;
	
	d = 1/ofref/oharmonic;
	sigma = 300.0e-9 / oharmonic;
	
	// Get start conditions right for repetative output
	b = 0.126144;
	
	for(i = 0; i < numSamples; i++, ox++){
		t = fmod((double)ox/osampleRate, (double)1/ofref) - 0.5 / ofref;

		y = 0;
		for(bunch = 0; bunch < oharmonic; bunch++){
			if(obunchSet & (1 << bunch)){
				if(oreduce){
					m = 1.0 - ((bunch * (1.0 - oreduce)) / oharmonic);
				}
				y += m * exp(-0.5 * pow((t + (oharmonic/2 - bunch - 0.5) * d) / sigma, 2.0));
			}
		}

		if(oblr)
			b = 0;
		else
			b = 0.99 * b + 0.01 * y;		// Baseline
			
//		data[i] = oamplitude * 0.05 * oharmonic * (y - b);
		data[i] = oamplitude * (y - b);
	}
//	printf("BaseLine: %f Fref: %f\n", b, ofref);

	return err;
}

BError	SigGenBeam::generateIntegrated(Sample* data, int numSamples){
	BError	err;
	int	i;
	int	bunch;
	int	nbunches = 0;
	
	for(i = 0; i < oharmonic; i++){
		if(obunchSet & (1 << i)){
			nbunches++;
		}
	}
	
	for(i = 0; i < numSamples; i++, ox++){
		bunch = ox % nbunches;
		data[i] = oamplitude / (bunch + 1);
	}

	return err;
}
