def get_max_cl(Re, r): """ Analyze airfoil at a fixed Re, changing aoa from 10 to 15 by 0.1 and returns cl, cd, aoa that makes maximum cl """ xf = XFoil() if r <= 0.175: xf.airfoil = naca6409 else: xf.airfoil = naca2412 xf.Re = Re xf.Re = Re xf.max_iter = 200 xf.n_crit = 9.00 xf.xtr = [1.00, 1.00] xf.M = 0 a_seq, cl_seq, cd_seq, cm_seq, cp_seq = xf.aseq(10, 15, 0.1) # ignore nan by making it 0 cl_seq = np.nan_to_num(cl_seq) # find the maximum cl cl_maxi = np.max(cl_seq) # index of the maximum cl idx = np.argmax(cl_seq) return round(cl_maxi, 2), round(a_seq[idx], 2), round(cd_seq[idx], 2)
def get_torque(angular_velocity): torque_sum_small = 0 torque_sum_large = 0 w = angular_velocity for key, value in dfdict.items(): value["blade_velocity"] = value['r_position'] * w value["relative_velocity"] = round( math.sqrt(value["blade_velocity"]**2 + value["wind_velocity"]**2), 2) value["arctan"] = math.degrees( math.atan2(value["wind_velocity"], value["blade_velocity"])) aoa = round(value["arctan"] - value["pitch_angle"], 2) value["angle_of_attack"] = aoa re_n = round( value["relative_velocity"] * value["chord_length"] / 0.00001511, 3) value["Reynolds_number"] = re_n xf = XFoil() if key < 13: xf.airfoil = naca6409 else: xf.airfoil = naca2412 xf.Re = re_n xf.max_iter = 100 xf.n_crit = 9.00 xf.xtr = [1.00, 1.00] xf.M = 0 value["Cl"], value["Cd"], value["Cm"], value["Cp"] = xf.a(aoa) force_reference = 0.5 * density * value["relative_velocity"]**2 if math.isnan(value["Cl"]): value["torque"] = 0 else: lift = value["Cl"] * force_reference * 0.0125 * value[ 'chord_length'] drag = value["Cd"] * force_reference * 0.0125 * value[ 'chord_length'] value["torque"] = value["r_position"] * ( lift * math.sin(math.radians(value["pitch_angle"])) - drag * math.cos(math.radians(value["pitch_angle"]))) if key < 13: torque_sum_small += value["torque"] else: pass if key > 0: torque_sum_large += value["torque"] else: pass df2 = pd.DataFrame.from_dict(dfdict, orient="index") df_collection.append(df2) torque_sum_avg = 0.5 * (torque_sum_small + torque_sum_large) return torque_sum_avg
def total_dict(angular_velocity): torque_sum = 0 w = angular_velocity for key, value in dfdict.items(): value["blade_velocity"] = value['r_position'] * w value["relative_velocity"] = round( math.sqrt(value["blade_velocity"]**2 + value["wind_velocity"]**2), 2) value["arctan"] = math.degrees( math.atan2(value["wind_velocity"], value["blade_velocity"])) aoa = round(value["arctan"] - value["pitch_angle"], 1) value["angle_of_attack"] = aoa re_n = round(value["relative_velocity"] * value["chord_length"] / 0.00001511) value["Reynolds_number"] = re_n xf = XFoil() if key < 13: xf.airfoil = naca6409 else: xf.airfoil = naca2412 xf.Re = round(re_n / 100) * 100 xf.max_iter = 200 xf.n_crit = 9.00 xf.xtr = [1.00, 1.00] xf.M = 0 c_l, c_d, c_m, c_p = xf.a(aoa) force_reference = 0.5 * density * value["relative_velocity"]**2 if math.isnan(c_l): pass else: value["Cl"] = c_l value["Cd"] = c_d value["Cm"] = c_m value["Cp"] = c_p lift = c_l * force_reference * 0.0125 * value['chord_length'] drag = c_d * force_reference * 0.0125 * value['chord_length'] value["lift"] = lift value["drag"] = drag # value["torque"] = value["r_position"] * lift * math.sin(math.radians(value["pitch_angle"])) torque = value["r_position"] * ( lift * math.sin(math.radians(value["pitch_angle"])) - drag * math.cos(math.radians(value["pitch_angle"]))) value["torque"] = torque torque_sum += torque xf.reset_bls() # detailed_df = pd.DataFrame.from_dict(dfdict, orient="index") # print(detailed_df) print(torque_sum, angular_velocity) return dfdict, torque_sum
def analyze_airfoil(x, y_u, y_l, cl, rey, mach=0, xf=None, pool=None, show_output=False): """ Analyze an airfoil at a given lift coefficient for given Reynolds and Mach numbers using XFoil. Parameters ---------- x : array_like Airfoil x-coordinates y_u, y_l : array_like Airfoil upper and lower curve y-coordinates cl : float Target lift coefficient rey, mach : float Reynolds and Mach numbers xf : XFoil, optional An instance of the XFoil class to use to perform the analysis. Will be created if not given pool : multiprocessing.ThreadPool, optional An instance of the multiprocessing.Threadpool class used to run the xfoil_worker. Will be created if not given show_output : bool, optional If True, a debug string will be printed after analyses. False by default. Returns ------- cd, cm : float or np.nan Drag and moment coefficients of the airfoil at specified conditions, or nan if XFoil did not run successfully """ # If the lower and upper curves swap, this is a bad, self-intersecting airfoil. Return 1e27 immediately. if np.any(y_l > y_u): return np.nan else: clean_xf = False if xf is None: xf = XFoil() xf.print = show_output clean_xf = True clean_pool = False if pool is None: pool = ThreadPool(processes=1) clean_pool = True xf.airfoil = Airfoil(x=np.concatenate((x[-1:0:-1], x)), y=np.concatenate((y_u[-1:0:-1], y_l))) xf.Re = rey xf.M = mach xf.max_iter = 100 xf.n_crit = 0.1 cd, cm = pool.apply(xfoil_worker, args=(xf, cl)) if clean_xf: del xf if clean_pool: del pool return cd, cm, None if clean_xf else xf
def feature_xfoil(cst_u, cst_l, t, Minf: float, Re, AoA, n_crit=0.1, fname='feature-xfoil.txt'): ''' Evaluate by xfoil and extract features. Inputs: --- cst-u, cst-l: list of upper/lower CST coefficients of the airfoil. \n t: airfoil thickness or None \n Minf: free stream Mach number for wall Mach number calculation \n Re, AoA (deg): flight condition (s), float or list, for Xfoil \n n_crit: critical amplification ratio for transition in xfoil \n fname: output file name. If None, then no output \n ### Dependencies: cst-modeling3d, xfoil ''' from cst_modeling.foil import cst_foil from xfoil import XFoil from xfoil.model import Airfoil #TODO: Build foil #! 201 is the maximum amount of points that xfoil can handle #! tail = 0.001 is to avoid point overlap xx, yu, yl, t0, R0 = cst_foil(201, cst_u, cst_l, x=None, t=t, tail=0.001) #! xfoil do not support leading edge of (0,0) on both upper and lower surface x = np.array(list(reversed(xx[1:])) + xx[1:]) y = np.array(list(reversed(yu[1:])) + yl[1:]) foil = Airfoil(x, y) #TODO: Xfoil xf = XFoil() xf.print = False xf.airfoil = foil xf.max_iter = 40 #* Transition by power law xf.n_crit = n_crit #TODO: Xfoil calculation if not isinstance(Re, list): Re = [Re] AoA = [AoA] n = len(Re) for i in range(n): xf.reset_bls() if Re[i] is not None: xf.Re = Re[i] cl, cd, cm, cp = xf.a(AoA[i]) x, cp = xf.get_cp_distribution() print(xf.Re, AoA[i], cl) #* Extract features fF = PhysicalXfoil(Minf, AoA[i], Re[i]) fF.setdata(x, y, cp) fF.extract_features() #* Output if fname is None: continue if i == 0: f = open(fname, 'w') else: f = open(fname, 'a') f.write('\n') f.write('%10s %15.6f \n' % ('Minf', Minf)) f.write('%10s %15.6f \n' % ('AoA', AoA[i])) f.write('%10s %15.6f \n' % ('Re', Re[i] / 1e6)) f.write('%10s %15.6f \n' % ('CL', cl)) f.write('%10s %15.6f \n' % ('Cd', cd)) f.write('%10s %15.6f \n' % ('Cm', cm)) f.close() fF.output_features(fname=fname, append=True)