def test__rel_tang_angle(self): airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/naca0018_360' blade = vb.VawtBlade(0.2, airfoil_dir, 1) # VECTORS rel_wind, blade_tangent_vector test_values = [ [vec.Vector2(r=1, theta=1), vec.Vector2(r=1, theta=1.2), -0.2], [vec.Vector2(r=1, theta=1), vec.Vector2(r=1, theta=1.2), -0.2] ] for rel_wind, blade_tangent, rel_tang_angle in test_values: self.assertAlmostEqual(blade._rel_tang_angle(rel_wind, blade_tangent), rel_tang_angle, 5, 'Wrong _rel_tang_angle')
def test_relative_wind(self): test_values = pd.DataFrame( { 'wind_vector': [ vec.Vector2(r=1, theta=1), vec.Vector2(r=2, theta=2), vec.Vector2(r=3, theta=0.5), vec.Vector2(r=4, theta=-1) ], 'blade_tangent_vector': [ vec.Vector2(r=1, theta=-2), vec.Vector2(r=1, theta=-1), vec.Vector2(r=1, theta=0.1), vec.Vector2(r=1, theta=3) ], 'rel_wind_r': [ 0.14, 1.02, 3.94, 3.43 ], 'rel_wind_theta': [ -0.5, 1.86, 0.4, -1.22 ] } ) for index, test_case in test_values.iterrows(): answer = relative_wind(test_case['wind_vector'], test_case['blade_tangent_vector']) self.assertAlmostEqual(answer.r, test_case['rel_wind_r'], 2, 'Wrong relative wind') self.assertAlmostEqual(answer.theta, test_case['rel_wind_theta'], 2, 'Wrong relative wind')
def test_get_wind_vector(self): test_values = [ [-1, 0.5, vec.Vector2(r=0.5, theta=2.14159265359)], [1, 2.5, vec.Vector2(r=2.5, theta=-2.14159265359)], [2, 3.5, vec.Vector2(r=3.5, theta=-1.14159265359)], [3, 4.5, vec.Vector2(r=4.5, theta=-0.14159265359)], [-2, 2, vec.Vector2(r=2, theta=1.14159265359)] ] for tc in test_values: wind_direction = tc[0] wind_speed = tc[1] answer = get_wind_vector(wind_direction, wind_speed) self.assertAlmostEqual(answer.theta, tc[2].theta, 5, 'Wrong get_wind_vector theta') self.assertAlmostEqual(answer.r, tc[2].r, 5, 'Wrong get_wind_vector radius')
def test_blade_chord_vec(self): # calculate blade chord angle on blade_tangent_angle and pitch airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/cp10_360' blade = vb.VawtBlade(0.2, airfoil_dir, 1) test_values = [ # pitch positive - rotates clockwise # positive pitch - 'takes wind under the wing of ascending plane' # positive pitch must be substracted from blade tangent to give actual blade chord vector # blade_tangent_vector, pitch, blade_chord_vector.theta [vec.Vector2(r=1, theta=-2), 1, -1], [vec.Vector2(r=1, theta=-1), -0.5, -1.5], [vec.Vector2(r=1, theta=0.1), 1, 1.1], [vec.Vector2(r=1, theta=3), -1, 2] ] for tc in test_values: answer = blade._blade_chord_vec(tc[0], tc[1]) self.assertAlmostEqual(answer.theta, tc[2], 5, 'Wrong blade chord vector')
def test_angle_of_attack(self): airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/cp10_360' blade = vb.VawtBlade(0.2, airfoil_dir, 1) test_values = [ # rel_wind_vector, blade_chord_vector, aoa_rad, aoa_360 [vec.Vector2(r=1, theta=-2.356194490192345), vec.Vector2(r=1, theta=-1.5707963267948966), -0.785398163397, -45], [vec.Vector2(r=1, theta=-1), vec.Vector2(r=1, theta=-0.0007162025873375634), -0.9992837974126625, -57.25474412755153], [vec.Vector2(r=1, theta=0.1), vec.Vector2(r=1, theta=-2), 2.1, 120.3211369], [vec.Vector2(r=1, theta=3), vec.Vector2(r=1, theta=-2), -1.28318530, -73.5211024] ] for tc in test_values: aoa_rad, aoa_360 = blade._angle_of_attack(tc[0], tc[1]) self.assertAlmostEqual(aoa_rad, tc[2], 5, 'Wrong aoa_rad') self.assertAlmostEqual(aoa_360, tc[3], 5, 'Wrong aoa_360')
def get_visualization_vectors(self, wind_vector, rotor_speed, theta, pitch): vectors = [] # relative wind vector blade_speed = rotor_speed * self.rotor_radius blade_tangent_line_angle = self._blade_tangent_line_angle(theta) blade_tangent_vector = vec.Vector2(r=blade_speed, theta=blade_tangent_line_angle) vectors.append(('blade_tangent', blade_tangent_vector)) rel_wind = relative_wind(wind_vector, blade_tangent_vector) vectors.append(('relative_wind', relative_wind)) re_number = reynolds_number(rel_wind.r, self.chord_length, kinematic_viscosity) blade_chord_vector = self._blade_chord_vec(blade_tangent_vector, pitch) vectors.append(('blade_chord', blade_chord_vector)) aoa_rad, aoa_360 = self._angle_of_attack(rel_wind, blade_chord_vector) cl, cd = self.get_coeffs(aoa_360, re_number) fl = lift_force(air_density, rel_wind.r, self.chord_length, cl) # lift force vector is perpendicular to rel_wind vector fl_vec = vec.Vector2(r=fl, theta=rel_wind.rotated(math.pi / 2).theta) vectors.append(('fl_vec', fl_vec)) fd = drag_force(air_density, rel_wind.r, self.chord_length, cd) # drag force is opposite to rel_wind fd_vec = vec.Vector2(r=fd, theta=rel_wind.rotated(math.pi).theta) vectors.append(('fd_vec', fd_vec)) tf = tangential_force(fl, fd, aoa_rad) # tangential force vector is opposite to blade tangential speed vector tangential_force_vec = vec.Vector2(r=tf, theta=blade_tangent_vector.rotated( math.pi).theta) vectors.append(('tangential_force_vec', tangential_force_vec)) return vectors
def get_tangential_force(self, wind_vector, rotor_speed, theta, pitch): """"Calculate tangential force. Chord length is used instead of area. Parameters ---------- wind_vector : vec vector describes wind speed and direction rotor_speed : float rotor angular speed in rad/s theta : float position of blade relative to rotor 0 position in rad pitch : float angle between blade chord line and tangent line in rad Returns ------- ft : float tangential force """ # relative wind vector try: blade_speed = rotor_speed * self.rotor_radius except TypeError: pass blade_tangent_line_angle = self._blade_tangent_line_angle(theta) blade_tangent_vector = vec.Vector2(r=blade_speed, theta=blade_tangent_line_angle) rel_wind = relative_wind(wind_vector, blade_tangent_vector) re_number = reynolds_number(rel_wind.r, self.chord_length, kinematic_viscosity) blade_chord_vector = self._blade_chord_vec(blade_tangent_vector, pitch) aoa_rad, aoa_360 = self._angle_of_attack(rel_wind, blade_chord_vector) cl, cd = self.get_coeffs(aoa_360, re_number) fl = lift_force(air_density, rel_wind.r, self.chord_length, cl) fd = drag_force(air_density, rel_wind.r, self.chord_length, cd) # casting angle is between rel_wind and blade tangent casting_angle = self._rel_tang_angle(rel_wind, blade_tangent_vector) return tangential_force(fl, fd, casting_angle)
import pandas as pd import numpy as np import matplotlib.pyplot as plt import vec import learn.airfoil_dynamics.ct_plot.vawt_blade as vb import math wind_vector = vec.Vector2(r=3, theta=0) # rotor_speed = 0.0001 rotor_speed = 0.0001 cp10_airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/cp10_360' naca0018_airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/naca0018_360' cp10_blade = vb.VawtBlade(0.2, cp10_airfoil_dir, 1) naca0018_blade = vb.VawtBlade(0.2, naca0018_airfoil_dir, 1) theta_range = [x * math.tau / 360 for x in range(-180, 180, 10)] # theta_range = [vec.normalize_angle(theta) for theta in theta_range] pitch_range = [x * math.tau / 360 for x in range(-90, 90, 10)] # pitch_range = [x*math.tau/360 for x in range(-30, 30, 1)] # theta_range = [x for x in range(0, 10, 1)] # pitch_range = [x for x in range(-8, 7, 1)] thetas = [] for theta in theta_range: theta_ct_polar = [ cp10_blade.get_tangential_force(wind_vector, rotor_speed, theta, pitch) for pitch in pitch_range ] thetas.append(theta_ct_polar)
import pandas as pd import numpy as np import matplotlib.pyplot as plt import vec import learn.airfoil_dynamics.ct_plot.vawt_blade as vb import math # plots tangential force in function of aoa and rotora blade theta wind_vector = vec.Vector2(r=3, theta=2) # rotor_speed = 0.0001 rotor_speed = 0.0001 # airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/cp10_360' airfoil_dir = '/home/aa/vawt_env/learn/AeroDyn polars/naca0018_360' blade = vb.VawtBlade(0.2, airfoil_dir, 1) reynolds_range = [x * 10000 for x in range(10, 100, 10)] # theta_range = [vec.normalize_angle(theta) for theta in theta_range] aoa_range = [x for x in range(-180, 179, 10)] cl_list = [] cd_list = [] for re_num in reynolds_range: cl_polar = [blade.get_coeffs(aoa_360, re_num)[0] for aoa_360 in aoa_range] cd_polar = [blade.get_coeffs(aoa_360, re_num)[1] for aoa_360 in aoa_range] cl_list.append(cl_polar) cd_list.append(cd_polar) df_cl = pd.DataFrame(cl_list, index=reynolds_range, columns=aoa_range) df_cd = pd.DataFrame(cd_list, index=reynolds_range, columns=aoa_range)
def rotate(vector2d, angle_radians): x, y = vector2d.x, vector2d.y xx = x * math.cos(angle_radians) - y * math.sin(angle_radians) yy = x * math.sin(angle_radians) + y * math.cos(angle_radians) return vec.Vector2(xx, yy)
def translate(vector2d, displacement_x, displacement_y): displacement_vector = vec.Vector2(displacement_x, displacement_y) return vector2d + displacement_vector