00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <FGFDMExec.h>
00040 #include "FGAerodynamics.h"
00041 #include "FGPropagate.h"
00042 #include "FGAircraft.h"
00043 #include "FGAuxiliary.h"
00044 #include "FGMassBalance.h"
00045 #include <input_output/FGPropertyManager.h>
00046
00047 namespace JSBSim {
00048
00049 static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.24 2009/05/17 13:55:48 jberndt Exp $";
00050 static const char *IdHdr = ID_AERODYNAMICS;
00051
00052
00053
00054
00055
00056
00057 FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
00058 {
00059 Name = "FGAerodynamics";
00060
00061 AxisIdx["DRAG"] = 0;
00062 AxisIdx["SIDE"] = 1;
00063 AxisIdx["LIFT"] = 2;
00064 AxisIdx["ROLL"] = 3;
00065 AxisIdx["PITCH"] = 4;
00066 AxisIdx["YAW"] = 5;
00067
00068 AxisIdx["AXIAL"] = 0;
00069 AxisIdx["NORMAL"] = 2;
00070
00071 AxisIdx["X"] = 0;
00072 AxisIdx["Y"] = 1;
00073 AxisIdx["Z"] = 2;
00074
00075 axisType = atNone;
00076
00077 Coeff = new CoeffArray[6];
00078
00079 impending_stall = stall_hyst = 0.0;
00080 alphaclmin = alphaclmax = 0.0;
00081 alphahystmin = alphahystmax = 0.0;
00082 clsq = lod = 0.0;
00083 alphaw = 0.0;
00084 bi2vel = ci2vel = 0.0;
00085 AeroRPShift = 0;
00086 vDeltaRP.InitMatrix();
00087
00088 bind();
00089
00090 Debug(0);
00091 }
00092
00093
00094
00095 FGAerodynamics::~FGAerodynamics()
00096 {
00097 unsigned int i,j;
00098
00099 for (i=0; i<6; i++)
00100 for (j=0; j<Coeff[i].size(); j++)
00101 delete Coeff[i][j];
00102
00103 delete[] Coeff;
00104
00105 for (i=0; i<variables.size(); i++)
00106 delete variables[i];
00107
00108 delete AeroRPShift;
00109
00110 Debug(1);
00111 }
00112
00113
00114
00115 bool FGAerodynamics::InitModel(void)
00116 {
00117 if (!FGModel::InitModel()) return false;
00118
00119 impending_stall = stall_hyst = 0.0;
00120 alphaclmin = alphaclmax = 0.0;
00121 alphahystmin = alphahystmax = 0.0;
00122 clsq = lod = 0.0;
00123 alphaw = 0.0;
00124 bi2vel = ci2vel = 0.0;
00125 AeroRPShift = 0;
00126 vDeltaRP.InitMatrix();
00127
00128 return true;
00129 }
00130
00131
00132 bool FGAerodynamics::Run(void)
00133 {
00134 unsigned int axis_ctr, ctr, i;
00135 double alpha, twovel;
00136
00137 if (FGModel::Run()) return true;
00138 if (FDMExec->Holding()) return false;
00139
00140
00141
00142 twovel = 2*Auxiliary->GetVt();
00143 if (twovel != 0) {
00144 bi2vel = Aircraft->GetWingSpan() / twovel;
00145 ci2vel = Aircraft->Getcbar() / twovel;
00146 }
00147 alphaw = Auxiliary->Getalpha() + Aircraft->GetWingIncidence();
00148 alpha = Auxiliary->Getalpha();
00149 qbar_area = Aircraft->GetWingArea() * Auxiliary->Getqbar();
00150
00151 if (alphaclmax != 0) {
00152 if (alpha > 0.85*alphaclmax) {
00153 impending_stall = 10*(alpha/alphaclmax - 0.85);
00154 } else {
00155 impending_stall = 0;
00156 }
00157 }
00158
00159 if (alphahystmax != 0.0 && alphahystmin != 0.0) {
00160 if (alpha > alphahystmax) {
00161 stall_hyst = 1;
00162 } else if (alpha < alphahystmin) {
00163 stall_hyst = 0;
00164 }
00165 }
00166
00167 vFw.InitMatrix();
00168 vFnative.InitMatrix();
00169
00170
00171
00172
00173
00174
00175 for (i=0; i<variables.size(); i++) variables[i]->cacheValue(true);
00176
00177 for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
00178 for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
00179 vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue();
00180 }
00181 }
00182
00183
00184
00185
00186
00187 switch (axisType) {
00188 case atBodyXYZ:
00189 vFw = GetTb2w()*vFnative;
00190 vForces = vFnative;
00191 break;
00192 case atLiftDrag:
00193 vFw = vFnative;
00194 vFw(eDrag)*=-1; vFw(eLift)*=-1;
00195 vForces = GetTw2b()*vFw;
00196 break;
00197 case atAxialNormal:
00198 vFw = GetTb2w()*vFnative;
00199 vFnative(eX)*=-1; vFnative(eZ)*=-1;
00200 vForces = vFnative;
00201 break;
00202 default:
00203 cerr << endl << " A proper axis type has NOT been selected. Check "
00204 << "your aerodynamics definition." << endl;
00205 exit(-1);
00206 }
00207
00208
00209 if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*Aircraft->Getcbar()*12.0;
00210
00211
00212 if ( Auxiliary->Getqbar() > 0) {
00213 clsq = vFw(eLift) / (Aircraft->GetWingArea()*Auxiliary->Getqbar());
00214 clsq *= clsq;
00215 }
00216
00217
00218 if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) );
00219
00220 vDXYZcg = MassBalance->StructuralToBody(Aircraft->GetXYZrp() + vDeltaRP);
00221
00222 vMoments = vDXYZcg*vForces;
00223
00224 for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
00225 for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
00226 vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->GetValue();
00227 }
00228 }
00229
00230 return false;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 FGMatrix33& FGAerodynamics::GetTw2b(void)
00250 {
00251 double ca, cb, sa, sb;
00252
00253 double alpha = Auxiliary->Getalpha();
00254 double beta = Auxiliary->Getbeta();
00255
00256 ca = cos(alpha);
00257 sa = sin(alpha);
00258 cb = cos(beta);
00259 sb = sin(beta);
00260
00261 mTw2b(1,1) = ca*cb;
00262 mTw2b(1,2) = -ca*sb;
00263 mTw2b(1,3) = -sa;
00264 mTw2b(2,1) = sb;
00265 mTw2b(2,2) = cb;
00266 mTw2b(2,3) = 0.0;
00267 mTw2b(3,1) = sa*cb;
00268 mTw2b(3,2) = -sa*sb;
00269 mTw2b(3,3) = ca;
00270
00271 return mTw2b;
00272 }
00273
00274
00275
00276 FGMatrix33& FGAerodynamics::GetTb2w(void)
00277 {
00278 double alpha,beta;
00279 double ca, cb, sa, sb;
00280
00281 alpha = Auxiliary->Getalpha();
00282 beta = Auxiliary->Getbeta();
00283
00284 ca = cos(alpha);
00285 sa = sin(alpha);
00286 cb = cos(beta);
00287 sb = sin(beta);
00288
00289 mTb2w(1,1) = ca*cb;
00290 mTb2w(1,2) = sb;
00291 mTb2w(1,3) = sa*cb;
00292 mTb2w(2,1) = -ca*sb;
00293 mTb2w(2,2) = cb;
00294 mTb2w(2,3) = -sa*sb;
00295 mTb2w(3,1) = -sa;
00296 mTb2w(3,2) = 0.0;
00297 mTb2w(3,3) = ca;
00298
00299 return mTb2w;
00300 }
00301
00302
00303
00304 bool FGAerodynamics::Load(Element *element)
00305 {
00306 string parameter, axis, scratch;
00307 string scratch_unit="";
00308 string fname="", file="";
00309 Element *temp_element, *axis_element, *function_element;
00310
00311 string separator = "/";
00312
00313 fname = element->GetAttributeValue("file");
00314 if (!fname.empty()) {
00315 file = FDMExec->GetFullAircraftPath() + separator + fname;
00316 document = LoadXMLDocument(file);
00317 } else {
00318 document = element;
00319 }
00320
00321 DetermineAxisSystem();
00322
00323 Debug(2);
00324
00325 if (temp_element = document->FindElement("alphalimits")) {
00326 scratch_unit = temp_element->GetAttributeValue("unit");
00327 if (scratch_unit.empty()) scratch_unit = "RAD";
00328 alphaclmin = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
00329 alphaclmax = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
00330 }
00331
00332 if (temp_element = document->FindElement("hysteresis_limits")) {
00333 scratch_unit = temp_element->GetAttributeValue("unit");
00334 if (scratch_unit.empty()) scratch_unit = "RAD";
00335 alphahystmin = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
00336 alphahystmax = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
00337 }
00338
00339 if (temp_element = document->FindElement("aero_ref_pt_shift_x")) {
00340 function_element = temp_element->FindElement("function");
00341 AeroRPShift = new FGFunction(PropertyManager, function_element);
00342 }
00343
00344 function_element = document->FindElement("function");
00345 while (function_element) {
00346 variables.push_back( new FGFunction(PropertyManager, function_element) );
00347 function_element = document->FindNextElement("function");
00348 }
00349
00350 axis_element = document->FindElement("axis");
00351 while (axis_element) {
00352 CoeffArray ca;
00353 axis = axis_element->GetAttributeValue("name");
00354 function_element = axis_element->FindElement("function");
00355 while (function_element) {
00356 ca.push_back( new FGFunction(PropertyManager, function_element) );
00357 function_element = axis_element->FindNextElement("function");
00358 }
00359 Coeff[AxisIdx[axis]] = ca;
00360 axis_element = document->FindNextElement("axis");
00361 }
00362
00363 return true;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 void FGAerodynamics::DetermineAxisSystem()
00377 {
00378 Element* axis_element = document->FindElement("axis");
00379 string axis;
00380 while (axis_element) {
00381 axis = axis_element->GetAttributeValue("name");
00382 if (axis == "LIFT" || axis == "DRAG" || axis == "SIDE") {
00383 if (axisType == atNone) axisType = atLiftDrag;
00384 else if (axisType != atLiftDrag) {
00385 cerr << endl << " Mixed aerodynamic axis systems have been used in the"
00386 << " aircraft config file." << endl;
00387 }
00388 } else if (axis == "AXIAL" || axis == "NORMAL") {
00389 if (axisType == atNone) axisType = atAxialNormal;
00390 else if (axisType != atAxialNormal) {
00391 cerr << endl << " Mixed aerodynamic axis systems have been used in the"
00392 << " aircraft config file." << endl;
00393 }
00394 } else if (axis == "X" || axis == "Y" || axis == "Z") {
00395 if (axisType == atNone) axisType = atBodyXYZ;
00396 else if (axisType != atBodyXYZ) {
00397 cerr << endl << " Mixed aerodynamic axis systems have been used in the"
00398 << " aircraft config file." << endl;
00399 }
00400 } else if (axis != "ROLL" && axis != "PITCH" && axis != "YAW") {
00401 cerr << endl << " An unknown axis type, " << axis << " has been specified"
00402 << " in the aircraft configuration file." << endl;
00403 exit(-1);
00404 }
00405 axis_element = document->FindNextElement("axis");
00406 }
00407 if (axisType == atNone) {
00408 axisType = atLiftDrag;
00409 cerr << endl << " The aerodynamic axis system has been set by default"
00410 << " to the Lift/Side/Drag system." << endl;
00411 }
00412 }
00413
00414
00415
00416 string FGAerodynamics::GetCoefficientStrings(string delimeter)
00417 {
00418 string CoeffStrings = "";
00419 bool firstime = true;
00420 unsigned int axis, sd;
00421
00422 for (sd = 0; sd < variables.size(); sd++) {
00423 if (firstime) {
00424 firstime = false;
00425 } else {
00426 CoeffStrings += delimeter;
00427 }
00428 CoeffStrings += variables[sd]->GetName();
00429 }
00430
00431 for (axis = 0; axis < 6; axis++) {
00432 for (sd = 0; sd < Coeff[axis].size(); sd++) {
00433 if (firstime) {
00434 firstime = false;
00435 } else {
00436 CoeffStrings += delimeter;
00437 }
00438 CoeffStrings += Coeff[axis][sd]->GetName();
00439 }
00440 }
00441 return CoeffStrings;
00442 }
00443
00444
00445
00446 string FGAerodynamics::GetCoefficientValues(string delimeter)
00447 {
00448 string SDValues = "";
00449 bool firstime = true;
00450 unsigned int sd;
00451
00452 for (sd = 0; sd < variables.size(); sd++) {
00453 if (firstime) {
00454 firstime = false;
00455 } else {
00456 SDValues += delimeter;
00457 }
00458 SDValues += variables[sd]->GetValueAsString();
00459 }
00460
00461 for (unsigned int axis = 0; axis < 6; axis++) {
00462 for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
00463 if (firstime) {
00464 firstime = false;
00465 } else {
00466 SDValues += delimeter;
00467 }
00468 SDValues += Coeff[axis][sd]->GetValueAsString();
00469 }
00470 }
00471
00472 return SDValues;
00473 }
00474
00475
00476
00477 void FGAerodynamics::bind(void)
00478 {
00479 typedef double (FGAerodynamics::*PMF)(int) const;
00480
00481 PropertyManager->Tie("forces/fbx-aero-lbs", this,1,
00482 (PMF)&FGAerodynamics::GetForces);
00483 PropertyManager->Tie("forces/fby-aero-lbs", this,2,
00484 (PMF)&FGAerodynamics::GetForces);
00485 PropertyManager->Tie("forces/fbz-aero-lbs", this,3,
00486 (PMF)&FGAerodynamics::GetForces);
00487 PropertyManager->Tie("moments/l-aero-lbsft", this,1,
00488 (PMF)&FGAerodynamics::GetMoments);
00489 PropertyManager->Tie("moments/m-aero-lbsft", this,2,
00490 (PMF)&FGAerodynamics::GetMoments);
00491 PropertyManager->Tie("moments/n-aero-lbsft", this,3,
00492 (PMF)&FGAerodynamics::GetMoments);
00493 PropertyManager->Tie("forces/fwx-aero-lbs", this,1,
00494 (PMF)&FGAerodynamics::GetvFw);
00495 PropertyManager->Tie("forces/fwy-aero-lbs", this,2,
00496 (PMF)&FGAerodynamics::GetvFw);
00497 PropertyManager->Tie("forces/fwz-aero-lbs", this,3,
00498 (PMF)&FGAerodynamics::GetvFw);
00499 PropertyManager->Tie("forces/lod-norm", this,
00500 &FGAerodynamics::GetLoD);
00501 PropertyManager->Tie("aero/cl-squared", this,
00502 &FGAerodynamics::GetClSquared);
00503 PropertyManager->Tie("aero/qbar-area", &qbar_area);
00504 PropertyManager->Tie("aero/alpha-max-rad", this,
00505 &FGAerodynamics::GetAlphaCLMax,
00506 &FGAerodynamics::SetAlphaCLMax,
00507 true);
00508 PropertyManager->Tie("aero/alpha-min-rad", this,
00509 &FGAerodynamics::GetAlphaCLMin,
00510 &FGAerodynamics::SetAlphaCLMin,
00511 true);
00512 PropertyManager->Tie("aero/bi2vel", this,
00513 &FGAerodynamics::GetBI2Vel);
00514 PropertyManager->Tie("aero/ci2vel", this,
00515 &FGAerodynamics::GetCI2Vel);
00516 PropertyManager->Tie("aero/alpha-wing-rad", this,
00517 &FGAerodynamics::GetAlphaW);
00518 PropertyManager->Tie("systems/stall-warn-norm", this,
00519 &FGAerodynamics::GetStallWarn);
00520 PropertyManager->Tie("aero/stall-hyst-norm", this,
00521 &FGAerodynamics::GetHysteresisParm);
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 void FGAerodynamics::Debug(int from)
00544 {
00545 if (debug_lvl <= 0) return;
00546
00547 if (debug_lvl & 1) {
00548 if (from == 2) {
00549 switch (axisType) {
00550 case (atLiftDrag):
00551 cout << endl << " Aerodynamics (Lift|Side|Drag axes):" << endl << endl;
00552 break;
00553 case (atAxialNormal):
00554 cout << endl << " Aerodynamics (Axial|Side|Normal axes):" << endl << endl;
00555 break;
00556 case (atBodyXYZ):
00557 cout << endl << " Aerodynamics (X|Y|Z axes):" << endl << endl;
00558 break;
00559 }
00560 }
00561 }
00562 if (debug_lvl & 2 ) {
00563 if (from == 0) cout << "Instantiated: FGAerodynamics" << endl;
00564 if (from == 1) cout << "Destroyed: FGAerodynamics" << endl;
00565 }
00566 if (debug_lvl & 4 ) {
00567 }
00568 if (debug_lvl & 8 ) {
00569 }
00570 if (debug_lvl & 16) {
00571 }
00572 if (debug_lvl & 64) {
00573 if (from == 0) {
00574 cout << IdSrc << endl;
00575 cout << IdHdr << endl;
00576 }
00577 }
00578 }
00579
00580 }