def m0_fn(Ma): if Ma <= 0.9: return (2 * math.pi) / numpy.sqrt(1 - Ma**2) else: return (2 * math.pi) / numpy.sqrt(1 - 0.9**2) def Cd_fn(Cl): return 0.0095 + 0.0040 * (Cl - 0.2)**2 nn = 101 h = 0 # m v_inf = 70 # m/s is_SI = True atm = AtmData(v_inf, h, is_SI) k = 1.4 R = 287 atm.expand(k, R) numB = 3 radius = 2 / 2 RPM = 2400 Cl = 0.4 alp0 = numpy.radians(-2) prop = Propeller(radius, numB, RPM, CP=0, CT=0, CQ=0, Cl=Cl, alp0=alp0) T_req = 13000 / 8 # N (TOGW/(L/D)) r_vec, c_vec, beta_vec, P_design, T_design, Q_design, eta_P, theta_vec = prop_design( atm, prop, T_req, m0_fn, Cd_fn) in_line = [0] * len(r_vec) plot_propeller_3D(r_vec, c_vec, beta_vec, prop, in_line)
T_design = [0] * nn Q_design = [0] * nn eta_P = [0] * nn for ii in range(0, nn): atm = AtmData(v_inf, h, is_SI) atm.expand(1.4, 287) prop = Propeller(radius, numB, RPM[ii], eta_P, CP=0, CT=0, CQ=0, Cl=0.4) [_, _, _, P_design[ii], T_design[ii], Q_design[ii], eta_P[ii], _] = prop_design(atm, prop, T_req, m0_fn, Cd_fn) label = "$V_\infty$ = " + str(v_inf) + " (m/s)" plt.figure(1) plt.plot(RPM, Q_design, label=label) plt.figure(2) plt.plot(RPM, eta_P, label=label) plt.figure(3) plt.plot(RPM, P_design, label=label) # plt.figure(7) # plt.plot(RPM,T_design,label=label) try: import formatfigures formatfigures.formatsubfigures() latex = True except:
RPM = 2400 alp0 = numpy.radians(-2) dens = atm_check.dens CT = 0.0509 T_req = CT * dens * (RPM / 60)**2 * (radius * 2)**4 v_seq = numpy.arange(v_climb - 30 * 0.3048, v_climb + 126 * 0.3048, 2) prop_check = Propeller(radius, numB, RPM, eta_P=0, CP=0, CT=0, CQ=0, Cl=0.4) r, prop_check.chord, prop_check.bet, P_design, T_design, Q_design, eta_P, prop_check.theta = prop_design( atm_check, prop_check, T_req, m0_fn, Cd_fn) ll = numpy.size(v_seq) J_var = numpy.zeros((ll, )) P_design_var = numpy.zeros((ll, )) T_design_var = numpy.zeros((ll, )) eta_P_var = numpy.zeros((ll, )) deta_P = numpy.zeros((ll, )) dT = numpy.zeros((ll, )) delta_bet = numpy.zeros((ll, )) RPM_fix = numpy.zeros((ll, )) for ii in range(ll): J_var[ii], P_design_var[ii], T_design_var[ii], Q_design_var[ ii], eta_P_var[ii], deta_P[ii], dT[ii], delta_bet[ii], RPM_fix[ ii] = prop_analysis_var_pitch(v_seq[ii], v_des, P_eng_data,
def STOL_power_req(m, dist_to, mot_distr, AtmData, Wing, Propeller_list): ''' Provides calculation for the least required power of STOL aircraft Inputs: m: kg, airplane mass dist_to: m, target rakeoff distance motDistr: 1xn vector of motor power distribution Wing.S: m^2, wing area Wing.CL_max: max CL during takeoff AtmData.dens: air density (to get ratio compared to standard sea level atm.) Propeller_list: list of class "Propeller" for power calculation in FAR 25 Outputs: outVec: if FAR 23, 1xn vector of motor power (hp) if FAR 25, 1xn vector of motor thrust (N) Calls: {none} Notes: 1. Function uses empirical expression provided in Roskam Part I 2. FAR 23/25 based on aircraft mass included 3. When integrating functions, mute the FAR23/25 fprintf sections 4. Not well tested yet History: 2.9.2021, created by X.Tang in Matlab 2.14.2021, translated to Python by X.Tang 2.14.2021, still has problem in FAR25 power with [1,1] distr, power way too high ''' std_sl_dens_SI = 1.225 # kg/m^3 std_sl_dens_Brit = 0.002377 # slug/ft^3 g = 9.81 # m/s^2 if AtmData.is_SI: sigma = AtmData.dens / std_sl_dens_SI else: sigma = AtmData.dens / std_sl_dens_Brit # FAR 23 / 25 check dist_to_Brit = dist_to * 3.28084 # meter to feet W = m * g # N W_Brit = W * 0.224809 # N to lbf S_Brit = Wing.area * 3.28084 ** 2 # m^2 to ft^2 bdy = 12500 * 0.453592 # kg tol = 1e-3 # tolerance for compare between double if m <= bdy: # FAR 23 a1 = 8.134 a2 = 0.0149 TOP23 = [0] * 2 delta = a2 ** 2 - 4 * a1 * (-dist_to_Brit) # Check real if delta > 0: TOP23[0] = (-a2 + numpy.sqrt(delta)) / (2 * a1) TOP23[1] = (-a2 - numpy.sqrt(delta)) / (2 * a1) # Check positive num if TOP23[0] > 0 and TOP23[1] <= 0: TOP23_val = TOP23[0] elif TOP23[0] <= 0 and TOP23[1] > 0: TOP23_val = TOP23[1] elif TOP23[0] > 0 and TOP23[1] > 0: print("Error: TOP23 has two positive roots") return else: print("Error: TOp23 has two negative roots") return elif abs(delta) <= tol: TOP23_val = numpy.mean(TOP23) if TOP23_val <= 0: print("Error: TOP23 has one negative root") else: # imaginary print("Error: No real root for TOP23") return # Calculation for power in hp PTO = (W_Brit ** 2 / S_Brit) / (TOP23_val * sigma * Wing.CL_max) # Power distribution if numpy.size(mot_distr) > 1: sum_distr = sum(mot_distr) power_vec = [0] * len(mot_distr) for i in range(len(mot_distr)): cur_distr = mot_distr[i] / sum_distr power_vec[i] = cur_distr * PTO else: power_vec = PTO # Can mute this following message print("Aircraft category: FAR 23, motor POWER vector output") return power_vec else: # FAR 25 a3 = 37.5 TOP25 = S_Brit / a3 TTO_lbf = (W_Brit ** 2 / S_Brit) / (TOP25 * sigma * Wing.CL_max) TTO = TTO_lbf * 4.44822 # from lbf to N print("Thrust is " + str(TTO) + " N") # Thrust distribution if numpy.size(mot_distr) > 1: sum_distr = sum(mot_distr) power_vec = [0] * len(mot_distr) for i in range(len(mot_distr)): cur_distr = mot_distr[i] / sum_distr cur_thrust = cur_distr * TTO # Calculating power using propeller design function _, _, _, power_vec[i], _, _, _, _ = prop_design(AtmData, Propeller_list, cur_thrust) power_vec[i] *= 0.00134102 # Converts to hp else: _, _, _, power_vec, _, _, _, _ = prop_design(AtmData, Propeller_list, TTO) power_vec *= 0.00134102 # Converts to hp # Can mute this following message print("Aircraft category: FAR 25, motor POWER vector output") return power_vec
# 3 Blades numB = 3 # Design condition T_req = 13000 / 8 * 1.2 * 0.601 # N (TOGW/(L/D)) Cl = 0.4 alp0 = np.radians(-2) v_design = 30 atm = AtmData(v_design, 0, is_SI) atm.expand(1.4, 287) Design_RPM = 3000 prop = Propeller(radius, numB, Design_RPM, eta_P=0, CP=0, CT=0, CQ=0, Cl=Cl) output = prop_design(atm, prop, T_req, m0_fn, Cd_fn, num=401) r, prop.chord, prop.bet, P_design, T_design, Q_design, eta_P, prop.theta = output # Point reduction and interpolation # Adjustment num_len = len(prop.bet) beta_75_index = int(num_len * 0.75) x = np.linspace(0, 1, num_len) x_need = x[x >= 0.15] c_need = prop.chord[x >= 0.15] AF = 10**5 / 16 * np.trapz(c_need / diameter * x_need**3, x_need) # activity factor CL_design = 4 * np.trapz(Cl * x_need**3, x_need) print( '====================== Propeller Design Parameters ======================'
def VTOL_power_req(m, g_factor, mot_distr, AtmData, Propeller_list): def m0_fn(Ma): if Ma <= 0.9: return (2 * math.pi) / numpy.sqrt(1 - Ma**2) else: return (2 * math.pi) / numpy.sqrt(1 - 0.9**2) def Cd_fn(Cl): return 0.0095 + 0.0040 * (Cl - 0.2)**2 ''' VTOL_power_req provides data and figures for required power of VTOL aircraft Input: m: kg, aircraft mass g_factor = loading factor (1 = hovering) mot_distr = Thrust distribution of motors (1xn) Ex. Enter [1,1,1] for same distr. with 3 motors Accepts single value AtmData = Class "AtmData" including atmospheric information, see Class130 file Propeller_list = list of Class "Propeller" including each propeller information, see Class130 file\ Please make sure the sequence are right! Outputs: powerVec = hp, list of power required by each motor Inner function: m0_fn: Kind of like lift curve slope function -- typical: m0_fn = @(Ma) (2 * pi ./ sqrt(1 - Ma.^2)) .* (Ma <= 0.9) + (2 * pi ./ ... sqrt(1 - 0.9^2)) .* (Ma > 0.9); Cd_fn: Blade sectional drag coefficient -- typical: Cd_fn = @(Cl) 0.0095 + 0.0040 * (Cl - 0.2).^2; Calls: prop_design_TVG: written by TGreenhill, translated and editted by XTang History: 2.09.2021, created by XTang 2.13.2021, translated by XTang 2.13.2021, briefly debugged by XTang ''' # Input size check if numpy.size(Propeller_list) != numpy.size(mot_distr): print("Error: Unequal number of propeller and motors") print("Number of propellers: " + str(numpy.size(Propeller_list))) print("Number of motors: " + str(numpy.size(mot_distr))) return g_accel = 9.81 # constant T_total = m * g_factor * g_accel if numpy.size(mot_distr) != 1: # Having a list of motor distribution for item in mot_distr: if item < 0: print("Error: mot_distr entry values have to be at least 0") return sum_distr = sum(mot_distr) power_vec = [0] * len(mot_distr) eta_vec = [0] * len(mot_distr) for i in range(len(mot_distr)): cur_distr = mot_distr[i] / sum_distr cur_T = cur_distr * T_total [_, _, _, power_vec[i], _, _, eta_vec[i], _] = prop_design(AtmData, Propeller_list[i], cur_T) power_vec[i] *= 0.00134102 # Converts to hp return power_vec, eta_vec else: # Having only one motor if mot_distr == 0: print("Cannot have 0 as value of mot_distr") return _, _, _, power_vec, _, _, eta_vec, _ = prop_design( AtmData, Propeller_list, T_total) power_vec *= 0.00134102 # Converts to hp return power_vec, eta_vec