def AnalyticalFindTP(s, h, v1, v2): """ Finds solution for the given parameters, solving the rearranged EOM analytically. Returns T and pitch needed """ # find the flight path angle gamma = math.degrees(math.atan2(v2, v1)) # find the total velocity V = math.sqrt(v1**2 + v2**2) # if v1 is above the zero-pitch flight velocity this should be negative if ZeroPitchCruiseV(s, 0) < v2: initialGuess = -1 else: initialGuess = 1 f = lambda p: 0.5 * Density(h) * AC['S'] * V ** 2 *\ ( GetCl(p-gamma) * (dsin(gamma)/dcos(p) + dcos(gamma)/dsin(p)) +\ GetCd(p-gamma, h) * (dcos(gamma)/dcos(p) - dsin(gamma)/dsin(p)) )\ - s.totalMass * AC['g'] / dsin(p) pitch = fsolve(f, initialGuess) # fsolve fails sometimes, can't figure out why. Initial guess changing doesnt seem to work if abs(f(pitch)) > 0.1: pitch = fsolve(f, -initialGuess) if abs(f(pitch)) > 0.1: print( 'AnalyticalFindTP() could not find the zero on the second attempt.', pitch, v1, v2, f(pitch)) raise ValueError('fsolve failed \n') T = 0.5 * Density(h) * AC['S'] * V ** 2 / dcos(pitch) * \ (GetCl(pitch-gamma) * dsin(gamma) + GetCd(pitch-gamma, h) * dcos(gamma)) T2 = 0.5 * Density(h) * AC['S'] * V ** 2 / dsin(pitch) *\ (GetCd(pitch-gamma, h) * dsin(gamma) - GetCl(pitch-gamma) * dcos(gamma)) + \ s.totalMass * AC['g'] / dsin(pitch) if abs(T - T2) > 1e-5: print('Error calculating T in AnalyticalFindTP()') print(T, T2, pitch, v1, v2) return T, pitch
def GetCoeffB(alpha, gamma, h): """ Returns a coefficient for the (vertical) equations of motion.Written out here to keep the EOMs shorter and neater. Should only be called the function which implements the EOMs for scipy.integrate.ode(int). Parameters ---------- alpha : int or float Angle of attack. gamma : int or float Flight path angle. h : int or float Altitude. Raises ------ ValueError When args of wrong type are passed Returns ------- float Value of the coefficient. """ return (0.5 * Density(h) * AC['S'] * (GetCl(alpha) * dcos(gamma) - GetCd(alpha, h) * dsin(gamma)))
def LevelFlight(s, h, vReq): """Equations of motion for alpha = pitch, v1 = vReq and v2 = 0 = a2 = a1 = 0 to return the correct pitch and thrust to obtain the required cruise velocity Parameters ---------- s : simulate OBJECT h : int or float Altitude. vReq : int or float Required cruise velocity. Returns ------- T : float Needed thrust signal. pitch : float Needed pitch signal. """ # Determine on which side of the discontinuity to start the numerical root finder levelFlightV = ZeroPitchCruiseV(s) if levelFlightV > vReq: initialGuess = 0.1 else: initialGuess = -0.1 W = s.totalMass * AC['g'] pitch = fsolve(lambda p: -0.5 * Density(h) * AC['S'] * vReq ** 2 * \ (GetCl(p) + dtan(p) * GetCd(p, h)) + W, initialGuess) T = 0.5 * Density(h) * AC['S'] * vReq**2 * GetCd(pitch, h) / dcos(pitch) return T, pitch