51 #include "FGFDMExec.h" 52 #include "models/FGAtmosphere.h" 53 #include "initialization/FGInitialCondition.h" 54 #include "FGTrimAnalysis.h" 55 #include "models/FGAircraft.h" 56 #include "models/FGMassBalance.h" 57 #include "models/FGGroundReactions.h" 58 #include "models/FGInertial.h" 59 #include "models/FGAerodynamics.h" 60 #include "math/FGColumnVector3.h" 62 #include "input_output/FGPropertyManager.h" 63 #include "input_output/FGXMLParse.h" 65 #include "models/propulsion/FGPiston.h" 66 #include "models/propulsion/FGPropeller.h" 67 #include "models/propulsion/FGTurbine.h" 69 #include "math/FGTable.h" 71 #if defined(sgi) && !defined(__GNUC__) 79 #include "math/direct_search/SMDSearch.h" 80 #include "math/direct_search/NMSearch.h" 81 #include "math/direct_search/vec.h" 84 #pragma warning (disable : 4786 4788) 89 IDENT(IdSrc,
"$Id: FGTrimAnalysis.cpp,v 1.16 2014/01/13 10:46:00 ehofman Exp $");
90 IDENT(IdHdr,ID_FGTRIMANALYSIS);
106 void find_CostFunctionFull(
long vars, Vector<double> &v,
double & f,
107 bool & success,
void* t_ptr)
109 (*(
Objective*)t_ptr).CostFunctionFull(vars, v, f);
125 void find_CostFunctionFullWingsLevel(
long vars, Vector<double> &v,
double & f,
126 bool & success,
void* t_ptr)
128 (*(
Objective*)t_ptr).CostFunctionFullWingsLevel(vars, v, f);
144 void find_CostFunctionLongitudinal(
long vars, Vector<double> &v,
double & f,
145 bool & success,
void* t_ptr)
147 (*(
Objective*)t_ptr).CostFunctionLongitudinal(vars, v, f);
163 void find_CostFunctionFullCoordinatedTurn(
long vars, Vector<double> &v,
double & f,
164 bool & success,
void* t_ptr)
166 (*(
Objective*)t_ptr).CostFunctionFullCoordinatedTurn(vars, v, f);
182 void find_CostFunctionFullTurn(
long vars, Vector<double> &v,
double & f,
183 bool & success,
void* t_ptr)
185 (*(
Objective*)t_ptr).CostFunctionFullTurn(vars, v, f);
201 void find_CostFunctionPullUp(
long vars, Vector<double> &v,
double & f,
202 bool & success,
void* t_ptr)
204 (*(
Objective*)t_ptr).CostFunctionPullUp(vars, v, f);
223 cerr <<
"\nError: (Cost function for taFull mode) Dimension must be 7 !!\n";
226 if (TrimAnalysis->
GetMode()!=taFull){
227 cerr <<
"\nError: must be taFull mode !!\n";
231 f = myCostFunctionFull(v);
238 cerr <<
"\nError: (Cost function for taFullWingsLevel mode) Dimension must be 6 !!\n";
241 if (TrimAnalysis->
GetMode()!=taFullWingsLevel){
242 cerr <<
"\nError: must be taFull mode !!\n";
246 f = myCostFunctionFullWingsLevel(v);
253 cerr <<
"\nError: (Cost function for taLongitudinal mode) Dimension must be 3 !!\n";
256 if (TrimAnalysis->
GetMode()!=taLongitudinal){
257 cerr <<
"\nError: trim mode must be taLongitudinal mode !!\n";
261 f = myCostFunctionLongitudinal(v);
268 cerr <<
"\nError: (Cost function for taTurn mode) Dimension must be 5 !!\n";
271 if (TrimAnalysis->
GetMode()!=taTurn){
272 cerr <<
"\nError: trim mode must be taTurn mode !!\n";
276 f = myCostFunctionFullCoordinatedTurn(v);
283 cerr <<
"\nError: (Cost function for taTurn mode) Dimension must be 6 !!\n";
286 if (TrimAnalysis->
GetMode()!=taTurnFull){
287 cerr <<
"\nError: trim mode must be taTurnFull ("<< (int)taTurnFull <<
") mode !!\n";
291 f = myCostFunctionFullTurn(v);
298 cerr <<
"\nError: (Cost function for taPullup mode) Dimension must be 5 !!\n";
301 if (TrimAnalysis->
GetMode()!=taPullup){
302 cerr <<
"\nError: trim mode must be taPullup mode !!\n";
306 f = myCostFunctionPullUp(v);
310 void Objective::Set_x_val(
double new_x)
329 stop_criterion=
"Stop-On-Delta";
331 Debug=0;DebugLevel=0;
344 _vtIC = fgic->GetVtrueFpsIC();
345 _hIC = fgic->GetAltitudeFtIC();
346 _gamma = fgic->GetFlightPathAngleRadIC();
347 _rocIC = _vtIC*cos(_gamma);
351 _u = fgic->GetUBodyFpsIC();
352 _v = fgic->GetVBodyFpsIC();
353 _w = fgic->GetWBodyFpsIC();
354 _p = fgic->GetPRadpsIC();
355 _q = fgic->GetQRadpsIC();
356 _r = fgic->GetRRadpsIC();
357 _alpha = fgic->GetAlphaRadIC();
358 _beta = fgic->GetBetaRadIC();
359 _theta = fgic->GetThetaRadIC();
360 _phi = fgic->GetPhiRadIC();
361 _psiIC = fgic->GetPsiRadIC();
367 _vgIC = _vtIC*cos(_gamma);
368 _vnorthIC = _vgIC * cos(_psigtIC);
369 _veastIC = _vgIC * sin(_psigtIC);
370 wnorthIC = _weastIC = _wdownIC = 0.;
372 _udot=_vdot=_wdot=_pdot=_qdot=_rdot=0.;
373 _psidot=_thetadot=0.;
374 _psiWdot = _phiWdot = _gammadot = 0.;
382 fdmex->SetTrimMode( (
int)tt );
384 trim_id =
"default-trim";
387 search_type =
"Nelder-Mead";
388 sigma_nm = 0.5; alpha_nm = 1.0; beta_nm = 0.5; gamma_nm = 2.0;
391 cost_function_value = 9999.0;
394 if (rf.is_open()) rf.close();
396 Auxiliary = fdmex->GetAuxiliary();
397 Aerodynamics = fdmex->GetAerodynamics();
398 Propulsion = fdmex->GetPropulsion();
399 FCS = fdmex->GetFCS();
409 vCL.clear(); vCD.clear(); vCm.clear();
410 vThrottleCmd.clear(); vElevatorCmd.clear();
411 vVn.clear(); vTn.clear();
413 if (rf.is_open()) rf.close();
415 fdmex->SetTrimStatus(
false);
416 fdmex->SetTrimMode( 99 );
422 double alpha0,
double beta0,
double phi0,
double theta0,
double psi0,
double gamma0)
426 _alpha=alpha0; _beta=beta0; _gamma=gamma0;
427 _theta=theta0; _phi=phi0; _psi=psi0;
435 _phi = phi; _cphi = cos(_phi); _sphi = sin(_phi);
436 _theta = theta; _ctheta = cos(_theta); _stheta = sin(_theta);
437 _psi = psi; _cpsi = cos(_psi); _spsi = sin(_psi);
445 _udot=udot; _vdot=vdot; _wdot=wdot; _pdot=pdot; _qdot=qdot; _rdot=rdot;
452 string name=
"", type=
"";
454 Element *element=0, *trimCfg=0, *search_element=0, *output_element=0;
461 if( useStoredPath ) {
462 trimDef = fdmex->GetFullAircraftPath() + sep + fname +
".xml";
467 document = this->LoadXMLDocument(trimDef);
469 trimCfg = document->FindElement(
"trim_config");
471 cerr <<
"File: " << trimDef <<
" does not contain a trim configuration tag" << endl;
475 name = trimCfg->GetAttributeValue(
"name");
480 search_element = trimCfg->FindElement(
"search");
481 if (!search_element) {
482 cerr <<
"Using the Nelder-Mead search algorithm (default)." << endl;
484 type = search_element->GetAttributeValue(
"type");
485 if (type.size() > 0) search_type = type;
486 if (search_type ==
"Nelder-Mead") {
489 if ( search_element->FindElement(
"sigma_nm") )
490 sigma_nm = search_element->FindElementValueAsNumber(
"sigma_nm");
491 if ( search_element->FindElement(
"alpha_nm") )
492 alpha_nm = search_element->FindElementValueAsNumber(
"alpha_nm");
493 if ( search_element->FindElement(
"beta_nm") )
494 beta_nm = search_element->FindElementValueAsNumber(
"beta_nm");
495 if ( search_element->FindElement(
"gamma_nm") )
496 gamma_nm = search_element->FindElementValueAsNumber(
"gamma_nm");
502 if ( search_element->FindElement(
"tolerance") ) {
503 tolerance = search_element->FindElement(
"tolerance")->GetAttributeValueAsNumber(
"value");
505 if ( search_element->FindElement(
"max_iterations") ) {
506 max_iterations = (
unsigned int)search_element->FindElement(
"max_iterations")->GetAttributeValueAsNumber(
"value");
508 if ( search_element->FindElement(
"stop_criterion") ) {
509 stop_criterion = search_element->FindElement(
"stop_criterion")->GetAttributeValue(
"type");
518 InitializeTrimControl(fgic->GetPhiRadIC(), element,
"RAD", JSBSim::taPhi);
519 if ( ( fabs(_phi) < 89.5*(FGJSBBase::degtorad ) ) && ( mode == taTurn ))
520 _targetNlf = 1./cos(_phi);
523 InitializeTrimControl(fgic->GetThetaRadIC(), element,
"RAD", JSBSim::taTheta);
526 InitializeTrimControl(fgic->GetPsiRadIC(), element,
"RAD", JSBSim::taHeading);
529 _gamma = fgic->GetFlightPathAngleRadIC();
531 if (element->GetNumDataLines() > 0) _gamma = element->
GetDataAsNumber();
533 element = trimCfg->FindElement(
"nlf");
535 if (element->GetNumDataLines() > 0) _targetNlf = element->GetDataAsNumber();
536 CalculatePhiWFromTargetNlfTurn(_targetNlf);
539 element = trimCfg->FindElement(
"throttle_cmd");
540 if (element) InitializeTrimControl(0, element,
"", JSBSim::taThrottle);
542 element = trimCfg->FindElement(
"elevator_cmd");
543 if (element) InitializeTrimControl(0, element,
"", JSBSim::taElevator);
545 element = trimCfg->FindElement(
"rudder_cmd");
546 if (element) InitializeTrimControl(0, element,
"", JSBSim::taRudder);
548 element = trimCfg->FindElement(
"aileron_cmd");
549 if (element) InitializeTrimControl(0, element,
"", JSBSim::taAileron);
551 output_element = trimCfg->FindElement(
"output_file");
552 if (output_element) {
553 rf_name = output_element->GetAttributeValue(
"name");
554 if (rf_name.empty()) {
555 cerr <<
"name must be specified in output_file \"name\" attribute."<< endl;
557 if ( !SetResultsFile(rf_name) )
558 cerr <<
"Unable to use output file "<< rf_name << endl;
567 bool FGTrimAnalysis::InitializeTrimControl(
double default_value,
Element* el,
568 string unit, TaControl type)
570 Element *step_size_element=0, *trim_config=0;
573 bool set_override =
false;
582 if (unit.empty()) iv = trim_config->FindElementValueAsNumber(name);
583 else iv = trim_config->FindElementValueAsNumberConvertTo(name, unit);
589 for (
unsigned int i=0; i<vTrimAnalysisControls.size(); i++) {
590 if (vTrimAnalysisControls[i]->GetControlType() == type) {
591 vTrimAnalysisControls[i]->SetControlInitialValue(iv);
592 vTrimAnalysisControls[i]->SetControlStep(step);
604 cout << endl <<
" Trim Statistics: " << endl;
605 cout <<
" Total Iterations: " << total_its << endl;
612 cout <<
"---------------------------------------------------------------------\n";
614 cout <<
"Trim report: " << endl;
615 cout <<
"\tTrim algorithm terminated with the following values:" << endl;
616 cout <<
"\tu, v, w (ft/s): " << _u <<
", "<< _v <<
", "<< _w << endl
617 <<
"\tp, q, r (rad/s): " << _p <<
", "<< _q <<
", "<< _r << endl
618 <<
"\talpha, beta (deg): " << _alpha*57.3 <<
", "<< _beta*57.3 << endl
619 <<
"\tphi, theta, psi (deg): " << _phi*57.3 <<
", "<< _theta*57.3 <<
", " << _psi*57.3 << endl
620 <<
"\tCost function value : " << cost_function_value << endl
621 <<
"\tCycles executed : " << total_its << endl << endl;
623 cout <<
"\tTrim variables adjusted:" << endl;
624 for (
unsigned int i=0; i<vTrimAnalysisControls.size();i++){
625 cout <<
"\t\t" << vTrimAnalysisControls[i]->GetControlName() <<
": ";
626 cout << vTrimAnalysisControls[i]->GetControl() << endl;
632 cout <<
"\t** Initial -> Final Conditions **" << endl;
633 cout <<
"\tAlpha IC: " << fgic->GetAlphaDegIC() <<
" Degrees" << endl;
634 cout <<
"\t Final: " << Auxiliary->Getalpha()*57.3 <<
" Degrees" << endl;
635 cout <<
"\tBeta IC: " << fgic->GetBetaDegIC() <<
" Degrees" << endl;
636 cout <<
"\t Final: " << Auxiliary->Getbeta()*57.3 <<
" Degrees" << endl;
637 cout <<
"\tGamma IC: " << fgic->GetFlightPathAngleDegIC() <<
" Degrees" << endl;
638 cout <<
"\t Final: " << Auxiliary->GetGamma()*57.3 <<
" Degrees" << endl;
639 cout <<
"\tPhi IC : " << fgic->GetPhiDegIC() <<
" Degrees" << endl;
640 cout <<
"\t Final: " << fdmex->GetPropagate()->GetEuler(1)*57.3 <<
" Degrees" << endl;
641 cout <<
"\tTheta IC: " << fgic->GetThetaDegIC() <<
" Degrees" << endl;
642 cout <<
"\t Final: " << fdmex->GetPropagate()->GetEuler(2)*57.3 <<
" Degrees" << endl;
643 cout <<
"\tPsi IC : " << fgic->GetPsiDegIC() <<
" Degrees" << endl;
644 cout <<
"\t Final: " << fdmex->GetPropagate()->GetEuler(3)*57.3 <<
" Degrees" << endl;
646 cout <<
"--------------------------------------------------------------------- \n\n";
648 fdmex->EnableOutput();
658 vector<FGTrimAnalysisControl*>::iterator iControls;
659 iControls = vTrimAnalysisControls.begin();
660 while (iControls != vTrimAnalysisControls.end()) {
667 vTrimAnalysisControls.clear();
679 vector <FGTrimAnalysisControl*>::iterator iControls = vTrimAnalysisControls.begin();
680 while (iControls != vTrimAnalysisControls.end()) {
700 vector <FGTrimAnalysisControl*>::iterator iControls = vTrimAnalysisControls.begin();
701 while (iControls != vTrimAnalysisControls.end()) {
705 vTrimAnalysisControls.erase(iControls);
722 vector <FGTrimAnalysisControl*>::iterator iControls = vTrimAnalysisControls.begin();
723 while (iControls != vTrimAnalysisControls.end()) {
728 vTrimAnalysisControls.erase(iControls+1);
739 void FGTrimAnalysis::setupPullup() {
741 g=fdmex->GetInertial()->gravity();
742 cgamma=cos(fgic->GetFlightPathAngleRadIC());
743 q=g*(_targetNlf-cgamma)/fgic->GetVtrueFpsIC();
744 cout << _targetNlf <<
", " << q << endl;
745 fgic->SetQRadpsIC(q);
753 if ( ( mode == taTurn ) || ( mode == taTurnFull ) ) {
757 _phiW = atan2( sqrt(_targetNlf*_targetNlf-cos(_gamma)*cos(_gamma)), cos(_gamma) );
762 void FGTrimAnalysis::setupTurn(
void){
764 if ( mode == taTurn ) {
767 _phiW = atan2( sqrt(_targetNlf*_targetNlf-cos(_gamma)*cos(_gamma)), cos(_gamma) );
768 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
769 sin(_phiW) *cos(_theta)*cos(_psi) ;
770 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
771 cos(_phiW)*sin(_gamma)*sin(_theta) ;
772 C3 = sin(_phiW) *sin(_theta)+
773 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
774 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
775 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
776 _sbeta = sqrt(1.-_cbeta*_cbeta );
777 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
781 _theta = atan2( sin(_psi)*cos(_gamma)+cos(_psi)*sin(_gamma), cos(_gamma) );
784 V = sqrt( _u*_u +_v*_v + _w*_w );
785 g=fdmex->GetInertial()->gravity();
786 _psiWdot = (g/V)*tan(_phiW);
789 if ( mode == taTurnFull ) {
791 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
792 sin(_phiW) *cos(_theta)*cos(_psi) ;
793 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
794 cos(_phiW)*sin(_gamma)*sin(_theta) ;
795 C3 = sin(_phiW) *sin(_theta)+
796 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
797 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
798 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
799 _sbeta = sqrt(1.-_cbeta*_cbeta );
800 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
804 V = sqrt( _u*_u +_v*_v + _w*_w );
805 g=fdmex->GetInertial()->gravity();
806 _psiWdot = (g/V)*tan(_phiW);
811 void FGTrimAnalysis::setupTurn(
double phiW){
812 if ( mode == taTurn ) {
815 _targetNlf = sqrt( cos(_gamma)*cos(_gamma)*tan(_phiW)*tan(_phiW) + cos(_gamma)*cos(_gamma) );
817 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
818 sin(_phiW) *cos(_theta)*cos(_psi) ;
819 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
820 cos(_phiW)*sin(_gamma)*sin(_theta) ;
821 C3 = sin(_phiW) *sin(_theta)+
822 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
823 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
824 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
825 _sbeta = sqrt(1.-_cbeta*_cbeta );
826 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
835 V = sqrt( _u*_u +_v*_v + _w*_w );
836 g=fdmex->GetInertial()->gravity();
837 _psiWdot = (g/V)*tan(_phiW);
840 if ( mode == taTurnFull ) {
843 _targetNlf = sqrt( cos(_gamma)*cos(_gamma)*tan(_phiW)*tan(_phiW) + cos(_gamma)*cos(_gamma) );
845 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
846 sin(_phiW) *cos(_theta)*cos(_psi) ;
847 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
848 cos(_phiW)*sin(_gamma)*sin(_theta) ;
849 C3 = sin(_phiW) *sin(_theta)+
850 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
851 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
852 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
853 _sbeta = sqrt(1.-_cbeta*_cbeta );
854 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
863 V = sqrt( _u*_u +_v*_v + _w*_w );
864 g=fdmex->GetInertial()->gravity();
865 _psiWdot = (g/V)*tan(_phiW);
872 void FGTrimAnalysis::setupTurnPhi(
double psi,
double theta){
873 if ( mode == taTurn ) {
874 _psi = psi; _cpsi = cos(_psi); _spsi = sin(_psi);
875 _theta = theta; _ctheta = cos(_theta); _stheta = sin(_theta);
877 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
878 sin(_phiW) *cos(_theta)*cos(_psi) ;
879 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
880 cos(_phiW)*sin(_gamma)*sin(_theta) ;
881 C3 = sin(_phiW) *sin(_theta)+
882 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
883 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
884 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
885 _sbeta = sqrt(1.-_cbeta*_cbeta );
887 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
891 if ( mode == taTurnFull ) {
892 _psi = psi; _cpsi = cos(_psi); _spsi = sin(_psi);
893 _theta = theta; _ctheta = cos(_theta); _stheta = sin(_theta);
895 C1 = cos(_phiW)*sin(_gamma)*cos(_theta)*sin(_psi)+
896 sin(_phiW) *cos(_theta)*cos(_psi) ;
897 C2 = cos(_phiW)*cos(_gamma)*cos(_theta)*cos(_psi)+
898 cos(_phiW)*sin(_gamma)*sin(_theta) ;
899 C3 = sin(_phiW) *sin(_theta)+
900 cos(_phiW)*cos(_gamma)*cos(_theta)*sin(_psi) ;
901 _cbeta = ( C1*sin(_phiW)*cos(_gamma)+C2*cos(_phiW) + C3*sin(_phiW)*sin(_gamma) )
902 /( sqrt(C1*C1 + C2*C2 + C3*C3) );
903 _sbeta = sqrt(1.-_cbeta*_cbeta );
905 _sphi = ( _cbeta*sin(_phiW) * cos(_gamma) - _sbeta*sin(_gamma) )/cos(_theta);
922 g=fdmex->GetInertial()->gravity();
923 cgamma=cos(fgic->GetFlightPathAngleRadIC());
925 _q = g*(_targetNlf-cgamma)/fgic->GetVtrueFpsIC();
928 fgic->SetQRadpsIC(_q);
932 void FGTrimAnalysis::updateRates(
void){
933 if ( ( mode == taTurn ) || ( mode == taTurnFull ) ){
935 double cth2 = cos(_theta)*cos(_theta),
936 sth2 = sin(_theta)*sin(_theta),
937 scth = sin(_theta)*cos(_theta),
938 cph2 = cos(_phiW)*cos(_phiW),
939 sph2 = sin(_phiW)*sin(_phiW),
940 scph = sin(_phiW)*cos(_phiW),
941 cga2 = cos(_gamma)*cos(_gamma),
942 scga = sin(_gamma)*cos(_gamma),
943 cps2 = cos(_psi)*cos(_psi),
944 scps = sin(_psi)*cos(_psi);
949 -2*scph*scth*cos(_gamma)*sin(_psi)+cph2*cga2*cth2
950 +cph2*cga2*cth2*(1-cps2)
951 +2*cph2*scga*scth*cos(_psi)
954 +2*scph*sin(_gamma)*cth2*scps
956 _salpha = sqrt( 1. - _calpha*_calpha );
959 ( sin(_gamma)*_calpha*_cbeta
960 +cos(_gamma)*sin(_phiW)*_calpha*_sbeta
961 +cos(_gamma)*cos(_phiW)*_salpha
966 -cos(_gamma)*sin(_phiW)*_cbeta
970 ( sin(_gamma)*_salpha*_cbeta
971 +cos(_gamma)*sin(_phiW)*_salpha*_sbeta
972 -cos(_gamma)*cos(_phiW)*_calpha
975 }
else if( mode == taPullup && fabs(_targetNlf-1) > 0.01) {
978 g=fdmex->GetInertial()->gravity();
979 cgamma=cos(fgic->GetFlightPathAngleRadIC());
980 q=g*(_targetNlf-cgamma)/fgic->GetVtrueFpsIC();
982 fgic->SetQRadpsIC(q);
988 void FGTrimAnalysis::setDebug(
void) {
999 cout <<
"---------------------------------------------------------------------" << endl;
1000 cout <<
"Trim analysis performed: ";
1003 case taLongitudinal:
1005 cout <<
" Longitudinal Trim" << endl;
1012 cout <<
" Full Trim" << endl;
1021 case taFullWingsLevel:
1023 cout <<
" Full Trim, Wings-Level" << endl;
1035 cout <<
" Full Trim, Coordinated turn" << endl;
1046 cout <<
" Non-coordinated Turn Trim" << endl;
1060 cout <<
" Full Trim, Pullup" << endl;
1071 cout <<
" Ground Trim" << endl;
1089 if ( rf.is_open() )
return false;
1092 rf.open(rf_name.c_str(), ios::out);
1093 if ( !rf.is_open() ) {
1094 cerr <<
"Unable to open " << rf_name << endl;
1104 bool FGTrimAnalysis::ensureRunning()
1106 bool success =
false;
1108 if ( Propulsion == 0L )
return false;
1110 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1112 if (!Propulsion->GetEngine(i)->GetRunning() ) {
1113 Propulsion->GetEngine(i)->SetStarter(
true );
1114 if ( Propulsion->GetEngine(i)->GetType() == JSBSim::FGEngine::etPiston )
1117 Piston->SetMagnetos(3);
1119 else if ( Propulsion->GetEngine(i)->GetType() == FGEngine::etTurbine )
1122 Turbine->SetCutoff(
false);
1123 Turbine->SetStarter(
true);
1126 Propulsion->GetEngine(i)->SetRunning(
true );
1130 Propulsion->SetActiveEngine(i);
1137 bool FGTrimAnalysis::ensureRunning(
unsigned int i)
1139 bool success =
false;
1141 if ( Propulsion == 0L )
return false;
1143 if ( i < Propulsion->GetNumEngines() )
1145 if (!Propulsion->GetEngine(i)->GetRunning() ) {
1146 Propulsion->GetEngine(i)->SetStarter(
true );
1147 if ( Propulsion->GetEngine(i)->GetType() == JSBSim::FGEngine::etPiston )
1150 Piston->SetMagnetos(3);
1152 else if ( Propulsion->GetEngine(i)->GetType() == FGEngine::etTurbine )
1155 Turbine->SetCutoff(
false);
1156 Turbine->SetStarter(
true);
1159 Propulsion->GetEngine(i)->SetRunning(
true );
1164 Propulsion->SetActiveEngine(i);
1173 bool FGTrimAnalysis::runForAWhile(
int nruns)
1175 bool result = fdmex->Run();
1180 while ( counter < nruns ) {
1182 result = fdmex->Run();
1188 bool FGTrimAnalysis::populateVecAlphaDeg(
double vmin,
double vmax,
int n)
1190 if ( !vAlphaDeg.empty() )
return false;
1191 for(
int i=0; i<n; i++)
1192 vAlphaDeg.push_back( vmin +
double(i)*(vmax - vmin)/
double(n-1) );
1197 bool FGTrimAnalysis::populateVecThrottleCmd(
double vmin,
double vmax,
int n)
1199 if ( !vThrottleCmd.empty() )
return false;
1200 for(
int i=0; i<n; i++)
1201 vThrottleCmd.push_back( vmin +
double(i)*(vmax - vmin)/
double(n-1) );
1205 bool FGTrimAnalysis::populateVecElevatorCmd(
double vmin,
double vmax,
int n)
1207 if ( !vElevatorCmd.empty() )
return false;
1208 for(
int i=0; i<n; i++)
1209 vElevatorCmd.push_back( vmin +
double(i)*(vmax - vmin)/
double(n-1) );
1214 bool FGTrimAnalysis::calculateAerodynamics(
1220 double S,
double mac,
double bw,
1221 double& CL,
double& CD,
double& Cm)
1223 double qBar = 0.5 * rho * Vt*Vt;
1224 double qBar_S = qBar * S;
1226 Auxiliary->SetVt( Vt );
1227 Auxiliary->Setalpha( alpha_deg*degtorad );
1229 Auxiliary->Setbeta( 0.0 );
1232 Auxiliary->Setadot( 0.0 );
1233 Auxiliary->Setbdot( 0.0 );
1239 FCS->SetDeCmd( dE_cmd );
1242 Aerodynamics->Run();
1245 vector <FGFunction*> * Coeff = Aerodynamics->GetAeroFunctions();
1247 if ( Coeff->empty() )
return false;
1250 unsigned int axis_ctr = 2;
1251 for (
unsigned int ctr=0; ctr < Coeff[axis_ctr].size(); ctr++)
1252 CL += Coeff[axis_ctr][ctr]->GetValue();
1257 for (
unsigned int ctr=0; ctr < Coeff[axis_ctr].size(); ctr++)
1258 CD += Coeff[axis_ctr][ctr]->GetValue();
1263 for (
unsigned int ctr=0; ctr < Coeff[axis_ctr].size(); ctr++)
1264 Cm += Coeff[axis_ctr][ctr]->GetValue();
1266 Cm /= ( qBar_S*mac );
1279 cout << endl <<
"Numerical trim algorithm: constrained optimization of a cost function" << endl;
1283 fdmex->SetTrimStatus(
true );
1290 double throttle = 1.0;
1291 for (
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1293 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1294 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1295 FCS->SetThrottleCmd(i,tMin + throttle *(tMax-tMin));
1296 if (Propulsion->GetEngine(i)->GetType()==FGEngine::etPiston)
1298 FCS->SetMixtureCmd(i,0.87);
1300 if (Propulsion->GetEngine(i)->GetType()==FGEngine::etTurbine)
1302 ((
FGTurbine*)Propulsion->GetEngine(i))->SetCutoff(
false);
1303 ((
FGTurbine*)Propulsion->GetEngine(i))->SetPhase(FGTurbine::tpRun);
1308 Propulsion->GetSteadyState();
1312 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1314 int engineStartCount = 0;
1315 bool engine_started =
false;
1317 int n_attempts = 100;
1318 if (Propulsion->GetEngine(i)->GetType()==FGEngine::etTurbine)
1321 while ( !engine_started && (engineStartCount < n_attempts) )
1323 engine_started = ensureRunning(i);
1332 Propulsion->GetSteadyState();
1334 fdmex->SetDebugLevel(0);
1340 for(
int i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
1341 fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(
false);
1344 fdmex->DisableOutput();
1346 fgic->SetPRadpsIC(0.0);
1347 fgic->SetQRadpsIC(0.0);
1348 fgic->SetRRadpsIC(0.0);
1350 if(mode == taPullup ) {
1352 }
else if (mode == taTurn) {
1354 }
else if (mode == taTurnFull) {
1357 fgic->SetPRadpsIC(0.0);
1358 fgic->SetQRadpsIC(0.0);
1359 fgic->SetRRadpsIC(0.0);
1379 "# iteration, costf, dT, dE, dA, dR, Phi (rad), Theta (rad), Psi (rad), uDot (fps2), vDot (fps2), wDot (fps2), pDot (rad/s2), qDot (rad/s2), rDot (rad/s2), u (fps), v (fps), w (fps), p (rad/s), q (rad/s), r (rad/s), alpha (rad), beta (rad), alphaDot (rad/s), betaDot (rad/s), Thrust" 1382 long n = vTrimAnalysisControls.size();
1389 Vector<double>* minVec =
new Vector<double>(n, 0.0);
1392 Vector<double>* Sminimum;
1393 new_Vector_Init(Sminimum,*minVec);
1407 sigma_nm, alpha_nm, beta_nm, gamma_nm,
1408 initial_step, tolerance,
1415 if ( GetMode()==taLongitudinal ) {
1418 if ( GetMode()==taFull ) {
1421 if ( GetMode()==taFullWingsLevel ) {
1424 if ( GetMode()==taTurn ) {
1427 if ( GetMode()==taTurnFull ) {
1430 if ( GetMode()==taPullup ) {
1447 stringstream ss (stringstream::in | stringstream::out);
1450 for (
unsigned int k=0; k<vTrimAnalysisControls.size();k++)
1451 ss << vTrimAnalysisControls[k]->GetControlInitialValue() <<
" ";
1454 for (
unsigned int k=0; k<vTrimAnalysisControls.size();k++)
1456 for(vector<FGTrimAnalysisControl*>::iterator vi=vTrimAnalysisControls.begin();
1457 vi!=vTrimAnalysisControls.end();vi++) {
1458 if ( (*vi)->GetControlType()==vTrimAnalysisControls[k]->GetControlType() )
1459 ss << (*vi)->GetControlInitialValue() + (*vi)->GetControlStep() <<
" ";
1461 ss << (*vi)->GetControlInitialValue() <<
" ";
1474 NMS.SetMaxCalls(max_iterations);
1476 if ( stop_criterion==
"Stop-On-Std" )
1477 NMS.Set_Stop_on_std();
1478 if ( stop_criterion==
"Stop-On-Delta" )
1479 NMS.Set_Stop_on_delta();
1486 fdmex->SetDebugLevel(0);
1495 NMS.GetMinPoint(*Sminimum);
1496 NMS.GetMinVal(SMinVal);
1497 Scalls = NMS.GetFunctionCalls();
1501 if ( ( mode == taFull ) ||
1502 ( mode == taTurnFull ) )
1504 FCS->SetDeCmd( (*Sminimum)[1] );
1505 FCS->SetDaCmd( (*Sminimum)[2] );
1506 FCS->SetDrCmd( (*Sminimum)[3] );
1508 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1510 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1511 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1512 FCS->SetThrottleCmd(i,tMin + (*Sminimum)[0] *(tMax-tMin));
1515 Propulsion->GetSteadyState();
1518 FGQuaternion quat( (*Sminimum)[4], (*Sminimum)[5], (*Sminimum)[6] );
1521 fgic->ResetIC(_u, _v, _w, _p, _q, _r, _alpha, _beta, _phi, _theta, _psi, _gamma);
1525 fdmex->GetPropagate()->SetVState(vstate);
1526 Auxiliary->Setalpha( _alpha );
1527 Auxiliary->Setbeta ( _beta );
1536 if ( mode == taLongitudinal )
1538 FCS->SetDeCmd( (*Sminimum)[1] );
1540 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1542 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1543 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1544 FCS->SetThrottleCmd(i,tMin + (*Sminimum)[0] *(tMax-tMin));
1547 Propulsion->GetSteadyState();
1550 FGQuaternion quat( 0, (*Sminimum)[2], fgic->GetPsiRadIC() );
1555 fgic->ResetIC(_u, _v, _w, _p, _q, _r, _alpha, _beta, _phi, _theta, _psi, _gamma);
1563 fdmex->GetPropagate()->SetVState(vstate);
1564 Auxiliary->Setalpha( _alpha );
1565 Auxiliary->Setbeta ( _beta );
1571 if ( mode == taFullWingsLevel)
1573 FCS->SetDeCmd( (*Sminimum)[1] );
1574 FCS->SetDaCmd( (*Sminimum)[2] );
1575 FCS->SetDrCmd( (*Sminimum)[3] );
1578 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1580 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1581 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1582 FCS->SetThrottleCmd(i,tMin + (*Sminimum)[0] *(tMax-tMin));
1585 Propulsion->GetSteadyState();
1588 FGQuaternion quat( 0, (*Sminimum)[2], fgic->GetPsiRadIC() );
1594 fgic->ResetIC(_u, _v, _w, _p, _q, _r, _alpha, _beta, _phi, _theta, _psi, _gamma);
1602 fdmex->GetPropagate()->SetVState(vstate);
1603 Auxiliary->Setalpha( _alpha );
1604 Auxiliary->Setbeta ( _beta );
1609 if ( mode == taTurn )
1611 FCS->SetDeCmd( (*Sminimum)[1] );
1612 FCS->SetDaCmd( (*Sminimum)[2] );
1613 FCS->SetDrCmd( (*Sminimum)[3] );
1616 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1618 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1619 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1620 FCS->SetThrottleCmd(i,tMin + (*Sminimum)[0] *(tMax-tMin));
1623 Propulsion->GetSteadyState();
1626 FGQuaternion quat( fgic->GetPhiRadIC(), (*Sminimum)[2], fgic->GetPsiRadIC() );
1632 fgic->ResetIC(_u, _v, _w, _p, _q, _r, _alpha, _beta, _phi, _theta, _psi, _gamma);
1640 fdmex->GetPropagate()->SetVState(vstate);
1641 Auxiliary->Setalpha( _alpha );
1642 Auxiliary->Setbeta ( 0.0 );
1643 Auxiliary->SetGamma( fgic->GetFlightPathAngleRadIC() );
1648 if ( mode == taPullup )
1650 FCS->SetDeCmd( (*Sminimum)[1] );
1651 FCS->SetDaCmd( (*Sminimum)[2] );
1652 FCS->SetDrCmd( (*Sminimum)[3] );
1655 for(
unsigned i=0;i<Propulsion->GetNumEngines();i++)
1657 tMin=Propulsion->GetEngine(i)->GetThrottleMin();
1658 tMax=Propulsion->GetEngine(i)->GetThrottleMax();
1659 FCS->SetThrottleCmd(i,tMin + (*Sminimum)[0] *(tMax-tMin));
1662 Propulsion->GetSteadyState();
1665 FGQuaternion quat( 0, (*Sminimum)[2], fgic->GetPRadpsIC() );
1671 fgic->ResetIC(_u, _v, _w, _p, _q, _r, _alpha, _beta, _phi, _theta, _psi, _gamma);
1679 fdmex->GetPropagate()->SetVState(vstate);
1680 Auxiliary->Setalpha( _alpha );
1681 Auxiliary->Setbeta ( 0.0 );
1682 Auxiliary->SetGamma( fgic->GetFlightPathAngleRadIC() );
1692 total_its = NMS.GetFunctionCalls();
1694 if( !trim_failed ) {
1695 if (debug_lvl > 0) {
1696 cout << endl <<
" Trim successful. (Cost function value: " << cost_function_value <<
")" << endl;
1700 cout << endl <<
" Trim failed" << endl;
1704 for (
unsigned int i=0; i<(
unsigned int)fdmex->GetGroundReactions()->GetNumGearUnits();i++){
1705 fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(
true);
1708 return !trim_failed;
1713 double Objective::myCostFunctionFull(Vector<double> & x)
1729 double delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R;
1731 double theta, phi, psi;
1733 double alpha = 0.0, beta = 0.0, gamma = 0.0;
1773 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
1774 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
1775 || ( (delta_cmd_A < -1) || (delta_cmd_A > 1) )
1776 || ( (delta_cmd_R < -1) || (delta_cmd_R > 1) )
1777 || ( (psi < 0.0 ) || (psi > 2.0*M_PI) )
1778 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) )
1779 || ( (phi < - M_PI) || (phi > M_PI) )
1787 }
else {calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
1799 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
1800 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
1801 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
1802 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
1812 static int count = 0;
1815 if ( f < TrimAnalysis->GetCostFunctionValue() )
1818 vector<FGTrimAnalysisControl*>::iterator vi;
1819 for(vi=TrimAnalysis->GetControls()->begin();
1820 vi!=TrimAnalysis->GetControls()->end();vi++)
1822 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
1823 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
1824 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(delta_cmd_A);
1825 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(delta_cmd_R);
1826 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(phi);
1827 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
1828 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl(psi);
1831 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
1844 << count <<
", "<< f <<
", " 1845 << delta_cmd_T <<
", "<< delta_cmd_E <<
", "<< delta_cmd_A <<
", "<< delta_cmd_R <<
", " 1847 << phi <<
", "<< theta <<
", "<< psi <<
", " 1848 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 1849 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 1850 << u <<
", "<< v <<
", "<< w <<
", " 1851 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 1864 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
1873 double Objective::myCostFunctionFullWingsLevel(Vector<double> & x)
1890 double delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R;
1892 double theta, phi, psi;
1894 double alpha = 0.0, beta = 0.0, gamma = 0.0;
1934 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
1935 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
1936 || ( (delta_cmd_A < -1) || (delta_cmd_A > 1) )
1937 || ( (delta_cmd_R < -1) || (delta_cmd_R > 1) )
1938 || ( (psi < 0.0 ) || (psi > 2.0*M_PI) )
1939 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) )
1949 calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
1961 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
1962 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
1963 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
1964 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
1974 static int count = 0;
1977 if ( f < TrimAnalysis->GetCostFunctionValue() )
1980 vector<FGTrimAnalysisControl*>::iterator vi;
1981 for(vi=TrimAnalysis->GetControls()->begin();
1982 vi!=TrimAnalysis->GetControls()->end();vi++)
1984 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
1985 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
1986 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(delta_cmd_A);
1987 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(delta_cmd_R);
1988 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(phi);
1989 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
1990 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl(psi);
1993 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
2006 << count <<
", "<< f <<
", " 2007 << delta_cmd_T <<
", "<< delta_cmd_E <<
", "<< delta_cmd_A <<
", "<< delta_cmd_R <<
", " 2009 << phi <<
", "<< theta <<
", "<< psi <<
", " 2010 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 2011 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 2012 << u <<
", "<< v <<
", "<< w <<
", " 2013 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 2026 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
2034 double Objective::myCostFunctionLongitudinal(Vector<double> & x)
2052 double delta_cmd_T, delta_cmd_E, delta_cmd_A = 0.0, delta_cmd_R = 0.0;
2054 double phi, theta, psi;
2056 double alpha = 0.0, beta = 0.0, gamma = 0.0;
2095 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
2096 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
2097 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) )
2106 calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
2118 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
2119 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
2120 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
2121 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
2130 static int count = 0;
2133 if ( f < TrimAnalysis->GetCostFunctionValue() )
2136 vector<FGTrimAnalysisControl*>::iterator vi;
2137 for(vi=TrimAnalysis->GetControls()->begin();
2138 vi!=TrimAnalysis->GetControls()->end();vi++)
2140 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
2141 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
2142 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(0);
2143 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(0);
2144 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(0);
2145 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
2146 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl( FDMExec->
GetIC()->
GetPsiRadIC());
2149 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
2162 << count <<
", "<< f <<
", " 2163 << delta_cmd_T <<
", " 2164 << delta_cmd_E <<
", " <<0.0 <<
", "<< 0.0 <<
", " 2165 << phi <<
", "<< theta <<
", "<< psi <<
", " 2166 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 2167 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 2168 << u <<
", "<< v <<
", "<< w <<
", " 2169 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 2181 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
2189 double Objective::myCostFunctionFullCoordinatedTurn(Vector<double> & x)
2204 double delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R;
2206 double phi, theta, psi;
2208 double alpha = 0.0, beta = 0.0;
2244 theta = atan2( sin(psi)*cos(gamma)+cos(psi)*sin(gamma), cos(gamma) );
2246 TrimAnalysis->setupTurnPhi(psi,theta);
2259 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
2260 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
2261 || ( (delta_cmd_A < -1) || (delta_cmd_A > 1) )
2262 || ( (delta_cmd_R < -1) || (delta_cmd_R > 1) )
2263 || ( (psi < 0.0 ) || (psi > 2.0*M_PI) )
2264 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) )
2273 calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
2285 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
2286 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
2287 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
2288 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
2298 static int count = 0;
2301 if ( f < TrimAnalysis->GetCostFunctionValue() )
2304 vector<FGTrimAnalysisControl*>::iterator vi;
2305 for(vi=TrimAnalysis->GetControls()->begin();
2306 vi!=TrimAnalysis->GetControls()->end();vi++)
2308 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
2309 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
2310 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(delta_cmd_A);
2311 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(delta_cmd_R);
2312 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(phi);
2313 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
2314 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl(psi);
2317 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
2330 << count <<
", "<< f <<
", " 2331 << delta_cmd_T <<
", " 2332 << delta_cmd_E <<
", " << delta_cmd_A <<
", "<< delta_cmd_R <<
", " 2333 << phi <<
", "<< theta <<
", "<< psi <<
", " 2334 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 2335 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 2336 << u <<
", "<< v <<
", "<< w <<
", " 2337 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 2349 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
2357 double Objective::myCostFunctionFullTurn(Vector<double> & x)
2372 double delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R;
2374 double phi, theta, psi;
2376 double alpha = 0.0, beta = 0.0;
2412 TrimAnalysis->setupTurn();
2425 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
2426 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
2427 || ( (delta_cmd_A < -1) || (delta_cmd_A > 1) )
2428 || ( (delta_cmd_R < -1) || (delta_cmd_R > 1) )
2429 || ( (psi < 0.0 ) || (psi > 2.0*M_PI) )
2430 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) )
2439 calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
2451 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
2452 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
2453 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
2454 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
2464 static int count = 0;
2467 if ( f < TrimAnalysis->GetCostFunctionValue() )
2470 vector<FGTrimAnalysisControl*>::iterator vi;
2471 for(vi=TrimAnalysis->GetControls()->begin();
2472 vi!=TrimAnalysis->GetControls()->end();vi++)
2474 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
2475 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
2476 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(delta_cmd_A);
2477 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(delta_cmd_R);
2478 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(phi);
2479 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
2480 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl(psi);
2483 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
2496 << count <<
", "<< f <<
", " 2497 << delta_cmd_T <<
", " 2498 << delta_cmd_E <<
", " << delta_cmd_A <<
", "<< delta_cmd_R <<
", " 2499 << phi <<
", "<< theta <<
", "<< psi <<
", " 2500 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 2501 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 2502 << u <<
", "<< v <<
", "<< w <<
", " 2503 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 2515 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
2524 double Objective::myCostFunctionPullUp(Vector<double> & x)
2539 double delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R;
2541 double phi, theta, psi;
2543 double alpha = 0.0, beta = 0.0, gamma = 0.0;
2585 bool penalty = ( (delta_cmd_T < 0) || (delta_cmd_T > 1) )
2586 || ( (delta_cmd_E < -1) || (delta_cmd_E > 1) )
2587 || ( (delta_cmd_A < -1) || (delta_cmd_A > 1) )
2588 || ( (delta_cmd_R < -1) || (delta_cmd_R > 1) )
2589 || ( (theta < -0.5*M_PI) || (theta > 0.5*M_PI) );
2597 calculateDottedStates(delta_cmd_T, delta_cmd_E, delta_cmd_A, delta_cmd_R,
2609 u = VState.
vUVW (1); v = VState.
vUVW (2); w = VState.
vUVW (3);
2610 p = VState.
vPQR (1); q = VState.
vPQR (2); r = VState.
vPQR (3);
2611 uDot = vUVWdot(1); vDot = vUVWdot(2); wDot = vUVWdot(3);
2612 pDot = vPQRdot(1); qDot = vPQRdot(2); rDot = vPQRdot(3);
2622 static int count = 0;
2625 if ( f < TrimAnalysis->GetCostFunctionValue() )
2628 vector<FGTrimAnalysisControl*>::iterator vi;
2629 for(vi=TrimAnalysis->GetControls()->begin();
2630 vi!=TrimAnalysis->GetControls()->end();vi++)
2632 if ( (*vi)->GetControlType()==JSBSim::taThrottle ) (*vi)->SetControl(delta_cmd_T);
2633 if ( (*vi)->GetControlType()==JSBSim::taElevator ) (*vi)->SetControl(delta_cmd_E);
2634 if ( (*vi)->GetControlType()==JSBSim::taAileron ) (*vi)->SetControl(delta_cmd_A);
2635 if ( (*vi)->GetControlType()==JSBSim::taRudder ) (*vi)->SetControl(delta_cmd_R);
2636 if ( (*vi)->GetControlType()==JSBSim::taPhi ) (*vi)->SetControl(phi);
2637 if ( (*vi)->GetControlType()==JSBSim::taTheta ) (*vi)->SetControl(theta);
2638 if ( (*vi)->GetControlType()==JSBSim::taHeading ) (*vi)->SetControl(psi);
2641 if ( f<=TrimAnalysis->GetTolerance() ) TrimAnalysis->SetTrimSuccessfull();
2654 << count <<
", "<< f <<
", " 2655 << delta_cmd_T <<
", " 2656 << delta_cmd_E <<
", " <<delta_cmd_A <<
", "<< delta_cmd_R <<
", " 2657 << phi <<
", "<< theta <<
", "<< psi <<
", " 2658 << uDot <<
", "<< vDot <<
", "<< wDot <<
", " 2659 << pDot <<
", "<< qDot <<
", "<< rDot <<
", " 2660 << u <<
", "<< v <<
", "<< w <<
", " 2661 << VState.
vPQR(1) <<
", "<< VState.
vPQR(2) <<
", "<< VState.
vPQR(3) <<
", " 2673 TrimAnalysis->
SetState(u, v, w, p, q, r, alpha, beta, phi, theta, psi, gamma);
2682 void Objective::calculateDottedStates(
double delta_cmd_T,
double delta_cmd_E,
double delta_cmd_A,
double delta_cmd_R,
2683 double phi,
double theta,
double psi,
2684 TrimAnalysisMode trimMode,
2685 double& alpha,
double& beta,
double& gamma,
2689 double stheta,sphi,spsi;
2690 double ctheta,cphi,cpsi;
2696 if ( ( trimMode == taTurn ) || ( trimMode == taTurnFull ) )
2702 cphi = cos(phi); sphi = sin(phi);
2703 ctheta = cos(theta); stheta = sin(theta);
2704 cpsi = cos(psi); spsi = sin(psi);
2713 for (
unsigned int i=0; i<Propulsion->
GetNumEngines(); i++) {
2714 Propulsion->
GetEngine(i)->SetRunning(
true);
2720 tMin=Propulsion->
GetEngine(i)->GetThrottleMin();
2721 tMax=Propulsion->
GetEngine(i)->GetThrottleMax();
2745 VState.vQtrn = Quat1;
2746 VState.vQtrn.Normalize();
2754 double hIC = FDMExec->
GetIC()->GetAltitudeFtIC();
2760 FDMExec->GetAtmosphere()->
Run();
2772 gammaIC = TrimAnalysis->
GetGamma();
2773 rocIC = vtIC * tan(gammaIC);
2776 double vdownIC = - rocIC;
2778 if ( ( trimMode == taTurn ) || ( trimMode == taTurnFull ) )
2781 vdownIC = TrimAnalysis->
GetVtFps() * tan(gamma);
2783 Auxiliary->SetGamma(gamma);
2790 double psigtIC = psiIC;
2794 double vgIC = vtIC * cos(gammaIC);
2796 double vnorthIC = vgIC * cos(psigtIC);
2797 double veastIC = vgIC * sin(psigtIC);
2807 u=vnorthIC*ctheta*cpsi +
2808 veastIC*ctheta*spsi -
2810 v=vnorthIC*( sphi*stheta*cpsi - cphi*spsi ) +
2811 veastIC*( sphi*stheta*spsi + cphi*cpsi ) +
2812 vdownIC*sphi*ctheta;
2813 w=vnorthIC*( cphi*stheta*cpsi + sphi*spsi ) +
2814 veastIC*( cphi*stheta*spsi - sphi*cpsi ) +
2815 vdownIC*cphi*ctheta;
2820 uw=wnorthIC*ctheta*cpsi +
2821 weastIC*ctheta*spsi -
2823 vw=wnorthIC*( sphi*stheta*cpsi - cphi*spsi ) +
2824 weastIC*( sphi*stheta*spsi + cphi*cpsi ) +
2825 wdownIC*sphi*ctheta;
2826 ww=wnorthIC*(cphi*stheta*cpsi + sphi*spsi) +
2827 weastIC*(cphi*stheta*spsi - sphi*cpsi) +
2828 wdownIC*cphi*ctheta;
2845 Auxiliary->SetVt(vtIC);
2847 if ((trimMode==taTurn)||(trimMode==taPullup))
2852 ua = u + uw; va = v + vw; wa = w + ww;
2856 if ( wa != 0.0 ) alpha = ua*ua > 0.0 ? atan2(wa, ua) : 0.0;
2857 if ( va != 0.0 ) beta = ua*ua+wa*wa > 0.0 ? atan2(va,sqrt(ua*ua+wa*wa)) : 0.0;
2858 double mUW = (ua*ua + wa*wa);
2860 if (ua != 0.0) signU = ua/fabs(ua);
2863 alpha = beta = adot = bdot = 0;
2876 if ( ( trimMode == taTurn ) || ( trimMode == taTurnFull ) )
2885 double qW = turnRate*sin(phiW);
2886 double rW = turnRate*cos(phiW);
2895 Auxiliary->SetGamma(0.);
2898 if ( trimMode == taPullup )
2913 double qbar = 0.5*FDMExec->GetAtmosphere()->
GetDensity()*vtIC*vtIC;
2914 double qbarUW = 0.5*FDMExec->GetAtmosphere()->
GetDensity()*(ua*ua + wa*wa);
2915 double qbarUV = 0.5*FDMExec->GetAtmosphere()->
GetDensity()*(ua*ua + va*va);
2916 double Mach = vtIC / FDMExec->GetAtmosphere()->
GetSoundSpeed();
2918 double MachU = ua / FDMExec->GetAtmosphere()->
GetSoundSpeed();
2919 double MachV = va / FDMExec->GetAtmosphere()->
GetSoundSpeed();
2920 double MachW = wa / FDMExec->GetAtmosphere()->
GetSoundSpeed();
2926 Auxiliary->Setalpha( alpha );
2927 Auxiliary->Setbeta ( beta );
2929 if ((trimMode==taTurn)||(trimMode==taPullup)) Auxiliary->Setbeta( 0.0 );
2932 Auxiliary->Setadot( 0.0 );
2933 Auxiliary->Setbdot( 0.0 );
2941 if ((trimMode==taTurn)||(trimMode==taPullup))
2947 Auxiliary->SetAeroUVW( vUVWAero );
2949 Auxiliary->Setqbar ( qbar );
2950 Auxiliary->SetqbarUV( qbarUV );
2951 Auxiliary->SetqbarUW( qbarUW );
2953 Auxiliary->SetVt ( vtIC );
2955 Auxiliary->SetMach ( Mach );
2956 Auxiliary->SetGamma ( gammaIC );
2991 hIC + FDMExec->
GetIC()->GetSeaLevelRadiusFtIC() );
3016 if (rd == 0.0) {cerr <<
"radius = 0 !" << endl; rd = 1e-16;}
3018 double rdInv = 1.0/rd;
3022 const FGMatrix33& Tl2b = VState.vQtrn.GetT();
3023 const FGMatrix33& Tb2l = VState.vQtrn.GetTInv();
3043 vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
3046 vUVWdot = VState.
vUVW*VState.
vPQR + vForces/mass;
3059 vUVWdot += Tl2b*gAccel;
3078 bool FGTrimAnalysis::getSteadyState(
int nrepeat )
3080 double currentThrust = 0, lastThrust=-1;
3084 while ( !steady && steady_count <= nrepeat )
3087 steady = Propulsion->GetSteadyState();
Element * GetParent(void)
Returns a pointer to the parent of an element.
double GetPhiRad()
Gets Euler angle phi.
double GetGamma()
Return the current flight path angle in TrimAnalysis object.
double GetPhiWRad()
Gets Euler angle phiW (wind axes)
~FGTrimAnalysis(void)
Destructor.
bool RemoveControl(TaControl control)
Remove a specific control from the current configuration.
FGInitialCondition * GetIC(void)
Returns a pointer to the FGInitialCondition object.
Models the Quaternion representation of rotations.
TrimAnalysisMode GetMode() const
double GetVtrueFpsIC(void) const
Gets the initial true velocity.
FGInertial * GetInertial(void)
Returns the FGInertial pointer.
bool DoTrim(void)
Execute the trim.
double GetFlightPathAngleRadIC(void) const
Gets the initial flight path angle.
bool SetResultsFile(string name)
Set the file where trim analysis results are written, open and get ready.
void SetMode(TrimAnalysisMode tam)
Clear all controls and set a predefined trim mode (Note: controls are intended here as those variable...
friend void find_CostFunctionFullWingsLevel(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Wings Level Trim cost function, to be called by optimization meth...
ofstream * GetResultsFile() const
Get the pointer to the file where trim analysis results are written,.
void Calculate(void)
Calculates the thrust of the engine, and other engine functions.
FGColumnVector3 UpdateRatesTurn(double psi, double theta, double phi, double phiW)
Updates angular rates for turn trim according to turning trim constraints.
void SetEulerAngles(double phi0, double theta0, double psi0)
Sets Euler angles.
bool AddControl(TaControl control)
Add a control to the current configuration.
double GetPhiRadIC(void) const
Gets the initial roll angle.
void SetCostFunctionValue(double value)
Set the value of the cost function.
FGAuxiliary * GetAuxiliary(void)
Returns the FGAuxiliary pointer.
FGLocation holds an arbitrary location in the Earth centered Earth fixed reference frame (ECEF)...
This class models a turbine engine.
FGLocation vLocation
Represents the current location of the vehicle in Earth centered Earth fixed (ECEF) frame...
FGEngine * GetEngine(unsigned int index) const
Retrieves an engine object pointer from the list of engines.
Element * FindElement(const std::string &el="")
Searches for a specified element.
bool EditState(TaControl new_control, double new_initvalue, double new_step, double new_min, double new_max)
Change the control settings previously configured.
friend void find_CostFunctionLongitudinal(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Longitudinal Trim cost function, to be called by optimization met...
unsigned int GetNumDataLines(void)
Returns the number of lines of data stored.
void Report(void)
Print the results of the trim.
void SetState(double u0, double v0, double w0, double p0, double q0, double r0, double alpha0, double beta0, double phi0, double theta0, double psi0, double gamma0)
Sets state variables.
void ClearControls(void)
Clear all controls from the current configuration.
void SetThrottleCmd(int engine, double cmd)
Sets the throttle command for the specified engine.
void SetDaCmd(double cmd)
Sets the aileron command.
bool Run(bool Holding)
Runs the Flight Controls model; called by the Executive Can pass in a value indicating if the executi...
The current vehicle state vector structure contains the translational and angular position...
void SetDottedValues(double udot, double vdot, double wdot, double pdot, double qdot, double rdot)
Sets Dotted values.
void CostFunctionFullTurn(long vars, Vector< double > &v, double &f)
Steady Turn Trim cost function.
double GetWindNFpsIC(void) const
Gets the initial wind velocity in local frame.
TaControl GetControlType(void)
Return the control type.
friend void find_CostFunctionPullUp(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Pullup Trim cost function, to be called by optimization method...
Objective(FGFDMExec *fdmex, FGTrimAnalysis *ta, double x)
Constructor.
bool Load(string fname, bool useStoredPath=true)
Loads the trim configuration from file.
FGTrimAnalysis(FGFDMExec *FDMExec, TrimAnalysisMode tam=taFull)
Initializes the trimming class.
void CostFunctionFullCoordinatedTurn(long vars, Vector< double > &v, double &f)
Steady Turn Trim cost function, NON-coordinated.
FGColumnVector3 vPQR
The angular velocity vector for the vehicle relative to the ECEF frame, expressed in the body frame...
double GetVtFps()
Gets true speed [fps] from IC.
double GetTargetNlfIC(void) const
Gets the target normal load factor set from IC.
Propulsion management class.
double GetTanLatitude() const
Get the cosine of Latitude.
double GetDataAsNumber(void)
Converts the element data to a number.
FGAircraft * GetAircraft(void)
Returns the FGAircraft pointer.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
virtual double GetSoundSpeed(void) const
Returns the speed of sound in ft/sec.
const std::string & GetName(void) const
Retrieves the element name.
FGGroundReactions * GetGroundReactions(void)
Returns the FGGroundReactions pointer.
double GetWindEFpsIC(void) const
Gets the initial wind velocity in local frame.
double GetPsiRadIC(void) const
Gets the initial heading angle.
FGColumnVector3 UpdateRatesPullup(void)
Updates angular rates for pull-up trim.
bool Run(bool Holding)
Runs the Ground Reactions model; called by the Executive Can pass in a value indicating if the execut...
double GetTargetNlf(void)
Gets target normal load factor in steady turn.
void SetDrCmd(double cmd)
Sets the rudder command.
void SetDeCmd(double cmd)
Sets the elevator command.
bool Run(bool Holding)
Runs the atmosphere forces model; called by the Executive.
void CostFunctionLongitudinal(long vars, Vector< double > &v, double &f)
Longitudinal Trim cost function.
void CostFunctionFullWingsLevel(long vars, Vector< double > &v, double &f)
Wings Level Trim cost function.
This class implements a 3 element column vector.
void TrimStats()
Iteration statistics.
virtual double GetDensity(void) const
Returns the density in slugs/ft^3.
void CostFunctionPullUp(long vars, Vector< double > &v, double &f)
Pullup Trim cost function.
FGFCS * GetFCS(void)
Returns the FGFCS pointer.
Encapsulates the Flight Control System (FCS) functionality.
double GetWindDFpsIC(void) const
Gets the initial wind velocity in local frame.
bool GetSteadyState(void)
Loops the engines until thrust output steady (used for trimming)
const FGMatrix33 & GetTec2l(void) const
Transform matrix from the earth centered to local horizontal frame.
double GetGammaRad()
Gets flight path angle.
friend void find_CostFunctionFull(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Full Trim cost function, to be called by optimization method...
Encapsulates various uncategorized scheduled functions.
Models a Supercharged Piston engine.
Handles matrix math operations.
void CostFunctionFull(long vars, Vector< double > &v, double &f)
Full Trim cost function.
FGAerodynamics * GetAerodynamics(void)
Returns the FGAerodynamics pointer.
void Normalize(void)
Normalize.
FGPropulsion * GetPropulsion(void)
Returns the FGPropulsion pointer.
Models an aircraft control variables for purposes of trimming.
const FGMatrix33 & GetTl2ec(void) const
Transform matrix from local horizontal to earth centered frame.
void CalculatePhiWFromTargetNlfTurn(double nlf)
Calculate the wind axis bank angle from a given Nlf (sets also the target Nlf)
Encapsulates the JSBSim simulation executive.
bool Run(bool Holding)
Runs the Aircraft model; called by the Executive Can pass in a value indicating if the executive is d...
FGColumnVector3 vUVW
The velocity vector of the vehicle with respect to the ECEF frame, expressed in the body system...
double GetClimbRateFpsIC(void) const
Gets the initial climb rate.
bool Run(bool Holding)
Runs the Aerodynamics model; called by the Executive Can pass in a value indicating if the executive ...
FGPropagate * GetPropagate(void)
Returns the FGPropagate pointer.
FGMassBalance * GetMassBalance(void)
Returns the FGAircraft pointer.
friend void find_CostFunctionFullCoordinatedTurn(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Steady Turn Trim cost function, to be called by optimization meth...
unsigned int GetNumEngines(void) const
Retrieves the number of engines defined for the aircraft.
friend void find_CostFunctionFullTurn(long vars, Vector< double > &v, double &f, bool &success, void *t_ptr)
Wrapping function for the effective Steady Turn Trim cost function, to be called by optimization meth...