-
Notifications
You must be signed in to change notification settings - Fork 88
/
DISCON_ITIBarge.F90
604 lines (435 loc) · 36.1 KB
/
DISCON_ITIBarge.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
!**********************************************************************************************************************************
! LICENSING
! Copyright (C) 2015-2016 National Renewable Energy Laboratory
! Copyright (C) 2016-2017 Envision Energy USA, LTD
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
! http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!**********************************************************************************************************************************
SUBROUTINE DISCON ( avrSWAP, aviFAIL, accINFILE, avcOUTNAME, avcMSG ) BIND (C, NAME='DISCON')
! This Bladed-style DLL controller is used to implement a variable-speed
! generator-torque controller and PI collective blade pitch controller for
! the NREL Offshore 5MW baseline wind turbine. This routine was written by
! J. Jonkman of NREL/NWTC for use in the IEA Annex XXIII OC3 studies.
! Modified for the ITI Barge configuration.
! Modified by B. Jonkman to conform to ISO C Bindings (standard Fortran 2003) and
! compile with either gfortran or Intel Visual Fortran (IVF)
! DO NOT REMOVE or MODIFY LINES starting with "!DEC$" or "!GCC$"
! !DEC$ specifies attributes for IVF and !GCC$ specifies attributes for gfortran.
!
! Note that gfortran v5.x on Mac produces compiler errors with the DLLEXPORT attribute,
! so I've added the compiler directive IMPLICIT_DLLEXPORT.
USE, INTRINSIC :: ISO_C_Binding
IMPLICIT NONE
#ifndef IMPLICIT_DLLEXPORT
!DEC$ ATTRIBUTES DLLEXPORT :: DISCON
!GCC$ ATTRIBUTES DLLEXPORT :: DISCON
#endif
! Passed Variables:
REAL(C_FLOAT), INTENT(INOUT) :: avrSWAP (*) ! The swap array, used to pass data to, and receive data from, the DLL controller.
INTEGER(C_INT), INTENT(INOUT) :: aviFAIL ! A flag used to indicate the success of this DLL call set as follows: 0 if the DLL call was successful, >0 if the DLL call was successful but cMessage should be issued as a warning messsage, <0 if the DLL call was unsuccessful or for any other reason the simulation is to be stopped at this point with cMessage as the error message.
CHARACTER(KIND=C_CHAR), INTENT(IN) :: accINFILE (NINT(avrSWAP(50))) ! The name of the parameter input file, 'DISCON.IN'.
CHARACTER(KIND=C_CHAR), INTENT(IN) :: avcOUTNAME(NINT(avrSWAP(51))) ! OUTNAME (Simulation RootName)
CHARACTER(KIND=C_CHAR), INTENT(INOUT) :: avcMSG (NINT(avrSWAP(49))) ! MESSAGE (Message from DLL to simulation code [ErrMsg]) The message which will be displayed by the calling program if aviFAIL <> 0.
! Local Variables:
REAL(4) :: Alpha ! Current coefficient in the recursive, single-pole, low-pass filter, (-).
REAL(4) :: BlPitch (3) ! Current values of the blade pitch angles, rad.
REAL(4) :: ElapTime ! Elapsed time since the last call to the controller, sec.
REAL(4), PARAMETER :: CornerFreq = 1.570796 ! Corner frequency (-3dB point) in the recursive, single-pole, low-pass filter, rad/s. -- chosen to be 1/4 the blade edgewise natural frequency ( 1/4 of approx. 1Hz = 0.25Hz = 1.570796rad/s)
REAL(4) :: GenSpeed ! Current HSS (generator) speed, rad/s.
REAL(4), SAVE :: GenSpeedF ! Filtered HSS (generator) speed, rad/s.
REAL(4) :: GenTrq ! Electrical generator torque, N-m.
REAL(4) :: GK ! Current value of the gain correction factor, used in the gain scheduling law of the pitch controller, (-).
REAL(4) :: HorWindV ! Horizontal hub-heigh wind speed, m/s.
REAL(4), SAVE :: IntSpdErr ! Current integral of speed error w.r.t. time, rad.
REAL(4), SAVE :: LastGenTrq ! Commanded electrical generator torque the last time the controller was called, N-m.
REAL(4), SAVE :: LastTime ! Last time this DLL was called, sec.
REAL(4), SAVE :: LastTimePC ! Last time the pitch controller was called, sec.
REAL(4), SAVE :: LastTimeVS ! Last time the torque controller was called, sec.
REAL(4), PARAMETER :: OnePlusEps = 1.0 + EPSILON(OnePlusEps) ! The number slighty greater than unity in single precision.
REAL(4), PARAMETER :: PC_DT = 0.00125 !JASON:THIS CHANGED FOR ITI BARGE: 0.0001 ! Communication interval for pitch controller, sec.
REAL(4), PARAMETER :: PC_KI = 0.003586059 !JASON:REDUCED GAIN 0.008068634 ! Integral gain for pitch controller at rated pitch (zero), (-). !JASON: -0.003134 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: PC_KK = 0.1099965 ! Pitch angle where the the derivative of the aerodynamic power w.r.t. pitch has increased by a factor of two relative to the derivative at rated pitch (zero), rad. !JASON: 9999.9 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: PC_KP = 0.01255121 !JASON:REDUCED GAIN: 0.01882681 ! Proportional gain for pitch controller at rated pitch (zero), sec. !JASON: -0.007312 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: PC_MaxPit = 1.570796 ! Maximum pitch setting in pitch controller, rad. !JASON: 0.0 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: PC_MaxRat = 0.1396263 ! Maximum pitch rate (in absolute value) in pitch controller, rad/s.
REAL(4), PARAMETER :: PC_MinPit = 0.0 ! Minimum pitch setting in pitch controller, rad. !JASON: -1.570796 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: PC_RefSpd = 122.9096 ! Desired (reference) HSS speed for pitch controller, rad/s.
REAL(4), SAVE :: PitCom (3) ! Commanded pitch of each blade the last time the controller was called, rad.
REAL(4) :: PitComI ! Integral term of command pitch, rad.
REAL(4) :: PitComP ! Proportional term of command pitch, rad.
REAL(4) :: PitComT ! Total command pitch based on the sum of the proportional and integral terms, rad.
REAL(4) :: PitRate (3) ! Pitch rates of each blade based on the current pitch angles and current pitch command, rad/s.
REAL(4), PARAMETER :: R2D = 57.295780 ! Factor to convert radians to degrees.
REAL(4), PARAMETER :: RPS2RPM = 9.5492966 ! Factor to convert radians per second to revolutions per minute.
REAL(4) :: SpdErr ! Current speed error, rad/s.
REAL(4) :: Time ! Current simulation time, sec.
REAL(4) :: TrqRate ! Torque rate based on the current and last torque commands, N-m/s.
REAL(4), PARAMETER :: VS_CtInSp = 70.16224 ! Transitional generator speed (HSS side) between regions 1 and 1 1/2, rad/s.
REAL(4), PARAMETER :: VS_DT = 0.00125 !JASON:THIS CHANGED FOR ITI BARGE: 0.0001 ! Communication interval for torque controller, sec.
REAL(4), PARAMETER :: VS_MaxRat = 15000.0 ! Maximum torque rate (in absolute value) in torque controller, N-m/s.
REAL(4), PARAMETER :: VS_MaxTq = 47402.91 ! Maximum generator torque in Region 3 (HSS side), N-m. -- chosen to be 10% above VS_RtTq = 43.09355kNm
REAL(4), PARAMETER :: VS_Rgn2K = 2.332287 ! Generator torque constant in Region 2 (HSS side), N-m/(rad/s)^2.
REAL(4), PARAMETER :: VS_Rgn2Sp = 91.21091 ! Transitional generator speed (HSS side) between regions 1 1/2 and 2, rad/s.
REAL(4), PARAMETER :: VS_Rgn3MP = 0.01745329 ! Minimum pitch angle at which the torque is computed as if we are in region 3 regardless of the generator speed, rad. -- chosen to be 1.0 degree above PC_MinPit !JASON: -0.01745329 !JASON:MODIFICATION FOR PITCH TO STALL
REAL(4), PARAMETER :: VS_RtGnSp = 121.6805 ! Rated generator speed (HSS side), rad/s. -- chosen to be 99% of PC_RefSpd
REAL(4), PARAMETER :: VS_RtPwr = 5296610.0 ! Rated generator generator power in Region 3, Watts. -- chosen to be 5MW divided by the electrical generator efficiency of 94.4%
REAL(4), SAVE :: VS_Slope15 ! Torque/speed slope of region 1 1/2 cut-in torque ramp , N-m/(rad/s).
REAL(4), SAVE :: VS_Slope25 ! Torque/speed slope of region 2 1/2 induction generator, N-m/(rad/s).
REAL(4), PARAMETER :: VS_SlPc = 10.0 ! Rated generator slip percentage in Region 2 1/2, %.
REAL(4), SAVE :: VS_SySp ! Synchronous speed of region 2 1/2 induction generator, rad/s.
REAL(4), SAVE :: VS_TrGnSp ! Transitional generator speed (HSS side) between regions 2 and 2 1/2, rad/s.
REAL(4), SAVE :: LastSpdErr !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
REAL(4) :: DSpdErrDT !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
REAL(4), PARAMETER :: PC_KD = 0.0 !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
REAL(4) :: PitComD !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
REAL(4) :: YawBrTAxp !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
REAL(4), SAVE :: YawBrTVxp !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
REAL(4), SAVE :: PitComTF !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
INTEGER(4) :: I ! Generic index.
INTEGER(4) :: iStatus ! A status flag set by the simulation as follows: 0 if this is the first call, 1 for all subsequent time steps, -1 if this is the final call at the end of the simulation.
INTEGER(4) :: K ! Loops through blades.
INTEGER(4) :: NumBl ! Number of blades, (-).
INTEGER(4), PARAMETER :: UnDb = 85 ! I/O unit for the debugging information
INTEGER(4), PARAMETER :: Un = 87 ! I/O unit for pack/unpack (checkpoint & restart)
INTEGER(4) :: ErrStat
!JASON:LOGICAL(1), SAVE :: HSSBrOn = .FALSE. !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
LOGICAL(1), PARAMETER :: PC_DbgOut = .FALSE. ! Flag to indicate whether to output debugging information
CHARACTER( 1), PARAMETER :: Tab = CHAR( 9 ) ! The tab character.
CHARACTER( 25), PARAMETER :: FmtDat = "(F8.3,99('"//Tab//"',ES10.3E2,:))" ! The format of the debugging data
CHARACTER(SIZE(accINFILE)-1) :: InFile ! a Fortran version of the input C string (not considered an array here) [subtract 1 for the C null-character]
CHARACTER(SIZE(avcOUTNAME)-1):: RootName ! a Fortran version of the input C string (not considered an array here) [subtract 1 for the C null-character]
CHARACTER(SIZE(avcMSG)-1) :: ErrMsg ! a Fortran version of the C string argument (not considered an array here) [subtract 1 for the C null-character]
! Load variables from calling program (See Appendix A of Bladed User's Guide):
iStatus = NINT( avrSWAP( 1) )
NumBl = NINT( avrSWAP(61) )
BlPitch (1) = avrSWAP( 4)
BlPitch (2) = avrSWAP(33)
BlPitch (3) = avrSWAP(34)
GenSpeed = avrSWAP(20)
HorWindV = avrSWAP(27)
Time = avrSWAP( 2)
YawBrTAxp = avrSWAP(53) !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
! Convert C character arrays to Fortran strings:
RootName = TRANSFER( avcOUTNAME(1:LEN(RootName)), RootName )
I = INDEX(RootName,C_NULL_CHAR) - 1 ! if this has a c null character at the end...
IF ( I > 0 ) RootName = RootName(1:I) ! remove it
InFile = TRANSFER( accINFILE(1:LEN(InFile)), InFile )
I = INDEX(InFile,C_NULL_CHAR) - 1 ! if this has a c null character at the end...
IF ( I > 0 ) InFile = InFile(1:I) ! remove it
! Initialize aviFAIL to 0:
aviFAIL = 0
! Read any External Controller Parameters specified in the User Interface
! and initialize variables:
IF ( iStatus == 0 ) THEN ! .TRUE. if we're on the first call to the DLL
! Inform users that we are using this user-defined routine:
aviFAIL = 1
ErrMsg = 'Running with torque and pitch control of the NREL offshore '// &
'5MW baseline wind turbine from DISCON.dll as written by J. '// &
'Jonkman of NREL/NWTC for use in the IEA Annex XXIII OC3 ' // &
'studies. Includes modifications for ITI Barge.'
! Determine some torque control parameters not specified directly:
VS_SySp = VS_RtGnSp/( 1.0 + 0.01*VS_SlPc )
VS_Slope15 = ( VS_Rgn2K*VS_Rgn2Sp*VS_Rgn2Sp )/( VS_Rgn2Sp - VS_CtInSp )
VS_Slope25 = ( VS_RtPwr/VS_RtGnSp )/( VS_RtGnSp - VS_SySp )
IF ( VS_Rgn2K == 0.0 ) THEN ! .TRUE. if the Region 2 torque is flat, and thus, the denominator in the ELSE condition is zero
VS_TrGnSp = VS_SySp
ELSE ! .TRUE. if the Region 2 torque is quadratic with speed
VS_TrGnSp = ( VS_Slope25 - SQRT( VS_Slope25*( VS_Slope25 - 4.0*VS_Rgn2K*VS_SySp ) ) )/( 2.0*VS_Rgn2K )
ENDIF
! Check validity of input parameters:
IF ( CornerFreq <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'CornerFreq must be greater than zero.'
ENDIF
IF ( VS_DT <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_DT must be greater than zero.'
ENDIF
IF ( VS_CtInSp < 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_CtInSp must not be negative.'
ENDIF
IF ( VS_Rgn2Sp <= VS_CtInSp ) THEN
aviFAIL = -1
ErrMsg = 'VS_Rgn2Sp must be greater than VS_CtInSp.'
ENDIF
IF ( VS_TrGnSp < VS_Rgn2Sp ) THEN
aviFAIL = -1
ErrMsg = 'VS_TrGnSp must not be less than VS_Rgn2Sp.'
ENDIF
IF ( VS_SlPc <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_SlPc must be greater than zero.'
ENDIF
IF ( VS_MaxRat <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_MaxRat must be greater than zero.'
ENDIF
IF ( VS_RtPwr < 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_RtPwr must not be negative.'
ENDIF
IF ( VS_Rgn2K < 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'VS_Rgn2K must not be negative.'
ENDIF
IF ( VS_Rgn2K*VS_RtGnSp*VS_RtGnSp > VS_RtPwr/VS_RtGnSp ) THEN
aviFAIL = -1
ErrMsg = 'VS_Rgn2K*VS_RtGnSp^2 must not be greater than VS_RtPwr/VS_RtGnSp.'
ENDIF
IF ( VS_MaxTq < VS_RtPwr/VS_RtGnSp ) THEN
aviFAIL = -1
ErrMsg = 'VS_RtPwr/VS_RtGnSp must not be greater than VS_MaxTq.'
ENDIF
IF ( PC_DT <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'PC_DT must be greater than zero.'
ENDIF
IF ( PC_KI == 0.0 ) THEN !JASON:MODIFICATION FOR PITCH TO STALL IF ( PC_KI <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'PC_KI must not be zero.' !JASON:MODIFICATION FOR PITCH TO STALL ErrMsg = 'PC_KI must be greater than zero.'
ENDIF
IF ( PC_KK <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'PC_KK must be greater than zero.'
ENDIF
IF ( PC_RefSpd <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'PC_RefSpd must be greater than zero.'
ENDIF
IF ( PC_MaxRat <= 0.0 ) THEN
aviFAIL = -1
ErrMsg = 'PC_MaxRat must be greater than zero.'
ENDIF
IF ( PC_MinPit >= PC_MaxPit ) THEN
aviFAIL = -1
ErrMsg = 'PC_MinPit must be less than PC_MaxPit.'
ENDIF
! If we're debugging the pitch controller, open the debug file and write the
! header:
IF ( PC_DbgOut ) THEN
OPEN ( UnDb, FILE=TRIM( RootName )//'.dbg', STATUS='REPLACE' )
WRITE (UnDb,'(/////)')
WRITE (UnDb,'(A)') 'Time '//Tab//'ElapTime'//Tab//'HorWindV'//Tab//'GenSpeed'//Tab//'GenSpeedF'//Tab//'RelSpdErr'//Tab// &
'SpdErr '//Tab//'IntSpdErr'//Tab//'GK '//Tab//'PitComP'//Tab//'PitComI'//Tab//'PitComT'//Tab// &
'PitRate1'//Tab//'PitCom1'
WRITE (UnDb,'(A)') '(sec)'//Tab//'(sec) '//Tab//'(m/sec) '//Tab//'(rpm) '//Tab//'(rpm) '//Tab//'(%) '//Tab// &
'(rad/s)'//Tab//'(rad) '//Tab//'(-)'//Tab//'(deg) '//Tab//'(deg) '//Tab//'(deg) '//Tab// &
'(deg/s) '//Tab//'(deg) '
ENDIF
! Initialize the SAVEd variables:
! NOTE: LastGenTrq, though SAVEd, is initialized in the torque controller
! below for simplicity, not here.
LastSpdErr = GenSpeed - PC_RefSpd !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
YawBrTVxp = 0.0 !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
PitComTF = 0.0 !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
GenSpeedF = GenSpeed ! This will ensure that generator speed filter will use the initial value of the generator speed on the first pass
PitCom = BlPitch ! This will ensure that the variable speed controller picks the correct control region and the pitch controller picks the correct gain on the first call
GK = 1.0/( 1.0 + PitCom(1)/PC_KK ) ! This will ensure that the pitch angle is unchanged if the initial SpdErr is zero
IntSpdErr = PitCom(1)/( GK*PC_KI ) ! This will ensure that the pitch angle is unchanged if the initial SpdErr is zero
LastTime = Time ! This will ensure that generator speed filter will use the initial value of the generator speed on the first pass
LastTimePC = Time - PC_DT ! This will ensure that the pitch controller is called on the first pass
LastTimeVS = Time - VS_DT ! This will ensure that the torque controller is called on the first pass
ENDIF
BlPitch = BlPitch - PitComTF !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
! Main control calculations:
IF ( ( iStatus >= 0 ) .AND. ( aviFAIL >= 0 ) ) THEN ! Only compute control calculations if no error has occured and we are not on the last time step
! Abort if the user has not requested a pitch angle actuator (See Appendix A
! of Bladed User's Guide):
IF ( NINT(avrSWAP(10)) /= 0 ) THEN ! .TRUE. if a pitch angle actuator hasn't been requested
aviFAIL = -1
ErrMsg = 'Pitch angle actuator not requested.'
ENDIF
! Set unused outputs to zero (See Appendix A of Bladed User's Guide):
avrSWAP(36) = 0.0 ! Shaft brake status: 0=off!JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED: avrSWAP(36) = 0.0 ! Shaft brake status: 0=off
avrSWAP(41) = 0.0 ! Demanded yaw actuator torque
avrSWAP(46) = 0.0 ! Demanded pitch rate (Collective pitch)
avrSWAP(48) = 0.0 ! Demanded nacelle yaw rate
avrSWAP(65) = 0.0 ! Number of variables returned for logging
avrSWAP(72) = 0.0 ! Generator start-up resistance
avrSWAP(79) = 0.0 ! Request for loads: 0=none
avrSWAP(80) = 0.0 ! Variable slip current status
avrSWAP(81) = 0.0 ! Variable slip current demand
!=======================================================================
! Filter the HSS (generator) speed measurement:
! NOTE: This is a very simple recursive, single-pole, low-pass filter with
! exponential smoothing.
! Update the coefficient in the recursive formula based on the elapsed time
! since the last call to the controller:
Alpha = EXP( ( LastTime - Time )*CornerFreq )
! Apply the filter:
GenSpeedF = ( 1.0 - Alpha )*GenSpeed + Alpha*GenSpeedF
!=======================================================================
! Variable-speed torque control:
! Compute the elapsed time since the last call to the controller:
ElapTime = Time - LastTimeVS
! Only perform the control calculations if the elapsed time is greater than
! or equal to the communication interval of the torque controller:
! NOTE: Time is scaled by OnePlusEps to ensure that the contoller is called
! at every time step when VS_DT = DT, even in the presence of
! numerical precision errors.
IF ( ( Time*OnePlusEps - LastTimeVS ) >= VS_DT ) THEN
! Compute the generator torque, which depends on which region we are in:
IF ( ( GenSpeedF >= VS_RtGnSp ) .OR. ( PitCom(1) >= VS_Rgn3MP ) ) THEN ! We are in region 3 - power is constant !JASON:IF ( ( GenSpeedF >= VS_RtGnSp ) .OR. ( PitCom(1) <= VS_Rgn3MP ) ) THEN !JASON:MODIFICATION FOR PITCH TO STALL
GenTrq = VS_RtPwr/GenSpeedF
ELSEIF ( GenSpeedF <= VS_CtInSp ) THEN ! We are in region 1 - torque is zero
GenTrq = 0.0
ELSEIF ( GenSpeedF < VS_Rgn2Sp ) THEN ! We are in region 1 1/2 - linear ramp in torque from zero to optimal
GenTrq = VS_Slope15*( GenSpeedF - VS_CtInSp )
ELSEIF ( GenSpeedF < VS_TrGnSp ) THEN ! We are in region 2 - optimal torque is proportional to the square of the generator speed
GenTrq = VS_Rgn2K*GenSpeedF*GenSpeedF
ELSE ! We are in region 2 1/2 - simple induction generator transition region
GenTrq = VS_Slope25*( GenSpeedF - VS_SySp )
ENDIF
! Saturate the commanded torque using the maximum torque limit:
GenTrq = MIN( GenTrq , VS_MaxTq ) ! Saturate the command using the maximum torque limit
! Saturate the commanded torque using the torque rate limit:
IF ( iStatus == 0 ) LastGenTrq = GenTrq ! Initialize the value of LastGenTrq on the first pass only
TrqRate = ( GenTrq - LastGenTrq )/ElapTime ! Torque rate (unsaturated)
TrqRate = MIN( MAX( TrqRate, -VS_MaxRat ), VS_MaxRat ) ! Saturate the torque rate using its maximum absolute value
GenTrq = LastGenTrq + TrqRate*ElapTime ! Saturate the command using the torque rate limit
! Reset the values of LastTimeVS and LastGenTrq to the current values:
LastTimeVS = Time
LastGenTrq = GenTrq
ENDIF
! Set the generator contactor status, avrSWAP(35), to main (high speed)
! variable-speed generator, the torque override to yes, and command the
! generator torque (See Appendix A of Bladed User's Guide):
avrSWAP(35) = 1.0 ! Generator contactor status: 1=main (high speed) variable-speed generator
avrSWAP(56) = 0.0 ! Torque override: 0=yes
avrSWAP(47) = LastGenTrq ! Demanded generator torque
!=======================================================================
! Pitch control:
! Compute the elapsed time since the last call to the controller:
ElapTime = Time - LastTimePC
! Only perform the control calculations if the elapsed time is greater than
! or equal to the communication interval of the pitch controller:
! NOTE: Time is scaled by OnePlusEps to ensure that the contoller is called
! at every time step when PC_DT = DT, even in the presence of
! numerical precision errors.
IF ( ( Time*OnePlusEps - LastTimePC ) >= PC_DT ) THEN
! Compute the gain scheduling correction factor based on the previously
! commanded pitch angle for blade 1:
GK = 1.0/( 1.0 + PitCom(1)/PC_KK )
! Compute the current speed error and its integral w.r.t. time; saturate the
! integral term using the pitch angle limits:
SpdErr = GenSpeedF - PC_RefSpd ! Current speed error
IntSpdErr = IntSpdErr + SpdErr*ElapTime ! Current integral of speed error w.r.t. time
IntSpdErr = MIN( MAX( IntSpdErr, PC_MinPit/( GK*PC_KI ) ), & !JASON:IntSpdErr = MAX( MIN( IntSpdErr, PC_MinPit/( GK*PC_KI ) ), & !JASON:MODIFICATION FOR PITCH TO STALL
PC_MaxPit/( GK*PC_KI ) ) ! Saturate the integral term using the pitch angle limits, converted to integral speed error limits !JASON: PC_MaxPit/( GK*PC_KI ) ) !JASON:MODIFICATION FOR PITCH TO STALL
DSpdErrDT = ( SpdErr - LastSpdErr )/ElapTime !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
YawBrTVxp = YawBrTVxp + YawBrTAxp*ElapTime !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
PitComTF = 0.0 !JASON:YawBrTVxp*0.0756 !JASON:*0.0056 !JASON:0.075 !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
! Compute the pitch commands associated with the proportional and integral
! gains:
PitComP = GK*PC_KP* SpdErr ! Proportional term
PitComI = GK*PC_KI*IntSpdErr ! Integral term (saturated)
PitComD = GK*PC_KD*DSpdErrDT !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
! Superimpose the individual commands to get the total pitch command;
! saturate the overall command using the pitch angle limits:
PitComT = PitComP + PitComI + PitComD !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER PitComT = PitComP + PitComI ! Overall command (unsaturated)
PitComT = MIN( MAX( PitComT, PC_MinPit ), PC_MaxPit ) ! Saturate the overall command using the pitch angle limits
! Saturate the overall commanded pitch using the pitch rate limit:
! NOTE: Since the current pitch angle may be different for each blade
! (depending on the type of actuator implemented in the structural
! dynamics model), this pitch rate limit calculation and the
! resulting overall pitch angle command may be different for each
! blade.
DO K = 1,NumBl ! Loop through all blades
PitRate(K) = ( PitComT - BlPitch(K) )/ElapTime ! Pitch rate of blade K (unsaturated)
PitRate(K) = MIN( MAX( PitRate(K), -PC_MaxRat ), PC_MaxRat ) ! Saturate the pitch rate of blade K using its maximum absolute value
PitCom (K) = BlPitch(K) + PitRate(K)*ElapTime ! Saturate the overall command of blade K using the pitch rate limit
PitCom(K) = MIN( MAX( PitCom(K), PC_MinPit ), PC_MaxPit ) ! Saturate the overall command using the pitch angle limits
ENDDO ! K - all blades
! Reset the value of LastTimePC to the current value:
LastTimePC = Time
LastSpdErr = SpdErr !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
! Output debugging information if requested:
IF ( PC_DbgOut ) WRITE (UnDb,FmtDat) Time, ElapTime, HorWindV, GenSpeed*RPS2RPM, GenSpeedF*RPS2RPM, &
100.0*SpdErr/PC_RefSpd, SpdErr, IntSpdErr, GK, PitComP*R2D, PitComI*R2D, &
PitComT*R2D, PitRate(1)*R2D, PitCom(1)*R2D
ENDIF
! Set the pitch override to yes and command the pitch demanded from the last
! call to the controller (See Appendix A of Bladed User's Guide):
avrSWAP(55) = 0.0 ! Pitch override: 0=yes
avrSWAP(42) = PitCom(1) ! Use the command angles of all blades if using individual pitch
avrSWAP(43) = PitCom(2) ! "
avrSWAP(44) = PitCom(3) ! "
avrSWAP(45) = PitCom(1) ! Use the command angle of blade 1 if using collective pitch
!JASON:IF ( (HorWindV-YawBrTVxp) < 11.4 ) THEN !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON: avrSWAP(45) = 0.0 !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON:ELSEIF ( (HorWindV-YawBrTVxp) < 12.0 ) THEN !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON: avrSWAP(45) = ( 5.5785* (HorWindV-YawBrTVxp) - 62.787 ) *0.0174533 !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON:ELSE !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON: avrSWAP(45) = MIN( ( 25.845*LOG(HorWindV-YawBrTVxp) - 59.811 ), 90.0 )*0.0174533 !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
!JASON:ENDIF !JASON:IMPLEMENT IDEAL PITCH CONTROL WHEN GenDOF IS DISABLED:
avrSWAP(45) = avrSWAP(45) + PitComTF !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
!JASON: IF ( HSSBrOn .OR. ( GenSpeedF < 0.01*PC_RefSpd ) ) THEN !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!JASON: avrSWAP(36) = 1.0 ! Shaft brake status: 1=on !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!JASON: HSSBrOn = .TRUE. !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!JASON: ELSE !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!JASON: avrSWAP(36) = 0.0 ! Shaft brake status: 0=off !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!JASON: ENDIF !JASON:THIS CHANGED FOR ITI BARGE:LOCK HSS-BRAKE AFTER SHUT-DOWN WHEN THE GENERATOR SPEED HAS REACHED 1% OF ITS RATED SPEED:
!=======================================================================
! Reset the value of LastTime to the current value:
LastTime = Time
ELSEIF ( iStatus == -8 ) THEN
! pack
OPEN( Un, FILE=TRIM( InFile ), STATUS='UNKNOWN', FORM='UNFORMATTED' , ACCESS='STREAM', IOSTAT=ErrStat, ACTION='WRITE' )
IF ( ErrStat /= 0 ) THEN
ErrMsg = 'Cannot open file "'//TRIM( InFile )//'". Another program may have locked it for writing.'
aviFAIL = -1
ELSE
! write all static variables to the checkpoint file (inverse of unpack):
WRITE( Un, IOSTAT=ErrStat ) GenSpeedF ! Filtered HSS (generator) speed, rad/s.
WRITE( Un, IOSTAT=ErrStat ) IntSpdErr ! Current integral of speed error w.r.t. time, rad.
WRITE( Un, IOSTAT=ErrStat ) LastGenTrq ! Commanded electrical generator torque the last time the controller was called, N-m.
WRITE( Un, IOSTAT=ErrStat ) LastTime ! Last time this DLL was called, sec.
WRITE( Un, IOSTAT=ErrStat ) LastTimePC ! Last time the pitch controller was called, sec.
WRITE( Un, IOSTAT=ErrStat ) LastTimeVS ! Last time the torque controller was called, sec.
WRITE( Un, IOSTAT=ErrStat ) PitCom ! Commanded pitch of each blade the last time the controller was called, rad.
WRITE( Un, IOSTAT=ErrStat ) VS_Slope15 ! Torque/speed slope of region 1 1/2 cut-in torque ramp , N-m/(rad/s).
WRITE( Un, IOSTAT=ErrStat ) VS_Slope25 ! Torque/speed slope of region 2 1/2 induction generator, N-m/(rad/s).
WRITE( Un, IOSTAT=ErrStat ) VS_SySp ! Synchronous speed of region 2 1/2 induction generator, rad/s.
WRITE( Un, IOSTAT=ErrStat ) VS_TrGnSp ! Transitional generator speed (HSS side) between regions 2 and 2 1/2, rad/s.
WRITE( Un, IOSTAT=ErrStat ) LastSpdErr !JASON:MODIFICATION FOR ADDITION OF DERIVATIVE TERM IN SPEED CONTROLLER
WRITE( Un, IOSTAT=ErrStat ) YawBrTVxp !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
WRITE( Un, IOSTAT=ErrStat ) PitComTF !JASON:MODIFICATION FOR TOWER-FEEDBACK DAMPING
CLOSE ( Un )
END IF
ELSEIF( iStatus == -9 ) THEN
!unpack
OPEN( Un, FILE=TRIM( InFile ), STATUS='OLD', FORM='UNFORMATTED', ACCESS='STREAM', IOSTAT=ErrStat, ACTION='READ' )
IF ( ErrStat /= 0 ) THEN
aviFAIL = -1
ErrMsg = ' Cannot open file "'//TRIM( InFile )//'" for reading. Another program may have locked.'
ELSE
! READ all static variables from the restart file (inverse of pack):
READ( Un, IOSTAT=ErrStat ) GenSpeedF ! Filtered HSS (generator) speed, rad/s.
READ( Un, IOSTAT=ErrStat ) IntSpdErr ! Current integral of speed error w.r.t. time, rad.
READ( Un, IOSTAT=ErrStat ) LastGenTrq ! Commanded electrical generator torque the last time the controller was called, N-m.
READ( Un, IOSTAT=ErrStat ) LastTime ! Last time this DLL was called, sec.
READ( Un, IOSTAT=ErrStat ) LastTimePC ! Last time the pitch controller was called, sec.
READ( Un, IOSTAT=ErrStat ) LastTimeVS ! Last time the torque controller was called, sec.
READ( Un, IOSTAT=ErrStat ) PitCom ! Commanded pitch of each blade the last time the controller was called, rad.
READ( Un, IOSTAT=ErrStat ) VS_Slope15 ! Torque/speed slope of region 1 1/2 cut-in torque ramp , N-m/(rad/s).
READ( Un, IOSTAT=ErrStat ) VS_Slope25 ! Torque/speed slope of region 2 1/2 induction generator, N-m/(rad/s).
READ( Un, IOSTAT=ErrStat ) VS_SySp ! Synchronous speed of region 2 1/2 induction generator, rad/s.
READ( Un, IOSTAT=ErrStat ) VS_TrGnSp ! Transitional generator speed (HSS side) between regions 2 and 2 1/2, rad/s.
CLOSE ( Un )
END IF
ENDIF
avcMSG = TRANSFER( TRIM(ErrMsg)//C_NULL_CHAR, avcMSG, SIZE(avcMSG) )
RETURN
END SUBROUTINE DISCON
!=======================================================================