package statistics.simulators;
import distributions.*;
import fileIO.*;
import java.lang.*;
public class SinusoidalModel extends Model{
boolean warpSeries=false;
void setWarp(boolean w){warpSeries=w;}
static double maxAmp=3;
//RANGE 0 ..1, offset gives the starting phase of the cycle. Note this can be randomised for each series at reset() by setting
// fixedOffset to false. This shifts ALL the offsets by a fixed, random amount, to retain relative effect.
double[] offset;
boolean fixedOffset=true;
public void setFixedOffset(boolean b){fixedOffset=b;}
//RANGE: 0 ... 1, 100*frequency gives the number of cycles between 0 and pi()
double[] frequency;
//RANGE:0 .. 1, gives the max height: maxAmp
double[] amplitude;
int maxN=100;
double interval = Math.PI/maxN;
//Default min max range
static double defaultMin=0;
static double defaultMax=1;
public SinusoidalModel(double[] p){
if(p.length%3!=0){
System.out.println(" Error in Sinusoidal Model, the parameter list must be divisible by three (offset, frequency and amplitude");
throw new IllegalArgumentException(" Error in Sinusoidal Model, the parameter list must be divisible by three (offset, frequency and amplitude");
}
offset=new double[p.length/3];
frequency=new double[p.length/3];
amplitude=new double[p.length/3];
int count=0;
for(int i=0;i<offset.length;i++)
offset[i]=p[count++];
for(int i=0;i<frequency.length;i++)
frequency[i]=p[count++];
for(int i=0;i<amplitude.length;i++)
amplitude[i]=p[count++];
}
public void setInterval(int n)
{
maxN=n;
interval = Math.PI/maxN;
}
/** from the base class. Simply split the array into three
*
* @param p
*/
@Override
public void setParameters(double[] p){
if(p.length%3!=0){
System.out.println(" Error in Sinusoidal Model, the parameter list must be divisible by three (offset, frequency and amplitude");
}
offset=new double[p.length/3];
frequency=new double[p.length/3];
amplitude=new double[p.length/3];
int count=0;
for(int i=0;i<offset.length;i++)
offset[i]=p[count++];
for(int i=0;i<frequency.length;i++)
frequency[i]=p[count++];
for(int i=0;i<amplitude.length;i++)
amplitude[i]=p[count++];
}
public SinusoidalModel(double[] offset, double[] frequency, double[] amplitude)
{
this.offset=new double[offset.length];
System.arraycopy(offset, 0, this.offset, 0, offset.length);
this.frequency=new double[frequency.length];
System.arraycopy(frequency, 0, this.frequency, 0, frequency.length);
this.amplitude=new double[amplitude.length];
System.arraycopy(amplitude, 0, this.amplitude, 0, amplitude.length);
t=0;
error = new NormalDistribution(0,variance);
}
public SinusoidalModel(double[] offset, double[] frequency, double[] amplitude, double s)
{
this.offset=new double[offset.length];
System.arraycopy(offset, 0, this.offset, 0, offset.length);
this.frequency=new double[frequency.length];
System.arraycopy(frequency, 0, this.frequency, 0, frequency.length);
this.amplitude=new double[amplitude.length];
System.arraycopy(amplitude, 0, this.amplitude, 0, amplitude.length);
t=0;
setVariance(s);
}
public void setSigma(double s){
setVariance(s);
}
@Override
public double generate(double x){
double res=0;
for(int i=0;i<offset.length;i++)
res+=((maxAmp)*amplitude[i])*(Math.sin(Math.PI*offset[i]+(2+100*frequency[i])*x));
res+= error.simulate();
return res;
}
public double generateError(){ return error.simulate();}
@Override
public double generate()
{
double res=0;
for(int i=0;i<offset.length;i++)
res+=((maxAmp)*amplitude[i])*(Math.sin(Math.PI*offset[i]+(2+100*frequency[i])*t));
this.t+=interval;
res+= error.simulate();
return res;
}
/** @Override
*
* @param l
* @return
*/
@Override
public double[] generateSeries(int l)
{
double[] data = new double[l];
reset();
setInterval(l);
for(int k=0;k<l;k++)
data[k] =generate();
if(!warpSeries)
return data;
//Warping.
double offsetPercent=10;
int offset=(int)(data.length*offsetPercent/100);
double[] newD=new double[data.length];
System.arraycopy(data,0,newD,0,data.length);
// Pick a random point somewhere between the first 10% and last 90%
int warpPoint=(int)(offset+Math.random()*(data.length-offset*2));
// Warp offset points into offset*2 points
newD[warpPoint+offset]=data[warpPoint];
//Warp offset points to fill the gap.
newD[warpPoint-offset]=data[warpPoint-offset];
for(int i=1;i<=offset;i++){
newD[warpPoint-offset+2*i-1]=data[warpPoint-offset+i];
newD[warpPoint-offset+2*i]=(data[warpPoint-offset+i]+data[warpPoint-offset+i+1])/2;
// System.out.println(i+","+warpPoint+","+offset+","+data[warpPoint-offset+i]+","+newD[warpPoint-offset+2*i-1]+","+newD[warpPoint-offset+2*i]);
}
// OutFile of = new OutFile("");
return newD;
}
static public double[][] generateSinusoidalData(SinusoidalModel[] models,int length,int nosPerModel)
{
double[][] data = new double[models.length*nosPerModel][];
for(int i=0;i<models.length;i++)
{
for(int j=0;j<nosPerModel;j++)
data[j+i*nosPerModel]= models[i].generateSeries(length);
}
return data;
}
/** @Override
*
*/
@Override
public void reset(){
//If th
super.reset();
if(!fixedOffset) //Shift all the offsets by a random amount
{
//Find the min and max of the whole offset, ta avoid shifting too much
double min=offset[0];
double max=offset[0];
for(int i=1;i<offset.length;i++){
if(min>offset[i])
min=offset[i];
if(max<offset[i])
max=offset[i];
}
//So now, any shift between -min to (1-max) should retain the relative offsets
double shift=-min+(1-max+min)*Math.random();
for(int i=1;i<offset.length;i++)
offset[i]+=shift;
}
}
/** A Load of static classes
*
* @param r
* @param min
* @param max
* @return
*/
public static SinusoidalModel generateRandomModel(int r, double min, double max)
{
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
for(int i=0;i<r;i++)
{
freq[i]=min+(max-min)*Distribution.RNG.nextDouble();
off[i]=min+(max-min)*Distribution.RNG.nextDouble();
amp[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModelAmp(SinusoidalModel m, double maxDeviation)
{
int r = m.frequency.length;
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
double min,max;
for(int i=0;i<r;i++)
{
freq[i]=m.frequency[i];
off[i]=m.offset[i];
min=m.amplitude[i]-maxDeviation;
if(min<0) min=0;
max=m.amplitude[i]+maxDeviation;
if(max>1) max=1;
amp[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModelOff(SinusoidalModel m, double maxDeviation)
{
int r = m.frequency.length;
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
double min,max;
for(int i=0;i<r;i++)
{
freq[i]=m.frequency[i];
amp[i]=m.amplitude[i];
min=m.offset[i]-maxDeviation;
if(min<0) min=0;
max=m.offset[i]+maxDeviation;
if(max>1) max=1;
off[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModelFreq(SinusoidalModel m, double maxDeviation)
{
int r = m.frequency.length;
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
double min,max;
for(int i=0;i<r;i++)
{
amp[i]=m.amplitude[i];
off[i]=m.offset[i];
min=m.frequency[i]-maxDeviation;
if(min<0) min=0;
max=m.frequency[i]+maxDeviation;
if(max>1) max=1;
freq[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModel(SinusoidalModel m, double maxDeviation)
{
int r = m.frequency.length;
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
double min,max;
for(int i=0;i<r;i++)
{
min=m.frequency[i]-maxDeviation;
if(min<0) min=0;
max=m.frequency[i]+maxDeviation;
if(max>1) max=1;
freq[i]=min+(max-min)*Distribution.RNG.nextDouble();
min=m.offset[i]-maxDeviation;
if(min<0) min=0;
max=m.offset[i]+maxDeviation;
if(max>1) max=1;
off[i]=min+(max-min)*Distribution.RNG.nextDouble();
min=m.amplitude[i]-maxDeviation;
if(min<0) min=0;
max=m.amplitude[i]+maxDeviation;
if(max>1) max=1;
amp[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModel(int r,
double minO, double maxO,double minF, double maxF,double minA, double maxA)
{
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
for(int i=0;i<r;i++)
{
freq[i]=minF+(maxF-minF)*Distribution.RNG.nextDouble();
off[i]=minO+(maxO-minO)*Distribution.RNG.nextDouble();
amp[i]=0.5+minA+(maxA-minA)*Distribution.RNG.nextDouble();
// off[i]=min+(max-min)*Distribution.RNG.nextDouble();
// amp[i]=min+(max-min)*Distribution.RNG.nextDouble();
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public static SinusoidalModel generateRandomModel(int r)
{
return generateRandomModel(r,defaultMin,defaultMax);
}
public static SinusoidalModel perturbSinusoidalModel(SinusoidalModel base, int maxPercentDev)
{
int r= base.frequency.length;
double[] freq=new double[r];
double[] off = new double[r];
double[] amp=new double[r];
int percentDev;
for(int i=0;i<r;i++)
{
percentDev = Distribution.RNG.nextInt(maxPercentDev);
if(Distribution.RNG.nextDouble()<0.5)
freq[i]=base.frequency[i]*(100.0-percentDev)/100.0;
else
freq[i]=base.frequency[i]*(100.0+percentDev)/100.0;
percentDev = Distribution.RNG.nextInt(maxPercentDev);
if(Distribution.RNG.nextDouble()<0.5)
off[i]=base.offset[i]*(100.0-percentDev)/100.0;
else
off[i]=base.offset[i]*(100.0+percentDev)/100.0;
percentDev = Distribution.RNG.nextInt(maxPercentDev);
if(Distribution.RNG.nextDouble()<0.5)
amp[i]=base.amplitude[i]*(100.0-percentDev)/100.0;
else
amp[i]=base.amplitude[i]*(100.0+percentDev)/100.0;
}
SinusoidalModel a = new SinusoidalModel(off,freq,amp);
return a;
}
public void randomiseOffset()
{
for(int i=0;i<offset.length;i++)
offset[i]=Distribution.RNG.nextDouble();
}
double[] getOffset(){ return offset;}
double[] getFrequency(){ return frequency;}
double[] getAmplitude(){return amplitude;}
void setAmplitude(double[] a){ amplitude=a;}
void setOffset(double[] o){ offset=o;}
public String toString(){
String str="";
for(int i=0;i<offset.length;i++)
str+=offset[i]+",";
str+="\n";
for(int i=0;i<frequency.length;i++)
str+=frequency[i]+",";
str+="\n";
for(int i=0;i<amplitude.length;i++)
str+=amplitude[i]+",";
str+="\n";
return str;
}
public static void sampleData()
{
OutFile of= new OutFile("randomFFTData_3Waves.csv");
int k=2;
int n=256;
int l=5;
SinusoidalModel[] models= new SinusoidalModel[k];
double[][] data = new double[k*l][n];
for(int i=0;i<k;i++)
{
models[i]= generateRandomModel(3);
for(int j=0;j<l;j++)
data[i*l+j]=models[i].generateSeries(n);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<k*l;j++)
of.writeString(data[j][i]+",");
of.writeString("\n");
}
for(int i=0;i<k;i++)
of.writeLine(models[i].toString());
}
static public void main(String[] args){
System.out.println(" To do: test harness for Sinusoidal models");
}
}