1 /***************************************************************************
5 ----------------------------------------------------------------------------
7 FUNCTION: Integration routine for equations of motion
10 ----------------------------------------------------------------------------
12 MODULE STATUS: developmental
14 ----------------------------------------------------------------------------
16 GENEALOGY: Written 920802 by Bruce Jackson. Based upon equations
17 given in reference [1] and a Matrix-X/System Build block
18 diagram model of equations of motion coded by David Raney
19 at NASA-Langley in June of 1992.
21 ----------------------------------------------------------------------------
23 DESIGNED BY: Bruce Jackson
25 CODED BY: Bruce Jackson
29 ----------------------------------------------------------------------------
35 921223 Modified calculation of Phi and Psi to use the "atan2" routine
36 rather than the "atan" to allow full circular angles.
37 "atan" limits to +/- pi/2. EBJ
39 940111 Changed from oldstyle include file ls_eom.h; also changed
40 from DATA to SCALAR type. EBJ
42 950207 Initialized Alpha_dot and Beta_dot to zero on first pass; calculated
45 950224 Added logic to avoid adding additional increment to V_east
46 in case V_east already accounts for rotating earth.
53 Revision 1.1 1997/05/29 00:09:59 curt
54 Initial Flight Gear revision.
56 * Revision 1.5 1995/03/02 20:24:13 bjax
57 * Added logic to avoid adding additional increment to V_east
58 * in case V_east already accounts for rotating earth. EBJ
60 * Revision 1.4 1995/02/07 20:52:21 bjax
61 * Added initialization of Alpha_dot and Beta_dot to zero on first
62 * pass; they get calculated by ls_aux on next pass... EBJ
64 * Revision 1.3 1994/01/11 19:01:12 bjax
65 * Changed from DATA to SCALAR type; also fixed header files (was ls_eom.h)
67 * Revision 1.2 1993/06/02 15:03:09 bjax
68 * Moved initialization of geocentric position to subroutine ls_geod_to_geoc.
70 * Revision 1.1 92/12/30 13:16:11 bjax
74 ----------------------------------------------------------------------------
78 [ 1] McFarland, Richard E.: "A Standard Kinematic Model
79 for Flight Simulation at NASA-Ames", NASA CR-2497,
82 [ 2] ANSI/AIAA R-004-1992 "Recommended Practice: Atmos-
83 pheric and Space Flight Vehicle Coordinate Systems",
87 ----------------------------------------------------------------------------
91 ----------------------------------------------------------------------------
95 ----------------------------------------------------------------------------
97 INPUTS: State derivatives
99 ----------------------------------------------------------------------------
103 --------------------------------------------------------------------------*/
105 #include "ls_types.h"
106 #include "ls_constants.h"
107 #include "ls_generic.h"
108 /* #include "ls_sim_control.h" */
111 extern SCALAR Simtime; /* defined in ls_main.c */
113 void ls_step( dt, Initialize )
119 static int inited = 0;
121 static SCALAR v_dot_north_past, v_dot_east_past, v_dot_down_past;
122 static SCALAR latitude_dot_past, longitude_dot_past, radius_dot_past;
123 static SCALAR p_dot_body_past, q_dot_body_past, r_dot_body_past;
124 SCALAR p_local_in_body, q_local_in_body, r_local_in_body;
125 SCALAR epsilon, inv_eps, local_gnd_veast;
126 SCALAR e_dot_0, e_dot_1, e_dot_2, e_dot_3;
127 static SCALAR e_0, e_1, e_2, e_3;
128 static SCALAR e_dot_0_past, e_dot_1_past, e_dot_2_past, e_dot_3_past;
130 /* I N I T I A L I Z A T I O N */
133 if ( (inited == 0) || (Initialize != 0) )
135 /* Set past values to zero */
136 v_dot_north_past = v_dot_east_past = v_dot_down_past = 0;
137 latitude_dot_past = longitude_dot_past = radius_dot_past = 0;
138 p_dot_body_past = q_dot_body_past = r_dot_body_past = 0;
139 e_dot_0_past = e_dot_1_past = e_dot_2_past = e_dot_3_past = 0;
141 /* Initialize geocentric position from geodetic latitude and altitude */
143 ls_geod_to_geoc( Latitude, Altitude, &Sea_level_radius, &Lat_geocentric);
144 Earth_position_angle = 0;
145 Lon_geocentric = Longitude;
146 Radius_to_vehicle = Altitude + Sea_level_radius;
148 /* Correct eastward velocity to account for earths' rotation, if necessary */
150 local_gnd_veast = OMEGA_EARTH*Sea_level_radius*cos(Lat_geocentric);
151 if( fabs(V_east - V_east_rel_ground) < 0.8*local_gnd_veast )
152 V_east = V_east + local_gnd_veast;
154 /* Initialize quaternions and transformation matrix from Euler angles */
156 e_0 = cos(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5)
157 + sin(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5);
158 e_1 = cos(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5)
159 - sin(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5);
160 e_2 = cos(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5)
161 + sin(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5);
162 e_3 =-cos(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5)
163 + sin(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5);
164 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
165 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
166 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
167 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
168 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
169 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
170 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
171 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
172 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
174 /* Calculate local gravitation acceleration */
176 ls_gravity( Radius_to_vehicle, Lat_geocentric, &Gravity );
178 /* Initialize vehicle model */
183 /* Calculate initial accelerations */
187 /* Initialize auxiliary variables */
193 /* set flag; disable integrators */
203 Simtime = Simtime + dt;
205 /* L I N E A R V E L O C I T I E S */
207 /* Integrate linear accelerations to get velocities */
208 /* Using predictive Adams-Bashford algorithm */
210 V_north = V_north + dth*(3*V_dot_north - v_dot_north_past);
211 V_east = V_east + dth*(3*V_dot_east - v_dot_east_past );
212 V_down = V_down + dth*(3*V_dot_down - v_dot_down_past );
214 /* record past states */
216 v_dot_north_past = V_dot_north;
217 v_dot_east_past = V_dot_east;
218 v_dot_down_past = V_dot_down;
220 /* Calculate trajectory rate (geocentric coordinates) */
222 if (cos(Lat_geocentric) != 0)
223 Longitude_dot = V_east/(Radius_to_vehicle*cos(Lat_geocentric));
225 Latitude_dot = V_north/Radius_to_vehicle;
226 Radius_dot = -V_down;
228 /* 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 */
230 /* Integrate rotational accelerations to get velocities */
232 P_body = P_body + dth*(3*P_dot_body - p_dot_body_past);
233 Q_body = Q_body + dth*(3*Q_dot_body - q_dot_body_past);
234 R_body = R_body + dth*(3*R_dot_body - r_dot_body_past);
236 /* Save past states */
238 p_dot_body_past = P_dot_body;
239 q_dot_body_past = Q_dot_body;
240 r_dot_body_past = R_dot_body;
242 /* Calculate local axis frame rates due to travel over curved earth */
244 P_local = V_east/Radius_to_vehicle;
245 Q_local = -V_north/Radius_to_vehicle;
246 R_local = -V_east*tan(Lat_geocentric)/Radius_to_vehicle;
248 /* Transform local axis frame rates to body axis rates */
250 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;
251 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;
252 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;
254 /* Calculate total angular rates in body axis */
256 P_total = P_body - p_local_in_body;
257 Q_total = Q_body - q_local_in_body;
258 R_total = R_body - r_local_in_body;
260 /* Transform to quaternion rates (see Appendix E in [2]) */
262 e_dot_0 = 0.5*( -P_total*e_1 - Q_total*e_2 - R_total*e_3 );
263 e_dot_1 = 0.5*( P_total*e_0 - Q_total*e_3 + R_total*e_2 );
264 e_dot_2 = 0.5*( P_total*e_3 + Q_total*e_0 - R_total*e_1 );
265 e_dot_3 = 0.5*( -P_total*e_2 + Q_total*e_1 + R_total*e_0 );
267 /* Integrate using trapezoidal as before */
269 e_0 = e_0 + dth*(e_dot_0 + e_dot_0_past);
270 e_1 = e_1 + dth*(e_dot_1 + e_dot_1_past);
271 e_2 = e_2 + dth*(e_dot_2 + e_dot_2_past);
272 e_3 = e_3 + dth*(e_dot_3 + e_dot_3_past);
274 /* calculate orthagonality correction - scale quaternion to unity length */
276 epsilon = sqrt(e_0*e_0 + e_1*e_1 + e_2*e_2 + e_3*e_3);
284 /* Save past values */
286 e_dot_0_past = e_dot_0;
287 e_dot_1_past = e_dot_1;
288 e_dot_2_past = e_dot_2;
289 e_dot_3_past = e_dot_3;
291 /* Update local to body transformation matrix */
293 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
294 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
295 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
296 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
297 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
298 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
299 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
300 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
301 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
303 /* Calculate Euler angles */
305 Theta = asin( -T_local_to_body_13 );
307 if( T_local_to_body_11 == 0 )
310 Psi = atan2( T_local_to_body_12, T_local_to_body_11 );
312 if( T_local_to_body_33 == 0 )
315 Phi = atan2( T_local_to_body_23, T_local_to_body_33 );
317 /* Resolve Psi to 0 - 359.9999 */
319 if (Psi < 0 ) Psi = Psi + 2*PI;
321 /* L I N E A R P O S I T I O N S */
323 /* Trapezoidal acceleration for position */
325 Lat_geocentric = Lat_geocentric + dth*(Latitude_dot + latitude_dot_past );
326 Lon_geocentric = Lon_geocentric + dth*(Longitude_dot + longitude_dot_past);
327 Radius_to_vehicle = Radius_to_vehicle + dth*(Radius_dot + radius_dot_past );
328 Earth_position_angle = Earth_position_angle + dt*OMEGA_EARTH;
330 /* Save past values */
332 latitude_dot_past = Latitude_dot;
333 longitude_dot_past = Longitude_dot;
334 radius_dot_past = Radius_dot;
338 /*************************************************************************/