/*
 * kalmanfilter implementation
 *
 * Copyright (C) YuanJun, Li Wei, Li Ming, Andreas Nuechter,
 *
 * Released under the GPL version 3.
 *
 */

/**
 * @file
 * @brief 
 *
 * @author Andreas Nuechter. Jacobs University Bremen, Germany
 * @author YuanJun, Wuhan University, China
 * @author Li Wei, Wuhan University, China
 * @author Li Ming, Wuhan University, China
 */
/***************By yuanjun**************************/
#include "veloslam/kalmanfilter.h"
#include "math.h"
#define delta_t 0.1


KalmanFilter::KalmanFilter()
{

}

KalmanFilter::KalmanFilter(clusterFeature &glu,double rollAngle)
{
	X1.SetMatrixRowAndCol(4,1);
	X2.SetMatrixRowAndCol(4,1);
	A.SetMatrixRowAndCol(4,4);
	H.SetMatrixRowAndCol(2,4);
	Z.SetMatrixRowAndCol(2,1);
	K.SetMatrixRowAndCol(4,2);
	Q.SetMatrixRowAndCol(4,4);
	R.SetMatrixRowAndCol(2,2);
	P1.SetMatrixRowAndCol(4,4);
	P2.SetMatrixRowAndCol(4,4);
	CoordinateRoll.SetMatrixRowAndCol(4,4);

	X1.m_pTMatrix[0][0]=glu.avg_x;
	X1.m_pTMatrix[1][0]=glu.avg_z;
	X1.m_pTMatrix[2][0]=X1.m_pTMatrix[3][0]=25;


	A.Eye();
	A.m_pTMatrix[0][2]=delta_t;
	A.m_pTMatrix[1][3]=delta_t;

	H.m_pTMatrix[0][0]=1;
	H.m_pTMatrix[1][1]=1;

	Q.Eye();

	R.Eye();

	P1.Eye();

	angle=rollAngle;

	CalCoorRoll(angle);
}

KalmanFilter::~KalmanFilter(void)
{

}

void KalmanFilter::InitialKalmanFilter(clusterFeature &glu)
{
	X1.SetMatrixRowAndCol(4,1);
	X2.SetMatrixRowAndCol(4,1);
	A.SetMatrixRowAndCol(4,4);
	H.SetMatrixRowAndCol(2,4);
	Z.SetMatrixRowAndCol(2,1);
	K.SetMatrixRowAndCol(4,2);
	Q.SetMatrixRowAndCol(4,4);
	R.SetMatrixRowAndCol(2,2);
	P1.SetMatrixRowAndCol(4,4);
	P2.SetMatrixRowAndCol(4,4);

	X1.m_pTMatrix[0][0]=glu.avg_x;
	X1.m_pTMatrix[1][0]=glu.avg_z;
	X1.m_pTMatrix[2][0]=X1.m_pTMatrix[3][0]=1;

	A.Eye();
	A.m_pTMatrix[0][2]=delta_t;
	A.m_pTMatrix[1][3]=delta_t;

	H.m_pTMatrix[0][0]=1;
	H.m_pTMatrix[1][1]=1;

	Q.Eye();

	R.Eye();

	P1.Eye();

}

void KalmanFilter::timeUpdate()
{
	CMatrix T1,T2;
	X2=A*X1;
	T1= A.Transpose();
	P2= A * P1 * T1 + Q;
//	X2=A*X1;
//	P2=A*P1*A.Transpose()+Q;
}

void KalmanFilter::stateUpdate(clusterFeature &glu,double rollangle,double *pos)
{
	  CMatrix T1,T2;
	//Z.m_pTMatrix[0][0]=glu.avg_x;
	//Z.m_pTMatrix[1][0]=glu.avg_z;

	//CMatrix temp(2,2);
	//   T1= H.Transpose();
	//temp=H*P2*T1+R;
	//   T2= temp.Inverse();
	//K=P2*T1*T2;

	//CalCoorRoll(rollangle);

	//X2=CoordinateRoll*X2;

	//   CMatrix T3,T4,T5;

	//   T4=H*X2;
	//   T3=Z-T4;
	//   T5=K*T3;
	//X1=X2+T5;

	//CMatrix I(4,4);
	//I.Eye();

	//   CMatrix T6,T7,T8;
	//   T6=K*H;
	//   T7=I-T6;
	//P1=T7*P2;

	Z.m_pTMatrix[0][0]=glu.avg_x;
	Z.m_pTMatrix[1][0]=glu.avg_z;

//	CMatrix temp(2,2);
//	temp=H*P2*H.Transpose()+R;

    CMatrix temp(2,2);
    T1= H.Transpose();
    temp=H*P2*T1+R;

    T2= temp.Inverse();
    K=P2*T1*T2;

//	K=P2*H.Transpose()*temp.Inverse();

	CalCoorRoll(rollangle);

	X2=CoordinateRoll*X2;

	X2.m_pTMatrix[0][0]+=pos[0];
	X2.m_pTMatrix[1][0]+=pos[2];


//	X1=X2+K*(Z-H*X2);

    CMatrix T3,T4,T5;

    T4=H*X2;
    T3=Z-T4;
    T5=K*T3;
    X1=X2+T5;

	CMatrix I(4,4);
	I.Eye();

//	P1=(I-K*H)*P2;

    CMatrix T6,T7,T8;
    T6=K*H;
    T7=I-T6;
    P1=T7*P2;

}

ObjectState KalmanFilter::GetCurrentState()
{
	ObjectState movestate;
	movestate.x_position=X1.m_pTMatrix[0][0];
	movestate.z_positon=X1.m_pTMatrix[1][0];
	movestate.x_speed=X1.m_pTMatrix[2][0];
	movestate.z_speed=X1.m_pTMatrix[3][0];

	return movestate;
}

ObjectState KalmanFilter::GetPredictState()
{
	ObjectState movestate;

	movestate.x_position=X2.m_pTMatrix[0][0];
	movestate.z_positon=X2.m_pTMatrix[1][0];
	movestate.x_speed=X2.m_pTMatrix[2][0];
	movestate.z_speed=X2.m_pTMatrix[3][0];

	return movestate;
}

Measurement KalmanFilter::GetPredictMeasurement(double rollAngle,double *pos)
{
	Measurement predictMeasurement;
	CMatrix temp(2,1);
	CalCoorRoll(rollAngle);
	X2=CoordinateRoll*X2;
	X2.m_pTMatrix[0][0]+=pos[0];
	X2.m_pTMatrix[1][0]+=pos[2];
	temp=H*X2;
	predictMeasurement.x_measurement=temp.m_pTMatrix[0][0];
	predictMeasurement.z_measurement=temp.m_pTMatrix[1][0];

	return predictMeasurement;
}

CMatrix KalmanFilter::CalMeasureDeviation()
{
	CMatrix Deviation(2,2),standardDeviation(2,2);

	CMatrix T6,T7,T8;
	T6=H.Transpose();
	T7=P2*T6;
	Deviation=H*T7+R;

//	Deviation=H*P2*H.Transpose()+R;

	for (int i=0;i<2;i++)
	{
		for(int j=0;j<2;j++)
		{
			standardDeviation.m_pTMatrix[i][j]=sqrt(Deviation.m_pTMatrix[i][j]);
		}
	}

	return standardDeviation;
}

KalmanFilter& KalmanFilter::operator = (const KalmanFilter& anotherKF)
{
	A=anotherKF.A;
	H=anotherKF.H;
	X1=anotherKF.X1;
	X2=anotherKF.X2;
	K=anotherKF.K;
	Z=anotherKF.Z;
	P1=anotherKF.P1;
	P2=anotherKF.P2;
	Q=anotherKF.Q;
	R=anotherKF.R;
	CoordinateRoll=anotherKF.CoordinateRoll;
	angle=anotherKF.angle;
	return *this;
}

void KalmanFilter::CalCoorRoll(double angle)
{
	CoordinateRoll.m_pTMatrix[0][0]=cos(angle);//angle is radian??
	CoordinateRoll.m_pTMatrix[0][1]=sin(angle);
	CoordinateRoll.m_pTMatrix[1][0]=-sin(angle);
	CoordinateRoll.m_pTMatrix[1][1]=cos(angle);
	CoordinateRoll.m_pTMatrix[2][2]=cos(angle);
	CoordinateRoll.m_pTMatrix[2][3]=sin(angle);
	CoordinateRoll.m_pTMatrix[3][2]=-sin(angle);
	CoordinateRoll.m_pTMatrix[3][3]=cos(angle);
}


