1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """The Tjaereborg turbine model. Still in very heavy development
23 but in progress. The documentation is incomplete as the design
24 is being done. This module manipulates however the objects from the
25 L{windSimSuite} and C{mbdyn} packages.
26
27 For more information on the simulated turbine, go to the
28 U{wind data site<http://www.winddata.com/>} done by
29 U{Kurt Schaldemose Hansen<http://www.dtu.dk/Service/Telefonbog.aspx?id=789&type=publications&lg=showcommon>}.
30 Navigate to 'Ressources Data -> 31 tjare -> description'. You can also
31 have a look to the link number 32."""
32 import numpy as N
33 import mbdyn as M
34 import windSimSuite as W
35
36
47
49 self._radius_coeff = (self.middle_radius - self.top_radius) / \
50 (self.aero_height - self.middle_height)
51
56
58 """The diameter is going from middle radius at the middle height
59 to the top radius. For a given height, M{x}, the radius, M{y}, will be::
60
61 y = (middle-radius - top_radius)/(height - middle_height)*(height - x)
62 + top_radius"""
63 if height < self.middle_height:
64 return self.middle_radius
65 else:
66 return self._radius_coeff * (self.aero_height - height) + \
67 self.top_radius
68
70 base_ref = M.ReferenceFrame(self.name + " base")
71 self.refs.add(base_ref, "base")
72
73 top_ref = M.ReferenceFrame(self.name + " mid")
74 top_ref.set_relative_from(base_ref)
75 top_ref.set_position(0., 0., 0.5 * self.height)
76 self.refs.add(top_ref, "mid")
77
78 top_ref = M.ReferenceFrame(self.name + " top")
79 top_ref.set_relative_from(base_ref)
80 top_ref.set_position(0., 0., self.height)
81 self.refs.add(top_ref, "top")
82
83
85
92
93 - def set_yaw(self, value, unit_key="deg"):
94 self._yaw[unit_key] = value
95
96 - def set_tilt(self, value, unit_key="deg"):
97 self._tilt[unit_key] = value
98
101
103 yaw_ref = M.ReferenceFrame(self.name + " yaw")
104 yaw_ref.set_relative_from(self.tower.refs.get("top"))
105 yaw_ref.set_orientation_matrix(three=(0., 0., 1.),
106 one=(N.cos(self._yaw["rad"]),
107 N.sin(self._yaw["rad"]),
108 0.))
109 self.refs.add(yaw_ref, "yaw")
110
111 tilt_ref = M.ReferenceFrame(self.name + " tilt")
112 tilt_ref.set_relative_from(yaw_ref)
113 tilt_ref.set_orientation_matrix(two=(0., 1., 0.),
114 one=(N.cos(self._tilt["rad"]),
115 0.,
116 -N.sin(self._tilt["rad"])))
117 self.refs.add(tilt_ref, "tilt")
118
119 ref = M.ReferenceFrame(self.name)
120 ref.set_relative_from(tilt_ref)
121 ref.set_position(-self.length, 0., 0.)
122 self.refs.add(ref, "fix")
123
124
126 """The node of the hub used by the rotor to
127 find the rotational speed"""
128
130 """Get the rotation matrix of the node,
131 used as a transformation matrix between the absolute reference frame
132 and the local reference frame, the one of the rotor"""
133 self.array = self.mbdyn_inst.get_rotation_matrix()
134 self.matrix = N.asmatrix(self.array)
135
136
138
140 self._direction = N.array([ [-1.],
141 [0.],
142 [0.] ])
143 self.amplitude = self.get_amplitude(self.simulation)
144
146 """Return the amplitude of the torque.
147 The generator model goes at that place.
148 Supposed to be overwritten by the input file
149 and the user model.
150 """
151 pass
152
154 self.amplitude = self.get_amplitude(simu)
155 value = self._direction * self.amplitude
156 rot_matrix = N.asmatrix(self.node.mbdyn_inst.get_rotation_matrix())
157 self.mbdyn_inst.set_value(N.asarray(rot_matrix * value))
158
159
161
167
170
173
175 """Create a first referential on the top of the fix node but
176 rotates its rotation axis and then place the referential
177 following the first blade"""
178 ref_tmp = M.ReferenceFrame("Hub tmp")
179 ref_tmp.set_relative_from(self.nacelle.refs.get("fix"))
180 ref_tmp.set_angular_velocity(rotational_speed["rad/s"], 0., 0.)
181 self.refs.add(ref_tmp, "hub tmp")
182
183 ref = M.ReferenceFrame("Hub")
184 ref.set_relative_from(ref_tmp)
185 ref.set_orientation_matrix(one=(1., 0., 0.),
186 two=(0.,
187 N.cos(wing_angle["rad"]),
188 N.sin(wing_angle["rad"])))
189 self.refs.add(ref, "hub")
190
192 self.node.set_relative_from(self.refs.get("hub"))
193 self.nodes.add(self.node, "hub")
194
196 joint = M.RevoluteHinge("Hub hinge")
197 joint.set_relative_from(self.refs.get("hub"))
198 joint.set_node1(self.nacelle.nodes.get("fix"))
199 joint.set_node2(self.nodes.get("hub"))
200 joint.set_rotation_axis(two=(0., 1., 0.),
201 three=(1., 0., 0.))
202 self.elts.add(joint)
203
205 self.torque.set_relative_from(self.refs.get("hub"))
206 self.torque.set_direction(-1., 0., 0.)
207 self.torque.set_amplitude(0.)
208 self.torque.attach_to_node(self.nodes.get("hub"))
209 self.elts.add(self.torque)
210
212
214 self._direction = N.array([ [0.],
215 [0.],
216 [1.] ])
217
219 self.pitch = blade_pitch
220
222 self.mbdyn_inst.set_value(self.pitch["rad"] * self._direction)
223
226
227
235
237 self.flange_distance = value
238
240 ref = M.ReferenceFrame(self.name + " base")
241 ref.set_relative_from(hub.refs.get("hub"))
242 offset_angle = self.offset_wing_angle["rad"]
243 ref.set_orientation_matrix(one=(1., 0., 0.),
244 two=(0.,
245 N.cos(offset_angle),
246 N.sin(offset_angle)))
247 self.refs.add(ref, "base")
248
249 ref_flange = M.ReferenceFrame(self.name + " flange fix")
250 ref_flange.set_relative_from(ref)
251 ref_flange.set_position(0., 0., self.flange_distance)
252 self.refs.add(ref_flange, "flange fix")
253
254
255 self.pitch_debug = 0.
256 ref = M.ReferenceFrame(self.name + "flange")
257 ref.set_relative_from(ref_flange)
258 ref.set_orientation_matrix(one=(N.cos(self.pitch_debug),
259 N.sin(self.pitch_debug),
260 0.),
261 three=(0., 0., 1.))
262 self.refs.add(ref, "flange")
263
265 node = M.StructuralNode(self.name + "flange")
266 node.set_relative_from(self.refs.get("flange"))
267 self.nodes.add(node, "flange")
268
270 """Add the StructuralNode of the bem nodes that exit
271 to the list of nodes"""
272 for bem_node in self.bem_nodes:
273 ref = M.ReferenceFrame(self.name + " " + bem_node.name)
274 ref.set_relative_from(self.refs.get("flange"))
275 ref.set_position(0.,
276 0.,
277 bem_node.radial_position)
278 self.refs.add(ref)
279
280 bem_node.structural.set_relative_from(ref)
281 bem_node.structural.set_comment("Node properties relative to %s" \
282 % ref.name)
283 self.nodes.add(bem_node.structural)
284
288
290 joint = M.SphericalHinge(self.name + " flange spherical")
291 joint.set_relative_from(self.refs.get("flange"))
292 joint.set_node1(hub.nodes.get("hub"))
293 joint.set_node2(self.nodes.get("flange"))
294 self.elts.add(joint)
295
296
297
298
299
300
301
302 joint = self.pitch_driver
303 joint.set_relative_from(self.refs.get("flange"))
304 joint.set_node1(hub.nodes.get("hub"))
305 joint.set_node2(self.nodes.get("flange"))
306 joint.set_orientation_axis(0., 0., 1.)
307 joint.set_value(self.pitch_debug)
308
309 self.elts.add(joint)
310
312 joint = M.Coincidence(self.name)
313 joint.set_relative_from(self.bem_nodes[0].structural.ref)
314 joint.set_node1(self.nodes.get("flange"))
315 joint.set_node2(self.bem_nodes[0].structural)
316 self.elts.add(joint)
317
319 for idx in range(self.nb_bem_nodes - 1):
320 node1 = self.bem_nodes[idx]
321 node2 = self.bem_nodes[idx + 1]
322
323 joint = M.Coincidence(self.name + " " + str(idx))
324 joint.set_relative_from(node1.structural.ref)
325 joint.set_node1(node1.structural)
326 joint.set_node2(node2.structural)
327 self.elts.add(joint)
328
330 beam = M.Beam3(self.name)
331 beam.set_relative_from(self.refs.get("root"))
332 beam.set_node1(self.nodes.get("root"))
333 beam.set_node2(self.nodes.get("mid"))
334 beam.set_node3(self.nodes.get("tip"))
335
336 beam.section1.set_orientation_matrix(M.EYE)
337 beam.section2.set_orientation_matrix(M.EYE)
338 self._set_stiffness(beam)
339
340 self.elts.add(beam, "beam")
341
343 """By default, the user will give the same constitutive law
344 for the upper and lower part: values are contained in the
345 'stifness' dictionary for a 6D diagonal matrix. As a an alternative,
346 he can manipulate the 'blades[i].beam.section1' instance and set what he
347 wants a law."""
348 law = M.law.LinearElasticGeneric()
349 stiff = self.stiffness
350 law.set_stiffness(diag=(stiff["GA"],
351 stiff["GA"],
352 stiff["EA"],
353 stiff["EIx"],
354 stiff["EIy"],
355 stiff["GIz"]))
356 beam.section1.set_constitutive_law(law)
357 beam.section2.set_constitutive_law(law)
358
371
373 """Update"""
374 pass
375
376
378
380 W.Rotor.__init__(self, name)
381 self.nacelle = None
382
383 self.rotational_speed_value = 0.
384 self.electrical_torque = 0.
385 self.electrical_power = 0.
386 self.will_save("rotational_speed_value",
387 "electrical_torque",
388 "electrical_power")
389
392
398
404
414
423
424
425
426
428 """Save the current status."""
429 self.hub.node.get_matrix()
430 angv = self.hub.node.mbdyn_inst.get_angular_velocity()
431 local_angv = N.asarray(self.hub.node.matrix * angv)
432
433 self.rotational_speed["rad/s"] = float(local_angv[0][0])
434
435 self.rotational_speed_value = self.rotational_speed["rad/s"]
436 self.electrical_torque = self.hub.torque.amplitude
437 self.electrical_power = self.electrical_torque * \
438 self.rotational_speed["rad/s"]
439
440 self.save_results()
441
442 for blade in self.blades:
443 blade.save()
444
446 """Update the value at each time step, before running
447 the unsteady BEM code."""
448 pass
449
450
452 """The wind turbine of a model is mainly supposed to
453 describe two methods: create and update.
454 'create()' is a method called at the beginning to fill
455 the 'refs', 'nodes' and 'elts' lists with MBDyn objects.
456 'update()' is called at each time step and is supposed
457 to update all the wind turbine parameters, according to
458 the MBDyn objects status. Then the unsteady BEM code
459 will be applied. This method must not be
460 confused with the update method called by WraptMBDyn,
461 that is called to update the MBDyn objects before a new
462 time step. This step actually occurs after the unsteady BEM.
463 """
464
465 - def __init__(self, name="tjaerborg", use_beams=True,
466 only_mbdyn_rotor=False):
471
495
497 """Suppose to create the complete turbine.
498 Still in development"""
499 if self.has_tower and self.has_nacelle:
500 self.nacelle.set_tower(self.tower)
501 if self.has_nacelle and self.has_rotor:
502 self.rotor.set_nacelle(self.nacelle)
503
505 """Called by the simulation at each MBDyn
506 time step"""
507 self.rotor.update()
508