package physics;

import math.FourierSeries;
import math.matrix.Matrix;
import math.matrix.Vector;
import math.number.NumberComplex;
import awt.Draw;
import exception.IllegalDimensionException;

/**
 * The motion of a vibrations
 * @author Daniel
 *
 */
public class Vibrations{
	
	enum Method{ANALYTIC, ANALYTICT, EULER}
	
	/**
	 * Time vector
	 */
	
	public Vibrations(){
	}
	
	/**
	 * harmonic vibration.
	 * Acos(&omega;<sub>0</sub>t+&phi;<sub>0</sub>).
	 * technical notation
	 * @param a amplitude,
	 * 		(&omega;<sub>0</sub><sup>2</sup> x<sub>0</sub><sup>2</sup>+v<sub>0</sub><sup>2</sup>)<sup>1/2</sup>/&omega;<sub>0</sub>
	 * @param o angular frequency &omega;<sub>0</sub>
	 * @param t time
	 * @param p phase &phi;<sub>0</sub>=-arctan(v<sub>0</sub>/(&omega;<sub>0</sub>x<sub>0</sub>))
	 * @return displacement vector x(t)
	 */
	public Vector harmonic(double a, double o, Vector t, double p){
		return (t.times(o).plus(p)).cos().times(a);
	}
	
	/**
	 * harmonic vibrations superpositioned.
	 * Acos(&omega;<sub>0</sub>t+&phi;<sub>0</sub>).
	 * technical notation
	 * @param a amplitude,
	 * 		(&omega;<sub>0</sub><sup>2</sup> x<sub>0</sub><sup>2</sup>+v<sub>0</sub><sup>2</sup>)<sup>1/2</sup>/&omega;<sub>0</sub>
	 * 		cos(&omega;<sub>0</sub>t)
	 * @param o angular frequency &omega;<sub>0</sub>
	 * @param t time
	 * @param p phase &phi;<sub>0</sub>=-arctan(v<sub>0</sub>/(&omega;<sub>0</sub>x<sub>0</sub>))
	 * @return displacement vector x(t)
	 * @throws IllegalDimensionException
	 */
	public Vector harmonic(Vector a, Vector o, Vector t, Vector p) throws IllegalDimensionException{
		Vector ones = Vector.ones(t.n()); // ones vector in the length of t
		Matrix A = a.tensorProduct(ones); // matrix of amplitudes
		Matrix P = p.tensorProduct(ones); // matrix of phases
		Matrix ot = o.tensorProduct(t); // angular frequency * time
		Matrix x = A.hadamardProduct(Matrix.cos(ot.plus(P)));
		return x.sum(); // superposition
	}
	
	/**
	 * harmonic vibration.
	 * Bcos(&omega;t)+Csin(&omega;t).
	 * mathematical notation
	 * @param b amplitude of cosine, x<sub>0</sub>
	 * @param c amplitude of sine, v<sub>0</sub>/&omega;<sub>0</sub>
	 * @param o angular frequency &omega;<sub>0</sub>
	 * @param t time
	 * @return displacement vector x(t)
	 */
	public Vector harmonic(double b, double c, double o, Vector t){
		return harmonic(bc2a(b,c),o,t,bc2p(b,c));
//		return Vector.cos(t.times(o)).times(b).plus(Vector.sin(t.times(o)).times(c));
	}
	
	/**
	 * harmonic vibration.
	 * Re(x&#770;e<sup>i&omega;t</sup>), x&#770;&isin;&#8450;.
	 * technical notation
	 * @param x complex number, x&#770; amplitude and phase
	 * @param o angular frequency &omega;
	 * @param t time
	 * @return displacement vector x(t)
	 */
	public Vector harmonic(NumberComplex x, double o, Vector t){
		double a = x.mod();
		double p = x.argd();
		return harmonic(a,o,t,p);
	}
	
	/**
	 * harmonic vibration.
	 * (&omega;<sub>0</sub><sup>2</sup> x<sub>0</sub><sup>2</sup>+v<sub>0</sub><sup>2</sup>)<sup>1/2</sup>/&omega;<sub>0</sub>
	 * cos(&omega;<sub>0</sub>t-arctan(v<sub>0</sub>/(&omega;<sub>0</sub>x<sub>0</sub>))).
	 * technical notation
	 * @param o0 angular frequency &omega;<sub>0</sub>
	 * @param t time
	 * @param x0 static displacement x<sub>0</sub>
	 * @param v0 static velocity v<sub>0</sub>
	 * @return displacement vector x(t)
	 */
	public Vector harmonic(double o0, Vector t, double x0, double v0){
		return (t.times(o0).plus(bc2p(x0,v0/o0))).cos().times(bc2a(x0,v0/o0));
	}
	
	public double bc2a(double b, double c){
		return Math.sqrt(b*b+c*c);
	}
	
	public double bc2p(double b, double c){
		return Math.atan2(-c,b);
	}
	
	public double km2o(double k, double m){
		return Math.sqrt(k/m);
	}
	
	/**
	 * stochastic vibrations demo
	 */
	public void demoStochastic(){
		Vector t = Vector.fill(0, 0.0005, 10);
		int n = 20; // number of superposition
		Vector a = Vector.rand(n,0.3); // amplitudes
		Vector p = Vector.rand(n,3); // phases
		Vector o = Vector.rand(n,60); // angular frequencies
		Vector xs = null;
		try {
			xs = harmonic(a,o,t,p);
			animate(t,xs);
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * periodic vibrations demo
	 */
	public void demoPeriodic(){
		double T = 3.8;
		double A = 1.7;
		Vector t = Vector.fill(10, Vector.fill(2., 9), Vector.fill(1, 2, 15)).times(T/4);
		Vector x = Vector.zeros(t.n());
		int n;
		for(n=1;n<t.n()-1;n+=2){ 
			x.set(n, A);
		    x.set(n+1, -A);
		}
		t.set(n, t.get(n-1)+T/4);
		x.set(n,0);
		try {
			animate(t,x);
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * harmonic vibration demo
	 */
	public void demoHarmonic(){
		Vector t = Vector.fill(0, 0.001, 10);
		double T = 3.8;
		double A = 1.7;
		double omega = 2*Math.PI/T;
		double phi = -Math.PI/6;
		Vector x = harmonic(A, omega, t, phi);
		try {
			animate(t,x);
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Fourier series demo
	 */
	public void demoFourierSeries(){
		new FourierSeries().demoSawtooth();
	}
	
	/**
	 * animation
	 * @param t time vector
	 * @param x displacement vector
	 * @throws IllegalDimensionException 
	 */
	public void animate(Vector t, Vector x) throws IllegalDimensionException{
        if(t.n() != x.n()) throw new IllegalDimensionException("Illegal vector dimensions.");
		Draw projectile = new Draw("Vibrations");
		projectile.animate(t,x);
	}
	
	/**
	 * animation of x(t) with x<sub>0</sub>, v<sub>0</sub>, &omega;<sub>0</sub>, t<sub>0</sub>, t<sub>end</sub>
	 * @param x0 static displacement x<sub>0</sub>
	 * @param v0 static velocity v<sub>0</sub>
	 * @param o0 angular frequency &omega;<sub>0</sub>
	 * @param t0 start time
	 * @param tend end time
	 */
	public void animateX(double x0, double v0, double o0, double t0, double tend){
		Draw projectile = new Draw("Vibrations");
		Vector T = Vector.fill(t0,0.002,tend);
		System.out.println(T.n());
		Vector X = harmonic(o0, T, x0, v0);
		projectile.animate(T,X);
	}
	
	/**
	 * animation of xp(t) with x<sub>0</sub>, v<sub>0</sub>, &omega;<sub>0</sub>t
	 * @param x0 static displacement x<sub>0</sub>
	 * @param v0 static velocity v<sub>0</sub>
	 * @param o0 angular frequency &omega;<sub>0</sub>
	 * @param t0 start time
	 * @param tend end time
	 */
	public void animateXp(double x0, double v0, double o0, double t0, double tend){
		Draw projectile = new Draw("Vibrations");
		Vector T = Vector.fill(t0,0.002,tend);
		Vector X = harmonic(v0, -o0*x0, o0, T).times(o0);
		projectile.animate(T,X);
	}
	
	/**
	 * animation of xpp(t) with x<sub>0</sub>, v<sub>0</sub>, &omega;<sub>0</sub>t
	 * @param x0 static displacement x<sub>0</sub>
	 * @param v0 static velocity v<sub>0</sub>
	 * @param o0 angular frequency &omega;<sub>0</sub>
	 * @param t0 start time
	 * @param tend end time
	 */
	public void animateXpp(double x0, double v0, double o0, double t0, double tend){
		Draw projectile = new Draw("Vibrations");
		Vector T = time(t0, tend);
		Vector X = harmonic(-o0*o0*x0, -o0*v0, o0, T).times(o0);
		projectile.animate(T,X);
	}
	
	public Vector time(double t0, double tend){
		int n = 2000;
		return Vector.fillN(t0,tend,n);
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Vibrations v = new Vibrations();
//		v.demoStochastic();
//		v.demoPeriodic();
//		v.demoHarmonic();
//		v.demoFourierSeries();
		{
			double o0 = 2;
			double x0 = 1;
			double v0 = 2;
			double t0 = 0;
			double tend = 4;
			v.animateXpp(x0, v0, o0, t0, tend);
		}
	}

}
