def calc_fan_flow(self, iphi=None): """Calculate flow angles.""" if iphi is not None: self.phi = iphi self.psi = 2 * (1 - self.reaction - self.phi * m.tan(r(self.alpha1))) self.u = self.rpm / 60 * 2 * m.pi * self.radius self.beta1 = d(m.atan((1 / self.phi) - m.tan(r(self.alpha1)))) self.beta2 = d( m.atan((2 * self.reaction - 1) / self.phi + m.tan(r(self.alpha1)))) self.betam = d( m.atan((m.tan(r(self.beta1)) + m.tan(r(self.beta2))) / 2)) self.alpha2 = d(m.atan((1 / self.phi) - m.tan(r(self.beta2)))) self.alpham = d( m.atan((m.tan(r(self.alpha1)) + m.tan(r(self.alpha2))) / 2)) self.cx = self.phi * self.u self.w1 = self.cx / m.cos(r(self.beta1)) self.w2 = self.cx / m.cos(r(self.beta2)) self.c1 = self.cx / m.cos(r(self.alpha1)) self.c2 = self.cx / m.cos(r(self.alpha2)) self.wt1 = self.w1 * m.sin(r(self.beta1)) self.wt2 = self.w1 * m.sin(r(self.beta2)) self.ct1 = self.c1 * m.sin(r(self.alpha1)) self.ct2 = self.c2 * m.sin(r(self.alpha2)) # Thermodynamics self.mach = self.cx / m.sqrt(self.GAMMA * self.R * self.t1) self.dt0 = self.psi * (self.u)**2 / self.CP self.t01 = self.t1 * (1 + ((self.GAMMA - 1) * self.mach**2) / 2) self.p01 = self.p1*(1 + ((self.GAMMA - 1)*self.mach**2)/2)\ ** (self.GAMMA/(self.GAMMA - 1)) self.t02 = self.t01 + self.dt0 self.p02 = self.p01 * (self.t02 / self.t01)**(self.GAMMA / (self.GAMMA - 1)) self.t2 = self.t02 / (1 + ((self.GAMMA - 1) * self.mach**2) / 2) self.p2 = self.p02 / ((1 + ( (self.GAMMA - 1) * self.mach**2) / 2)**(self.GAMMA / (self.GAMMA - 1))) self.eta_p = ((self.GAMMA - 1)/self.GAMMA)\ * m.log(self.p2/self.p1)/m.log(self.t2/self.t1) self.eta_c = ((self.p02/self.p01)**(self.GAMMA/(self.GAMMA - 1)) - 1)\ / (self.dt0/self.t01) self.pr = (1 + (self.dt0/self.t01))\ ** (self.GAMMA*self.eta_p/(self.GAMMA-1)) self.cp = (self.p2 - self.p1) / (self.p01 - self.p1) self.work = self.CP * self.dt0 self.torque = self.work / (self.u / self.radius) self.capacity = self.GAMMA/m.sqrt(self.GAMMA - 1)*self.mach\ * (1 + (self.GAMMA - 1)/2*self.mach**2)\ ** (-(1/2)*(self.GAMMA + 1)/(self.GAMMA - 1))
def redefine_task_cs(self, translate_x, translate_y, rotate_z): if not (translate_x == 0 and translate_y == 0 and rotate_z == 0): # calculate movement vector angle current_foot_pos_thorax = self.get_node("foot-thorax") odom_cs = self.cs.parent.parent # leg->thorax->odom foot_pos_odom = odom_cs.to_this(current_foot_pos_thorax) moved_thorax_cs = self.cs.parent.get_derivative("tmp_thorax_for_tcs_vector", translate_x, translate_y, 0, 0, 0, rotate_z) new_foot_pos_thorax = moved_thorax_cs.to_this(foot_pos_odom, caller="redefine_task_cs") dx = new_foot_pos_thorax.x - current_foot_pos_thorax.x dy = new_foot_pos_thorax.y - current_foot_pos_thorax.y angle = d(atan2(dx, dy)) - 180 home_pos = self.home_position_thorax self.task_cs.redefine_tuple(home_pos.tuple, (None, None, -angle)) self.update_swings_inwards() else: self.swings_inwards = None
def calc_joint_angles(self, target_position, best_effort): general_calculation = True position_leg_cs = self.cs.to_this(target_position) angle_coxa = -1 * d(atan2(position_leg_cs.x, position_leg_cs.y)) femur_to_position_projection = 0 femur_segment = self.segments["femur"] femur_length = femur_segment.length tibia_segment = self.segments["tibia"] tibia_length = tibia_segment.length tarsus_segment = self.segments["tarsus"] tarsus_length = tarsus_segment.length coxa_segment = self.segments["coxa"] if best_effort: tgt_tarsus = position_leg_cs.clone tgt_tarsus.z += tarsus_length femur = self.get_node("femur") # check if we can actually reach target_position distance = femur.distance_to(tgt_tarsus) max_dist = femur_length + tibia_length min_dist = third_side(femur_length, tibia_length, 180 + tibia_segment.min_angle) dz = femur.z - tgt_tarsus.z # are we too far? if distance > max_dist: # yep, too far # calculate femur angle to target femur_to_position_projection = sqrt(max_dist ** 2 - dz ** 2) general_calculation = False elif distance < min_dist: # we are too close femur_to_position_projection = sqrt(min_dist ** 2 - dz ** 2) general_calculation = False else: # we are not too close and not too far general_calculation = True if general_calculation: # works either when not best_effort or when best_effort and distance is ok coxa_to_position_projection = sqrt(position_leg_cs.x ** 2 + position_leg_cs.y ** 2) femur_to_position_projection = coxa_to_position_projection - coxa_segment.length distance_to_tarsus_top = sqrt(femur_to_position_projection ** 2 + (position_leg_cs.z + tarsus_length) ** 2) if position_leg_cs.z + tarsus_length == 0: angle_down_to_tarsus_top = 0 else: angle_down_to_tarsus_top = 90 - angle_ab(-1 * (position_leg_cs.z + tarsus_length), distance_to_tarsus_top, femur_to_position_projection) angle_femur = angle_ab(femur_length, distance_to_tarsus_top, tibia_length) - angle_down_to_tarsus_top angle_tibia = -180 + angle_ac(femur_length, distance_to_tarsus_top, tibia_length) angle_tarsus = -180 + 90 - angle_femur - angle_tibia if coxa_segment.min_angle > angle_coxa: if best_effort: angle_coxa = coxa_segment.min_angle else: raise Exception(self.name + " coxa angle too low") elif coxa_segment.max_angle < angle_coxa: if best_effort: angle_coxa = coxa_segment.max_angle else: raise Exception(self.name + " coxa angle too high") if femur_segment.min_angle > angle_femur: if best_effort: angle_femur = femur_segment.min_angle else: raise Exception(self.name + " femur angle too low") elif femur_segment.max_angle < angle_femur: if best_effort: angle_femur = femur_segment.max_angle else: raise Exception(self.name + " femur angle too high") if tibia_segment.min_angle > angle_tibia: if best_effort: angle_tibia = tibia_segment.min_angle else: raise Exception(self.name + " tibia angle too low") elif tibia_segment.max_angle < angle_tibia: if best_effort: angle_tibia = tibia_segment.max_angle else: raise Exception(self.name + " tibia angle too high") if tarsus_segment.min_angle > angle_tarsus: if best_effort: angle_tarsus = tarsus_segment.min_angle else: raise Exception(self.name + " tarsus angle too low") elif tarsus_segment.max_angle < angle_tarsus: if best_effort: angle_tarsus = tarsus_segment.max_angle else: raise Exception(self.name + " tarsus angle too high") return angle_coxa, angle_femur, angle_tibia, angle_tarsus
def create_coord_file(filename: str, plot: bool, xc, yc, kc, bc, xt, yt, kt, bt, cle, cte, wte, rle=0): # pylint: disable=W0613 """Generate airfoil coordinate file.""" bp = { 'x': { 'LET': [0, 0, bt, xt], 'TET': [ xt, 2 * xt - bt, 1 + (0 - (1.5 * kt * (xt - bt)**2 + yt)) * ut.cot(r(wte)), 1 ], 'LEC': [ 0, bc * ut.cot(r(cle)), xc - ((2 * (bc - yc)) / (3 * kc))**0.5, xc ], 'TEC': [ xc, xc + ((2 * (bc - yc)) / (3 * kc))**0.5, 1 + (0 - bc) * ut.cot(r(cte)), 1 ] }, 'y': { 'LET': [0, (1.5 * kt * (xt - bt)**2 + yt), yt, yt], 'TET': [yt, yt, (1.5 * kt * (xt - bt)**2 + yt), 0], 'LEC': [0, bc, yc, yc], 'TEC': [yc, yc, bc, 0] } } c = {'x': [], 'yC': [], 'yT': []} dc = {'xC': [], 'xT': [], 'yC': [], 'yT': []} # x, y coordinates and slopes for LE and TE of T and C bezier curves n_points = 80 for i in range(0, n_points + 1): x = (1 - m.cos(i * m.pi / n_points)) / 2 c['x'].append(x) for j in ['C', 'T']: if j == 'C': xmax = xc elif j == 'T': xmax = xt if x <= xmax: loc = 'LE' bp_xi = bp['x'][loc + j] elif x > xmax: loc = 'TE' bp_xi = bp['x'][loc + j] u_x = [ -bp_xi[0] + 3 * bp_xi[1] - 3 * bp_xi[2] + bp_xi[3], 3 * bp_xi[0] - 6 * bp_xi[1] + 3 * bp_xi[2], -3 * bp_xi[0] + 3 * bp_xi[1], bp_xi[0] - x ] u = [ root.real for root in np.roots(u_x) if root.imag == 0 and 0 <= root <= (1 + 1 / (20 * n_points)) ] u = u[0] c['y' + j].append(bp['y'][loc + j][0] * (1 - u)**3 + 3 * bp['y'][loc + j][1] * (u) * (1 - u)**2 + 3 * bp['y'][loc + j][2] * (u)**2 * (1 - u) + bp['y'][loc + j][3] * (u)**3) for k in ['x', 'y']: dc[k + j].append(bp[k][loc + j][0] * (-3 * (1 - u)**2) + 3 * bp[k][loc + j][1] * (3 * u**2 - 4 * u + 1) + 3 * bp[k][loc + j][2] * (-3 * u**2 + 2 * u) + bp[k][loc + j][3] * (3 * u**2)) theta = [] xu = [] yu = [] xl = [] yl = [] lines = [] for i in range(0, len(c['x'])): # theta[0] is a divide by 0 error theta.append(d(m.atan(dc['yC'][i] / dc['xC'][i]))) xu.append(c['x'][i] - c['yT'][i] * m.sin(r(theta[i]))) yu.append(c['yC'][i] + c['yT'][i] * m.cos(r(theta[i]))) xl.append(c['x'][i] + c['yT'][i] * m.sin(r(theta[i]))) yl.append(c['yC'][i] - c['yT'][i] * m.cos(r(theta[i]))) lines.append([(xu[i], yu[i]), (xl[i], yl[i])]) # Organize coordinates so that xfoil can read them xcoord = list(reversed(xu))[:-1] + xl ycoord = list(reversed(yu))[:-1] + yl # Create airfoil file for xfoil os.chdir('Input') with open(filename, 'w') as datafile: for i, _ in enumerate(xcoord): datafile.write(f' {xcoord[i]:.6f} {ycoord[i]:.6f}\n') os.chdir('..') if plot: lc = mc.LineCollection(lines) _, ax = plt.subplots() ax.add_collection(lc) plt.scatter(c['x'], c['yC'], color='red', marker='^') plt.scatter(c['x'], c['yT'], color='blue', marker='^') plt.scatter(xu, yu, color='green') plt.scatter(xl, yl, color='green') plt.axis('equal') plt.show()
def calcairfoil(self, stage, blade: str, station: str, plot_airfoil=False, plot_ploar=False, plot_cp=False, plot_sv=False): """Calculate Bezier-PARSEC variables and airfoil properties.""" avle, avte, rvle, rvte, v1, v2, radius = ut.get_vars(stage=stage, blade=blade, station=station) cx = v1 * m.cos(r(avle)) u = stage.rpm / 60 * 2 * m.pi * radius betam = d(m.atan((m.tan(r(avle)) + m.tan(r(avte))) / 2)) self.dh = v2 / v1 self.space = (2 * m.pi * radius) / self.z # self.chord = stage.span/self.ar # self.sigma = self.chord/self.space # self.df = ((1 - m.cos(r(avle))/m.cos(r(avte))) # + ((m.cos(r(avle))*(m.tan(r(avle)) - m.tan(r(avte)))) # / (2*self.sigma))) self.sigma = ((m.cos(r(avle)) * (m.tan(r(avle)) - m.tan(r(avte)))) / (2 * (m.cos(r(avle)) / m.cos(r(avte)) - 1 + self.df))) self.chord = self.sigma * self.space # Incidence, deviation, and blade angle calculation self.deflection = abs(avle - avte) self.incidence, _n_slope = ut.calcincidence(thickness=2 * self.yt, solidity=self.sigma, relative_inlet_angle=rvle) self.deviation, _m_slope = ut.calcdeviation(thickness=2 * self.yt, solidity=self.sigma, relative_inlet_angle=rvle) self.blade_angle_i = avle - self.incidence self.blade_angle_e = avte - self.deviation self.camber = abs(self.blade_angle_i - self.blade_angle_e) # Compare to: # self.camber2 = (self.deflection # - (self.incidence # - self.deviation))/(1 - m_slope + n_slope) # self.blade_angle_e2 = self.blade_angle_i + self.camber2 # Assumes double circular arc airfoil to estimate stagger self.stagger = (self.blade_angle_i * self.xcr + self.blade_angle_e * (1 - self.xcr)) self.aoa = abs(self.stagger - avle) # Redefine blade angles to sw blade angles (stagger independent) self.cle = self.blade_angle_i - self.stagger self.cte = self.stagger - self.blade_angle_e # Assume NACA 4 definition of wedge angle and leading edge radius self.rle = 1.1019 * (2 * self.yt)**2 self.wte = 2 * d(m.atan(1.16925 * (2 * self.yt))) # TE radius done in sw # Calculate natural xc,yc from cle and cte using ycr altitutde ratio self.xc = m.tan(r( self.cte)) / (m.tan(r(self.cle)) + m.tan(r(self.cte))) # self.ycr = (self.xc + 1)/2 self.yc = self.ycr * self.xc * abs(m.tan(r(self.cle))) # Assume NACA 4 curvature self.kc, self.kt = ut.curvatures(xc=self.xc, yc=self.yc, xt=self.xt, yt=self.yt) self.bc, self.bt = ut.beziers(xc=self.xc, yc=self.yc, kc=self.kc, xt=self.xt, yt=self.yt, kt=self.kt, cle=self.cle, cte=self.cte, rle=self.rle, blade=blade, station=station) airfoil_name = blade + '_' + station wf.create_coord_file(filename=airfoil_name, plot=plot_airfoil, xc=self.xc, yc=self.yc, kc=self.kc, bc=self.bc, xt=self.xt, yt=self.yt, kt=self.kt, bt=self.bt, cle=self.cle, cte=self.cte, wte=self.wte, rle=self.rle) self.Re = self.rho * v1 * self.chord / self.mu self.polar = xf.find_coefficients(airfoil=airfoil_name, indir='Input', outdir='Output', alpha=self.aoa, Reynolds=self.Re, iteration=500, echo=False, delete=False, NACA=False, PANE=True) self.cp = xf.find_pressure_coefficients(airfoil=airfoil_name, alpha=self.aoa, indir='Input', outdir='Output', Reynolds=self.Re, iteration=500, echo=False, NACA=False, chord=1., PANE=True, delete=False) self.sv = {'x': list(), 'y': list(), 'v': list()} for i in range(len(self.cp['Cp'])): self.sv['x'].append(self.cp['x'][i]) # self.sv['y'].append(self.cp['y'][i]) self.sv['v'].append(m.sqrt(1 - self.cp['Cp'][i])) if plot_cp: plt.plot(self.cp['x'], self.cp['Cp']) plt.show() if plot_sv: plt.plot(self.sv['x'], self.sv['v']) plt.show() if plot_ploar: # Gather multiple angles of attack for airfoil and get polars alphas = list(range(-30, 30)) polars = xf.find_coefficients(airfoil=airfoil_name, alpha=alphas, Reynolds=self.Re, iteration=500, delete=True, echo=False, NACA=False, PANE=True) # Plot airfoil plt.plot(polars['alpha'], polars['CL']) plt.show() try: cl = self.polar['CL'] cd = self.polar['CD'] gamma = m.atan(cd / cl) self._psi = (((cx / u) / 2) * ut.sec(r(betam)) * self.sigma * (cl + cd * m.tan(r(betam)))) self.psi_opt = (((cx / u) / m.sqrt(2)) * self.sigma * (cl + cd)) self.dX = ((self.rho * cx**2 * self.chord * cl / (2 * m.cos(r(betam))**2)) * m.sin(r(betam) - gamma) / m.cos(gamma)) self.dTau = ( (self.rho * cx**2 * self.chord * cl * self.z * radius / (2 * m.cos(r(betam))**2)) * m.cos(r(betam) - gamma) / m.cos(gamma)) self.delta_p = cl * ((self.rho * cx**2 * self.chord / (2 * self.space * m.cos(r(betam))**2)) * m.sin(r(betam) - gamma) / m.cos(gamma)) self.delta_T = (cl / 1.005) * ( (u * cx * self.chord / (2 * self.space * m.cos(r(betam))**2)) * m.cos(r(betam) - gamma) / m.cos(gamma)) self.efficiency = (cx/u)*m.tan(r(betam) - gamma)\ + cx*m.tan(r(rvte))/(2*u) except TypeError: print('Design point did not converge in xfoil.') # pass print(f'{station} {blade} Performance') print(f' DF: {self.df:.2f} (<=0.6)') print(f' DH: {self.dh:.2f} (>=0.72)') print(f' i : {self.incidence:.2f} deg') print(f' d : {self.deviation:.2f} deg') print('\n')
def chk(x): nonlocal nums return sum([d(n/x) for n in nums])