def example1(): # run trim analysis import aircraft ac = aircraft.load('V0510') fc = flightConditions() CG = numpy.array([1.7,0,0]) I = numpy.array([500., 1000, 1000]) M = 600. V = 50. density = 1.2255 Cd0 = ac.get_drag(V,0.0) fc.addTrimmedFlightCondition('cruise1',M,CG,I,V,density,CmTrim=0.0,Cd0=Cd0) a3d = aero3d_VLM(ac) rslt = a3d.runVLM(fc,False) print 'GENERAL' rslt.results[0].display() print 'PHUGOID' rslt.results[0].dynamicStability.phugoid.display() print 'SHORT PERIOD' rslt.results[0].dynamicStability.shortPeriod.display() print 'DUTCH ROLL' rslt.results[0].dynamicStability.dutchRoll.display() print 'SPIRAL' rslt.results[0].dynamicStability.spiral.display() print 'ROLL' rslt.results[0].dynamicStability.roll.display()
def calc_hinges(): import aircraft ac = aircraft.load('V0510') fc = flightConditions() CG = [1.824,0.0,-0.125] I = ac.get_inertia() m = 620.0 V = 75.0 rho = 1.2255 CD0 = ac.get_drag(V,0.0) n = 1.0 fc.add_flight_condition('hinge',m,CG,I,V,rho,n,CD0,alpha=20.0,elevator=30.0) aero3d = aero3d_VLM(ac) rslt = aero3d.runVLM(fc) rslt.results[0].hingeMoments.display()
def run_test(): import aircraft ac = aircraft.load('V0510') fc = flightConditions() CG = ac.get_CG(False) I = ac.get_inertia(False) M = ac.get_mass_total(False) V = 1.0 rho = 1.2255 Cd0 = ac.get_drag(V,0.0) fc.addTrimmedFlightCondition('trim',M, CG, I, V, rho) fc.flightConditionList[0].setRudder(0.) aero3D = aero3d_VLM(ac) rslt = aero3D.runVLM(fc) rslt.results[0].display()
def add_flight_condition(self,name,mass,CG,inertia,velocity,density, loadFactor=1.0,CD0=0.0,alpha=0.0,beta=0.0,flap=0.0 ,elevator=0.0,aileron=0.0,rudder=0.0): """ Non trimmed flight conditions """ newFC =self._flightCondition() newFC.pitchTrim =False newFC.CG =CG newFC.name =name newFC.mass =float(mass) newFC.inertia =inertia newFC.velocity =float(velocity) newFC.density =float(density) newFC.densityAltitude =fc.get_density_altitude(newFC.density) atm =fc.ISAtmosphere(newFC.densityAltitude,0.0) newFC.soundSpeed =atm.soundSpeed newFC.pressure =atm.pressure newFC.temperature =atm.temperature newFC.Mach =newFC.velocity/newFC.soundSpeed newFC.loadFactor =loadFactor newFC.Cd0 =CD0 newFC.alpha =alpha newFC.beta =beta newFC.flap =flap newFC.elevator =elevator newFC.aileron =aileron newFC.rudder =rudder self.flightConditionList.append(newFC)
def run_climbRate(self,airspeed,powerSetting): """ Calculates the climb rate at a given airspeed and power setting. Supports descent calculations which will appear as negative climb rates. Does not utilize small angle approximations. """ basicInput = self.bi thrustModule = self.tm V =airspeed rho =basicInput.density Cd0 =basicInput.Cd0 g =basicInput.g k =basicInput.k S =basicInput.refArea W =basicInput.mass*g Q =0.5*rho*V*V tol =1.0e-4 change =tol+1.0 CA =0.0 #climb angle, rad iMax =100 i =0 if powerSetting>=5.0: tm=thrustModule.runAnalysis else: tm=thrustModule._zeroThrustModule while change>tol and i<=iMax: tm(V,rho,powerSetting) T =thrustModule.thrust L =W*np.cos(CA)-T*np.sin(CA) Cl =L/Q/S Cd =Cd0+k*Cl*Cl D =Q*S*Cd PR =D*V PA =T*V RC =(PA-PR)/W ca =CA CA =np.arcsin(RC/V) change=np.abs(ca-CA) i+=1 self.__init__(self.bi, self.tm) self.velocity =V self.equivalentAirspeed=self.EAS(V,basicInput.density) self.densityAltitude =fc.get_density_altitude(basicInput.density) self.density =basicInput.density self.climbRate =RC self.climbAngle =CA self.fuelFlow =thrustModule.fuelFlow self.RPM =thrustModule.RPM self.powerSetting =powerSetting self.thrust =T self.power =PA self.propEfficiency =thrustModule.propEfficiency self.beta =thrustModule.beta self.SAR_km_per_kg =thrustModule.SAR_km_per_kg self.lift =L self.drag =D self.L_D =L/D self.turnRadius =0.0 self.bankAngle =0.0 self.loadFactor =1.0
def addTrimmedFlightCondition(self,name,mass,CG,inertia,velocity,density, loadFactor=1.0,Cd0=0.0,CmTrim=0.0,flapDefl=0.0, aileron=0.0,rudder=0.0): """ Sets and stores a list of flight conditions to be analyzed by the aerodynamics solvers. Parameters ---------- name : string name of the flight condition case mass : float, kg total mass of the aircraft CG : float array, m array of CG coordinates [x,y,z] inertia : float array array of moments of inertia [Ixx, Iyy, Izz] velocity : float, m/sec aircraft TAS density : float, kg/m**3 atmospheric density loadFactor : float load factor for steady pull-out flight conditions Cd0 : float zero lift drag coefficient of aircraft CmTrim : float trim pitch moment coefficient. Set CmTrim=None if non-trimmed flight condition is required flapDefl : float, deg plain flap deflection angle """ newFC =self._flightCondition() newFC.pitchTrim =True newFC.CG =CG newFC.name =name newFC.mass =float(mass) newFC.inertia =inertia newFC.velocity =float(velocity) newFC.density =float(density) newFC.densityAltitude =fc.get_density_altitude(newFC.density) atm =fc.ISAtmosphere(newFC.densityAltitude,0.0) newFC.soundSpeed =atm.soundSpeed newFC.pressure =atm.pressure newFC.temperature =atm.temperature newFC.Mach =newFC.velocity/newFC.soundSpeed newFC.loadFactor =loadFactor newFC.Cd0 =Cd0 newFC.CmTrim =CmTrim newFC.flap =flapDefl newFC.aileron =aileron newFC.rudder =rudder self.flightConditionList.append(newFC)
def run_test3(): import aircraft import matplotlib.pyplot as plt ac = aircraft.load('V0510') fc = flightConditions() CG = ac.get_CG() I = ac.get_inertia() m = ac.get_mass_total() V = 50.0 rho = 1.2255 CD0 = ac.get_drag(V,0.0) ail = [-10,0,2,5,7,10] ailDisp = list() r = 15 for a in ail: fc.add_flight_condition('untrimmed',m,CG,I,V,rho,CD0=CD0,aileron=a,rudder=r) ailDisp.append(a) aero3d = aero3d_VLM(ac) rslt = aero3d.runVLM(fc) cl = [rslt.results[i].coefficients.Cl for i in range(len(ail))] plt.plot(ailDisp,cl,'ro-') plt.show()
def update_notrim(self,velocity,density,loadFactor=1.0,flap=0.0,aileron=0.0, elevator=0.0,rudder=0.0,alpha=0.0,beta=0.0,mass=None, CG=None,inertia=None): """ Performs aerodynamic analysis at specified flight conditions. Parameters ---------- velocity : float, m/s density : float, kg/m**3 loadFactor : float flap : float,deg flap deflection angle. Note that plain flap is analyzed, slotted flap analysis is not available aileron : +float, deg aileron deflection angle. Deflection is mirrored. elevator : float, deg elevator deflection angle rudder : float, deg rudder deflection angle alpha : float, deg angle of attack. Note that solver may fail on high angles of attack. Use values [-5;5]. beta : float, deg sideslip angle. mass : float, kg if mass is not defined, than it will be obtained from current aircraft configuration CG : float vector, m aircraft center of gravity in format [x,y,z]. If CG is not defined it will be obtained from current aircraft configuration inertia : float vector, kg*m**2 aircraft moment of inertia in format [Ixx,Iyy,Izz]. """ if mass==None: mass = self.aircraft.get_mass_total() if CG==None: CG = self.aircraft.get_CG() if inertia==None: inertia = self.aircraft.get_inertia() altitude = fc.get_density_altitude(density) CD0 = self.aircraft.get_drag(velocity,altitude) flightCond = flightConditions() flightCond.add_flight_condition('untrimmed',mass,CG,inertia,velocity,density, loadFactor,CD0,alpha,beta,flap,elevator, aileron,rudder) vlm = aero3d_VLM(self.aircraft) out = vlm.runVLM(flightCond) return out.results[0]
def getCd0(self,V,rho): """ Executes AeroCD0 skin friction / form factor drag analysis code Returns parasite drag (Cd0) Parameters ---------- V : float, m/sec velocity rho : float, kg/m**3 density """ alt = fc.get_density_altitude(rho) Cd0= self.aircraft.get_drag(V,alt) return Cd0
def _setAttributes(self,velocity): drag=self.requiredThrust(velocity) self.__init__(self.bi, self.tm) self.tm.matchRequiredThrust(velocity,self.bi.density,drag) self.velocity =velocity self.equivalentAirspeed=self.get_EAS(velocity,self.bi.density) self.densityAltitude =fc.get_density_altitude(self.bi.density) self.density =self.bi.density self.fuelFlow =self.tm.fuelFlow self.RPM =self.tm.RPM self.powerSetting =self.tm.powerSetting self.thrust =self.tm.thrust self.power =self.tm.power self.propEfficiency =self.tm.propEfficiency self.beta =self.tm.beta self.SAR_km_per_kg =self.tm.SAR_km_per_kg self.drag =drag self.lift =self.bi.wt self.L_D =self.lift/self.drag
def update(self,velocity,density,loadFactor=1.0,CmTrim=0.0,flapDefl=0.0, mass=None,CG=None,inertia=None,name='default'): """ Updates aerodynamics results in self.results Parameters ---------- velocity : float, m/sec aircraft TAS density : float, kg/m**3 air density loadFactor : float load factor CmTrim : float trim pitch moment coefficient flapDefl : float, deg plain flap deflection """ self.flightConditions =flightConditions() densityAltitude =fc.get_density_altitude(density) if mass==None: mass =self.aircraft.get_mass_total() if CG==None: CG =self.aircraft.get_CG() if inertia==None: inertia =self.aircraft.get_inertia() Cd0 =self.aircraft.get_drag(velocity,densityAltitude) self.flightConditions.addTrimmedFlightCondition(name,mass,CG,inertia,velocity,density,loadFactor,Cd0,CmTrim,flapDefl) vlm =aero3d_VLM(self.aircraft) out =vlm.runVLM(self.flightConditions) self.results =out.results[0] self.results.name = name NP = self.results.xNP self.results.SM = (NP-CG[0])/self.aircraft.wing.MAC self.results.mass = mass self.results.CG = CG self.results.inertia = inertia self.results.velocity = velocity self.results.density = density
def _setAttributes(self,n,airspeed,powerSetting): V =airspeed rho =self.bi.density Cd0 =self.bi.Cd0 g =self.bi.g k =self.bi.k S =self.bi.refArea W =self.bi.mass*g Q =0.5*rho*V**2 self.tm.runAnalysis(V,rho,powerSetting) phi =np.arccos(1./n) turnRadius =V**2/(g*(n**2-1.)**.5) turnRate =g*(n**2-1)**.5/V L =n*W Cl =L/Q/S Cd =Cd0+k*Cl**2 D =Q*S*Cd self.tm.matchRequiredThrust(V,self.bi.density,D) self.__init__(self.bi,self.tm) self.velocity =V self.equivalentAirspeed=self.EAS(V,self.bi.density) self.densityAltitude =fc.get_density_altitude(self.bi.density) self.density =self.bi.density self.fuelFlow =self.tm.fuelFlow self.RPM =self.tm.RPM self.powerSetting =powerSetting self.thrust =self.tm.thrust self.power =self.tm.power self.propEfficiency =self.tm.propEfficiency self.beta =self.tm.beta self.SAR_km_per_kg =self.tm.SAR_km_per_kg self.lift =L self.drag =D self.L_D =L/D self.turnRadius =turnRadius self.bankAngle =phi self.loadFactor =n self.turnRate =turnRate
def analyze_prop(self,betaSet,N,V,rho): """ Performs propeller analysis using BEMT. In case of poor convergence (required J cannot be achieved at given rpm and airspeed) function returns advance ratio and CP=None, CT=None, effy=None. Method returns thrust, power required, propeller advance ratio *J*, thrust coefficient *CT*, power coefficient *CP* and efficiency *effy* at given pitch angle, rpm, velocity and density Parameters ---------- betaSet : float, degree pitch angle setting at 75% of diameter N : float, rpm propeller rotation speed V : float, m/sec true airspeed of aircraft (propeller) rho : float, kg/m^3 air density Returns ------- J : float advance ratio CT : float thrust coefficient CP : float power coefficient effy : float propeller efficiency """ if N*V*rho==0.0: return zeros(6) if betaSet!=None: self.set_beta(betaSet) Jcorr = 0.97 n = N/60.0 d = self.diameter B = self.numBlades dT = list() dQ = list() altitude = FlightConditions.get_density_altitude(rho) soundSpeed = FlightConditions.ISAtmosphere(altitude).soundSpeed Jreq = Jcorr * V / (n*d) def master_func(alpha,beta,x,r,B,soundSpeed,d,af,c,n): phi = radians(beta - alpha) # compute Prandtl loss factor sinPhiL1 = (1.0 + 1.0/(x*tan(phi))**2)**0.5 f = B * (1.0/x-1.0) * sinPhiL1/2.0 F = 2.0 * arccos(exp(-f)) / pi vLocal = pi*x*n*d / cos(phi) mach = vLocal / soundSpeed cl = float(af.polar.clAlpha(mach,alpha)) cd = float(af.polar.cdAlpha(mach,alpha)) sinPhi = sin(phi) cosPhi = cos(phi) lambdaT = cl*cosPhi - cd*sinPhi lambdaP = cl*sinPhi + cd*cosPhi sigma = c*B / (2.0*pi*r) J = pi*x*(4.0*F*sinPhi**2 - lambdaT*sigma) / (4.0*F*sinPhi*cosPhi + lambdaP*sigma) return J,vLocal, lambdaT,lambdaP def get_J(alpha,Jreq,beta,x,r,B,soundSpeed,d,af,c,n): rslt = master_func(alpha,beta,x,r,B,soundSpeed,d,af,c,n) return rslt[0] - Jreq for i in range(self.numStations): x = self.x[i] c = self.chord[i] beta = self.beta[i] r = self.r[i] alpha0List = [-20,-10,-5,0,5,10,20,30,40,50] af = self.airfoil[i] for alpha0 in alpha0List: try: alpha = newton(get_J,alpha0,args=(Jreq,beta,x,r,B,soundSpeed,d,af,c,n),tol=0.01) break except RuntimeError: return 0.0,0.0,Jreq, 0.0, 0.0, 0.0 J,vLocal,lambdaT,lambdaP = master_func(alpha,beta,x,r,B,soundSpeed,d,af,c,n) dT.append( rho*vLocal**2*lambdaT*c*B / 2.0 ) dQ.append( rho*vLocal**2*lambdaP*c*B*r / 2.0 ) dT.insert(0,0.0) dQ.insert(0,0.0) dT.append(0.0) dQ.append(0.0) r_ = copy(self.r) radius = self.diameter/2.0 r_ = hstack([0.0,r_,radius]) T = simps(dT,r_) Q = simps(dQ,r_) CT = T / (rho*n**2*d**4) CQ = Q / (rho*n**2*d**5) effy = CT/CQ*Jreq/(2.0*pi) effy = effy CP = Jreq*CT/effy P = CP*rho*n**3*d**5 if CT<=0.0 or CT>1.0: CT=0.0 effy = 0.0 if CQ<=0.0 or CQ>1.0: CQ=0.0 effy = 0.0 if CP<=0.0: CP=0.0 if not effy==None: effy = effy*0.95 return T,P,Jreq/Jcorr,CT,CP,effy