1 /*******************************************************************************
3 Header: FGInitialCondition.cpp
7 ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA.
23 Further information about the GNU General Public License can also be found on
24 the world wide web at http://www.gnu.org.
28 --------------------------------------------------------------------------------
32 FUNCTIONAL DESCRIPTION
33 --------------------------------------------------------------------------------
35 The purpose of this class is to take a set of initial conditions and provide
36 a kinematically consistent set of body axis velocity components, euler
37 angles, and altitude. This class does not attempt to trim the model i.e.
38 the sim will most likely start in a very dynamic state (unless, of course,
39 you have chosen your IC's wisely) even after setting it up with this class.
41 ********************************************************************************
43 *******************************************************************************/
45 #include "FGInitialCondition.h"
46 #include "FGFDMExec.h"
48 #include "FGAtmosphere.h"
50 #include "FGAircraft.h"
51 #include "FGTranslation.h"
52 #include "FGRotation.h"
53 #include "FGPosition.h"
54 #include "FGAuxiliary.h"
58 static const char *IdSrc = "$Header$";
59 static const char *IdHdr = ID_INITIALCONDITION;
61 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) {
71 if(FDMExec != NULL ) {
73 fdmex->GetPosition()->Seth(altitude);
74 fdmex->GetAtmosphere()->Run();
76 cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
82 FGInitialCondition::~FGInitialCondition(void) {}
85 void FGInitialCondition::SetVcalibratedKtsIC(float tt) {
87 if(getMachFromVcas(&mach,tt*KTSTOFPS)) {
88 //cout << "Mach: " << mach << endl;
91 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
92 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
93 //cout << "Vt: " << vt*FPSTOKTS << " Vc: " << vc*FPSTOKTS << endl;
96 cout << "Failed to get Mach number for given Vc and altitude, Vc unchanged." << endl;
97 cout << "Please mail the set of initial conditions used to apeden@earthlink.net" << endl;
101 void FGInitialCondition::SetVequivalentKtsIC(float tt) {
104 vt=ve*1/sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
105 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
109 void FGInitialCondition::SetVtrueKtsIC(float tt) {
112 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
114 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
117 void FGInitialCondition::SetMachIC(float tt) {
119 lastSpeedSet=setmach;
120 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
122 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
123 //cout << "Vt: " << vt*FPSTOKTS << " Vc: " << vc*FPSTOKTS << endl;
126 void FGInitialCondition::SetClimbRateFpmIC(float tt) {
127 SetClimbRateFpsIC(tt/60.0);
130 void FGInitialCondition::SetClimbRateFpsIC(float tt) {
138 void FGInitialCondition::SetFlightPathAngleRadIC(float tt) {
145 void FGInitialCondition::SetUBodyFpsIC(float tt) {
147 vt=sqrt(u*u+v*v+w*w);
152 void FGInitialCondition::SetVBodyFpsIC(float tt) {
154 vt=sqrt(u*u+v*v+w*w);
158 void FGInitialCondition::SetWBodyFpsIC(float tt) {
160 vt=sqrt(u*u+v*v+w*w);
165 void FGInitialCondition::SetAltitudeFtIC(float tt) {
167 fdmex->GetPosition()->Seth(altitude);
168 fdmex->GetAtmosphere()->Run();
170 //lets try to make sure the user gets what they intended
172 switch(lastSpeedSet) {
174 SetVtrueKtsIC(vt*FPSTOKTS);
177 SetVcalibratedKtsIC(vc*FPSTOKTS);
180 SetVequivalentKtsIC(ve*FPSTOKTS);
188 void FGInitialCondition::SetAltitudeAGLFtIC(float tt) {
189 fdmex->GetPosition()->SetDistanceAGL(tt);
190 altitude=fdmex->GetPosition()->Geth();
191 SetAltitudeFtIC(altitude);
194 void FGInitialCondition::calcUVWfromNED(void) {
195 u=vnorth*cos(theta)*cos(psi) +
196 veast*cos(theta)*sin(psi) -
198 v=vnorth*(sin(phi)*sin(theta)*cos(psi) - cos(phi)*sin(psi)) +
199 veast*(sin(phi)*sin(theta)*sin(psi) + cos(phi)*cos(psi)) +
200 vdown*sin(phi)*cos(theta);
201 w=vnorth*(cos(phi)*sin(theta)*cos(psi) + sin(phi)*sin(psi)) +
202 veast*(cos(phi)*sin(theta)*sin(psi) - sin(phi)*cos(psi)) +
203 vdown*cos(phi)*cos(theta);
206 void FGInitialCondition::SetVnorthFpsIC(float tt) {
209 vt=sqrt(u*u + v*v + w*w);
213 void FGInitialCondition::SetVeastFpsIC(float tt) {
216 vt=sqrt(u*u + v*v + w*w);
220 void FGInitialCondition::SetVdownFpsIC(float tt) {
223 vt=sqrt(u*u + v*v + w*w);
224 SetClimbRateFpsIC(-1*vdown);
228 bool FGInitialCondition::getMachFromVcas(float *Mach,float vcas) {
234 sfunc=&FGInitialCondition::calcVcas;
235 if(findInterval(vcas,guess)) {
236 if(solve(&mach,vcas))
242 bool FGInitialCondition::getAlpha(void) {
244 float guess=theta-gamma;
246 xmin=fdmex->GetAircraft()->GetAlphaCLMin();
247 xmax=fdmex->GetAircraft()->GetAlphaCLMax();
248 sfunc=&FGInitialCondition::GammaEqOfAlpha;
249 if(findInterval(0,guess)){
257 bool FGInitialCondition::getTheta(void) {
259 float guess=alpha+gamma;
262 sfunc=&FGInitialCondition::GammaEqOfTheta;
263 if(findInterval(0,guess)){
273 float FGInitialCondition::GammaEqOfTheta(float Theta) {
276 a=cos(alpha)*cos(beta)*sin(Theta);
277 b=sin(beta)*sin(phi);
278 c=sin(alpha)*cos(beta)*cos(phi);
279 return sin(gamma)-a+(b+c)*cos(Theta);
282 float FGInitialCondition::GammaEqOfAlpha(float Alpha) {
285 a=cos(Alpha)*cos(beta)*sin(theta);
286 b=sin(beta)*sin(phi);
287 c=sin(Alpha)*cos(beta)*cos(phi);
288 return sin(gamma)-a+(b+c)*cos(theta);
292 float FGInitialCondition::calcVcas(float Mach) {
294 float p=fdmex->GetAtmosphere()->GetPressure();
295 float psl=fdmex->GetAtmosphere()->GetPressureSL();
296 float rhosl=fdmex->GetAtmosphere()->GetDensitySL();
299 if(Mach < 1) //calculate total pressure assuming isentropic flow
300 pt=p*pow((1 + 0.2*Mach*Mach),3.5);
302 // shock in front of pitot tube, we'll assume its normal and use
303 // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
304 // pressure behind the shock to the static pressure in front
307 //the normal shock assumption should not be a bad one -- most supersonic
308 //aircraft place the pitot probe out front so that it is the forward
309 //most point on the aircraft. The real shock would, of course, take
310 //on something like the shape of a rounded-off cone but, here again,
311 //the assumption should be good since the opening of the pitot probe
312 //is very small and, therefore, the effects of the shock curvature
313 //should be small as well. AFAIK, this approach is fairly well accepted
314 //within the aerospace community
316 B = 5.76*Mach*Mach/(5.6*Mach*Mach - 0.8);
318 // The denominator above is zero for Mach ~ 0.38, for which
319 // we'll never be here, so we're safe
321 D = (2.8*Mach*Mach-0.4)*0.4167;
325 A = pow(((pt-p)/psl+1),0.28571);
326 vcas = sqrt(7*psl/rhosl*(A-1));
327 //cout << "calcVcas: vcas= " << vcas*FPSTOKTS << " mach= " << Mach << " pressure: " << pt << endl;
331 bool FGInitialCondition::findInterval(float x,float guess) {
332 //void find_interval(inter_params &ip,eqfunc f,float y,float constant, int &flag){
336 float flo,fhi,fguess;
339 fguess=(this->*sfunc)(guess)-x;
345 if(lo < xmin) lo=xmin;
346 if(hi > xmax) hi=xmax;
348 flo=(this->*sfunc)(lo)-x;
349 fhi=(this->*sfunc)(hi)-x;
350 if(flo*fhi <=0) { //found interval with root
352 if(flo*fguess <= 0) { //narrow interval down a bit
353 hi=lo+step; //to pass solver interval that is as
356 else if(fhi*fguess <= 0) {
360 //cout << "findInterval: i=" << i << " Lo= " << lo << " Hi= " << hi << endl;
362 while((found == 0) && (i <= 100));
371 bool FGInitialCondition::solve(float *y,float x) {
372 float x1,x2,x3,f1,f2,f3,d,d0;
374 float const relax =0.9;
382 f1=(this->*sfunc)(x1)-x;
383 f3=(this->*sfunc)(x3)-x;
388 while ((fabs(d) > eps) && (i < 100)) {
390 x2=x1-d*d0*f1/(f3-f1);
392 f2=(this->*sfunc)(x2)-x;
393 //cout << "solve x1,x2,x3: " << x1 << "," << x2 << "," << x3 << endl;
394 //cout << " " << f1 << "," << f2 << "," << f3 << endl;
396 if(fabs(f2) <= 0.001) {
398 } else if(f1*f2 <= 0.0) {
402 } else if(f2*f3 <= 0) {
415 //cout << "Success= " << success << " Vcas: " << vcas*FPSTOKTS << " Mach: " << x2 << endl;