for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table(airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} if Cl_tables and allowable_Re: Cl_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re ])) Cd_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re ])) def get_performance(o, c, t, v_climb): chord_meters = c * radius prop = propeller.Propeller(t, chord_meters, radius, n_blades,
def main(): ########################################### # Define some values ########################################### n_blades = 2 n_elements = 10 radius = unit_conversion.in2m(9.6) / 2 root_cutout = 0.1 * radius dy = float(radius - root_cutout) / n_elements dr = float(1) / n_elements y = root_cutout + dy * np.arange(1, n_elements + 1) r = y / radius pitch = 0.0 airfoils = (('SDA1075_494p', 0.0, 1.0), ) allowable_Re = [ 1000000., 500000., 250000., 100000., 90000., 80000., 70000., 60000., 50000., 40000., 30000., 20000., 10000. ] vehicle_weight = 12.455 max_chord = 0.3 max_chord_tip = 5. alt = 0 tip_loss = True mach_corr = False # Forward flight parameters v_inf = 4. # m/s alpha0 = 0.0454 # Starting guess for trimmed alpha in radians n_azi_elements = 5 # Mission times time_in_hover = 300. # Time in seconds time_in_ff = 500. mission_time = [time_in_hover, time_in_ff] Cl_tables = {} Cd_tables = {} Clmax = {} # Get lookup tables if any(airfoil[0] != 'simple' for airfoil in airfoils): for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table( airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} lift_curve_info_dict = {} if Cl_tables and allowable_Re: Cl_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re ])) Cd_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re ])) lift_curve_info_dict = aero_coeffs.create_liftCurveInfoDict( allowable_Re, Cl_tables[airfoils[0][0]]) ########################################### # Set design variable bounds ########################################### # Hover opt 500 gen, 1000 pop, 12.455 N weight, 9.6 in prop chord = np.array([ 0.11923604, 0.2168746, 0.31540216, 0.39822882, 0.42919, 0.35039799, 0.3457828, 0.28567224, 0.23418368, 0.13502483 ]) twist = np.array([ 0.45316866, 0.38457724, 0.38225075, 0.34671967, 0.33151445, 0.28719111, 0.25679667, 0.25099005, 0.19400679, 0.10926302 ]) omega = 3811.03596674 * 2 * np.pi / 60 original = (omega, chord, twist) dtwist = np.array( [twist[i + 1] - twist[i] for i in xrange(len(twist) - 1)]) dchord = np.array( [chord[i + 1] - chord[i] for i in xrange(len(chord) - 1)]) twist0 = twist[0] chord0 = chord[0] omega_start = omega dtwist_start = dtwist dchord_start = dchord twist0_start = twist0 chord0_start = chord0 omega_lower = 2000 * 2 * np.pi / 60 omega_upper = 8000.0 * 2 * np.pi / 60 twist0_lower = 0. * 2 * np.pi / 360 twist0_upper = 60. * 2 * np.pi / 360 chord0_upper = 0.1198 chord0_lower = 0.05 dtwist_lower = -10.0 * 2 * np.pi / 360 dtwist_upper = 10.0 * 2 * np.pi / 360 dchord_lower = -0.1 dchord_upper = 0.1 opt_prob = Optimization('Mission Simulator', objfun) opt_prob.addVar('omega_h', 'c', value=omega_start, lower=omega_lower, upper=omega_upper) opt_prob.addVar('twist0', 'c', value=twist0_start, lower=twist0_lower, upper=twist0_upper) opt_prob.addVar('chord0', 'c', value=chord0_start, lower=chord0_lower, upper=chord0_upper) opt_prob.addVarGroup('dtwist', n_elements - 1, 'c', value=dtwist_start, lower=dtwist_lower, upper=dtwist_upper) opt_prob.addVarGroup('dchord', n_elements - 1, 'c', value=dchord_start, lower=dchord_lower, upper=dchord_upper) opt_prob.addObj('f') opt_prob.addCon('thrust', 'i') opt_prob.addCon('c_tip', 'i') opt_prob.addConGroup('c_lower', n_elements, 'i') opt_prob.addConGroup('c_upper', n_elements, 'i') print opt_prob slsqp = SLSQP() slsqp.setOption('IPRINT', 1) slsqp.setOption('MAXIT', 1000) slsqp.setOption('ACC', 1e-8) fstr, xstr, inform = slsqp(opt_prob, sens_type='FD', n_blades=n_blades, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, airfoils=airfoils, vehicle_weight=vehicle_weight, max_chord=max_chord, tip_loss=tip_loss, mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, Cd_tables=Cd_tables, allowable_Re=allowable_Re, alt=alt, v_inf=v_inf, alpha0=alpha0, mission_time=mission_time, n_azi_elements=n_azi_elements, lift_curve_info_dict=lift_curve_info_dict, max_chord_tip=max_chord_tip) print opt_prob.solution(0) # pop_size = 300 # max_gen = 500 # opt_method = 'nograd' # nsga2 = NSGA2() # nsga2.setOption('PrintOut', 2) # nsga2.setOption('PopSize', pop_size) # nsga2.setOption('maxGen', max_gen) # nsga2.setOption('pCross_real', 0.85) # nsga2.setOption('xinit', 1) # fstr, xstr, inform = nsga2(opt_prob, n_blades=n_blades, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, vehicle_weight=vehicle_weight, max_chord=max_chord, tip_loss=tip_loss, # mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, # Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method, alt=alt, # v_inf=v_inf, alpha0=alpha0, mission_time=mission_time, n_azi_elements=n_azi_elements, # pop_size=pop_size, max_gen=max_gen, lift_curve_info_dict=lift_curve_info_dict, # max_chord_tip=max_chord_tip) # print opt_prob.solution(0) # opt_method = 'nograd' # xstart_alpso = np.concatenate((np.array([omega_start, twist0_start, chord0_start]), dtwist_start, dchord_start)) # alpso = ALPSO() # alpso.setOption('xinit', 0) # alpso.setOption('SwarmSize', 200) # alpso.setOption('maxOuterIter', 100) # alpso.setOption('stopCriteria', 0) # fstr, xstr, inform = alpso(opt_prob, xstart=xstart_alpso, n_blades=n_blades, n_elements=n_elements, # root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, thrust=thrust, max_chord=max_chord, tip_loss=tip_loss, # mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, # Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method) # print opt_prob.solution(0) def get_performance(o, c, t): chord_meters = c * radius prop = propeller.Propeller(t, chord_meters, radius, n_blades, r, y, dr, dy, airfoils=airfoils, Cl_tables=Cl_tables, Cd_tables=Cd_tables) quad = quadrotor.Quadrotor(prop, vehicle_weight) ff_kwargs = { 'propeller': prop, 'pitch': pitch, 'n_azi_elements': n_azi_elements, 'allowable_Re': allowable_Re, 'Cl_funs': Cl_funs, 'Cd_funs': Cd_funs, 'tip_loss': tip_loss, 'mach_corr': mach_corr, 'alt': alt, 'lift_curve_info_dict': lift_curve_info_dict } trim0 = np.array([alpha0, o]) alpha_trim, omega_trim, converged = trim.trim(quad, v_inf, trim0, ff_kwargs) T_ff, H_ff, P_ff = bemt.bemt_forward_flight( quad, pitch, omega_trim, alpha_trim, v_inf, n_azi_elements, alt=alt, tip_loss=tip_loss, mach_corr=mach_corr, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, lift_curve_info_dict=lift_curve_info_dict) dT_h, P_h = bemt.bemt_axial(prop, pitch, o, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, alt=alt) return sum(dT_h), P_h, T_ff, P_ff, alpha_trim, omega_trim omega = xstr[0] twist0 = xstr[1] chord0 = xstr[2] dtwist = xstr[3:3 + len(r) - 1] dchord = xstr[3 + len(r) - 1:] twist = calc_twist_dist(twist0, dtwist) chord = calc_chord_dist(chord0, dchord) print "chord = " + repr(chord) print "twist = " + repr(twist) # twist_base = calc_twist_dist(twist0_base, dtwist_base) # chord_base = calc_chord_dist(chord0_base, dchord_base) perf_opt = get_performance(omega, chord, twist) perf_orig = get_performance(original[0], original[1], original[2]) print "omega_orig = " + str(original[0]) print "Hover Thrust of original = " + str(perf_orig[0]) print "Hover Power of original = " + str(perf_orig[1]) print "FF Thrust of original = " + str(perf_orig[2]) print "FF Power of original = " + str(perf_orig[3]) print "Trim original (alpha, omega) = (%f, %f)" % (perf_orig[4], perf_orig[5]) print "omega = " + str(omega * 60 / 2 / np.pi) print "Hover Thrust of optimized = " + str(perf_opt[0]) print "Hover Power of optimized = " + str(perf_opt[1]) print "FF Thrust of optimized = " + str(perf_opt[2]) print "FF Power of optimized = " + str(perf_opt[3]) print "Trim optimized (alpha, omega) = (%f, %f)" % (perf_opt[4], perf_opt[5]) # print "Omega base = " + str(omega_start*60/2/np.pi) # print "Thrust of base = " + str(sum(perf_base[0])) # print "Power of base = " + str(sum(perf_base[1])) # plt.figure(1) plt.plot(r, original[1], '-b') plt.plot(r, chord, '-r') plt.xlabel('radial location') plt.ylabel('c/R') plt.legend(['start', 'opt']) plt.figure(2) plt.plot(r, original[2] * 180 / np.pi, '-b') plt.plot(r, twist * 180 / np.pi, '-r') plt.xlabel('radial location') plt.ylabel('twist') plt.legend(['start', 'opt']) plt.show()
if any(airfoil[0] != 'simple' for airfoil in airfoils): for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table(airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} lift_curve_info_dict = {} if any(Cl_tables) and allowable_Re: Cl_funs = dict(zip(allowable_Re, [aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re])) Cd_funs = dict(zip(allowable_Re, [aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re])) lift_curve_info_dict = aero_coeffs.create_liftCurveInfoDict(allowable_Re, Cl_tables[airfoils[0][0]]) radius = in2m(15./2) twist = np.array([6.97, 15.97, 21.77, 21.72, 19.91, 18.14, 16.55, 15.28, 14.01, 13., 12.18, 11.39, 10.76, 10.24, 9.85, 9.4, 9.07, 8.7, 8.46, 8.29, 8.19, 8.17]) * 2 * np.pi / 360 chord = in2m(np.array([0.77, 0.97, 1.18, 1.34, 1.44, 1.49, 1.50, 1.49, 1.46, 1.42, 1.38, 1.33, 1.27, 1.21, 1.14, 1.07, 1., 0.93, 0.86, 0.77, 0.67, 0.44])) prop = propeller.Propeller(twist, chord, radius, n_blades, r, y, dr, dy, airfoils=airfoils, Cl_tables=Cl_tables, Cd_tables=Cd_tables) quad = quadrotor.Quadrotor(prop, vehicle_weight)
def main(): n_blades = 2 n_elements = 10 #radius = unit_conversion.in2m(9.0)/2 radius = 0.193 root_cutout = 0.1 * radius dy = float(radius - root_cutout) / n_elements dr = float(1) / n_elements y = root_cutout + dy * np.arange(1, n_elements + 1) r = y / radius pitch = 0.0 airfoils = (('SDA1075_494p', 0.0, 1.0), ) allowable_Re = [] allowable_Re = [ 1000000., 500000., 250000., 100000., 90000., 80000., 70000., 60000., 50000., 40000., 30000., 20000., 10000. ] thrust = 5.5 max_chord = 0.6 alt = 4000 tip_loss = True mach_corr = False Cl_tables = {} Cd_tables = {} Clmax = {} # Get lookup tables if any(airfoil[0] != 'simple' for airfoil in airfoils): for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table( airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} if Cl_tables and allowable_Re: Cl_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re ])) Cd_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re ])) ########################################### # Set design variable bounds ########################################### # The DA4002 blade chord = np.array([ 0.1198, 0.1128, 0.1436, 0.1689, 0.1775, 0.1782, 0.1773, 0.1782, 0.1790, 0.1787, 0.1787, 0.1786, 0.1785, 0.1790, 0.1792, 0.1792, 0.1692, 0.0154 ]) #chord = np.array([chord[i] for i in [0, 4, 8, 12, 16]]) #chord = np.array([chord[i] for i in [0, 3, 6, 9, 11, 13, 15, 17]]) chord = np.array([chord[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) #chord = chord[-1] / r twist = np.array([ 42.481, 44.647, 41.154, 37.475, 34.027, 30.549, 27.875, 25.831, 23.996, 22.396, 21.009, 19.814, 18.786, 17.957, 17.245, 16.657, 13.973, 2.117 ]) * 2 * np.pi / 360 #twist = np.array([twist[i] for i in [0, 4, 8, 12, 16]]) #twist = np.array([twist[i] for i in [0, 3, 6, 9, 11, 13, 15, 17]]) twist = np.array([twist[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) ##################### NSGA 10 pt Reallowed=1M T=6.31 xinit=base ################## # chord = np.array([0.1074969, 0.20649294, 0.30477175, 0.34034408, 0.39389147, 0.38511651, 0.39240366, 0.32613037, # 0.33806846, 0.26398963]) # twist = np.array([0.90281547, 0.80337759, 0.636879, 0.46309343, 0.33774749, 0.33234442, 0.30418376, 0.2819689, # 0.26313925, 0.24413934]) # omega = 4611.67993997 * 2*np.pi/60 #################### NSGA 10 pt 5000p 500g Reallowed=All T=4.61 xinit=base tiploss ####### # chord = np.array([0.11470868, 0.21117422, 0.30252118, 0.39582241, 0.42498534, 0.41241736, 0.32928823, 0.23259937, # 0.17993009, 0.11100332]) # twist = np.array([0.55653743, 0.45683294, 0.38657942, 0.39545834, 0.3270524, 0.3053103, 0.27289751, 0.23934658, # 0.20193655, 0.034115]) # omega = 5286.48230542 *2*np.pi/60 chord = np.array([ 0.08527494, 0.18305166, 0.28003061, 0.37723735, 0.39791253, 0.38551352, 0.30090341, 0.20180039, 0.14683824, 0.06464163 ]) twist = np.array([ 0.00114182, 0.16927357, 0.33062163, 0.36775474, 0.32781283, 0.30751832, 0.27097053, 0.24367986, 0.21398367, 0.10101229 ]) omega = 2675.92469603 * 2 * np.pi / 60 chord0 = chord[0] twist0 = twist[0] dchord = np.array( [chord[i + 1] - chord[i] for i in xrange(len(chord) - 1)]) dtwist = np.array( [twist[i + 1] - twist[i] for i in xrange(len(twist) - 1)]) #omega = 5943.0 * 2*np.pi/60 omega_upper = 7000 * 2 * np.pi / 60 omega_lower = 2000. * 2 * np.pi / 60 # # Twist at the hub must be less than or equal to arcsin(hub_height/hub_diameter), approx 23 degrees twist0_lower = 0.0 * 2 * np.pi / 360 twist0_upper = 0.1 * 2 * np.pi / 360 # Chord values at the hub must be less than or equal to the diameter of the hub chord0_upper = 0.09 chord0_lower = 0.05 # dtwist_start = 0.0 * 2 * np.pi / 360 dtwist_lower = -10.0 * 2 * np.pi / 360 dtwist_upper = 10.0 * 2 * np.pi / 360 dchord_lower = -0.1 dchord_upper = 0.1 twist_start = twist chord_start = chord omega_start = omega iteration = 0 fit_old = 1000. fit_2old = 1000. converged = False while not converged: iteration += 1 fstr, xstr = optimize_twist(omega=omega, omega_lower=omega_lower, omega_upper=omega_upper, twist0=twist0, twist0_lower=twist0_lower, twist0_upper=twist0_upper, n_elements=n_elements, dtwist=dtwist, dtwist_lower=dtwist_lower, dtwist_upper=dtwist_upper, n_blades=n_blades, root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, airfoils=airfoils, thrust=thrust, chord=chord, allowable_Re=allowable_Re, Cl_tables=Cl_tables, Cd_tables=Cd_tables, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, alt=alt) omega = xstr[0] twist = calc_twist_dist(xstr[1], xstr[2:]) fstr, xstr = optimize_chord(omega=omega, omega_lower=omega_lower, omega_upper=omega_upper, chord0=chord0, chord0_lower=chord0_lower, chord0_upper=chord0_upper, n_elements=n_elements, dchord=dchord, dchord_lower=dchord_lower, dchord_upper=dchord_upper, n_blades=n_blades, root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, airfoils=airfoils, thrust=thrust, max_chord=max_chord, twist=twist, allowable_Re=allowable_Re, Cl_tables=Cl_tables, Cd_tables=Cd_tables, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, alt=alt) omega = xstr[0] chord = calc_chord_dist(xstr[1], xstr[2:]) converged = abs( (fit_old - fstr) / fstr) < 0.005 #and abs((fit_2old - fit_old) / fit_old) < 0.0005 fit_2old = fit_old fit_old = fstr print "omega = " + str(omega * 60 / 2 / np.pi) print "chord = " + str(chord) print "twist = " + str(twist) print "iterations = " + str(iteration) def get_performance(o, c, t): chord_meters = c * radius prop = propeller.Propeller(t, chord_meters, radius, n_blades, r, y, dr, dy, airfoils=airfoils, Cl_tables=Cl_tables, Cd_tables=Cd_tables) return bemt.bemt_axial(prop, pitch, o, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, output='long', alt=alt) perf_opt = get_performance(omega, chord, twist) perf_start = get_performance(omega_start, chord_start, twist_start) print "Thrust of optimized = " + str(sum(perf_opt[0])) print "Power of optimized = " + str(sum(perf_opt[1])) print "Thrust of start = " + str(sum(perf_start[0])) print "Power of start = " + str(sum(perf_start[1])) plt.figure(1) plt.plot(r, chord_start, '-b') plt.plot(r, chord, '-r') plt.xlabel('radial location') plt.ylabel('c/R') plt.legend(['start', 'opt']) plt.figure(2) plt.plot(r, twist_start * 180 / np.pi, '-b') plt.plot(r, twist * 180 / np.pi, '-r') plt.xlabel('radial location') plt.ylabel('twist') plt.legend(['start', 'opt']) plt.show()
def main(): ########################################### # Define some values ########################################### n_blades = 2 n_elements = 10 radius = unit_conversion.in2m(9.6) / 2 root_cutout = 0.1 * radius dy = float(radius - root_cutout) / n_elements dr = float(1) / n_elements y = root_cutout + dy * np.arange(1, n_elements + 1) r = y / radius pitch = 0.0 airfoils = (('SDA1075_494p', 0.0, 1.0), ) #allowable_Re = [] allowable_Re = [ 1000000., 500000., 250000., 100000., 90000., 80000., 70000., 60000., 50000., 40000., 30000., 20000., 10000. ] vehicle_weight = 12.455 max_chord = 0.6 max_chord_tip = 5. alt = 0 tip_loss = True mach_corr = False # Forward flight parameters v_inf = 4. # m/s alpha0 = 0.0454 # Starting guess for trimmed alpha in radians n_azi_elements = 5 # Mission times time_in_hover = 0. # Time in seconds time_in_ff = 500. mission_time = [time_in_hover, time_in_ff] Cl_tables = {} Cd_tables = {} Clmax = {} # Get lookup tables if any(airfoil[0] != 'simple' for airfoil in airfoils): for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table( airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} lift_curve_info_dict = {} if Cl_tables and allowable_Re: Cl_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re ])) Cd_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re ])) lift_curve_info_dict = aero_coeffs.create_liftCurveInfoDict( allowable_Re, Cl_tables[airfoils[0][0]]) ########################################### # Set design variable bounds ########################################### omega_start = 4250. * 2 * np.pi / 60 # These are c/R values for the DA4002 propeller given at the UIUC propeller database chord_base = np.array([ 0.1198, 0.1128, 0.1436, 0.1689, 0.1775, 0.1782, 0.1773, 0.1782, 0.1790, 0.1787, 0.1787, 0.1786, 0.1785, 0.1790, 0.1792, 0.1792, 0.1692, 0.0154 ]) chord_base = np.array( [chord_base[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) twist_base = np.array([ 42.481, 44.647, 41.154, 37.475, 34.027, 30.549, 27.875, 25.831, 23.996, 22.396, 21.009, 19.814, 18.786, 17.957, 17.245, 16.657, 13.973, 2.117 ]) * 2 * np.pi / 360 twist_base = np.array( [twist_base[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) dtwist_base = np.array([ twist_base[i + 1] - twist_base[i] for i in xrange(len(twist_base) - 1) ]) dchord_base = np.array([ chord_base[i + 1] - chord_base[i] for i in xrange(len(chord_base) - 1) ]) twist0_base = twist_base[0] chord0_base = chord_base[0] chord_start = chord_base twist_start = twist_base dtwist_start = dtwist_base dchord_start = dchord_base twist0_start = twist0_base chord0_start = chord0_base print "chord0_start = " + str(chord0_start) omega_lower = 2000 * 2 * np.pi / 60 omega_upper = 8000.0 * 2 * np.pi / 60 twist0_lower = 0. * 2 * np.pi / 360 twist0_upper = 60. * 2 * np.pi / 360 chord0_upper = 0.1198 chord0_lower = 0.05 dtwist_lower = -10.0 * 2 * np.pi / 360 dtwist_upper = 10.0 * 2 * np.pi / 360 dchord_lower = -0.1 dchord_upper = 0.1 opt_prob = Optimization('Mission Simulator', objfun) opt_prob.addVar('omega_h', 'c', value=omega_start, lower=omega_lower, upper=omega_upper) opt_prob.addVar('twist0', 'c', value=twist0_start, lower=twist0_lower, upper=twist0_upper) opt_prob.addVar('chord0', 'c', value=chord0_start, lower=chord0_lower, upper=chord0_upper) opt_prob.addVarGroup('dtwist', n_elements - 1, 'c', value=dtwist_start, lower=dtwist_lower, upper=dtwist_upper) opt_prob.addVarGroup('dchord', n_elements - 1, 'c', value=dchord_start, lower=dchord_lower, upper=dchord_upper) opt_prob.addObj('f') opt_prob.addCon('thrust', 'i') opt_prob.addCon('c_tip', 'i') opt_prob.addConGroup('c_lower', n_elements, 'i') opt_prob.addConGroup('c_upper', n_elements, 'i') print opt_prob pop_size = 300 max_gen = 1100 opt_method = 'nograd' nsga2 = NSGA2() nsga2.setOption('PrintOut', 2) nsga2.setOption('PopSize', pop_size) nsga2.setOption('maxGen', max_gen) nsga2.setOption('pCross_real', 0.85) nsga2.setOption('pMut_real', 0.2) nsga2.setOption('xinit', 1) fstr, xstr, inform = nsga2(opt_prob, n_blades=n_blades, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, airfoils=airfoils, vehicle_weight=vehicle_weight, max_chord=max_chord, tip_loss=tip_loss, mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method, alt=alt, v_inf=v_inf, alpha0=alpha0, mission_time=mission_time, n_azi_elements=n_azi_elements, pop_size=pop_size, max_gen=max_gen, lift_curve_info_dict=lift_curve_info_dict, max_chord_tip=max_chord_tip) print opt_prob.solution(0) # opt_method = 'nograd' # xstart_alpso = np.concatenate((np.array([omega_start, twist0_start, chord0_start]), dtwist_start, dchord_start)) # alpso = ALPSO() # alpso.setOption('xinit', 0) # alpso.setOption('SwarmSize', 200) # alpso.setOption('maxOuterIter', 100) # alpso.setOption('stopCriteria', 0) # fstr, xstr, inform = alpso(opt_prob, xstart=xstart_alpso, n_blades=n_blades, n_elements=n_elements, # root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, thrust=thrust, max_chord=max_chord, tip_loss=tip_loss, # mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, # Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method) # print opt_prob.solution(0) # opt_method = 'grad' # slsqp = SLSQP() # slsqp.setOption('IPRINT', 1) # slsqp.setOption('MAXIT', 1000) # slsqp.setOption('ACC', 1e-7) # fstr, xstr, inform = slsqp(opt_prob, sens_type='FD', n_blades=n_blades, n_elements=n_elements, # root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, thrust=thrust, max_chord=max_chord, # tip_loss=tip_loss, mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, # Cl_tables=Cl_tables, Cd_tables=Cd_tables, allowable_Re=allowable_Re, # opt_method=opt_method, alt=alt) # print opt_prob.solution(0) def get_performance(o, c, t): chord_meters = c * radius prop = propeller.Propeller(t, chord_meters, radius, n_blades, r, y, dr, dy, airfoils=airfoils, Cl_tables=Cl_tables, Cd_tables=Cd_tables) quad = quadrotor.Quadrotor(prop, vehicle_weight) ff_kwargs = { 'propeller': prop, 'pitch': pitch, 'n_azi_elements': n_azi_elements, 'allowable_Re': allowable_Re, 'Cl_funs': Cl_funs, 'Cd_funs': Cd_funs, 'tip_loss': tip_loss, 'mach_corr': mach_corr, 'alt': alt, 'lift_curve_info_dict': lift_curve_info_dict } trim0 = np.array([alpha0, o]) alpha_trim, omega_trim, converged = trim.trim(quad, v_inf, trim0, ff_kwargs) T_ff, H_ff, P_ff = bemt.bemt_forward_flight( quad, pitch, omega_trim, alpha_trim, v_inf, n_azi_elements, alt=alt, tip_loss=tip_loss, mach_corr=mach_corr, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, lift_curve_info_dict=lift_curve_info_dict) dT_h, P_h = bemt.bemt_axial(prop, pitch, o, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, alt=alt) return sum(dT_h), P_h, T_ff, P_ff, alpha_trim, omega_trim omega = xstr[0] twist0 = xstr[1] chord0 = xstr[2] dtwist = xstr[3:3 + len(r) - 1] dchord = xstr[3 + len(r) - 1:] twist = calc_twist_dist(twist0, dtwist) chord = calc_chord_dist(chord0, dchord) print "chord = " + repr(chord) print "twist = " + repr(twist) # twist_base = calc_twist_dist(twist0_base, dtwist_base) # chord_base = calc_chord_dist(chord0_base, dchord_base) perf_opt = get_performance(omega, chord, twist) #perf_base = get_performance(omega_start, chord_base, twist_base) print "omega = " + str(omega * 60 / 2 / np.pi) print "Hover Thrust of optimized = " + str(perf_opt[0]) print "Hover Power of optimized = " + str(perf_opt[1]) print "FF Thrust of optimized = " + str(perf_opt[2]) print "FF Power of optimized = " + str(perf_opt[3]) print "Trim (alpha, omega) = (%f, %f)" % (perf_opt[4], perf_opt[5])
def main(): ########################################### # Define some values ########################################### n_blades = 2 n_elements = 10 radius = unit_conversion.in2m(9.6) / 2 #radius = 0.1397 root_cutout = 0.1 * radius dy = float(radius - root_cutout) / n_elements dr = float(1) / n_elements y = root_cutout + dy * np.arange(1, n_elements + 1) r = y / radius pitch = 0.0 airfoils = (('SDA1075_494p', 0.0, 1.0), ) #allowable_Re = [] allowable_Re = [ 1000000., 500000., 250000., 100000., 90000., 80000., 70000., 60000., 50000., 40000., 30000., 20000., 10000. ] vehicle_weight = 12.455 max_chord = 0.6 alt = 0 tip_loss = True mach_corr = False Cl_tables = {} Cd_tables = {} Clmax = {} # Get lookup tables if any(airfoil[0] != 'simple' for airfoil in airfoils): for airfoil in airfoils: Cl_table, Cd_table, Clmax = aero_coeffs.create_Cl_Cd_table( airfoil[0]) Cl_tables[airfoil[0]] = Cl_table Cd_tables[airfoil[0]] = Cd_table Clmax[airfoil[0]] = Clmax # Create list of Cl functions. One for each Reynolds number. Cl_tables (and Cd_tables) will be empty for the # 'simple' case, therefore this will be skipped for the simple case. For the full table lookup case this will be # skipped because allowable_Re will be empty. Cl_funs = {} Cd_funs = {} lift_curve_info_dict = {} if Cl_tables and allowable_Re: Cl_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cl_fun(Re, Cl_tables[airfoils[0][0]], Clmax[airfoils[0][0]][Re]) for Re in allowable_Re ])) Cd_funs = dict( zip(allowable_Re, [ aero_coeffs.get_Cd_fun(Re, Cd_tables[airfoils[0][0]]) for Re in allowable_Re ])) lift_curve_info_dict = aero_coeffs.create_liftCurveInfoDict( allowable_Re, Cl_tables[airfoils[0][0]]) ########################################### # Set design variable bounds ########################################### omega_start = 4250. * 2 * np.pi / 60 chord_base = np.array([ 0.1198, 0.1128, 0.1436, 0.1689, 0.1775, 0.1782, 0.1773, 0.1782, 0.1790, 0.1787, 0.1787, 0.1786, 0.1785, 0.1790, 0.1792, 0.1792, 0.1692, 0.0154 ]) chord_base = np.array( [chord_base[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) twist_base = np.array([ 42.481, 44.647, 41.154, 37.475, 34.027, 30.549, 27.875, 25.831, 23.996, 22.396, 21.009, 19.814, 18.786, 17.957, 17.245, 16.657, 13.973, 2.117 ]) * 2 * np.pi / 360 twist_base = np.array( [twist_base[i] for i in [0, 2, 4, 6, 8, 10, 12, 14, 15, 17]]) dtwist_base = np.array([ twist_base[i + 1] - twist_base[i] for i in xrange(len(twist_base) - 1) ]) dchord_base = np.array([ chord_base[i + 1] - chord_base[i] for i in xrange(len(chord_base) - 1) ]) twist0_base = twist_base[0] chord0_base = chord_base[0] chord_start = chord_base twist_start = twist_base dtwist_start = dtwist_base dchord_start = dchord_base twist0_start = twist0_base chord0_start = chord0_base # chord = np.array([8.92386048e-02, 1.73000845e-01, 2.70523039e-01, 2.71542807e-01, 2.78749355e-01, 2.36866151e-01, # 2.04103526e-01, 1.37456074e-01, 8.68094589e-02, 1.05601135e-04]) # twist = np.array([0.00161645, 0.15105685, 0.28791442, 0.31577392, 0.28644651, 0.27418749, 0.24854514, 0.21812646, # 0.19802027, 0.14972058]) # omega_start = 3184.41320387 * 2*np.pi/60 # chord_start = chord # twist_start = twist # dchord_start = np.array([chord[i+1]-chord[i] for i in xrange(len(chord)-1)]) # dtwist_start = np.array([twist[i+1]-twist[i] for i in xrange(len(twist)-1)]) # twist0_start = twist[0] # chord0_start = chord[0] ## Initialize everything to zeros # dtwist_start = np.zeros(n_elements-1) # dchord_start = np.zeros(n_elements-1) # twist0_start = 0.0 # chord0_start = 0.0 omega_lower = 2000 * 2 * np.pi / 60 omega_upper = 8000.0 * 2 * np.pi / 60 twist0_lower = 0.0 * 2 * np.pi / 360 twist0_upper = 60. * 2 * np.pi / 360 chord0_upper = 0.1198 chord0_lower = 0.05 dtwist_lower = -10.0 * 2 * np.pi / 360 dtwist_upper = 10.0 * 2 * np.pi / 360 dchord_lower = -0.1 dchord_upper = 0.1 opt_prob = Optimization('Rotor in Hover', objfun) opt_prob.addVar('omega', 'c', value=omega_start, lower=omega_lower, upper=omega_upper) opt_prob.addVar('twist0', 'c', value=twist0_start, lower=twist0_lower, upper=twist0_upper) opt_prob.addVar('chord0', 'c', value=chord0_start, lower=chord0_lower, upper=chord0_upper) opt_prob.addVarGroup('dtwist', n_elements - 1, 'c', value=dtwist_start, lower=dtwist_lower, upper=dtwist_upper) opt_prob.addVarGroup('dchord', n_elements - 1, 'c', value=dchord_start, lower=dchord_lower, upper=dchord_upper) opt_prob.addObj('f') opt_prob.addCon('thrust', 'i') opt_prob.addConGroup('c_lower', n_elements, 'i') opt_prob.addConGroup('c_upper', n_elements, 'i') print opt_prob opt_method = 'nograd' nsga2 = NSGA2() nsga2.setOption('PrintOut', 2) nsga2.setOption('PopSize', 300) nsga2.setOption('maxGen', 1100) nsga2.setOption('pCross_real', 0.85) nsga2.setOption('xinit', 1) fstr, xstr, inform = nsga2(opt_prob, n_blades=n_blades, n_elements=n_elements, root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, airfoils=airfoils, vehicle_weight=vehicle_weight, max_chord=max_chord, tip_loss=tip_loss, mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method, alt=alt, lift_curve_info_dict=lift_curve_info_dict) print opt_prob.solution(0) # opt_method = 'nograd' # xstart_alpso = np.concatenate((np.array([omega_start, twist0_start, chord0_start]), dtwist_start, dchord_start)) # alpso = ALPSO() # alpso.setOption('xinit', 0) # alpso.setOption('SwarmSize', 200) # alpso.setOption('maxOuterIter', 100) # alpso.setOption('stopCriteria', 0) # fstr, xstr, inform = alpso(opt_prob, xstart=xstart_alpso, n_blades=n_blades, n_elements=n_elements, # root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, thrust=thrust, max_chord=max_chord, tip_loss=tip_loss, # mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, Cl_tables=Cl_tables, # Cd_tables=Cd_tables, allowable_Re=allowable_Re, opt_method=opt_method) # print opt_prob.solution(0) # opt_method = 'grad' # slsqp = SLSQP() # slsqp.setOption('IPRINT', 1) # slsqp.setOption('MAXIT', 1000) # slsqp.setOption('ACC', 1e-7) # fstr, xstr, inform = slsqp(opt_prob, sens_type='FD', n_blades=n_blades, n_elements=n_elements, # root_cutout=root_cutout, radius=radius, dy=dy, dr=dr, y=y, r=r, pitch=pitch, # airfoils=airfoils, thrust=thrust, max_chord=max_chord, # tip_loss=tip_loss, mach_corr=mach_corr, Cl_funs=Cl_funs, Cd_funs=Cd_funs, # Cl_tables=Cl_tables, Cd_tables=Cd_tables, allowable_Re=allowable_Re, # opt_method=opt_method, alt=alt) # print opt_prob.solution(0) def get_performance(o, c, t): chord_meters = c * radius prop = propeller.Propeller(t, chord_meters, radius, n_blades, r, y, dr, dy, airfoils=airfoils, Cl_tables=Cl_tables, Cd_tables=Cd_tables) return bemt.bemt_axial(prop, pitch, o, allowable_Re=allowable_Re, Cl_funs=Cl_funs, Cd_funs=Cd_funs, tip_loss=tip_loss, mach_corr=mach_corr, output='long', alt=alt) omega = xstr[0] twist0 = xstr[1] chord0 = xstr[2] dtwist = xstr[3:3 + len(r) - 1] dchord = xstr[3 + len(r) - 1:] twist = calc_twist_dist(twist0, dtwist) chord = calc_chord_dist(chord0, dchord) print "chord = " + repr(chord) print "twist = " + repr(twist) # twist_base = calc_twist_dist(twist0_base, dtwist_base) # chord_base = calc_chord_dist(chord0_base, dchord_base) perf_opt = get_performance(omega, chord, twist) #perf_base = get_performance(omega_start, chord_base, twist_base) print "omega = " + str(omega * 60 / 2 / np.pi) print "Thrust of optimized = " + str(sum(perf_opt[0])) print "Power of optimized = " + str(perf_opt[1]) # print "Omega base = " + str(omega_start*60/2/np.pi) # print "Thrust of base = " + str(sum(perf_base[0])) # print "Power of base = " + str(sum(perf_base[1])) plt.figure(1) plt.plot(r, chord_start, '-b') plt.plot(r, chord, '-r') plt.xlabel('radial location') plt.ylabel('c/R') plt.legend(['start', 'opt']) plt.figure(2) plt.plot(r, twist_start * 180 / np.pi, '-b') plt.plot(r, twist * 180 / np.pi, '-r') plt.xlabel('radial location') plt.ylabel('twist') plt.legend(['start', 'opt']) plt.show()