bool FGAerodynamics::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; // if paused don't execute unsigned int axis_ctr, ctr; const double twovel=2*in.Vt; RunPreFunctions(); // calculate some oft-used quantities for speed if (twovel != 0) { bi2vel = in.Wingspan / twovel; ci2vel = in.Wingchord / twovel; } alphaw = in.Alpha + in.Wingincidence; qbar_area = in.Wingarea * in.Qbar; if (alphaclmax != 0) { if (in.Alpha > 0.85*alphaclmax) { impending_stall = 10*(in.Alpha/alphaclmax - 0.85); } else { impending_stall = 0; } } if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (in.Alpha > alphahystmax) { stall_hyst = 1; } else if (in.Alpha < alphahystmin) { stall_hyst = 0; } } vFw.InitMatrix(); vFnative.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctions[axis_ctr].size(); ctr++) { vFnative(axis_ctr+1) += AeroFunctions[axis_ctr][ctr]->GetValue(); } } // Note that we still need to convert to wind axes here, because it is // used in the L/D calculation, and we still may want to look at Lift // and Drag. switch (axisType) { case atBodyXYZ: // Forces already in body axes; no manipulation needed vFw = in.Tb2w*vFnative; vForces = vFnative; break; case atLiftDrag: // Copy forces into wind axes vFw = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vForces = in.Tw2b*vFw; break; case atAxialNormal: // Convert native forces into Axial|Normal|Side system vFw = in.Tb2w*vFnative; vFnative(eX)*=-1; vFnative(eZ)*=-1; vForces = vFnative; break; default: cerr << endl << " A proper axis type has NOT been selected. Check " << "your aerodynamics definition." << endl; exit(-1); } // Calculate lift coefficient squared if ( in.Qbar > 0) { clsq = vFw(eLift) / (in.Wingarea*in.Qbar); clsq *= clsq; } // Calculate lift Lift over Drag if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) ); // Calculate aerodynamic reference point shift, if any. The shift // takes place in the structual axis. That is, if the shift is positive, // it is towards the back (tail) of the vehicle. The AeroRPShift // function should be non-dimensionalized by the wing chord. The // calculated vDeltaRP will be in feet. if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord; vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY); vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ); vMoments = vDXYZcg*vForces; // M = r X F for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr = 0; ctr < AeroFunctions[axis_ctr+3].size(); ctr++) { vMoments(axis_ctr+1) += AeroFunctions[axis_ctr+3][ctr]->GetValue(); } } RunPostFunctions(); return false; }
bool FGAerodynamics::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; // if paused don't execute unsigned int axis_ctr, ctr; const double twovel=2*in.Vt; RunPreFunctions(); // calculate some oft-used quantities for speed if (twovel != 0) { bi2vel = in.Wingspan / twovel; ci2vel = in.Wingchord / twovel; } alphaw = in.Alpha + in.Wingincidence; qbar_area = in.Wingarea * in.Qbar; if (alphaclmax != 0) { if (in.Alpha > 0.85*alphaclmax) { impending_stall = 10*(in.Alpha/alphaclmax - 0.85); } else { impending_stall = 0; } } if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (in.Alpha > alphahystmax) { stall_hyst = 1; } else if (in.Alpha < alphahystmin) { stall_hyst = 0; } } vFw.InitMatrix(); vFwAtCG.InitMatrix(); vFnative.InitMatrix(); vFnativeAtCG.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctions[axis_ctr].size(); ctr++) { vFnative(axis_ctr+1) += AeroFunctions[axis_ctr][ctr]->GetValue(); } } for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctionsAtCG[axis_ctr].size(); ctr++) { vFnativeAtCG(axis_ctr+1) += AeroFunctionsAtCG[axis_ctr][ctr]->GetValue(); } } // Note that we still need to convert to wind axes here, because it is // used in the L/D calculation, and we still may want to look at Lift // and Drag. // JSB 4/27/12 - After use, convert wind axes to produce normal lift // and drag values - not negative ones! // As a clarification, JSBSim assumes that drag and lift values are defined // in wind axes - BUT with a 180 rotation about the Y axis. That is, lift and // drag will be positive up and aft, respectively, so that they are reported // as positive numbers. However, the wind axes themselves assume that the X // and Z forces are positive forward and down. switch (axisType) { case atBodyXYZ: // Forces already in body axes; no manipulation needed vFw = in.Tb2w*vFnative; vForces = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vFwAtCG = in.Tb2w*vFnativeAtCG; vForcesAtCG = vFnativeAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; break; case atLiftDrag: // Copy forces into wind axes vFw = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vForces = in.Tw2b*vFw; vFw(eDrag)*=-1; vFw(eLift)*=-1; vFwAtCG = vFnativeAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; vForcesAtCG = in.Tw2b*vFwAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; break; case atAxialNormal: // Convert native forces into Axial|Normal|Side system vFw = in.Tb2w*vFnative; vFnative(eX)*=-1; vFnative(eZ)*=-1; vForces = vFnative; vFwAtCG = in.Tb2w*vFnativeAtCG; vFnativeAtCG(eX)*=-1; vFnativeAtCG(eZ)*=-1; vForcesAtCG = vFnativeAtCG; break; default: cerr << endl << " A proper axis type has NOT been selected. Check " << "your aerodynamics definition." << endl; exit(-1); } // Calculate lift coefficient squared if ( in.Qbar > 0) { clsq = (vFw(eLift) + vFwAtCG(eLift))/ (in.Wingarea*in.Qbar); clsq *= clsq; } // Calculate lift Lift over Drag if ( fabs(vFw(eDrag) + vFwAtCG(eDrag)) > 0.0) lod = fabs( (vFw(eLift) + vFwAtCG(eLift))/ (vFw(eDrag) + vFwAtCG(eDrag))); // Calculate aerodynamic reference point shift, if any. The shift // takes place in the structual axis. That is, if the shift is positive, // it is towards the back (tail) of the vehicle. The AeroRPShift // function should be non-dimensionalized by the wing chord. The // calculated vDeltaRP will be in feet. if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord; vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY); vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ); vMomentsMRC.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr = 0; ctr < AeroFunctions[axis_ctr+3].size(); ctr++) { vMomentsMRC(axis_ctr+1) += AeroFunctions[axis_ctr+3][ctr]->GetValue(); } } vMoments = vMomentsMRC + vDXYZcg*vForces; // M = r X F // Now add the "at CG" values to base forces - after the moments have been transferred vForces += vForcesAtCG; vFnative += vFnativeAtCG; vFw += vFwAtCG; RunPostFunctions(); return false; }