/***************************************************************************

	TITLE:	ls_step
	
----------------------------------------------------------------------------

	FUNCTION:	Integration routine for equations of motion 
			(vehicle states)

----------------------------------------------------------------------------

	MODULE STATUS:	developmental

----------------------------------------------------------------------------

	GENEALOGY:	Written 920802 by Bruce Jackson.  Based upon equations
			given in reference [1] and a Matrix-X/System Build block
			diagram model of equations of motion coded by David Raney
			at NASA-Langley in June of 1992.

----------------------------------------------------------------------------

	DESIGNED BY:	Bruce Jackson
	
	CODED BY:	Bruce Jackson
	
	MAINTAINED BY:	

----------------------------------------------------------------------------

	MODIFICATION HISTORY:
	
	DATE	PURPOSE						BY

	921223  Modified calculation of Phi and Psi to use the "atan2" routine
	        rather than the "atan" to allow full circular angles.
		"atan" limits to +/- pi/2.                      EBJ
		
	940111	Changed from oldstyle include file ls_eom.h; also changed
		from DATA to SCALAR type.			EBJ

	950207  Initialized Alpha_dot and Beta_dot to zero on first pass; calculated
		thereafter.					EBJ

	950224	Added logic to avoid adding additional increment to V_east
		in case V_east already accounts for rotating earth. 
								EBJ

	CURRENT RCS HEADER:

$Header$
$Log$
Revision 1.1  1997/05/29 00:09:59  curt
Initial Flight Gear revision.

 * Revision 1.5  1995/03/02  20:24:13  bjax
 * Added logic to avoid adding additional increment to V_east
 * in case V_east already accounts for rotating earth. EBJ
 *
 * Revision 1.4  1995/02/07  20:52:21  bjax
 * Added initialization of Alpha_dot and Beta_dot to zero on first
 * pass; they get calculated by ls_aux on next pass...  EBJ
 *
 * Revision 1.3  1994/01/11  19:01:12  bjax
 * Changed from DATA to SCALAR type; also fixed header files (was ls_eom.h)
 *
 * Revision 1.2  1993/06/02  15:03:09  bjax
 * Moved initialization of geocentric position to subroutine ls_geod_to_geoc.
 *
 * Revision 1.1  92/12/30  13:16:11  bjax
 * Initial revision
 * 

----------------------------------------------------------------------------

	REFERENCES:
	
		[ 1]	McFarland, Richard E.: "A Standard Kinematic Model
			for Flight Simulation at NASA-Ames", NASA CR-2497,
			January 1975
			 
		[ 2]	ANSI/AIAA R-004-1992 "Recommended Practice: Atmos-
			pheric and Space Flight Vehicle Coordinate Systems",
			February 1992
			

----------------------------------------------------------------------------

	CALLED BY:

----------------------------------------------------------------------------

	CALLS TO:	None.

----------------------------------------------------------------------------

	INPUTS:	State derivatives

----------------------------------------------------------------------------

	OUTPUTS:	States

--------------------------------------------------------------------------*/

#include "ls_types.h"
#include "ls_constants.h"
#include "ls_generic.h"
/* #include "ls_sim_control.h" */
#include <math.h>

extern SCALAR Simtime;		/* defined in ls_main.c */

void ls_step( dt, Initialize )

SCALAR dt;
int Initialize;

{
	static	int	inited = 0;
		SCALAR	dth;
	static	SCALAR	v_dot_north_past, v_dot_east_past, v_dot_down_past;
	static	SCALAR	latitude_dot_past, longitude_dot_past, radius_dot_past;
	static	SCALAR	p_dot_body_past, q_dot_body_past, r_dot_body_past;
		SCALAR	p_local_in_body, q_local_in_body, r_local_in_body;
		SCALAR	epsilon, inv_eps, local_gnd_veast;
		SCALAR	e_dot_0, e_dot_1, e_dot_2, e_dot_3;
	static	SCALAR	e_0, e_1, e_2, e_3;
	static	SCALAR	e_dot_0_past, e_dot_1_past, e_dot_2_past, e_dot_3_past;

/*  I N I T I A L I Z A T I O N   */


	if ( (inited == 0) || (Initialize != 0) )
	{
/* Set past values to zero */
	v_dot_north_past = v_dot_east_past = v_dot_down_past      = 0;
	latitude_dot_past = longitude_dot_past = radius_dot_past  = 0;
	p_dot_body_past = q_dot_body_past = r_dot_body_past       = 0;
	e_dot_0_past = e_dot_1_past = e_dot_2_past = e_dot_3_past = 0;
	
/* Initialize geocentric position from geodetic latitude and altitude */
	
	ls_geod_to_geoc( Latitude, Altitude, &Sea_level_radius, &Lat_geocentric);
	Earth_position_angle = 0;
	Lon_geocentric = Longitude;
	Radius_to_vehicle = Altitude + Sea_level_radius;

/* Correct eastward velocity to account for earths' rotation, if necessary */

	local_gnd_veast = OMEGA_EARTH*Sea_level_radius*cos(Lat_geocentric);
	if( fabs(V_east - V_east_rel_ground) < 0.8*local_gnd_veast )
    	V_east = V_east + local_gnd_veast;

/* Initialize quaternions and transformation matrix from Euler angles */

	    e_0 = cos(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5) 
		+ sin(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5);
	    e_1 = cos(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5) 
		- sin(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5);
	    e_2 = cos(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5) 
		+ sin(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5);
	    e_3 =-cos(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5) 
		+ sin(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5);
	    T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
	    T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
	    T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
	    T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
	    T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
	    T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
	    T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
	    T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
	    T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;

/*	Calculate local gravitation acceleration	*/

		ls_gravity( Radius_to_vehicle, Lat_geocentric, &Gravity );

/*	Initialize vehicle model 			*/

		ls_aux();
		ls_model();

/* 	Calculate initial accelerations */

		ls_accel();
		
/* Initialize auxiliary variables */

		ls_aux();
		Alpha_dot = 0.;
		Beta_dot = 0.;

/* set flag; disable integrators */

		inited = -1;
		dt = 0;
		
	}

/* Update time */

	dth = 0.5*dt;
	Simtime = Simtime + dt;

/*  L I N E A R   V E L O C I T I E S   */

/* Integrate linear accelerations to get velocities */
/*    Using predictive Adams-Bashford algorithm     */

    V_north = V_north + dth*(3*V_dot_north - v_dot_north_past);
    V_east  = V_east  + dth*(3*V_dot_east  - v_dot_east_past );
    V_down  = V_down  + dth*(3*V_dot_down  - v_dot_down_past );
    
/* record past states */

    v_dot_north_past = V_dot_north;
    v_dot_east_past  = V_dot_east;
    v_dot_down_past  = V_dot_down;
    
/* Calculate trajectory rate (geocentric coordinates) */

    if (cos(Lat_geocentric) != 0)
    	Longitude_dot = V_east/(Radius_to_vehicle*cos(Lat_geocentric));
    	
    Latitude_dot = V_north/Radius_to_vehicle;
    Radius_dot = -V_down;
    	
/*  A N G U L A R   V E L O C I T I E S   A N D   P O S I T I O N S  */
    
/* Integrate rotational accelerations to get velocities */

    P_body = P_body + dth*(3*P_dot_body - p_dot_body_past);
    Q_body = Q_body + dth*(3*Q_dot_body - q_dot_body_past);
    R_body = R_body + dth*(3*R_dot_body - r_dot_body_past);

/* Save past states */

    p_dot_body_past = P_dot_body;
    q_dot_body_past = Q_dot_body;
    r_dot_body_past = R_dot_body;
    
/* Calculate local axis frame rates due to travel over curved earth */

    P_local =  V_east/Radius_to_vehicle;
    Q_local = -V_north/Radius_to_vehicle;
    R_local = -V_east*tan(Lat_geocentric)/Radius_to_vehicle;
    
/* Transform local axis frame rates to body axis rates */

    p_local_in_body = T_local_to_body_11*P_local + T_local_to_body_12*Q_local + T_local_to_body_13*R_local;
    q_local_in_body = T_local_to_body_21*P_local + T_local_to_body_22*Q_local + T_local_to_body_23*R_local;
    r_local_in_body = T_local_to_body_31*P_local + T_local_to_body_32*Q_local + T_local_to_body_33*R_local;
    
/* Calculate total angular rates in body axis */

    P_total = P_body - p_local_in_body;
    Q_total = Q_body - q_local_in_body;
    R_total = R_body - r_local_in_body;
    
/* Transform to quaternion rates (see Appendix E in [2]) */

    e_dot_0 = 0.5*( -P_total*e_1 - Q_total*e_2 - R_total*e_3 );
    e_dot_1 = 0.5*(  P_total*e_0 - Q_total*e_3 + R_total*e_2 );
    e_dot_2 = 0.5*(  P_total*e_3 + Q_total*e_0 - R_total*e_1 );
    e_dot_3 = 0.5*( -P_total*e_2 + Q_total*e_1 + R_total*e_0 );

/* Integrate using trapezoidal as before */

	e_0 = e_0 + dth*(e_dot_0 + e_dot_0_past);
	e_1 = e_1 + dth*(e_dot_1 + e_dot_1_past);
	e_2 = e_2 + dth*(e_dot_2 + e_dot_2_past);
	e_3 = e_3 + dth*(e_dot_3 + e_dot_3_past);
	
/* calculate orthagonality correction  - scale quaternion to unity length */
	
	epsilon = sqrt(e_0*e_0 + e_1*e_1 + e_2*e_2 + e_3*e_3);
	inv_eps = 1/epsilon;
	
	e_0 = inv_eps*e_0;
	e_1 = inv_eps*e_1;
	e_2 = inv_eps*e_2;
	e_3 = inv_eps*e_3;

/* Save past values */

	e_dot_0_past = e_dot_0;
	e_dot_1_past = e_dot_1;
	e_dot_2_past = e_dot_2;
	e_dot_3_past = e_dot_3;
	
/* Update local to body transformation matrix */

	T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
	T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
	T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
	T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
	T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
	T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
	T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
	T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
	T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
	
/* Calculate Euler angles */

	Theta = asin( -T_local_to_body_13 );

	if( T_local_to_body_11 == 0 )
	Psi = 0;
	else
	Psi = atan2( T_local_to_body_12, T_local_to_body_11 );

	if( T_local_to_body_33 == 0 )
	Phi = 0;
	else
	Phi = atan2( T_local_to_body_23, T_local_to_body_33 );

/* Resolve Psi to 0 - 359.9999 */

	if (Psi < 0 ) Psi = Psi + 2*PI;

/*  L I N E A R   P O S I T I O N S   */

/* Trapezoidal acceleration for position */

	Lat_geocentric    = Lat_geocentric    + dth*(Latitude_dot  + latitude_dot_past );
	Lon_geocentric    = Lon_geocentric    + dth*(Longitude_dot + longitude_dot_past);
	Radius_to_vehicle = Radius_to_vehicle + dth*(Radius_dot    + radius_dot_past );
	Earth_position_angle = Earth_position_angle + dt*OMEGA_EARTH;
	
/* Save past values */

	latitude_dot_past  = Latitude_dot;
	longitude_dot_past = Longitude_dot;
	radius_dot_past    = Radius_dot;
	
/* end of ls_step */
}
/*************************************************************************/