1
0
Fork 0

Next big step: proper ground reactions. Also make it possible to run fgfs --aircraft=aisim --aero=<aircraft> for different aircraft configurations (which requires an upcoming update to FGData

This commit is contained in:
Erik Hofman 2020-09-25 13:19:10 +02:00
parent 5329c4024b
commit 56d4662468
2 changed files with 227 additions and 180 deletions

View file

@ -48,10 +48,6 @@
# include "simd4x4.hxx"
#endif
#ifndef _MINMAX
# define _MINMAX(a,b,c) (((a)>(c)) ? (c) : (((a)<(b)) ? (b) : (a)))
#endif
#define FEET_TO_INCHES 12.0f
#define INCHES_TO_FEET (1.0f/FEET_TO_INCHES)
@ -64,13 +60,16 @@ FGAISim::FGAISim(double dt)
{
contact_pos[i] = 0.0f;
contact_spring[i] = contact_damp[i] = 0.0f;
FT[i] = FTM[i] = MT[i] = 0.0f;
FT[i] = MT[i] = 0.0f;
}
#ifdef ENABLE_SP_FDM
SGPath aircraft_path( fgGetString("/sim/aircraft-dir") );
SGPath aircraft_path( fgGetString("/sim/fg-root") );
SGPropertyNode_ptr aero = fgGetNode("sim/aero", true);
aircraft_path.append(aero->getStringValue() );
aircraft_path.append("Aircraft-aisim");
aircraft_path.append(aero->getStringValue());
aircraft_path.concat(".json");
load(aircraft_path.str());
#else
load("");
@ -105,34 +104,36 @@ FGAISim::FGAISim(double dt)
xCDYLT.ptr()[MIN][DRAG] = -CDmin;
/* m is assigned in the load function */
inv_m = 1.0f/m;
inv_mass = aiVec3(1.0f)/mass;
// calculate aircraft position when resting on the landing gear.
float cg_agl = -cg[Z];
if (no_contacts)
{
for (size_t i=0; i<no_contacts; ++i) {
cg_agl -= contact_pos[i][Z];
cg_agl += contact_pos[i][Z];
}
cg_agl *= FEET_TO_INCHES/static_cast<float>(no_contacts);
cg_agl /= static_cast<float>(no_contacts);
}
set_altitude_agl_ft(cg_agl);
// Contact point at the center of gravity
contact_pos[no_contacts] = 0.0f;
contact_spring[no_contacts] = 20000.0f;
contact_damp[no_contacts] = 2000.0f;
contact_spring[no_contacts] = -20000.0f;
contact_damp[no_contacts] = -2000.0f;
no_contacts++;
aiMtx4 mcg;
simd4x4::unit(mcg);
simd4x4::translate(mcg, cg);
mI = aiMtx4( I[XX], 0.0f, -I[XZ], 0.0f,
mJ = aiMtx4( I[XX], 0.0f, -I[XZ], 0.0f,
0.0f, I[YY], 0.0f, 0.0f,
-I[XZ], 0.0f, I[ZZ], 0.0f,
0.0f, 0.0f, 0.0f, 0.0f);
mIinv = invert_inertia(mI);
mI *= mcg;
mIinv *= matrix_inverse(mcg);
mJinv = invert_inertia(mJ);
mJ *= mcg;
mJinv *= matrix_inverse(mcg);
}
FGAISim::~FGAISim()
@ -152,8 +153,8 @@ FGAISim::init()
// now do init specific to the AISim
SG_LOG( SG_FLIGHT, SG_INFO, "Starting initializing AISim" );
// right now cg_agl holds the lowest contact point of the aircraft
set_Altitude( get_Altitude()-cg_agl );
// cg_agl holds the lowest contact point of the aircraft
set_Altitude( get_Altitude() + cg_agl );
set_location_geod( get_Latitude(), get_Longitude(), get_Altitude() );
set_euler_angles_rad( get_Phi(), get_Theta(), get_Psi() );
set_velocity_fps( fgGetFloat("sim/presets/uBody-fps"),
@ -177,33 +178,41 @@ FGAISim::update(double ddt)
copy_to_AISim();
#endif
#if 0
printf("pitch: % 7.5f, roll: % 7.5f, heading: % 7.5f\n", euler[THETA], euler[PHI], euler[PSI]);
printf("wind north: % 7.5f, east: % 7.5f, down: % 7.5f\n", wind_ned[0], wind_ned[1], wind_ned[2]);
#endif
/* Earth-to-Body-Axis Transformation Matrix */
/* matrices to compensate for pitch, roll and heading */
aiVec3 vector = euler;
float angle = simd4::normalize(vector);
aiMtx4 mNed2Body = simd4x4::rotation_matrix(angle, vector);
aiVec3 vector = euler; // simd4::normalize alters the vector
float len = simd4::normalize(vector);
aiMtx4 mNed2Body = simd4x4::rotation_matrix(len, vector);
aiMtx4 mBody2Ned = simd4x4::transpose(mNed2Body);
aiVec3 gravity_body = mNed2Body*gravity_ned;
aiVec3 wind = mNed2Body*wind_ned;
/* Air-Relative velocity vector */
vUVWaero = vUVW + mNed2Body*wind_ned;
update_velocity( simd4::magnitude( simd4_t<float,2>(vUVWaero) ) );
vUVWaero = vUVW + wind;
update_velocity( simd4::magnitude( vUVWaero ) );
aiVec3 WindAxis = AOA;
float alpha = std::atan2(vUVWaero[W], vUVWaero[U]);
set_alpha_rad( _MINMAX(alpha, -0.25f, 0.25f) ); // -14 to 14 degrees
/* Wind angles */
aiVec3 prevAOA = AOA;
alpha = (vUVWaero[U] == 0.0f) ? 0.0f : std::atan2(vUVWaero[W], vUVWaero[U]);
set_alpha_rad( alpha );
float beta = (velocity == 0) ? 0 : std::asin(vUVWaero[V]/velocity);
set_beta_rad( _MINMAX(beta, -0.30f, 0.30f) ); // -17 to 17 degrees
AOAdot = (AOA - WindAxis)/dt;
beta = (velocity == 0.0f) ? 0.0f : std::asin(vUVWaero[V]/velocity);
set_beta_rad( beta );
/* set_alpha_rad and set_beta_rad set the new AOA */
AOAdot = (AOA - prevAOA)/dt;
#if 0
printf("velocity: %f, vUVWaero: %3.2f, %3.2f, %3.2f, mach: %3.2f\n", velocity, vUVWaero[0], vUVWaero[1], vUVWaero[2], mach);
printf("velocity: %f, vUVWaero: %3.2f, %3.2f, %3.2f, mach: %3.2f\n", velocity, vUVWaero[U], vUVWaero[V], vUVWaero[W], mach);
printf("cg_agl: %5.4f, alpha: %5.4f, beta: %5.4f, adot: %5.4f, bdot: %5.4f\n", cg_agl, AOA[ALPHA], AOA[BETA], AOAdot[ALPHA], AOAdot[BETA]);
#endif
/* Force and Moment Coefficients */
/* Sum all Drag, Side, Lift, Roll, Pitch, Yaw and Thrust coefficients */
/* Sum all Drag, Side, Lift, Roll, Pitch and Yaw and Thrust coefficients */
float p = vPQR[P];
float q = vPQR[Q];
float r = vPQR[R];
@ -218,8 +227,10 @@ FGAISim::update(double ddt)
* Clmn[YAW] = (Cnp*p + Cnr*r)*b_2U;
*/
aiVec4 Ccbar2U = (xCq*q + xCadot*adot)*cbar_2U;
aiVec4 Cb2U = (xCp*p + xCr*r )*b_2U;
aiVec4 Cb2U = (xCp*p + xCr*r)*b_2U;
/* xCDYLT and xClmnT already have their factors applied */
/* in the functions in the header file. */
aiVec4 CDYL(0.0f, Cb2U[SIDE], Ccbar2U[LIFT]);
aiVec4 Clmn(Cb2U[ROLL], Ccbar2U[PITCH], Cb2U[YAW]);
size_t i = 3;
@ -232,6 +243,7 @@ FGAISim::update(double ddt)
float CL = CDYL[LIFT];
CDYL += aiVec3(CDi*CL*CL, 0.0f, 0.0f);
#if 0
printf(" p: %6.3f, q: %6.3f, r: %6.3f, adot: %6.3f\n", p, q, r, adot);
printf(" CLa: %6.3f, CLadot: %6.3f, CLq: %6.3f\n", xCDYLT.ptr()[ALPHA][LIFT],CLadot*adot,CLq*q);
printf(" CDa: %6.3f, CDb: %6.3f, CDi: %6.3f\n", xCDYLT.ptr()[ALPHA][DRAG],xCDYLT.ptr()[BETA][DRAG],CDi*CL*CL);
printf(" CYb: %6.3f, CYp: %6.3f, CYr: %6.3f\n", xCDYLT.ptr()[BETA][SIDE],CYp*p,CYr*r);
@ -243,6 +255,7 @@ FGAISim::update(double ddt)
printf(" CYdr: %6.3f, Cldr: %6.3f, Cndr: %6.3f\n", xCDYLT.ptr()[RUDDER][SIDE], xClmnT.ptr()[RUDDER][ROLL], xClmnT.ptr()[RUDDER][YAW]);
printf(" Clda: %6.3f, CYda: %6.3f\n", xClmnT.ptr()[AILERON][ROLL], xClmnT.ptr()[AILERON][YAW]);
printf(" Cldf: %6.3f, CDdf: %6.3f, Cmdf: %6.3f\n", xCDYLT.ptr()[FLAPS][LIFT], xCDYLT.ptr()[FLAPS][DRAG], xClmnT.ptr()[FLAPS][PITCH]);
printf("\n");
#endif
/* State Accelerations (convert coefficients to forces and moments) */
@ -251,101 +264,112 @@ FGAISim::update(double ddt)
/* convert from wind axes to body axes */
vector = AOA;
angle = simd4::normalize(vector);
aiMtx4 mWindBody = simd4x4::rotation_matrix(angle, vector);
aiVec3 FXYZ = mWindBody*FDYL;
len = simd4::normalize(vector);
aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, vector);
aiVec3 FXYZ_body = mWind2Body*FDYL;
aiVec3 gravity_body = mNed2Body*gravity_ned;
FXYZ_body += gravity_body*mass;
/* Thrust */
aiVec3 Cth = rho*th;
aiVec3 Cmach = rho*mach;
for (size_t i=0; i<no_engines; ++i)
float Cth = rho*throttle*throttle;
i = no_engines-1;
do
{
FXYZ += FT[i]*Cth + FTM[i]*Cmach;
Mlmn += MT[i]*Cth;
#if 0
aiVec3 FTCth = FT[i]*Cth + FTM[i]*Cmach;
aiVec3 MTCth = MT[i]*Cth;
printf("FT[%i]: %5.4f, %5.4f, %5.4f\n", i, FTCth[X], FTCth[Y], FTCth[Z]);
printf("MT[%i]: %5.4f, %7.2f, %5.4f\n", i, MTCth[ROLL], MTCth[PITCH], MTCth[YAW]);
#endif
aiVec3 FEngine = FT[i]*(Cth*n2[i]);
aiVec3 MEngine = MT[i]*Cth;
FXYZ_body += FEngine;
Mlmn += MEngine;
#if 0
printf("FT[%lu]: %5.4f, %5.4f, %5.4f\n", i, FEngine[X], FEngine[Y], FEngine[Z]);
printf("MT[%lu]: %5.4f, % 7.5f, %5.4f\n", i, MEngine[ROLL], MEngine[PITCH], MEngine[YAW]);
#endif
}
while (i--);
#if 0
printf("FXYZ: %5.4f, %5.4f, %5.4f\n", FXYZ[X], FXYZ[Y], FXYZ[Z]);
printf("Mlmn: %5.4f, %7.2f, %5.4f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
printf("FXYZ: %5.4f, %5.4f, %5.4f\n", FXYZ_body[X], FXYZ_body[Y], FXYZ_body[Z]);
printf("Mlmn: %5.4f, % 7.5f, %5.4f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
#endif
/* gear forces */
/* contact point (landing gear) forces and moments */
WoW = false;
if (cg_agl < 10.0f)
if (no_contacts && cg_agl < 10.0f)
{
size_t WoW_main = 0;
aiVec3 cg_cg_agl_neu(0.0f, 0.0f, cg_agl);
for (size_t i=0; i<no_contacts; ++i)
i = 0;
do
{
aiVec3 contact_ned = mBody2Ned*contact_pos[i];
aiVec3 lg_ground_neu = contact_ned + cg_cg_agl_neu;
if (lg_ground_neu[Z] < 0.0f)
aiVec3 lg_ground_ned = mBody2Ned*contact_pos[i];
if (lg_ground_ned[Z] > cg_agl)
{ // weight on wheel
aiVec3 lg_vrot = simd4::cross(vPQR, contact_pos[i]);
aiVec3 lg_cg_vned = mBody2Ned*lg_vrot;
aiVec3 lg_vned = vNEDdot + lg_cg_vned;
float Fn;
aiVec3 lg_vned = vNED + lg_cg_vned;
float Fn = std::min((contact_spring[i]*lg_ground_ned[Z] +
contact_damp[i]*lg_vned[Z]), 0.0f);
Fn = contact_spring[i]*lg_ground_neu[Z] - contact_damp[i]*lg_vned[Z];
if (Fn > 0.0f) Fn = 0.0f;
aiVec3 Fgear(0.0f, 0.0f, Fn);
aiVec3 Fbody = mNed2Body*Fgear;
aiVec3 Fbrake = mu_body*Fbody;
aiVec3 Fn_lg(0.0f, 0.0f, Fn);
aiVec3 mu_body(-0.02f-0.7f*br, 0.8f, 0.0f);
aiVec3 FLGear = mNed2Body*Fn_lg + vUVWaero*mu_body;
FXYZ += FLGear;
aiVec3 FLGear = Fbody + Fbrake;
FXYZ_body += FLGear;
// aiVec3 MLGear = simd4::cross(contact_pos[i], FLGear);
// Mlmn += MLGear;
#if 0
printf("FLGear[%i]: %10.2f %10.2f %10.2f\n",i,FLGear[0], FLGear[1], FLGear[2]);
printf("MLGear[%i]: %10.2f %10.2f %10.2f\n",i,MLGear[0], MLGear[1], MLGear[2]);
printf("gear: %lu: pos: % 3.2f % 3.2f % 3.2f\n", i,
lg_ground_ned[0], lg_ground_ned[1], lg_ground_ned[2]);
printf(" Fbody: % 7.2f % 7.2f % 7.2f\n", Fbody[0], Fbody[1], Fbody[2]);
printf(" Fbrake: % 7.2f % 7.2f % 7.2f\n", Fbrake[0], Fbrake[1], Fbrake[2]);
printf(" Fgear: % 7.2f % 7.2f % 7.2f\n", lg_ground_ned[0], lg_ground_ned[1], lg_ground_ned[2]);
printf(" Mgear: % 7.2f % 7.2f % 7.2f\n", MLGear[0], MLGear[1], MLGear[2]);
#endif
if (i<3) WoW_main++;
}
WoW = (WoW_main == 3);
}
while(++i < no_contacts);
}
/* local body accelrations */
aXYZ = FXYZ*inv_m + gravity_body;
XYZdot = FXYZ_body*inv_mass;
#if 0
printf("aXYZ: %7.2f, %7.2f, %7.2f\n", aXYZ[X]/m, aXYZ[Y]/m, aXYZ[Z]/m);
printf("Mlmn: %7.2f, %7.2f, %7.2f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
printf("AOAdot: %5.4f, AOA: %5.4f, up: XYZdot: % 7.5f, XYZ: % 7.5f, gravity: % 7.5f\n", AOAdot[ALPHA], AOA[ALPHA], XYZdot[Z], FXYZ_body[Z]/mass, gravity_body[DOWN]);
#endif
#if 0
printf("XYZdot % 7.5f, % 7.5f, % 7.5f\n", XYZdot[X], XYZdot[Y], XYZdot[Z]);
printf("Mlmn: % 7.5f, % 7.5f, % 7.5f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
#endif
/* Dynamic Equations */
/* body-axis translational accelerations: forward, sideward, upward */
vUVWdot = aXYZ - simd4::cross(vPQR, vUVW);
vUVWdot = XYZdot - simd4::cross(vPQR, vUVW);
vUVW += vUVWdot*dt;
/* body-axis rotational accelerations: rolling, pitching, yawing */
vPQRdot = mIinv*(Mlmn - vPQR*(mI*vPQR));
vPQRdot = mJinv*(Mlmn - vPQR*(mJ*vPQR));
vPQR += vPQRdot*dt;
#if 0
printf("PQRdot: %7.2f, %7.2f, %7.2f\n", vPQRdot[P], vPQRdot[Q], vPQRdot[R]);
printf("PQR: %7.2f, %7.2f, %7.2f\n", vPQR[P], vPQR[Q], vPQR[R]);
printf("UVWdot: %7.2f, %7.2f, %7.2f\n", vUVWdot[U], vUVWdot[V], vUVWdot[W]);
printf("UVW: %7.2f, %7.2f, %7.2f\n", vUVW[U], vUVW[V], vUVW[W]);
printf("PQRdot: % 7.5f, % 7.5f, % 7.5f\n", vPQRdot[P], vPQRdot[Q], vPQRdot[R]);
printf("PQR: % 7.5f, % 7.5f, % 7.5f\n", vPQR[P], vPQR[Q], vPQR[R]);
printf("UVWdot: % 7.5f, % 7.5f, % 7.5f\n", vUVWdot[U], vUVWdot[V], vUVWdot[W]);
printf("UVW: % 7.5f, % 7.5f, %1.7f\n", vUVW[U], vUVW[V], vUVW[W]);
#endif
/* position of center of mass wrt earth: north, east, down */
vNEDdot = mBody2Ned*vUVW;
NEDdist = vNEDdot*dt;
vNED = mBody2Ned*vUVW;
aiVec3 NEDdist = vNED*dt;
#if 0
printf("NEDdot: %7.2f, %7.2f, %7.2f\n", vNEDdot[0], vNEDdot[1], vNEDdot[2]);
printf("NEDdist: %7.2f, %7.2f, %7.2f\n", NEDdist[0], NEDdist[1], NEDdist[2]);
printf("vNED: % 7.5f, % 7.5f, % 7.5f\n", vNED[NORTH], vNED[EAST], vNED[DOWN]);
printf("NEDdist: % 7.5f, % 7.5f, % 7.5f\n", NEDdist[NORTH], NEDdist[EAST], NEDdist[DOWN]);
#endif
#ifdef ENABLE_SP_FDM
double dist = simd4::magnitude( simd4_t<float,2>(NEDdist) );
double dist = simd4::magnitude( aiVec2(NEDdist) );
double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
geo_direct_wgs_84( 0.0, location_geod[LATITUDE] * SGD_RADIANS_TO_DEGREES,
@ -363,23 +387,37 @@ FGAISim::update(double ddt)
set_altitude_cg_agl_ft(location_geod[DOWN]);
#endif
#if 0
printf("GEOD: %7.2f, %7.2f, %7.2f\n", location_geod[0], location_geod[1], location_geod[2]);
printf("GEOD: % 7.5f, % 7.5f, % 7.5f\n", location_geod[0], location_geod[1], location_geod[2]);
#endif
/* angle of body wrt earth: phi (pitch), theta (roll), psi (heading) */
#if 0
{
vector = simd4::normalize(euler);
float len = simd4::normalize(vector);
aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, vector);
euler_dot = mWind2Body*vPQR;
euler += euler_dot*dt;
}
#else
/* angle of body wrt earth: phi (roll), theta (pitch), psi (heading) */
float sin_p = std::sin(euler[PHI]);
float cos_p = std::cos(euler[PHI]);
float sin_t = std::sin(euler[THETA]);
float cos_t = std::cos(euler[THETA]);
if (std::abs(cos_t) < 0.00001f) cos_t = std::copysign(0.00001f,cos_t);
euler_dot[PSI] = (q*sin_p + r*cos_p)/cos_t;
if (cos_t == 0.0f) {
euler_dot[PSI] = 0.0f;
} else {
euler_dot[PSI] = (q*sin_p + r*cos_p)/cos_t;
}
euler_dot[THETA] = q*cos_p - r*sin_p;
// euler_dot[PHI] = p + (q*sin_p + r*cos_p)*sin_t/cos_t;
/* euler_dot[PHI] = p + (q*sin_p + r*cos_p)*sin_t/cos_t; */
euler_dot[PHI] = p + euler_dot[PSI]*sin_t;
euler += euler_dot*dt;
#if 0
printf("euler: %7.2f, %7.2f, %7.2f\n", euler[PHI], euler[THETA], euler[PSI]);
printf("euler: % 7.5f, % 7.5f, % 7.5f\n", euler[PHI], euler[THETA], euler[PSI]);
#endif
#endif
#ifdef ENABLE_SP_FDM
@ -401,7 +439,7 @@ FGAISim::copy_to_AISim()
set_altitude_asl_ft(get_Altitude());
set_altitude_agl_ft(get_Altitude_AGL()-cg_agl);
set_altitude_agl_ft(get_Altitude_AGL());
// set_location_geod(get_Latitude(), get_Longitude(), altitde);
// set_velocity_fps(get_V_calibrated_kts());
@ -413,7 +451,7 @@ bool
FGAISim::copy_from_AISim()
{
// Mass properties and geometry values
// _set_Inertias( m, I[XX], I[YY], I[ZZ], I[XZ] );
// _set_Inertias( mass, I[XX], I[YY], I[ZZ], I[XZ] );
_set_CG_Position( cg[X], cg[Y], cg[Z]);
// Accelerations
@ -422,11 +460,11 @@ FGAISim::copy_from_AISim()
// Velocities
_set_V_equiv_kts( velocity*std::sqrt(sigma) * SG_FPS_TO_KT );
_set_V_calibrated_kts( std::sqrt( 2.0f*qbar*sigma/rho) * SG_FPS_TO_KT );
_set_V_ground_speed( simd4::magnitude(vNEDdot) * SG_FPS_TO_KT );
_set_V_ground_speed( simd4::magnitude(aiVec2(vNED)) * SG_FPS_TO_KT );
_set_Mach_number( mach );
_set_Velocities_Local( vNEDdot[NORTH], vNEDdot[EAST], vNEDdot[DOWN] );
_set_Velocities_Local_Airmass( vUVWaero[U], vUVWaero[V], vUVWaero[W] );
_set_Velocities_Local( vNED[NORTH], vNED[EAST], vNED[DOWN] );
// _set_Velocities_Local_Airmass( vUVWaero[U], vUVWaero[V], vUVWaero[W] );
_set_Velocities_Body( vUVW[U], vUVW[V], vUVW[W] );
_set_Omega_Body( vPQR[P], vPQR[Q], vPQR[R] );
_set_Euler_Rates( euler_dot[PHI], euler_dot[THETA], euler_dot[PSI] );
@ -434,20 +472,22 @@ FGAISim::copy_from_AISim()
// Positions
double lon = location_geod[LONGITUDE];
double lat_geod = location_geod[LATITUDE];
double sl_radius, lat_geoc;
altitude = location_geod[ALTITUDE];
sgGeodToGeoc(lat_geod, altitude, &sl_radius, &lat_geoc);
double altitude = location_geod[ALTITUDE];
double lat_geoc;
sgGeodToGeoc( lat_geod, altitude, &sl_radius, &lat_geoc );
_set_Geocentric_Position( lat_geoc, lon, sl_radius+altitude );
_set_Geodetic_Position( lat_geod, lon, altitude);
// float heading = euler[PSI];
// if (heading < 0) heading += (2.0f*SG_PI);
_set_Euler_Angles( euler[PHI], euler[THETA], euler[PSI]); // heading );
_set_Geodetic_Position( lat_geod, lon, altitude );
_set_Altitude_AGL( altitude - get_Runway_altitude());
_set_Euler_Angles( euler[PHI], euler[THETA],
SGMiscd::normalizePeriodic(0, SGD_2PI, euler[PSI]) );
_set_Alpha( AOA[ALPHA] );
_set_Beta( AOA[BETA] );
set_altitude_agl_ft( altitude - get_Runway_altitude() );
_set_Altitude_AGL( cg_agl );
// _set_Alpha( alpha );
// _set_Beta( beta );
// _set_Gamma_vert_rad( Gamma_vert_rad );
@ -457,14 +497,14 @@ FGAISim::copy_from_AISim()
// _set_Static_temperature( Static_temperature );
_set_Sea_level_radius( sl_radius * SG_METER_TO_FEET);
_set_Sea_level_radius( sl_radius * SG_METER_TO_FEET );
// _set_Earth_position_angle( Earth_position_angle );
_set_Runway_altitude( get_Runway_altitude() );
// _set_Runway_altitude( get_Runway_altitude() );
_set_Climb_Rate( -vNEDdot[DOWN] );
_set_Climb_Rate( -vNED[DOWN] );
// _update_ground_elev_at_pos();
_update_ground_elev_at_pos();
return true;
}
@ -472,10 +512,7 @@ FGAISim::copy_from_AISim()
// ----------------------------------------------------------------------------
#ifndef _MINMAX
# define _MINMAX(a,b,c) (((a)>(c)) ? (c) : (((a)<(b)) ? (b) : (a)))
#endif
#define OMEGA_EARTH 0.00007272205217f
#define MAX_ALT 101
// 1976 Standard Atmosphere - Density (slugs/ft2): 0 - 101,000 ft
@ -528,7 +565,7 @@ FGAISim::update_velocity(float v)
velocity = v;
/* altitude related */
float alt_kft = _MINMAX(altitude/1000.0f, 0, MAX_ALT);
float alt_kft = _MINMAX(location_geod[ALTITUDE]/1000.0f, 0, MAX_ALT);
float alt_idx = std::floor(alt_kft);
size_t idx = static_cast<size_t>(alt_idx);
float fract = alt_kft - alt_idx;
@ -540,7 +577,7 @@ FGAISim::update_velocity(float v)
sigma = rho/density[0];
float Sqbar = Sw*qbar;
float Sbqbar = Sqbar*b;
float Sbqbar = Sqbar*span;
float Sqbarcbar = Sqbar*cbar;
Coef2Force = aiVec3(Sqbar);
@ -552,9 +589,14 @@ FGAISim::update_velocity(float v)
mach = v/vs;
/* useful semi-constants */
if (v < 0.0000001f) v = 0.0000001f;
b_2U = 0.5f*b/v;
cbar_2U = 0.5f*cbar/v;
if (v == 0.0f) {
cbar_2U = b_2U = 0.0f;
}
else
{
b_2U = 0.5f*span/v;
cbar_2U = 0.5f*cbar/v;
}
}
// structural: x is pos. aft., y is pos. right, z is pos. up. in inches.
@ -688,8 +730,6 @@ FGAISim::jsonParse(const char *str)
bool
FGAISim::load(std::string path)
{
path += ".json";
std::ifstream file(path);
std::string jsonString;
@ -704,9 +744,9 @@ FGAISim::load(std::string path)
Sw = data["Sw"];
cbar = data["cbar"];
b = data["b"];
span = data["b"];
m = data["mass"]/AISIM_G;
mass = data["mass"]/AISIM_G;
I[XX] = data["Ixx"];
I[YY] = data["Iyy"];
@ -725,7 +765,7 @@ FGAISim::load(std::string path)
cg[Z] = data["cg[2]"];
struct_to_body(cg);
// Gear ground contact points relative to c.g.
// Gear ground contact points relative to center of gravity.
no_contacts = 0;
do
{
@ -740,13 +780,13 @@ FGAISim::load(std::string path)
contact_pos[i][Z] = data[gearstr + "/pos[2]"];
struct_to_body(contact_pos[i]);
contact_spring[i] = data[gearstr + "/spring"];
contact_damp[i] = data[gearstr + "/damp"];
contact_spring[i] = -data[gearstr + "/spring"];
contact_damp[i] = -data[gearstr + "/damp"];
#if 0
printf("%i: posZ %f, %f, %f, spring: %f, damp: %f\n", q, contact_pos[q][X], contact_pos[q][Y], contact_pos[q][Z], contact_spring[q], contact_damp[q]);
printf("%lu: pos: % 3.2f, % 3.2f, % 3.2f, spring: % 7.1f, damp: % 7.1f\n", i, contact_pos[i][X], contact_pos[i][Y], contact_pos[i][Z], contact_spring[i], contact_damp[i]);
#endif
}
while (++no_contacts < (AISIM_MAX-1));
while (++no_contacts < AISIM_MAX);
/* Thuster / propulsion locations relative to c.g. */
no_engines = 0;
@ -755,14 +795,14 @@ FGAISim::load(std::string path)
size_t i = no_engines;
std::string engstr = "engine[" + std::to_string(i) + "]";
float CTu = data[engstr + "/CTu"];
float CTmax = data[engstr + "/CTmax"];
if (!CTmax) break;
float FTmax = data[engstr + "/FT_max"];
if (!FTmax) break;
engine_pos[i][0] = data[engstr + "/pos[0]"];
engine_pos[i][1] = data[engstr + "/pos[1]"];
engine_pos[i][2] = data[engstr + "/pos[2]"];
struct_to_body(engine_pos[i]);
aiVec3 pos;
pos[0] = data[engstr + "/pos[0]"];
pos[1] = data[engstr + "/pos[1]"];
pos[2] = data[engstr + "/pos[2]"];
struct_to_body(pos);
// Thruster orientation is in the following sequence: pitch, roll, yaw
aiVec3 orientation(data[engstr + "/dir[1]"], // roll (degrees)
@ -770,29 +810,29 @@ FGAISim::load(std::string path)
data[engstr + "/dir[2]"]); // yaw (degrees)
orientation *= SG_DEGREES_TO_RADIANS;
float angle = simd4::normalize(orientation);
aiMtx4 mWindBody = simd4x4::rotation_matrix(angle, orientation);
aiVec3 dir = mWindBody*aiVec3(1.0f, 0.0f, 0.0f);
#if 0
printf("dir: %f %f %f\n", dir[0], dir[1], dir[2]);
#endif
float len = simd4::normalize(orientation);
aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, orientation);
aiVec3 dir = mWind2Body*aiVec3(1.0f, 0.0f, 0.0f);
aiVec3 rot = simd4::cross(pos, dir);
float D = data[engstr + "/D"]*INCHES_TO_FEET;
if (D) // if propeller driven
{
float RPM = data[engstr + "/RPM"]/60.0f;
float Ixx = data[engstr + "/Ixx"];
float rho = 0.002379f;
// float MTmax = data[engstr + "/MT_max"];
FT[i] = dir * (CTmax * RPM*RPM * D*D*D*D); // Thrust force
FTM[i] = dir * (CTu/(RPM*D))*vsound[0]; // Thrust due to Mach
MT[i] = dir * (-Ixx*(2.0f*RPM*SG_PI)); // Thrus moment
MT[i] += engine_pos[i];
float max_rpm = data[engstr + "/rpm_max"];
if (max_rpm == 0.0f) {
n2[i] = 1.0f;
}
else
{
FT[i] = dir * CTmax; // Thrust force
FTM[i] = dir * CTu*vsound[0]; // Thrust due to Mach
n2[i] = max_rpm/60.0f;
n2[i] *= n2[i];
}
FTmax /= (rho*n2[i]);
// MTmax /= rho / max_rpm;
FT[i] = dir * FTmax;
MT[i] = rot * FT[i]; // + dir * MTmax;
}
while(++no_engines < AISIM_MAX);

View file

@ -52,6 +52,10 @@
#define AISIM_MAX 4
#define AISIM_G 32.174f
#ifndef _MINMAX
# define _MINMAX(a,b,c) (((a)>(c)) ? (c) : (((a)<(b)) ? (b) : (a)))
#endif
class FGAISim
#ifdef ENABLE_SP_FDM
: public FGInterface
@ -67,12 +71,13 @@ private:
enum { FLAPS=2, RUDDER=2, MIN=3, AILERON=3, ELEVATOR=3 };
enum { DRAG=0, SIDE=1, LIFT=2 };
enum { ROLL=0, PITCH=1, YAW=2, THRUST=3 };
enum { PHI=0, THETA, PSI };
enum { ALPHA=0, BETA=1 };
enum { PHI, THETA, PSI };
enum { P=0, Q=1, R=2 };
enum { U=0, V=1, W=2 };
using aiVec2 = simd4_t<float,2>;
using aiVec3d = simd4_t<double,3>;
using aiVec3 = simd4_t<float,3>;
using aiVec4 = simd4_t<float,4>;
@ -119,8 +124,8 @@ public:
xCDYLT.ptr()[FLAPS][DRAG] = -CDdf_n*std::abs(f);
xClmnT.ptr()[FLAPS][PITCH] = Cmdf_n*f;
}
inline void set_throttle_norm(float f) { th = f; }
inline void set_brake_norm(float f) { br = f; }
inline void set_throttle_norm(float f) { throttle = f; }
inline void set_brake_norm(float f) { mu_body[0] = -0.02f-0.7f*f; }
/* (initial) state, local frame */
inline void set_location_geod(aiVec3d& p) {
@ -138,8 +143,8 @@ public:
inline void set_euler_angles_rad(float phi, float theta, float psi) {
euler = aiVec3(phi, theta, psi);
}
inline void set_pitch_rad(float f) { euler[PHI] = f; }
inline void set_roll_rad(float f) { euler[THETA] = f; }
inline void set_roll_rad(float f) { euler[PHI] = f; }
inline void set_pitch_rad(float f) { euler[THETA] = f; }
inline void set_heading_rad(float f) { euler[PSI] = f; }
void set_velocity_fps(const aiVec3& v) { vUVW = v; }
@ -156,12 +161,14 @@ public:
}
inline void set_alpha_rad(float f) {
f = _MINMAX(f, -0.25f, 0.25f); // -14 to 14 degrees
xCDYLT.ptr()[ALPHA][LIFT] = -CLa*f;
xCDYLT.ptr()[ALPHA][DRAG] = -CDa*std::abs(f);
xClmnT.ptr()[ALPHA][PITCH] = Cma*f;
AOA[ALPHA] = f;
}
inline void set_beta_rad(float f) {
f = _MINMAX(f, -0.30f, 0.30f); // -17 to 17 degrees
xCDYLT.ptr()[BETA][DRAG] = -CDb*std::abs(f);
xCDYLT.ptr()[BETA][SIDE] = CYb*f;
xClmnT.ptr()[BETA][ROLL] = Clb*f;
@ -183,41 +190,42 @@ private:
void struct_to_body(aiVec3 &pos);
/* aircraft normalized controls */
float th; /* throttle command */
float br = 0.0f; /* brake command */
float throttle = 0.0f; /* throttle command */
/* aircraft state */
aiVec3d location_geod = 0.0; /* lat, lon, altitude */
aiVec3 aXYZ = 0.0f; /* local body accelrations */
aiVec3 vNEDdot = 0.0f; /* North, East, Down velocity */
aiVec3 vUVW = 0.0f; /* fwd, side, down velocity */
aiVec3 vUVWdot = 0.0f; /* fwd, side, down accel. */
aiVec3 vPQR = 0.0f; /* roll, pitch, yaw rate */
aiVec3 vPQRdot = 0.0f; /* roll, pitch, yaw accel. */
aiVec3 AOA = 0.0f; /* alpha, beta */
aiVec3 AOAdot = 0.0f; /* adot, bdot */
aiVec3 euler = 0.0f; /* phi, theta, psi */
aiVec3 euler_dot = 0.0f; /* change in phi, theta, psi */
aiVec3 wind_ned = 0.0f; /* wind north, east, down */
aiVec3d location_geod = 0.0; /* lat, lon, altitude */
aiVec3 XYZdot = 0.0f; /* local body accelrations */
aiVec3 vNED = 0.0f; /* North, East, Down velocity */
aiVec3 vUVW = 0.0f; /* fwd, side, down velocity */
aiVec3 vUVWdot = 0.0f; /* fwd, side, down acceleration */
aiVec3 vPQR = 0.0f; /* roll, pitch, yaw rate */
aiVec3 vPQRdot = 0.0f; /* roll, pitch, yaw acceleration */
aiVec3 AOA = 0.0f; /* alpha, beta */
aiVec3 AOAdot = 0.0f; /* adot, bdot */
aiVec3 euler = 0.0f; /* phi, theta, psi */
aiVec3 euler_dot = 0.0f; /* change in phi, theta, psi */
aiVec3 wind_ned = 0.0f; /* wind north, east, down */
aiVec3 mu_body = { -0.02f, -0.8f, 0.0f };
/* ---------------------------------------------------------------- */
/* This should reduce the time spent in update() since controls */
/* change less often than the update function runs which might */
/* run 20 to 60 times (or more) per second */
/* cache_ */
aiVec3 NEDdist;
aiVec3 vUVWaero = 0.0f; /* airmass relative to the body */
aiVec3 FT[AISIM_MAX]; /* thrust force */
aiVec3 FTM[AISIM_MAX]; /* thrust due to mach force */
aiVec3 MT[AISIM_MAX]; /* thrust moment */
/* cache */
aiVec3 vUVWaero = 0.0f; /* airmass relative to the body */
aiVec3 FT[AISIM_MAX]; /* thrust force */
aiVec3 MT[AISIM_MAX]; /* thrust moment */
float n2[AISIM_MAX];
aiVec3 b_2U = 0.0f;
aiVec3 cbar_2U = 0.0f;
aiVec3 inv_m;
float altitude = 0.0f;
aiVec3 inv_mass;
float cg_agl = 0.0f;
float alpha = 0.0f;
float beta = 0.0f;
float velocity = 0.0f;
float mach = 0.0f;
float cg_agl = 0.0f;
double sl_radius = 0.0;
bool WoW = true;
/* dynamic coefficients (already multiplied with their value) */
@ -234,15 +242,14 @@ private:
/* aircraft static data */
size_t no_engines = 0;
size_t no_contacts = 0;
aiMtx4 mI, mIinv; /* inertia matrix */
aiVec3 engine_pos[AISIM_MAX]; /* pos in structural frame */
aiVec3 contact_pos[AISIM_MAX]; /* pos in structural frame */
aiMtx4 mJ, mJinv; /* inertia matrix */
aiVec3 contact_pos[AISIM_MAX+1]; /* pos in structural frame */
aiVec3 mass = 0.0f; /* mass */
aiVec3 cg = 0.0f; /* center of gravity */
aiVec4 I = 0.0f; /* inertia */
float Sw = 0.0f; /* wing area */
float cbar = 0.0f; /* mean average chord */
float b = 0.0f; /* wing span */
float m = 0.0f; /* mass */
float span = 0.0f; /* wing span */
/* static coefficients, *_n is for normalized surface deflection */
float contact_spring[AISIM_MAX]; /* contact spring coeffients */