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 1999/06/17 18:07:33 curt
56 Revision 1.1.1.1 1999/04/05 21:32:45 curt
57 Start of 0.6.x branch.
59 Revision 1.4 1998/08/24 20:09:27 curt
60 Code optimization tweaks from Norman Vine.
62 Revision 1.3 1998/07/12 03:11:04 curt
63 Removed some printf()'s.
64 Fixed the autopilot integration so it should be able to update it's control
65 positions every time the internal flight model loop is run, and not just
66 once per rendered frame.
67 Added a routine to do the necessary stuff to force an arbitrary altitude
69 Gave the Navion engine just a tad more power.
71 Revision 1.2 1998/01/19 18:40:28 curt
72 Tons of little changes to clean up the code and to remove fatal errors
73 when building with the c++ compiler.
75 Revision 1.1 1997/05/29 00:09:59 curt
76 Initial Flight Gear revision.
78 * Revision 1.5 1995/03/02 20:24:13 bjax
79 * Added logic to avoid adding additional increment to V_east
80 * in case V_east already accounts for rotating earth. EBJ
82 * Revision 1.4 1995/02/07 20:52:21 bjax
83 * Added initialization of Alpha_dot and Beta_dot to zero on first
84 * pass; they get calculated by ls_aux on next pass... EBJ
86 * Revision 1.3 1994/01/11 19:01:12 bjax
87 * Changed from DATA to SCALAR type; also fixed header files (was ls_eom.h)
89 * Revision 1.2 1993/06/02 15:03:09 bjax
90 * Moved initialization of geocentric position to subroutine ls_geod_to_geoc.
92 * Revision 1.1 92/12/30 13:16:11 bjax
96 ----------------------------------------------------------------------------
100 [ 1] McFarland, Richard E.: "A Standard Kinematic Model
101 for Flight Simulation at NASA-Ames", NASA CR-2497,
104 [ 2] ANSI/AIAA R-004-1992 "Recommended Practice: Atmos-
105 pheric and Space Flight Vehicle Coordinate Systems",
109 ----------------------------------------------------------------------------
113 ----------------------------------------------------------------------------
117 ----------------------------------------------------------------------------
119 INPUTS: State derivatives
121 ----------------------------------------------------------------------------
125 --------------------------------------------------------------------------*/
127 #include "ls_types.h"
128 #include "ls_constants.h"
129 #include "ls_generic.h"
130 #include "ls_accel.h"
132 #include "ls_model.h"
134 #include "ls_geodesy.h"
135 #include "ls_gravity.h"
136 /* #include "ls_sim_control.h" */
139 extern SCALAR Simtime; /* defined in ls_main.c */
141 void ls_step( SCALAR dt, int Initialize ) {
142 static int inited = 0;
144 static SCALAR v_dot_north_past, v_dot_east_past, v_dot_down_past;
145 static SCALAR latitude_dot_past, longitude_dot_past, radius_dot_past;
146 static SCALAR p_dot_body_past, q_dot_body_past, r_dot_body_past;
147 SCALAR p_local_in_body, q_local_in_body, r_local_in_body;
148 SCALAR epsilon, inv_eps, local_gnd_veast;
149 SCALAR e_dot_0, e_dot_1, e_dot_2, e_dot_3;
150 static SCALAR e_0, e_1, e_2, e_3;
151 static SCALAR e_dot_0_past, e_dot_1_past, e_dot_2_past, e_dot_3_past;
152 SCALAR cos_Lat_geocentric, inv_Radius_to_vehicle;
154 /* I N I T I A L I Z A T I O N */
157 if ( (inited == 0) || (Initialize != 0) )
159 /* Set past values to zero */
160 v_dot_north_past = v_dot_east_past = v_dot_down_past = 0;
161 latitude_dot_past = longitude_dot_past = radius_dot_past = 0;
162 p_dot_body_past = q_dot_body_past = r_dot_body_past = 0;
163 e_dot_0_past = e_dot_1_past = e_dot_2_past = e_dot_3_past = 0;
165 /* Initialize geocentric position from geodetic latitude and altitude */
167 ls_geod_to_geoc( Latitude, Altitude, &Sea_level_radius, &Lat_geocentric);
168 Earth_position_angle = 0;
169 Lon_geocentric = Longitude;
170 Radius_to_vehicle = Altitude + Sea_level_radius;
172 /* Correct eastward velocity to account for earths' rotation, if necessary */
174 local_gnd_veast = OMEGA_EARTH*Sea_level_radius*cos(Lat_geocentric);
175 if( fabs(V_east - V_east_rel_ground) < 0.8*local_gnd_veast )
176 V_east = V_east + local_gnd_veast;
178 /* Initialize quaternions and transformation matrix from Euler angles */
180 e_0 = cos(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5)
181 + sin(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5);
182 e_1 = cos(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5)
183 - sin(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5);
184 e_2 = cos(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5)
185 + sin(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5);
186 e_3 =-cos(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5)
187 + sin(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5);
188 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
189 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
190 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
191 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
192 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
193 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
194 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
195 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
196 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
198 /* Calculate local gravitation acceleration */
200 ls_gravity( Radius_to_vehicle, Lat_geocentric, &Gravity );
202 /* Initialize vehicle model */
207 /* Calculate initial accelerations */
211 /* Initialize auxiliary variables */
217 /* set flag; disable integrators */
227 Simtime = Simtime + dt;
229 /* L I N E A R V E L O C I T I E S */
231 /* Integrate linear accelerations to get velocities */
232 /* Using predictive Adams-Bashford algorithm */
234 V_north = V_north + dth*(3*V_dot_north - v_dot_north_past);
235 V_east = V_east + dth*(3*V_dot_east - v_dot_east_past );
236 V_down = V_down + dth*(3*V_dot_down - v_dot_down_past );
238 /* record past states */
240 v_dot_north_past = V_dot_north;
241 v_dot_east_past = V_dot_east;
242 v_dot_down_past = V_dot_down;
244 /* Calculate trajectory rate (geocentric coordinates) */
246 inv_Radius_to_vehicle = 1.0/Radius_to_vehicle;
247 cos_Lat_geocentric = cos(Lat_geocentric);
249 if ( cos_Lat_geocentric != 0) {
250 Longitude_dot = V_east/(Radius_to_vehicle*cos_Lat_geocentric);
253 Latitude_dot = V_north*inv_Radius_to_vehicle;
254 Radius_dot = -V_down;
256 /* 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 */
258 /* Integrate rotational accelerations to get velocities */
260 P_body = P_body + dth*(3*P_dot_body - p_dot_body_past);
261 Q_body = Q_body + dth*(3*Q_dot_body - q_dot_body_past);
262 R_body = R_body + dth*(3*R_dot_body - r_dot_body_past);
264 /* Save past states */
266 p_dot_body_past = P_dot_body;
267 q_dot_body_past = Q_dot_body;
268 r_dot_body_past = R_dot_body;
270 /* Calculate local axis frame rates due to travel over curved earth */
272 P_local = V_east*inv_Radius_to_vehicle;
273 Q_local = -V_north*inv_Radius_to_vehicle;
274 R_local = -V_east*tan(Lat_geocentric)*inv_Radius_to_vehicle;
276 /* Transform local axis frame rates to body axis rates */
278 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;
279 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;
280 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;
282 /* Calculate total angular rates in body axis */
284 P_total = P_body - p_local_in_body;
285 Q_total = Q_body - q_local_in_body;
286 R_total = R_body - r_local_in_body;
288 /* Transform to quaternion rates (see Appendix E in [2]) */
290 e_dot_0 = 0.5*( -P_total*e_1 - Q_total*e_2 - R_total*e_3 );
291 e_dot_1 = 0.5*( P_total*e_0 - Q_total*e_3 + R_total*e_2 );
292 e_dot_2 = 0.5*( P_total*e_3 + Q_total*e_0 - R_total*e_1 );
293 e_dot_3 = 0.5*( -P_total*e_2 + Q_total*e_1 + R_total*e_0 );
295 /* Integrate using trapezoidal as before */
297 e_0 = e_0 + dth*(e_dot_0 + e_dot_0_past);
298 e_1 = e_1 + dth*(e_dot_1 + e_dot_1_past);
299 e_2 = e_2 + dth*(e_dot_2 + e_dot_2_past);
300 e_3 = e_3 + dth*(e_dot_3 + e_dot_3_past);
302 /* calculate orthagonality correction - scale quaternion to unity length */
304 epsilon = sqrt(e_0*e_0 + e_1*e_1 + e_2*e_2 + e_3*e_3);
312 /* Save past values */
314 e_dot_0_past = e_dot_0;
315 e_dot_1_past = e_dot_1;
316 e_dot_2_past = e_dot_2;
317 e_dot_3_past = e_dot_3;
319 /* Update local to body transformation matrix */
321 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
322 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
323 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
324 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
325 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
326 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
327 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
328 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
329 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
331 /* Calculate Euler angles */
333 Theta = asin( -T_local_to_body_13 );
335 if( T_local_to_body_11 == 0 )
338 Psi = atan2( T_local_to_body_12, T_local_to_body_11 );
340 if( T_local_to_body_33 == 0 )
343 Phi = atan2( T_local_to_body_23, T_local_to_body_33 );
345 /* Resolve Psi to 0 - 359.9999 */
347 if (Psi < 0 ) Psi = Psi + 2*PI;
349 /* L I N E A R P O S I T I O N S */
351 /* Trapezoidal acceleration for position */
353 Lat_geocentric = Lat_geocentric + dth*(Latitude_dot + latitude_dot_past );
354 Lon_geocentric = Lon_geocentric + dth*(Longitude_dot + longitude_dot_past);
355 Radius_to_vehicle = Radius_to_vehicle + dth*(Radius_dot + radius_dot_past );
356 Earth_position_angle = Earth_position_angle + dt*OMEGA_EARTH;
358 /* Save past values */
360 latitude_dot_past = Latitude_dot;
361 longitude_dot_past = Longitude_dot;
362 radius_dot_past = Radius_dot;
366 /*************************************************************************/