1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """The rotor and hub definitions.
23 """
24 import numpy as N
25
26 from windSimSuite.references import REFERENCE_FRAME, ReferenceFrames
27 from windSimSuite.common import BasicObject, ObjectWithNodesAndElems
28 from windSimSuite.common import RotationalSpeed, Angle
29 from windSimSuite.blade import Blade
30
31 -class Hub(ObjectWithNodesAndElems):
32 """The hub definition, it concerns only the MBDyn part
33 """
34
37
38
40 """The unsteady BEM calculations applied on the rotor.
41 """
42
44 self.rotational_speed = RotationalSpeed()
45 self.delta = 2.*N.pi / 100.
46 self.wing_angle = Angle(0., "deg")
47
48 self.tangential_force = 0.
49 self.normal_force = 0.
50 self.torque = 0.
51 self.power = 0.
52
53 self.skew_radius_ratio = 0.7
54 self.prandtl_blade_ratio = 0.9
55
56 self.force = {}
57
59 """Set the wing angle for the rotor and recalculate
60 the corresponding reference frame.
61
62 @type value: a float
63 @param value: the wing value
64
65 @type unit: a string
66 @param unit: the 'rad' or 'deg' value"""
67 self.wing_angle[unit] = value
68 for blade in self.blades:
69 blade.set_wing_angle(self.wing_angle, unit)
70
72 """Update the values entered by the user on the blades.
73 The wing angle information passes from the rotor to
74 the blades."""
75 for blade in self.blades:
76 blade.set_wing_angle(self.wing_angle, "rad")
77
83
85 """Get the angle of the deepest point into the wake,
86 depend of the yaw and tilt angles.
87 Due to the orientation, all the M{x} values are positive.
88 The deepest point into the wake is the one with
89 the maximum M{x} value.
90 """
91 rotation_values = N.arange(2.*N.pi, -self.delta, -self.delta) + \
92 self.wing_angle["rad"]
93 blade = self.blades[0]
94 radius_test = N.matrix([ [0.],
95 [0.],
96 [10.] ])
97 xlist = []
98 for wing_angle in rotation_values:
99 self.set_wing_angle(wing_angle, "rad")
100 mat = blade.references.get_matrix_from("cone")
101 absolute_vec = mat * radius_test
102 xlist.append(absolute_vec[0][0])
103 x_deepest_pt = max(xlist)
104 self.deepest_pt_angle = rotation_values[xlist.index(x_deepest_pt)]
105
107 """Set the rotor rotational speed.
108
109 @type value: a float
110 @param value: the rotational speed value
111
112 @type unit_key: a string
113 @param unit_key: the 'rad/s' or 'rpm' value"""
114 self.rotational_speed[unit_key] = value
115
117 """Find the wing angle from the time and rotational speed value.
118 The time is supposed to be in seconds."""
119 wing_angle = self.rotational_speed["rad/s"] * time
120 self.set_wing_angle(wing_angle, "rad")
121
123 """Return the Prandtl correction factor"""
124
125 blade_radius = blade.radius
126
127
128 num = self.nb_blades * (blade_radius - section.radial_position)
129 dem = 2. * section.radial_position * N.sin(section.flow_angle["rad"])
130 factor = num/dem
131 return 2. * N.arccos(N.exp(-factor)) / N.pi
132
133
135 """The same induced velocity is calculated for the the whole wake"""
136 for sid in range(self.blades[0].nb_sections):
137 velocity_sum = N.zeros((3,1))
138 for blade in self.blades:
139 velocity_sum += blade.sections[sid].induced_velocity["cu"]
140 averaged_velocity = velocity_sum / self.nb_blades
141 for blade in self.blades:
142 blade.sections[sid].induced_velocity["cu"] = \
143 averaged_velocity.copy()
144
146 """Find the section used to compute the skew angle"""
147 blade_test = self.blades[0]
148 radius_list = []
149 for section in blade_test.sections:
150 radius_list.append(section.radial_position)
151 skew_section_radius = self.skew_radius_ratio * blade_test.radius
152 indices = N.where(N.asarray(radius_list) <= skew_section_radius)
153 low_id = int(indices[0][-1])
154 high_id = low_id + 1
155 low_dist = skew_section_radius - \
156 blade_test.sections[low_id].radial_position
157 high_dist = blade_test.sections[high_id].radial_position - \
158 skew_section_radius
159 if high_dist < low_dist:
160 return high_id
161 else:
162 return low_id
163
171
173 """Apply the yaw model, a restoring couple when the
174 rotor is not facing the wind"""
175 for blade in self.blades:
176 yaw_model_coeff = blade.get_yaw_model_coeff(self)
177 for section in blade.sections:
178 section.induced_velocity["cu"] *= yaw_model_coeff
179
181 """Update the induced velocity for the whole wake.
182 There are still problems with the yaw model"""
183 self._average_induced_velocity()
184
185
187 """Supposed to return a velocity correction in
188 the tower shadow model but not yet used"""
189 lim = N.pi/18.
190 theta = N.fmod(self.wing_angle["rad"], 2*N.pi)
191 if (N.pi/2.-0.35) <= theta < (N.pi-lim):
192 K=1.2/(N.pi/2.-lim)
193 return K*(theta - N.pi/2.)
194 elif (N.pi-lim) <= theta <= (N.pi+lim):
195 return 1
196 elif (N.pi+lim) < theta <= (3*N.pi/2.+0.35):
197 K = -1.2/(N.pi/2.-lim)
198 return K*(theta - 3*N.pi/2.)
199 else:
200 print "It happens?"
201 return 1
202
204 """Get the forces, tangential and normal,
205 as well as the torque and power on the rotor.
206 Do not return any values but store them as attributes"""
207 self.power = 0.
208 self.torque = 0.
209 for fkey in ["tangential", "normal"]:
210 self.force[fkey] = 0.
211 for blade in self.blades:
212 self.power += blade.power
213 self.torque += blade.torque
214 for fkey in ["tangential", "normal"]:
215 self.force[fkey] += blade.force[fkey]
216 self.tangential_force = self.force["tangential"]
217 self.normal_force = self.force["normal"]
218
219
220 -class Rotor(AerodynamicsRotor, BasicObject):
221 """The rotor manipulated by the user. It gathers the
222 aerodynamics calculations and the MBDyn part.
223 """
224
226 AerodynamicsRotor.__init__(self)
227 BasicObject.__init__(self, name)
228
229 self.blades = []
230 self.blade_paras = []
231 self.nb_blades = 0
232
233 self.hub = None
234 self.hub_para = None
235 self.has_hub = False
236
237 self.rotational_speed_value = 0.
238 self.will_save("tangential_force",
239 "normal_force",
240 "torque",
241 "power",
242 "rotational_speed_value")
243
244 self.own_para_names += ["blade_paras",
245 "has_hub",
246 "hub_para",
247 "rotational_speed"]
248
250 """Set the C{Hub} instance from L{windSimSuite.rotor}"""
251 self.hub = hub
252 self.has_hub = True
253
255 """Add a C{Blade} instance from L{windSimSuite.blade}"""
256 self.blades.append(blade)
257 self.nb_blades += 1
258
266
273
275 """Init the results for the rotor as well as for the blades"""
276 self.common_init_results()
277
278 for blade in self.blades:
279 blade.init_results()
280
282 """Save the unsteady values"""
283 self.save_results()
284 for blade in self.blades:
285 blade.save()
286
288 """Collect the rotor parameters in a dictionary"""
289 if self.has_hub:
290 self.hub.collect_parameters()
291 self.hub_para = self.hub.para
292 for blade in self.blades:
293 blade.collect_parameters()
294 self.blade_paras.append(blade.para)
295 self.collect_own_parameters()
296
308