]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim.cxx
Fix a screwup I introduced with radians to degree conversion in passing data
[flightgear.git] / src / FDM / JSBSim.cxx
1 // JSBsim.cxx -- interface to the JSBsim flight model
2 //
3 // Written by Curtis Olson, started February 1999.
4 //
5 // Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <simgear/compiler.h>
25
26 #ifdef SG_MATH_EXCEPTION_CLASH
27 #  include <math.h>
28 #endif
29
30 #include STL_STRING
31
32 #include <simgear/constants.h>
33 #include <simgear/debug/logstream.hxx>
34 #include <simgear/math/sg_geodesy.hxx>
35 #include <simgear/misc/sg_path.hxx>
36
37 #include <Scenery/scenery.hxx>
38
39 #include <Aircraft/aircraft.hxx>
40 #include <Controls/controls.hxx>
41 #include <Main/globals.hxx>
42 #include <Main/fg_props.hxx>
43
44 #include <FDM/JSBSim/FGFDMExec.h>
45 #include <FDM/JSBSim/FGAircraft.h>
46 #include <FDM/JSBSim/FGFCS.h>
47 #include <FDM/JSBSim/FGPosition.h>
48 #include <FDM/JSBSim/FGRotation.h>
49 #include <FDM/JSBSim/FGState.h>
50 #include <FDM/JSBSim/FGTranslation.h>
51 #include <FDM/JSBSim/FGAuxiliary.h>
52 #include <FDM/JSBSim/FGDefs.h>
53 #include <FDM/JSBSim/FGInitialCondition.h>
54 #include <FDM/JSBSim/FGTrim.h>
55 #include <FDM/JSBSim/FGAtmosphere.h>
56 #include <FDM/JSBSim/FGMassBalance.h>
57 #include <FDM/JSBSim/FGAerodynamics.h>
58 #include "JSBSim.hxx"
59
60 /******************************************************************************/
61
62 FGJSBsim::FGJSBsim( double dt ) 
63   : FGInterface(dt)
64 {
65     bool result;
66    
67     fdmex=new FGFDMExec;
68     
69     State        = fdmex->GetState();
70     Atmosphere   = fdmex->GetAtmosphere();
71     FCS          = fdmex->GetFCS();
72     MassBalance  = fdmex->GetMassBalance();
73     Propulsion   = fdmex->GetPropulsion();
74     Aircraft     = fdmex->GetAircraft();
75     Translation  = fdmex->GetTranslation();
76     Rotation     = fdmex->GetRotation();
77     Position     = fdmex->GetPosition();
78     Auxiliary    = fdmex->GetAuxiliary();
79     Aerodynamics = fdmex->GetAerodynamics();
80     
81     Atmosphere->UseInternal();
82     
83     fgic=new FGInitialCondition(fdmex);
84     needTrim=true;
85   
86     SGPath aircraft_path( globals->get_fg_root() );
87     aircraft_path.append( "Aircraft" );
88
89     SGPath engine_path( globals->get_fg_root() );
90     engine_path.append( "Engine" );
91     set_delta_t( dt );
92     State->Setdt( dt );
93
94     result = fdmex->LoadModel( aircraft_path.str(),
95                                engine_path.str(),
96                                fgGetString("/sim/aircraft") );
97     
98
99     if (result) {
100       SG_LOG( SG_FLIGHT, SG_INFO, "  loaded aircraft.");
101     } else {
102       SG_LOG( SG_FLIGHT, SG_INFO,
103               "  aircraft does not exist (you may have mis-typed the name).");
104       throw(-1);
105     }
106
107     int Neng = Propulsion->GetNumEngines();
108     SG_LOG(SG_FLIGHT,SG_INFO, "Neng: " << Neng );
109     
110     for(int i=0;i<Neng;i++) {
111         add_engine( FGEngInterface() );
112     }  
113     
114     fgSetDouble("/fdm/trim/pitch-trim", FCS->GetPitchTrimCmd());
115     fgSetDouble("/fdm/trim/throttle",   FCS->GetThrottleCmd(0));
116     fgSetDouble("/fdm/trim/aileron",    FCS->GetDaCmd());
117     fgSetDouble("/fdm/trim/rudder",     FCS->GetDrCmd());
118
119     startup_trim = fgGetNode("/sim/startup/trim", true);
120
121     trimmed = fgGetNode("/fdm/trim/trimmed", true);
122     trimmed->setBoolValue(false);
123
124     pitch_trim = fgGetNode("/fdm/trim/pitch-trim", true );
125     throttle_trim = fgGetNode("/fdm/trim/throttle", true );
126     aileron_trim = fgGetNode("/fdm/trim/aileron", true );
127     rudder_trim = fgGetNode("/fdm/trim/rudder", true );
128 }
129
130 /******************************************************************************/
131 FGJSBsim::~FGJSBsim(void) {
132     if (fdmex != NULL) {
133         delete fdmex; fdmex=NULL;
134         delete fgic; fgic=NULL;
135     }  
136 }
137
138 /******************************************************************************/
139
140 // Initialize the JSBsim flight model, dt is the time increment for
141 // each subsequent iteration through the EOM
142
143 void FGJSBsim::init() {
144     
145     SG_LOG( SG_FLIGHT, SG_INFO, "Starting and initializing JSBsim" );
146    
147     // Explicitly call the superclass's
148     // init method first.
149     FGInterface::init();
150
151     fdmex->GetState()->Initialize(fgic);
152     // fdmex->RunIC(fgic); //loop JSBSim once w/o integrating
153     fdmex->Run();       //loop JSBSim once
154     copy_from_JSBsim(); //update the bus
155
156     SG_LOG( SG_FLIGHT, SG_INFO, "  Initialized JSBSim with:" );
157
158     switch(fgic->GetSpeedSet()) {
159     case setned:
160         SG_LOG(SG_FLIGHT,SG_INFO, "  Vn,Ve,Vd= "
161                << Position->GetVn() << ", "
162                << Position->GetVe() << ", "
163                << Position->GetVd() << " ft/s");
164     break;
165     case setuvw:
166         SG_LOG(SG_FLIGHT,SG_INFO, "  U,V,W= "
167                << Translation->GetUVW(1) << ", "
168                << Translation->GetUVW(2) << ", "
169                << Translation->GetUVW(3) << " ft/s");
170     break;
171     case setmach:
172         SG_LOG(SG_FLIGHT,SG_INFO, "  Mach: "
173                << Translation->GetMach() );
174     break;
175     case setvc:
176     default:
177         SG_LOG(SG_FLIGHT,SG_INFO, "  Indicated Airspeed: "
178                << Auxiliary->GetVcalibratedKTS() << " knots" );
179     break;
180     }
181
182     SG_LOG( SG_FLIGHT, SG_INFO, "  Bank Angle: "
183             <<  Rotation->Getphi()*RADTODEG << " deg" );
184     SG_LOG( SG_FLIGHT, SG_INFO, "  Pitch Angle: "
185             << Rotation->Gettht()*RADTODEG << " deg" );
186     SG_LOG( SG_FLIGHT, SG_INFO, "  True Heading: "
187             << Rotation->Getpsi()*RADTODEG << " deg" );
188     SG_LOG( SG_FLIGHT, SG_INFO, "  Latitude: "
189             << Position->GetLatitude() << " deg" );
190     SG_LOG( SG_FLIGHT, SG_INFO, "  Longitude: "
191             << Position->GetLongitude() << " deg" );
192     SG_LOG( SG_FLIGHT, SG_INFO, "  Altitude: "
193             << Position->Geth() << " feet" );
194     SG_LOG( SG_FLIGHT, SG_INFO, "  loaded initial conditions" );
195
196     SG_LOG( SG_FLIGHT, SG_INFO, "  set dt" );
197
198     SG_LOG( SG_FLIGHT, SG_INFO, "Finished initializing JSBSim" );
199 }
200
201 /******************************************************************************/
202
203 // Run an iteration of the EOM (equations of motion)
204
205 bool FGJSBsim::update( int multiloop ) {
206
207     int i;
208
209     double save_alt = 0.0;
210
211     copy_to_JSBsim();
212
213     trimmed->setBoolValue(false);
214
215     if ( needTrim && startup_trim->getBoolValue() ) {
216
217         //fgic->SetSeaLevelRadiusFtIC( get_Sea_level_radius() );
218         //fgic->SetTerrainAltitudeFtIC( scenery.cur_elev * SG_METER_TO_FEET );
219
220         FGTrim *fgtrim;
221         if(fgic->GetVcalibratedKtsIC() < 10 ) {
222             fgic->SetVcalibratedKtsIC(0.0);
223             fgtrim=new FGTrim(fdmex,fgic,tGround);
224         } else {
225             fgtrim=new FGTrim(fdmex,fgic,tLongitudinal);
226         }
227         if(!fgtrim->DoTrim()) {
228             fgtrim->Report();
229             fgtrim->TrimStats();
230         } else {
231             trimmed->setBoolValue(true);
232         }
233         fgtrim->ReportState();
234         delete fgtrim;
235
236         needTrim=false;
237
238         pitch_trim->setDoubleValue( FCS->GetPitchTrimCmd() );
239         throttle_trim->setDoubleValue( FCS->GetThrottleCmd(0) );
240         aileron_trim->setDoubleValue( FCS->GetDaCmd() );
241         rudder_trim->setDoubleValue( FCS->GetDrCmd() );
242
243         globals->get_controls()->set_elevator_trim(FCS->GetPitchTrimCmd());
244         globals->get_controls()->set_elevator(FCS->GetDeCmd());
245         globals->get_controls()->set_throttle(FGControls::ALL_ENGINES,
246                                               FCS->GetThrottleCmd(0));
247
248         globals->get_controls()->set_aileron(FCS->GetDaCmd());
249         globals->get_controls()->set_rudder( FCS->GetDrCmd());
250     
251         SG_LOG( SG_FLIGHT, SG_INFO, "  Trim complete" );
252     }
253   
254     for( i=0; i<get_num_engines(); i++ ) {
255       FGEngInterface * e = get_engine(i);
256       FGEngine * eng = Propulsion->GetEngine(i);
257       FGThruster * thrust = Propulsion->GetThruster(i);
258       e->set_Manifold_Pressure( eng->getManifoldPressure_inHg() );
259       e->set_RPM( thrust->GetRPM() );
260       e->set_EGT( eng->getExhaustGasTemp_degF() );
261       e->set_CHT( eng->getCylinderHeadTemp_degF() );
262       e->set_Oil_Temp( eng->getOilTemp_degF() );
263       e->set_Throttle( globals->get_controls()->get_throttle(i) );
264     }
265
266     for ( i=0; i < multiloop; i++ ) {
267         fdmex->Run();
268     }
269
270     // printf("%d FG_Altitude = %.2f\n", i, FG_Altitude * 0.3048);
271     // printf("%d Altitude = %.2f\n", i, Altitude * 0.3048);
272
273     // translate JSBsim back to FG structure so that the
274     // autopilot (and the rest of the sim can use the updated values
275
276     copy_from_JSBsim();
277     return true;
278 }
279
280 /******************************************************************************/
281
282 // Convert from the FGInterface struct to the JSBsim generic_ struct
283
284 bool FGJSBsim::copy_to_JSBsim() {
285     // copy control positions into the JSBsim structure
286
287     FCS->SetDaCmd( globals->get_controls()->get_aileron());
288     FCS->SetDeCmd( globals->get_controls()->get_elevator());
289     FCS->SetPitchTrimCmd(globals->get_controls()->get_elevator_trim());
290     FCS->SetDrCmd( -globals->get_controls()->get_rudder());
291     FCS->SetDfCmd(  globals->get_controls()->get_flaps() );
292     FCS->SetDsbCmd( 0.0 ); //speedbrakes
293     FCS->SetDspCmd( 0.0 ); //spoilers
294     FCS->SetLBrake( globals->get_controls()->get_brake( 0 ) );
295     FCS->SetRBrake( globals->get_controls()->get_brake( 1 ) );
296     FCS->SetCBrake( globals->get_controls()->get_brake( 2 ) );
297     for (int i = 0; i < get_num_engines(); i++) {
298       FCS->SetThrottleCmd(i, globals->get_controls()->get_throttle(i));
299       FCS->SetMixtureCmd(i, globals->get_controls()->get_mixture(i));
300     }
301
302     Position->SetSeaLevelRadius( get_Sea_level_radius() );
303     Position->SetRunwayRadius( scenery.get_cur_elev()*SG_METER_TO_FEET
304                                + get_Sea_level_radius() );
305
306     Atmosphere->SetExTemperature(get_Static_temperature());
307     Atmosphere->SetExPressure(get_Static_pressure());
308     Atmosphere->SetExDensity(get_Density());
309     Atmosphere->SetWindNED(get_V_north_airmass(),
310                            get_V_east_airmass(),
311                            get_V_down_airmass());
312 //    SG_LOG(SG_FLIGHT,SG_INFO, "Wind NED: "
313 //                  << get_V_north_airmass() << ", "
314 //                  << get_V_east_airmass()  << ", "
315 //                  << get_V_down_airmass() );
316
317     return true;
318 }
319
320 /******************************************************************************/
321
322 // Convert from the JSBsim generic_ struct to the FGInterface struct
323
324 bool FGJSBsim::copy_from_JSBsim() {
325     unsigned int i, j;
326
327     _set_Inertias( MassBalance->GetMass(),
328                    MassBalance->GetIxx(),
329                    MassBalance->GetIyy(),
330                    MassBalance->GetIzz(),
331                    MassBalance->GetIxz() );
332
333     _set_CG_Position( MassBalance->GetXYZcg(1),
334                       MassBalance->GetXYZcg(2),
335                       MassBalance->GetXYZcg(3) );
336
337     _set_Accels_Body( Translation->GetUVWdot(1),
338                       Translation->GetUVWdot(2),
339                       Translation->GetUVWdot(3) );
340
341     _set_Accels_CG_Body( Translation->GetUVWdot(1),
342                          Translation->GetUVWdot(2),
343                          Translation->GetUVWdot(3) );
344
345     //_set_Accels_CG_Body_N ( Translation->GetNcg(1),
346     //                       Translation->GetNcg(2),
347     //                       Translation->GetNcg(3) );
348     //
349     _set_Accels_Pilot_Body( Auxiliary->GetPilotAccel(1),
350                             Auxiliary->GetPilotAccel(2),
351                             Auxiliary->GetPilotAccel(3) );
352
353     //_set_Accels_Pilot_Body_N( Auxiliary->GetNpilot(1),
354     //                         Auxiliary->GetNpilot(2),
355     //                         Auxiliary->GetNpilot(3) );
356
357     _set_Nlf( Aerodynamics->GetNlf() );
358
359     // Velocities
360
361     _set_Velocities_Local( Position->GetVn(),
362                            Position->GetVe(),
363                            Position->GetVd() );
364
365     _set_Velocities_Wind_Body( Translation->GetUVW(1),
366                                Translation->GetUVW(2),
367                                Translation->GetUVW(3) );
368
369     _set_V_rel_wind( Translation->GetVt() );
370
371     _set_V_equiv_kts( Auxiliary->GetVequivalentKTS() );
372
373     // _set_V_calibrated( Auxiliary->GetVcalibratedFPS() );
374
375     _set_V_calibrated_kts( Auxiliary->GetVcalibratedKTS() );
376
377     _set_V_ground_speed( Position->GetVground() );
378
379     _set_Omega_Body( Rotation->GetPQR(1),
380                      Rotation->GetPQR(2),
381                      Rotation->GetPQR(3) );
382
383     _set_Euler_Rates( Rotation->GetEulerRates(1),
384                       Rotation->GetEulerRates(2),
385                       Rotation->GetEulerRates(3) );
386
387     _set_Geocentric_Rates(Position->GetLatitudeDot(),
388                           Position->GetLongitudeDot(),
389                           Position->Gethdot() );
390
391     _set_Mach_number( Translation->GetMach() );
392
393     // Positions
394     _updatePosition( Position->GetLatitude(),
395                      Position->GetLongitude(),
396                      Position->Geth() );
397
398     _set_Altitude_AGL( Position->GetDistanceAGL() );
399
400     _set_Euler_Angles( Rotation->Getphi(),
401                        Rotation->Gettht(),
402                        Rotation->Getpsi() );
403
404     _set_Alpha( Translation->Getalpha() );
405     _set_Beta( Translation->Getbeta() );
406
407
408     _set_Gamma_vert_rad( Position->GetGamma() );
409     // set_Gamma_horiz_rad( Gamma_horiz_rad );
410
411     _set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() );
412
413     _set_Climb_Rate( Position->Gethdot() );
414
415
416     for ( i = 1; i <= 3; i++ ) {
417         for ( j = 1; j <= 3; j++ ) {
418             _set_T_Local_to_Body( i, j, State->GetTl2b(i,j) );
419         }
420     }
421     return true;
422 }
423
424 void FGJSBsim::snap_shot(void) {
425     fgic->SetLatitudeRadIC(get_Lat_geocentric() );
426     fgic->SetLongitudeRadIC( get_Longitude() );
427     fgic->SetAltitudeFtIC( get_Altitude() );
428     fgic->SetTerrainAltitudeFtIC( get_Runway_altitude() );
429     fgic->SetVtrueFpsIC( get_V_rel_wind() );
430     fgic->SetPitchAngleRadIC( get_Theta() );
431     fgic->SetRollAngleRadIC( get_Phi() );
432     fgic->SetTrueHeadingRadIC( get_Psi() );
433     fgic->SetClimbRateFpsIC( get_Climb_Rate() );
434 }
435
436
437 bool FGJSBsim::ToggleDataLogging(void) {
438     return fdmex->GetOutput()->Toggle();
439 }
440
441
442 bool FGJSBsim::ToggleDataLogging(bool state) {
443     if (state) {
444       fdmex->GetOutput()->Enable();
445       return true;
446     } else {
447       fdmex->GetOutput()->Disable();
448       return false;
449     }
450 }
451
452
453 //Positions
454 void FGJSBsim::set_Latitude(double lat) {
455     static const SGPropertyNode *altitude
456         = fgGetNode("/position/altitude-ft");
457     double alt;
458     if ( altitude->getDoubleValue() > -9990 ) {
459         alt = altitude->getDoubleValue();
460     } else {
461         alt = 0.0;
462     }
463
464     double sea_level_radius_meters, lat_geoc;
465
466     SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::set_Latitude: " << lat );
467     SG_LOG(SG_FLIGHT,SG_INFO," cur alt (ft) =  " << alt );
468
469     sgGeodToGeoc( lat, alt * SG_FEET_TO_METER,
470                   &sea_level_radius_meters, &lat_geoc );
471     _set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET  );
472     fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET  );
473     fgic->SetLatitudeRadIC( lat_geoc );
474     needTrim=true;
475 }
476
477 void FGJSBsim::set_Longitude(double lon) {
478
479     SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::set_Longitude: " << lon );
480
481     fgic->SetLongitudeRadIC( lon );
482     needTrim=true;
483 }
484
485 void FGJSBsim::set_Altitude(double alt) {
486     static const SGPropertyNode *latitude
487         = fgGetNode("/position/latitude-deg");
488
489     double sea_level_radius_meters,lat_geoc;
490
491     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Altitude: " << alt );
492     SG_LOG(SG_FLIGHT,SG_INFO, "  lat (deg) = " << latitude->getDoubleValue() );
493
494     sgGeodToGeoc( latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, alt,
495                   &sea_level_radius_meters, &lat_geoc);
496     _set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET  );
497     fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
498     fgic->SetLatitudeRadIC( lat_geoc );
499     fgic->SetAltitudeFtIC(alt);
500     needTrim=true;
501 }
502
503 void FGJSBsim::set_V_calibrated_kts(double vc) {
504     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_V_calibrated_kts: " <<  vc );
505
506     fgic->SetVcalibratedKtsIC(vc);
507     needTrim=true;
508 }
509
510 void FGJSBsim::set_Mach_number(double mach) {
511     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Mach_number: " <<  mach );
512
513     fgic->SetMachIC(mach);
514     needTrim=true;
515 }
516
517 void FGJSBsim::set_Velocities_Local( double north, double east, double down ){
518     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Velocities_Local: "
519        << north << ", " <<  east << ", " << down );
520
521     fgic->SetVnorthFpsIC(north);
522     fgic->SetVeastFpsIC(east);
523     fgic->SetVdownFpsIC(down);
524     needTrim=true;
525 }
526
527 void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w){
528     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Velocities_Wind_Body: "
529        << u << ", " <<  v << ", " <<  w );
530
531     fgic->SetUBodyFpsIC(u);
532     fgic->SetVBodyFpsIC(v);
533     fgic->SetWBodyFpsIC(w);
534     needTrim=true;
535 }
536
537 //Euler angles
538 void FGJSBsim::set_Euler_Angles( double phi, double theta, double psi ) {
539     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Euler_Angles: "
540        << phi << ", " << theta << ", " << psi );
541
542     fgic->SetPitchAngleRadIC(theta);
543     fgic->SetRollAngleRadIC(phi);
544     fgic->SetTrueHeadingRadIC(psi);
545     needTrim=true;
546 }
547
548 //Flight Path
549 void FGJSBsim::set_Climb_Rate( double roc) {
550     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Climb_Rate: " << roc );
551
552     fgic->SetClimbRateFpsIC(roc);
553     needTrim=true;
554 }
555
556 void FGJSBsim::set_Gamma_vert_rad( double gamma) {
557     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Gamma_vert_rad: " << gamma );
558
559     fgic->SetFlightPathAngleRadIC(gamma);
560     needTrim=true;
561 }
562
563 //Earth
564 void FGJSBsim::set_Sea_level_radius(double slr) {
565     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Sea_level_radius: " << slr );
566
567     fgic->SetSeaLevelRadiusFtIC(slr);
568     needTrim=true;
569 }
570
571 void FGJSBsim::set_Runway_altitude(double ralt) {
572     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Runway_altitude: " << ralt );
573
574     _set_Runway_altitude( ralt );
575     fgic->SetTerrainAltitudeFtIC( ralt );
576     needTrim=true;
577 }
578
579 void FGJSBsim::set_Static_pressure(double p) {
580     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Static_pressure: " << p );
581
582     Atmosphere->SetExPressure(p);
583     if(Atmosphere->External() == true)
584     needTrim=true;
585 }
586
587 void FGJSBsim::set_Static_temperature(double T) {
588     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Static_temperature: " << T );
589     
590     Atmosphere->SetExTemperature(T);
591     if(Atmosphere->External() == true)
592     needTrim=true;
593 }
594  
595
596 void FGJSBsim::set_Density(double rho) {
597     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Density: " << rho );
598     
599     Atmosphere->SetExDensity(rho);
600     if(Atmosphere->External() == true)
601     needTrim=true;
602 }
603   
604
605 void FGJSBsim::set_Velocities_Local_Airmass (double wnorth, 
606                          double weast, 
607                          double wdown ) {
608     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Velocities_Local_Airmass: " 
609        << wnorth << ", " << weast << ", " << wdown );
610     
611     _set_Velocities_Local_Airmass( wnorth, weast, wdown );
612     Atmosphere->SetWindNED(wnorth, weast, wdown );
613     if(Atmosphere->External() == true)
614         needTrim=true;
615 }     
616
617
618 //Positions
619 void FGJSBsim::update_Latitude(double lat) {
620     double sea_level_radius_meters, lat_geoc;
621
622     SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::update_Latitude: " << lat );
623     SG_LOG(SG_FLIGHT,SG_INFO," cur alt =  " << get_Altitude() );
624
625     snap_shot();
626     sgGeodToGeoc( lat, get_Altitude(), &sea_level_radius_meters, &lat_geoc);
627     _set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET  );
628     fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET  );
629     fgic->SetLatitudeRadIC( lat_geoc );
630     fdmex->RunIC(fgic); //loop JSBSim once
631     copy_from_JSBsim(); //update the bus
632     needTrim=true;
633 }
634
635 void FGJSBsim::update_Longitude(double lon) {
636
637     SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::update_Longitude: " << lon );
638     SG_LOG(SG_FLIGHT,SG_INFO," cur alt =  " << get_Altitude() );
639
640     snap_shot();
641     fgic->SetLongitudeRadIC(lon);
642     fdmex->RunIC(fgic); //loop JSBSim once
643     copy_from_JSBsim(); //update the bus
644     needTrim=true;
645 }
646
647 void FGJSBsim::update_Altitude(double alt) {
648     double sea_level_radius_meters,lat_geoc;
649
650     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Altitude: " << alt );
651
652     snap_shot();
653     sgGeodToGeoc( get_Latitude(), alt , &sea_level_radius_meters, &lat_geoc);
654     _set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET  );
655     fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
656     fgic->SetLatitudeRadIC( lat_geoc );
657     fgic->SetAltitudeFtIC(alt);
658     fdmex->RunIC(fgic); //loop JSBSim once
659     copy_from_JSBsim(); //update the bus
660     needTrim=true;
661 }
662
663 void FGJSBsim::update_V_calibrated_kts(double vc) {
664     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_V_calibrated_kts: " <<  vc );
665
666     snap_shot();
667     fgic->SetVcalibratedKtsIC(vc);
668     fdmex->RunIC(fgic); //loop JSBSim once
669     copy_from_JSBsim(); //update the bus
670     needTrim=true;
671 }
672
673 void FGJSBsim::update_Mach_number(double mach) {
674     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Mach_number: " <<  mach );
675
676     snap_shot();
677     fgic->SetMachIC(mach);
678     fdmex->RunIC(fgic); //loop JSBSim once
679     copy_from_JSBsim(); //update the bus
680     needTrim=true;
681 }
682
683 void FGJSBsim::update_Velocities_Local( double north, double east, double down ){
684     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Velocities_Local: "
685        << north << ", " <<  east << ", " << down );
686
687     snap_shot();
688     fgic->SetVnorthFpsIC(north);
689     fgic->SetVeastFpsIC(east);
690     fgic->SetVdownFpsIC(down);
691     fdmex->RunIC(fgic); //loop JSBSim once
692     copy_from_JSBsim(); //update the bus
693     needTrim=true;
694 }
695
696 void FGJSBsim::update_Velocities_Wind_Body( double u, double v, double w){
697     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Velocities_Wind_Body: "
698        << u << ", " <<  v << ", " <<  w );
699
700     snap_shot();
701     fgic->SetUBodyFpsIC(u);
702     fgic->SetVBodyFpsIC(v);
703     fgic->SetWBodyFpsIC(w);
704     fdmex->RunIC(fgic); //loop JSBSim once
705     copy_from_JSBsim(); //update the bus
706     needTrim=true;
707 }
708
709 //Euler angles
710 void FGJSBsim::update_Euler_Angles( double phi, double theta, double psi ) {
711     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Euler_Angles: "
712        << phi << ", " << theta << ", " << psi );
713
714     snap_shot();
715     fgic->SetPitchAngleRadIC(theta);
716     fgic->SetRollAngleRadIC(phi);
717     fgic->SetTrueHeadingRadIC(psi);
718     fdmex->RunIC(fgic); //loop JSBSim once
719     copy_from_JSBsim(); //update the bus
720     needTrim=true;
721 }
722
723 //Flight Path
724 void FGJSBsim::update_Climb_Rate( double roc) {
725     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Climb_Rate: " << roc );
726
727     snap_shot();
728     fgic->SetClimbRateFpsIC(roc);
729     fdmex->RunIC(fgic); //loop JSBSim once
730     copy_from_JSBsim(); //update the bus
731     needTrim=true;
732 }
733
734 void FGJSBsim::update_Gamma_vert_rad( double gamma) {
735     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Gamma_vert_rad: " << gamma );
736
737     snap_shot();
738     fgic->SetFlightPathAngleRadIC(gamma);
739     fdmex->RunIC(fgic); //loop JSBSim once
740     copy_from_JSBsim(); //update the bus
741     needTrim=true;
742 }
743
744 //Earth
745 void FGJSBsim::update_Sea_level_radius(double slr) {
746     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Sea_level_radius: " << slr );
747
748     snap_shot();
749     fgic->SetSeaLevelRadiusFtIC(slr);
750     fdmex->RunIC(fgic); //loop JSBSim once
751     copy_from_JSBsim(); //update the bus
752     needTrim=true;
753 }
754
755 void FGJSBsim::update_Runway_altitude(double ralt) {
756     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Runway_altitude: " << ralt );
757
758     snap_shot();
759     _set_Runway_altitude( ralt );
760     fgic->SetTerrainAltitudeFtIC( ralt );
761     fdmex->RunIC(fgic); //loop JSBSim once
762     copy_from_JSBsim(); //update the bus
763     needTrim=true;
764 }
765
766 void FGJSBsim::update_Static_pressure(double p) {
767     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Static_pressure: " << p );
768
769     snap_shot();
770     Atmosphere->SetExPressure(p);
771     if(Atmosphere->External() == true)
772     needTrim=true;
773 }
774
775 void FGJSBsim::update_Static_temperature(double T) {
776     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Static_temperature: " << T );
777     
778     snap_shot();
779     Atmosphere->SetExTemperature(T);
780     if(Atmosphere->External() == true)
781     needTrim=true;
782 }
783  
784
785 void FGJSBsim::update_Density(double rho) {
786     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Density: " << rho );
787     
788     snap_shot();
789     Atmosphere->SetExDensity(rho);
790     if(Atmosphere->External() == true)
791     needTrim=true;
792 }
793   
794
795 void FGJSBsim::update_Velocities_Local_Airmass (double wnorth, 
796                          double weast, 
797                          double wdown ) {
798     SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::update_Velocities_Local_Airmass: " 
799        << wnorth << ", " << weast << ", " << wdown );
800     
801     _set_Velocities_Local_Airmass( wnorth, weast, wdown );
802     snap_shot();
803     Atmosphere->SetWindNED(wnorth, weast, wdown );
804     if(Atmosphere->External() == true)
805         needTrim=true;
806 }     
807