]> git.mxchange.org Git - flightgear.git/blob - src/FDM/LaRCsimIC.cxx
69af5ecdd031c35e749c86d06d4c7db497d8e630
[flightgear.git] / src / FDM / LaRCsimIC.cxx
1 /*******************************************************************************
2  
3  Header:       LaRCsimIC.cxx
4  Author:       Tony Peden
5  Date started: 10/9/99
6  
7  ------------- Copyright (C) 1999  Anthony K. Peden (apeden@earthlink.net) -------------
8  
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
12  version.
13  
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
17  details.
18  
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.
22  
23  Further information about the GNU General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 */ 
26  
27
28 #include <simgear/compiler.h>
29
30 #include <math.h>
31 #include <iostream>
32
33 #include "FDM/LaRCsimIC.hxx"
34 #include <FDM/LaRCsim/ls_cockpit.h>
35 #include <FDM/LaRCsim/ls_generic.h>
36 #include <FDM/LaRCsim/ls_interface.h>
37 #include <FDM/LaRCsim/atmos_62.h>
38 #include <FDM/LaRCsim/ls_constants.h>
39 #include <FDM/LaRCsim/ls_geodesy.h>
40
41 SG_USING_STD(cout);
42 SG_USING_STD(endl);
43
44
45 LaRCsimIC::LaRCsimIC(void) {
46   vt=vtg=vw=vc=ve=0;
47   mach=0;
48   alpha=beta=gamma=0;
49   theta=phi=psi=0;
50   altitude=runway_altitude=hdot=alt_agl=0;
51   latitude_gd=latitude_gc=longitude=0;
52   u=v=w=0;  
53   vnorth=veast=vdown=0;
54   vnorthwind=veastwind=vdownwind=0;
55   lastSpeedSet=lssetvt;
56   lastAltSet=lssetasl;
57   get_atmosphere();
58   ls_geod_to_geoc( latitude_gd,altitude,&sea_level_radius,&latitude_gc); 
59   
60 }
61
62
63 LaRCsimIC::~LaRCsimIC(void) {}
64
65 void LaRCsimIC::get_atmosphere(void) {
66   Altitude=altitude; //set LaRCsim variable
67   ls_atmos(Altitude, &density_ratio, &soundspeed, &T, &p);
68   rho=density_ratio*SEA_LEVEL_DENSITY;
69 }  
70
71 void LaRCsimIC::SetVcalibratedKtsIC( SCALAR tt) {
72     vc=tt*KTS_TO_FPS;
73     lastSpeedSet=lssetvc;
74     vt=sqrt(1/density_ratio*vc*vc);
75 }
76
77 void LaRCsimIC::SetVtrueFpsIC( SCALAR tt) {
78   vt=tt;
79   lastSpeedSet=lssetvt;
80 }
81
82 void LaRCsimIC::SetMachIC( SCALAR tt) {
83   mach=tt;
84   vt=mach*soundspeed;
85   lastSpeedSet=lssetmach;
86 }
87
88 void LaRCsimIC::SetVequivalentKtsIC(SCALAR tt) {
89   ve=tt*KTS_TO_FPS;
90   lastSpeedSet=lssetve;
91   vt=sqrt(SEA_LEVEL_DENSITY/rho)*ve;
92 }  
93
94 void LaRCsimIC::SetClimbRateFpmIC( SCALAR tt) {
95   SetClimbRateFpsIC(tt/60.0);
96 }
97
98 void LaRCsimIC::SetClimbRateFpsIC( SCALAR tt) {
99   vtg=vt+vw;
100   cout << "vtg: " << vtg << endl;
101   if(vtg > 0.1) {
102     hdot = tt - vdownwind;
103     gamma=asin(hdot/vtg);
104     getTheta();
105     vdown=-1*hdot;
106     cout << "hdot: " << hdot << endl;
107     cout << "gamma: " << gamma*RAD_TO_DEG << endl;
108     cout << "vdown: " << vdown << endl;
109   }
110 }
111
112 void LaRCsimIC::SetFlightPathAngleRadIC( SCALAR tt) {
113   gamma=tt;
114   getTheta();
115   vtg=vt+vw;
116   hdot=vtg*sin(tt);
117   cout << "hdot: " << hdot << endl;
118   vdown=-1*hdot;
119 }
120
121 void LaRCsimIC::SetPitchAngleRadIC(SCALAR tt) { 
122   if(alt_agl < (DEFAULT_AGL_ALT + 0.1) || vt < 10 ) 
123     theta=DEFAULT_PITCH_ON_GROUND; 
124   else
125     theta=tt;  
126   getAlpha();
127 }
128
129 void LaRCsimIC::SetUVWFpsIC(SCALAR vu, SCALAR vv, SCALAR vw) {
130   u=vu; v=vv; w=vw;
131   vt=sqrt(u*u+v*v+w*w);
132   lastSpeedSet=lssetuvw;
133 }
134
135   
136 void LaRCsimIC::SetVNEDAirmassFpsIC(SCALAR north, SCALAR east, SCALAR down ) {
137   vnorthwind=north; veastwind=east; vdownwind=down;
138   vw=sqrt(vnorthwind*vnorthwind + veastwind*veastwind + vdownwind*vdownwind);
139   vtg=vt+vw;
140   SetClimbRateFpsIC(-1*(vdown+vdownwind));
141 }  
142
143 void LaRCsimIC::SetAltitudeFtIC( SCALAR tt) {
144   if(tt > (runway_altitude + DEFAULT_AGL_ALT)) {
145     altitude=tt;
146   } else {
147     altitude=runway_altitude + DEFAULT_AGL_ALT;
148     alt_agl=DEFAULT_AGL_ALT;
149     theta=DEFAULT_PITCH_ON_GROUND; 
150   }  
151   lastAltSet=lssetasl;
152   get_atmosphere();
153   //lets try to make sure the user gets what they intended
154
155   switch(lastSpeedSet) {
156   case lssetned:
157     calcVtfromNED();
158     break;  
159   case lssetuvw:
160   case lssetvt:
161     SetVtrueFpsIC(vt);
162     break;
163   case lssetvc:
164     SetVcalibratedKtsIC(vc*V_TO_KNOTS);
165     break;
166   case lssetve:
167     SetVequivalentKtsIC(ve*V_TO_KNOTS);
168     break;
169   case lssetmach:
170     SetMachIC(mach);
171     break;
172   }
173 }
174
175 void LaRCsimIC::SetAltitudeAGLFtIC( SCALAR tt) {
176   alt_agl=tt;
177   lastAltSet=lssetagl;
178   altitude=runway_altitude + alt_agl;
179 }
180
181 void LaRCsimIC::SetRunwayAltitudeFtIC( SCALAR tt) {
182   runway_altitude=tt;
183   if(lastAltSet == lssetagl) 
184       altitude = runway_altitude + alt_agl;
185 }  
186         
187 void LaRCsimIC::calcVtfromNED(void) {
188   //take the earth's rotation out of veast first
189   //float veastner = veast- OMEGA_EARTH*sea_level_radius*cos( latitude_gd );
190   float veastner=veast;
191   u = (vnorth - vnorthwind)*cos(theta)*cos(psi) + 
192       (veastner - veastwind)*cos(theta)*sin(psi) - 
193       (vdown - vdownwind)*sin(theta);
194   v = (vnorth - vnorthwind)*(sin(phi)*sin(theta)*cos(psi) - cos(phi)*sin(psi)) +
195       (veastner - veastwind)*(sin(phi)*sin(theta)*sin(psi) + cos(phi)*cos(psi)) +
196       (vdown - vdownwind)*sin(phi)*cos(theta);
197   w = (vnorth - vnorthwind)*(cos(phi)*sin(theta)*cos(psi) + sin(phi)*sin(psi)) +
198       (veastner - veastwind)*(cos(phi)*sin(theta)*sin(psi) - sin(phi)*cos(psi)) +
199       (vdown - vdownwind)*cos(phi)*cos(theta);
200   vt = sqrt(u*u + v*v + w*w);
201
202
203 void LaRCsimIC::calcNEDfromVt(void) {
204   float veastner;
205   
206   //get the body components of vt
207   u = GetUBodyFpsIC();
208   v = GetVBodyFpsIC();   
209   w = GetWBodyFpsIC();
210   
211   //transform them to local axes and add on the wind components
212   vnorth = u*cos(theta)*cos(psi) +
213            v*(sin(phi)*sin(theta)*cos(psi) - cos(phi)*sin(psi)) +
214            w*(cos(phi)*sin(theta)*cos(psi) + sin(phi)*sin(psi)) +
215            vnorthwind;
216   
217   //need to account for the earth's rotation here
218   veastner = u*cos(theta)*sin(psi) +
219              v*(sin(phi)*sin(theta)*sin(psi) + cos(phi)*cos(psi)) +
220              w*(cos(phi)*sin(theta)*sin(psi) - sin(phi)*cos(psi)) +
221              veastwind;
222   veast = veastner;
223   //veast = veastner + OMEGA_EARTH*sea_level_radius*cos( latitude_gd );  
224   
225   vdown =  u*sin(theta) +
226            v*sin(phi)*cos(theta) +
227            w*cos(phi)*cos(theta) +
228            vdownwind;
229 }           
230
231 void LaRCsimIC::SetVNEDFpsIC( SCALAR north, SCALAR east, SCALAR down) {
232   vnorth=north;
233   veast=east;
234   vdown=down;
235   SetClimbRateFpsIC(-1*vdown);
236   lastSpeedSet=lssetned;
237   calcVtfromNED();
238 }        
239   
240 void LaRCsimIC::SetLatitudeGDRadIC(SCALAR tt) {
241   latitude_gd=tt;
242   ls_geod_to_geoc(latitude_gd,altitude,&sea_level_radius, &latitude_gc);
243 }
244   
245 bool LaRCsimIC::getAlpha(void) {
246   bool result=false;
247   float guess=theta-gamma;
248   xlo=xhi=0;
249   xmin=-89;
250   xmax=89;
251   sfunc=&LaRCsimIC::GammaEqOfAlpha;
252   if(findInterval(0,guess)){
253     if(solve(&alpha,0)){
254       result=true;
255     }
256   }
257   return result;
258 }      
259
260       
261 bool LaRCsimIC::getTheta(void) {
262   bool result=false;
263   float guess=alpha+gamma;
264   xlo=xhi=0;
265   xmin=-89;xmax=89;
266   sfunc=&LaRCsimIC::GammaEqOfTheta;
267   if(findInterval(0,guess)){
268     if(solve(&theta,0)){
269       result=true;
270     }
271   }
272   return result;
273 }      
274   
275
276
277 SCALAR LaRCsimIC::GammaEqOfTheta( SCALAR theta_arg) {
278   SCALAR a,b,c;
279   
280   a=cos(alpha)*cos(beta)*sin(theta_arg);
281   b=sin(beta)*sin(phi);
282   c=sin(alpha)*cos(beta)*cos(phi);
283   return sin(gamma)-a+(b+c)*cos(theta_arg);
284 }
285
286 SCALAR LaRCsimIC::GammaEqOfAlpha( SCALAR alpha_arg) {
287   float a,b,c;
288   
289   a=cos(alpha_arg)*cos(beta)*sin(theta);
290   b=sin(beta)*sin(phi);
291   c=sin(alpha_arg)*cos(beta)*cos(phi);
292   return sin(gamma)-a+(b+c)*cos(theta);
293 }
294
295   
296
297
298
299
300 bool LaRCsimIC::findInterval( SCALAR x,SCALAR guess) {
301   //void find_interval(inter_params &ip,eqfunc f,float y,float constant, int &flag){
302
303   int i=0;
304   bool found=false;
305   float flo,fhi,fguess;
306   float lo,hi,step;
307   step=0.1;
308   fguess=(this->*sfunc)(guess)-x;
309   lo=hi=guess;
310   do {
311     step=2*step;
312     lo-=step;
313     hi+=step;
314     if(lo < xmin) lo=xmin;
315     if(hi > xmax) hi=xmax;
316     i++;
317     flo=(this->*sfunc)(lo)-x;
318     fhi=(this->*sfunc)(hi)-x;
319     if(flo*fhi <=0) {  //found interval with root
320       found=true;
321       if(flo*fguess <= 0) {  //narrow interval down a bit
322         hi=lo+step;    //to pass solver interval that is as
323         //small as possible
324       }
325       else if(fhi*fguess <= 0) {
326         lo=hi-step;
327       }
328     }
329     //cout << "findInterval: i=" << i << " Lo= " << lo << " Hi= " << hi << endl;
330   }
331   while((found == 0) && (i <= 100));
332   xlo=lo;
333   xhi=hi;
334   return found;
335 }
336
337
338
339
340 bool LaRCsimIC::solve( SCALAR *y,SCALAR x) {  
341   float x1,x2,x3,f1,f2,f3,d,d0;
342   float eps=1E-5;
343   float const relax =0.9;
344   int i;
345   bool success=false;
346   
347    //initializations
348   d=1;
349   
350     x1=xlo;x3=xhi;
351     f1=(this->*sfunc)(x1)-x;
352     f3=(this->*sfunc)(x3)-x;
353     d0=fabs(x3-x1);
354   
355     //iterations
356     i=0;
357     while ((fabs(d) > eps) && (i < 100)) {
358       d=(x3-x1)/d0;
359       x2=x1-d*d0*f1/(f3-f1);
360       
361       f2=(this->*sfunc)(x2)-x;
362       //cout << "solve x1,x2,x3: " << x1 << "," << x2 << "," << x3 << endl;
363       //cout << "                " << f1 << "," << f2 << "," << f3 << endl;
364
365       if(fabs(f2) <= 0.001) {
366         x1=x3=x2;
367       } else if(f1*f2 <= 0.0) {
368         x3=x2;
369         f3=f2;
370         f1=relax*f1;
371       } else if(f2*f3 <= 0) {
372         x1=x2;
373         f1=f2;
374         f3=relax*f3;
375       }
376       //cout << i << endl;
377       i++;
378     }//end while
379     if(i < 100) {
380       success=true;
381       *y=x2;
382     }
383
384   //cout << "Success= " << success << " Vcas: " << vcas*V_TO_KNOTS << " Mach: " << x2 << endl;
385   return success;
386 }