diff --git a/DISCON/DISCON_glin64.so b/DISCON/DISCON_glin64.so index d92a78ac..25dafcc3 100755 Binary files a/DISCON/DISCON_glin64.so and b/DISCON/DISCON_glin64.so differ diff --git a/Parameter_files/NREL5MW/DISCON.IN b/Parameter_files/NREL5MW/DISCON.IN index e742edba..6ad757f8 100644 --- a/Parameter_files/NREL5MW/DISCON.IN +++ b/Parameter_files/NREL5MW/DISCON.IN @@ -8,10 +8,11 @@ 1 ! F_LPFType - {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) 0 ! F_NotchType - Notch on the measured generator speed {0: disable, 1: enable} 0 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} -1 ! VS_ControlMode - Generator torque control mode in above rated conditions {0: constant torque, 1: constant power} +0 ! VS_ControlMode - Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} 1 ! PC_ControlMode - Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} 0 ! Y_ControlMode - Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} 1 ! SS_Mode - Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} +0 ! WE_Mode - Wind speed estimator mode {0: One-second low pass filtered hub height wind speed, 1: Imersion and Invariance Estimator (Ortega et al.)} !------- FILTERS ---------------------------------------------------------- 1.570796326 ! F_LPFCornerFreq - Corner frequency (-3dB point) in the low-pass filters, [Hz] @@ -56,8 +57,8 @@ 43093.55 ! VS_RtTq - Rated torque, [Nm]. 120.113 ! VS_RefSpd - Rated generator speed [rad/s] 1 ! VS_n - Number of generator PI torque controller gains --4200 ! VS_KP - Proportional gain for generator PI torque controller, used in the transitional 2.5 region, [1/(rad/s) Nm] --2100 ! VS_KI - Integral gain for generator PI torque controller, used in the transitional 2.5 region, [1/rad Nm] +-4200 ! VS_KP - Proportional gain for generator PI torque controller [1/(rad/s) Nm]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) +-2100 ! VS_KI - Integral gain for generator PI torque controller [1/rad Nm]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) !------- Setpoint Smoother ------------------------------------------------ 30 ! SS_VSGainBias - Variable speed torque controller gain bias, [(rad/s)/rad]. diff --git a/Source/ControllerBlocks.f90 b/Source/ControllerBlocks.f90 index 45fd2423..db4190c0 100644 --- a/Source/ControllerBlocks.f90 +++ b/Source/ControllerBlocks.f90 @@ -17,7 +17,8 @@ MODULE ControllerBlocks CONTAINS !------------------------------------------------------------------------------------------------------------------------------- - ! State machines, determines the state of the wind turbine to specify the corresponding control actions + SUBROUTINE StateMachine(CntrPar, LocalVar) + ! State machine, determines the state of the wind turbine to specify the corresponding control actions ! PC States: ! PC_State = 0, No pitch control active, BldPitch = PC_MinPit ! PC_State = 1, Active PI blade pitch control enabled @@ -28,7 +29,7 @@ MODULE ControllerBlocks ! VS_State = 3, Region 2.5, transition between below and above-rated operating conditions (near-rated region) using PI torque control ! VS_State = 4, above-rated operation using pitch control (constant torque mode) ! VS_State = 5, above-rated operation using pitch and torque control (constant power mode) - SUBROUTINE StateMachine(CntrPar, LocalVar) + ! VS_State = 6, Tip-Speed-Ratio tracking PI controller USE DRC_Types, ONLY : LocalVariables, ControlParameters IMPLICIT NONE @@ -42,7 +43,7 @@ SUBROUTINE StateMachine(CntrPar, LocalVar) IF (LocalVar%PitCom(1) >= CntrPar%VS_Rgn3Pitch) THEN ! We are in region 3 IF (CntrPar%VS_ControlMode == 1) THEN ! Constant power tracking LocalVar%VS_State = 5 - LocalVar%PC_State = 2 + LocalVar%PC_State = 1 ELSE ! Constant torque tracking LocalVar%VS_State = 4 LocalVar%PC_State = 1 @@ -54,57 +55,70 @@ SUBROUTINE StateMachine(CntrPar, LocalVar) ! Operational States ELSE - ! Pitch controller state machine + ! --- Pitch controller state machine --- IF (CntrPar%PC_ControlMode == 1) THEN LocalVar%PC_State = 1 ELSE LocalVar%PC_State = 0 END IF - ! Torque control state machine - IF (LocalVar%PC_PitComT >= CntrPar%VS_Rgn3Pitch) THEN - ! Region 3 - IF (CntrPar%VS_ControlMode == 1) THEN ! Constant power tracking - LocalVar%VS_State = 5 - ELSE ! Constant torque tracking - LocalVar%VS_State = 4 + ! --- Torque control state machine --- + IF (LocalVar%PC_PitComT >= CntrPar%VS_Rgn3Pitch) THEN ! Region 3 + IF (CntrPar%VS_ControlMode == 1) THEN + LocalVar%VS_State = 5 ! Constant power tracking + ELSE + LocalVar%VS_State = 4 ! Constant torque tracking END IF ELSE - ! Region 2 1/2 - active PI torque control - IF (LocalVar%GenArTq >= CntrPar%VS_MaxOMTq*1.01) THEN - LocalVar%VS_State = 3 - ! Region 1 1/2 - ELSEIF (LocalVar%GenBrTq <= CntrPar%VS_MinOMTq*0.99) THEN - LocalVar%VS_State = 1 - ! Region 2 - optimal torque is proportional to the square of the generator speed - ELSEIF (LocalVar%GenSpeedF < CntrPar%VS_RefSpd) THEN + IF (LocalVar%GenArTq >= CntrPar%VS_MaxOMTq*1.01) THEN ! Region 2 1/2 - active PI torque control + LocalVar%VS_State = 3 + ELSEIF (LocalVar%GenSpeedF < CntrPar%VS_RefSpd) THEN ! Region 2 - optimal torque is proportional to the square of the generator speed + LocalVar%VS_State = 2 - ! Error state, Debug - ELSE + ELSEIF (LocalVar%GenBrTq <= CntrPar%VS_MinOMTq*0.99) THEN ! Region 1 1/2 + + LocalVar%VS_State = 1 + ELSE ! Error state, Debug LocalVar%VS_State = 0 END IF END IF END IF END SUBROUTINE StateMachine !------------------------------------------------------------------------------------------------------------------------------- - SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar) - USE DRC_Types, ONLY : LocalVariables, ControlParameters + SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst) + ! Wind Speed Estimator estimates wind speed at hub height. Currently implements two types of estimators + ! WE_Mode = 0, Filter hub height wind speed as passed from servodyn using first order low pass filter with 1Hz cornering frequency + ! WE_Mode = 1, Use Inversion and Inveriance filter as defined by Ortege et. al. + USE DRC_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances IMPLICIT NONE ! Inputs - TYPE(ControlParameters), INTENT(IN) :: CntrPar - TYPE(LocalVariables), INTENT(INOUT) :: LocalVar - - ! Body - LocalVar%WE_VwIdot = CntrPar%WE_Gamma/CntrPar%WE_Jtot*(LocalVar%VS_LastGenTrq*CntrPar%WE_GearboxRatio - AeroDynTorque(LocalVar, CntrPar)) - - LocalVar%WE_VwI = LocalVar%WE_VwI + LocalVar%WE_VwIdot*LocalVar%DT - LocalVar%WE_Vw = LocalVar%WE_VwI + CntrPar%WE_Gamma*LocalVar%RotSpeed + TYPE(ControlParameters), INTENT(IN) :: CntrPar + TYPE(LocalVariables), INTENT(INOUT) :: LocalVar + TYPE(ObjectInstances), INTENT(INOUT) :: objInst + ! Allocate Variables + REAL(4) :: F_WECornerFreq ! Corner frequency (-3dB point) for first order low pass filter for measured hub height wind speed [Hz] + ! Define Variables + F_WECornerFreq = 0.0333 ! Fix to 30 second time constant for now + ! Define wind speed estimate + IF (CntrPar%WE_Mode == 1) THEN + ! Inversion and Invariance Filter implementation + LocalVar%WE_VwIdot = CntrPar%WE_Gamma/CntrPar%WE_Jtot*(LocalVar%VS_LastGenTrq*CntrPar%WE_GearboxRatio - AeroDynTorque(LocalVar, CntrPar)) + LocalVar%WE_VwI = LocalVar%WE_VwI + LocalVar%WE_VwIdot*LocalVar%DT + LocalVar%WE_Vw = LocalVar%WE_VwI + CntrPar%WE_Gamma*LocalVar%RotSpeed + ELSE + ! Filter wind speed at hub height as directly passed from OpenFAST + LocalVar%WE_Vw = LPFilter(LocalVar%HorWindV, LocalVar%DT, F_WECornerFreq, LocalVar%iStatus, .FALSE., objInst%instLPF) + END IF + END SUBROUTINE WindSpeedEstimator !------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE SetpointSmoother(LocalVar, CntrPar, objInst) - USE DRC_Types!, ONLY : LocalVariables, ControlParameters, ObjectInstances + ! Setpoint smoother modifies controller reference in order to separate generator torque and blade pitch control actions + ! SS_Mode = 0, No setpoint smoothing + ! SS_Mode = 1, Implement setpoint smoothing + USE DRC_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances IMPLICIT NONE ! Inputs @@ -114,16 +128,16 @@ SUBROUTINE SetpointSmoother(LocalVar, CntrPar, objInst) ! Allocate Variables Real(4) :: DelOmega ! Reference generator speed shift, rad/s. - ! Setpoint Smoothing + ! ------ Setpoint Smoothing ------ IF ( CntrPar%SS_Mode == 1) THEN ! Find setpoint shift amount DelOmega = (LocalVar%BlPitch(1) - CntrPar%PC_MinPit)*CntrPar%SS_VSGainBias - (CntrPar%VS_RtTq - LocalVar%VS_LastGenTrq)*CntrPar%SS_PCGainBias ! Filter LocalVar%SS_DelOmegaF = LPFilter(DelOmega, LocalVar%DT, CntrPar%F_SSCornerFreq, LocalVar%iStatus, .FALSE., objInst%instLPF) ELSE - LocalVar%SS_DelOmegaF = 0 + LocalVar%SS_DelOmegaF = 0 ! No setpoint smoothing ENDIF END SUBROUTINE SetpointSmoother !------------------------------------------------------------------------------------------------------------------------------- -END MODULE ControllerBlocks \ No newline at end of file +END MODULE ControllerBlocks diff --git a/Source/Controllers.f90 b/Source/Controllers.f90 index 6c2fb800..c75a71ff 100644 --- a/Source/Controllers.f90 +++ b/Source/Controllers.f90 @@ -7,51 +7,55 @@ MODULE Controllers IMPLICIT NONE CONTAINS +!------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE PitchControl(avrSWAP, CntrPar, LocalVar, objInst) - + ! Blade pitch controller, generally maximizes rotor speed below rated (region 2) and regulates rotor speed above rated (region 3) + ! PC_State = 0, fix blade pitch to fine pitch angle (PC_FinePit) + ! PC_State = 1, is gain scheduled PI controller + ! Additional loops/methods (enabled via switches in DISCON.IN): + ! Individual pitch control + ! Tower fore-aft damping + ! Sine excitation on pitch USE DRC_Types, ONLY : ControlParameters, LocalVariables, ObjectInstances - - ! Local Variables: - REAL(C_FLOAT), INTENT(INOUT) :: avrSWAP(*) ! The swap array, used to pass data to, and receive data from the DLL controller. - INTEGER(4) :: K ! Index used for looping through blades. + ! Inputs TYPE(ControlParameters), INTENT(INOUT) :: CntrPar TYPE(LocalVariables), INTENT(INOUT) :: LocalVar TYPE(ObjectInstances), INTENT(INOUT) :: objInst - - !.............................................................................................................................. - ! Pitch control - !.............................................................................................................................. - IF (LocalVar%PC_State >= 1) THEN - LocalVar%PC_MaxPitVar = CntrPar%PC_MaxPit + ! Allocate Variables: + REAL(C_FLOAT), INTENT(INOUT) :: avrSWAP(*) ! The swap array, used to pass data to, and receive data from the DLL controller. + INTEGER(4) :: K ! Index used for looping through blades. + + + ! ------- Blade Pitch Controller -------- + ! Load PC State + IF (LocalVar%PC_State == 1) THEN ! PI BldPitch control + LocalVar%PC_MaxPit = CntrPar%PC_MaxPit ELSE ! debug mode, fix at fine pitch - LocalVar%PC_MaxPitVar = CntrPar%PC_FinePit + LocalVar%PC_MaxPit = CntrPar%PC_FinePit END IF - ! Compute the gain scheduling correction factor based on the previously - ! commanded pitch angle for blade 1: - LocalVar%PC_KP = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KP, LocalVar%PC_PitComT) - LocalVar%PC_KI = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KI, LocalVar%PC_PitComT) - LocalVar%PC_KD = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KD, LocalVar%PC_PitComT) - LocalVar%PC_TF = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_TF, LocalVar%PC_PitComT) + ! Compute (interpolate) the gains based on previously commanded blade pitch angles and lookup table: + LocalVar%PC_KP = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KP, LocalVar%PC_PitComT) ! Proportional gain + LocalVar%PC_KI = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KI, LocalVar%PC_PitComT) ! Integral gain + LocalVar%PC_KD = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_KD, LocalVar%PC_PitComT) ! Derivative gain + LocalVar%PC_TF = interp1d(CntrPar%PC_GS_angles, CntrPar%PC_GS_TF, LocalVar%PC_PitComT) ! TF gains (derivative filter) !NJA - need to clarify - ! Integrate the error signal w.r.t. time; saturate the integral term using the pitch angle limits: - ! Compute the pitch commands associated with the proportional and integral - ! gains: + ! Compute the collective pitch command associated with the proportional and integral gains: IF (LocalVar%iStatus == 0) THEN - LocalVar%PC_PitComT = PIController(LocalVar%PC_SpdErr, LocalVar%PC_KP, LocalVar%PC_KI, CntrPar%PC_FinePit, LocalVar%PC_MaxPitVar, LocalVar%DT, LocalVar%PitCom(1), .TRUE., objInst%instPI) + LocalVar%PC_PitComT = PIController(LocalVar%PC_SpdErr, LocalVar%PC_KP, LocalVar%PC_KI, CntrPar%PC_FinePit, LocalVar%PC_MaxPit, LocalVar%DT, LocalVar%PitCom(1), .TRUE., objInst%instPI) ELSE - LocalVar%PC_PitComT = PIController(LocalVar%PC_SpdErr, LocalVar%PC_KP, LocalVar%PC_KI, CntrPar%PC_FinePit, LocalVar%PC_MaxPitVar, LocalVar%DT, CntrPar%PC_FinePit, .FALSE., objInst%instPI) + LocalVar%PC_PitComT = PIController(LocalVar%PC_SpdErr, LocalVar%PC_KP, LocalVar%PC_KI, CntrPar%PC_FinePit, LocalVar%PC_MaxPit, LocalVar%DT, CntrPar%PC_FinePit, .FALSE., objInst%instPI) END IF - ! Individual pitch control + ! Find individual pitch control contribution IF ((CntrPar%IPC_ControlMode >= 1) .OR. (CntrPar%Y_ControlMode == 2)) THEN CALL IPC(CntrPar, LocalVar, objInst) ELSE LocalVar%IPC_PitComF = 0.0 ! THIS IS AN ARRAY!! END IF - ! Fore-aft tower vibration damping control + ! Include tower fore-aft tower vibration damping control IF ((CntrPar%FA_KI > 0.0) .OR. (CntrPar%Y_ControlMode == 2)) THEN CALL ForeAftDamping(CntrPar, LocalVar, objInst) ELSE @@ -81,42 +85,58 @@ SUBROUTINE PitchControl(avrSWAP, CntrPar, LocalVar, objInst) END SUBROUTINE PitchControl !------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst) - + ! Generator torque controller + ! VS_State = 0, Error state, for debugging purposes, GenTq = VS_RtTq + ! VS_State = 1, Region 1(.5) operation, torque control to keep the rotor at cut-in speed towards the Cp-max operational curve + ! VS_State = 2, Region 2 operation, maximum rotor power efficiency (Cp-max) tracking using K*omega^2 law, fixed fine-pitch angle in BldPitch controller + ! VS_State = 3, Region 2.5, transition between below and above-rated operating conditions (near-rated region) using PI torque control + ! VS_State = 4, above-rated operation using pitch control (constant torque mode) + ! VS_State = 5, above-rated operation using pitch and torque control (constant power mode) + ! VS_State = 6, Tip-Speed-Ratio tracking PI controller USE DRC_Types, ONLY : ControlParameters, LocalVariables, ObjectInstances - - REAL(C_FLOAT), INTENT(INOUT) :: avrSWAP(*) ! The swap array, used to pass data to, and receive data from, the DLL controller. - + ! Inputs TYPE(ControlParameters), INTENT(INOUT) :: CntrPar TYPE(LocalVariables), INTENT(INOUT) :: LocalVar TYPE(ObjectInstances), INTENT(INOUT) :: objInst + ! Allocate Variables + REAL(C_FLOAT), INTENT(INOUT) :: avrSWAP(*) ! The swap array, used to pass data to, and receive data from, the DLL controller. + REAL(4) :: VS_MaxTq ! Locally allocated maximum torque saturation limits - !.............................................................................................................................. - ! VARIABLE-SPEED TORQUE CONTROL: - ! Compute the generator torque, which depends on which region we are in: - !.............................................................................................................................. - IF (LocalVar%VS_State >= 4) THEN - LocalVar%GenArTq = PIController(LocalVar%VS_SpdErrAr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MaxOMTq, CntrPar%VS_ArSatTq, LocalVar%DT, CntrPar%VS_ArSatTq, .TRUE., objInst%instPI) - LocalVar%GenBrTq = PIController(LocalVar%VS_SpdErrBr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MinTq, CntrPar%VS_MinOMTq, LocalVar%DT, CntrPar%VS_MinOMTq, .TRUE., objInst%instPI) - IF (LocalVar%VS_State == 4) THEN - LocalVar%GenTq = CntrPar%VS_RtTq - ELSEIF (LocalVar%VS_State == 5) THEN - LocalVar%GenTq = (CntrPar%VS_RtPwr/CntrPar%VS_GenEff)/LocalVar%GenSpeedF - END IF + ! -------- Variable-Speed Torque Controller -------- + ! Optimal Tip-Speed-Ratio tracking controller + IF (CntrPar%VS_ControlMode == 2) THEN + ! Define max torque + IF (LocalVar%VS_State >= 4) THEN + VS_MaxTq = CntrPar%VS_RtTq + ELSE + ! VS_MaxTq = CntrPar%VS_MaxTq + VS_MaxTq = CntrPar%VS_RtTq + ENDIF + LocalVar%GenTq = PIController(LocalVar%VS_SpdErr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MinTq, VS_MaxTq, LocalVar%DT, CntrPar%VS_MaxOMTq, .FALSE., objInst%instPI) + + ! K*Omega^2 control law with PI torque control in transition regions ELSE + ! Update PI loops for region 1.5 and 2.5 PI control + ! LocalVar%GenArTq = PIController(LocalVar%VS_SpdErrAr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MaxOMTq, CntrPar%VS_ArSatTq, LocalVar%DT, CntrPar%VS_RtTq, .TRUE., objInst%instPI) LocalVar%GenArTq = PIController(LocalVar%VS_SpdErrAr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MaxOMTq, CntrPar%VS_ArSatTq, LocalVar%DT, CntrPar%VS_MaxOMTq, .FALSE., objInst%instPI) - LocalVar%GenBrTq = PIController(LocalVar%VS_SpdErrBr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MinTq, CntrPar%VS_MinOMTq, LocalVar%DT, CntrPar%VS_MinOMTq, .FALSE., objInst%instPI) - IF (LocalVar%VS_State == 3) THEN - LocalVar%GenTq = LocalVar%GenArTq - ELSEIF (LocalVar%VS_State == 1) THEN + LocalVar%GenBrTq = PIController(LocalVar%VS_SpdErrBr, CntrPar%VS_KP(1), CntrPar%VS_KI(1), CntrPar%VS_MinTq, CntrPar%VS_MinOMTq, LocalVar%DT, CntrPar%VS_MinOMTq, .TRUE., objInst%instPI) + + IF (LocalVar%VS_State == 1) THEN ! Region 1.5 LocalVar%GenTq = LocalVar%GenBrTq - ELSEIF (LocalVar%VS_State == 2) THEN + ELSEIF (LocalVar%VS_State == 2) THEN ! Region 2 LocalVar%GenTq = CntrPar%VS_Rgn2K*LocalVar%GenSpeedF*LocalVar%GenSpeedF - ELSE - LocalVar%GenTq = CntrPar%VS_MaxOMTq + ELSEIF (LocalVar%VS_State == 3) THEN ! Region 2.5 + LocalVar%GenTq = LocalVar%GenArTq + ELSEIF (LocalVar%VS_State == 4) THEN ! Region 3, constant torque + LocalVar%GenTq = CntrPar%VS_RtTq + ELSEIF (LocalVar%VS_State == 5) THEN ! Region 3, constant power + LocalVar%GenTq = (CntrPar%VS_RtPwr/CntrPar%VS_GenEff)/LocalVar%GenSpeedF END IF - END IF - - ! Saturate the commanded torque using the maximum torque limit: + + ENDIF + + + ! Saturate the commanded torque using the maximum torque limit: LocalVar%GenTq = MIN(LocalVar%GenTq, CntrPar%VS_MaxTq) ! Saturate the command using the maximum torque limit ! Saturate the commanded torque using the torque rate limit: diff --git a/Source/DISCON.f90 b/Source/DISCON.f90 index ba8c3fbb..2650b74f 100644 --- a/Source/DISCON.f90 +++ b/Source/DISCON.f90 @@ -51,7 +51,7 @@ SUBROUTINE DISCON(avrSWAP, aviFAIL, accINFILE, avcOUTNAME, avcMSG) BIND (C, NAME CALL ComputeVariablesSetpoints(CntrPar, LocalVar) CALL StateMachine(CntrPar, LocalVar) - CALL WindSpeedEstimator(LocalVar, CntrPar) + CALL WindSpeedEstimator(LocalVar, CntrPar, objInst) CALL SetpointSmoother(LocalVar, CntrPar, objInst) diff --git a/Source/DRC_Types.f90 b/Source/DRC_Types.f90 index 26248e3a..bf49453e 100644 --- a/Source/DRC_Types.f90 +++ b/Source/DRC_Types.f90 @@ -54,9 +54,10 @@ MODULE DRC_Types REAL(4), DIMENSION(:), ALLOCATABLE :: VS_KI ! Integral gain for generator PI torque controller, used in the transitional 2.5 region INTEGER(4) :: SS_Mode ! Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} - REAL(4) :: SS_VSGainBias ! Variable speed torque controller gain bias, [(rad/s)/rad]. - REAL(4) :: SS_PCGainBias ! Collective pitch controller gain bias, [(rad/s)/Nm]. + REAL(4) :: SS_VSGainBias ! Variable speed torque controller gain bias, [(rad/s)/rad]. + REAL(4) :: SS_PCGainBias ! Collective pitch controller gain bias, [(rad/s)/Nm]. + INTEGER(4) :: WE_Mode ! Wind speed estimator mode {0: One-second low pass filtered hub height wind speed, 1: Imersion and Invariance Estimator (Ortega et al.) REAL(4) :: WE_BladeRadius ! Blade length [m] INTEGER(4) :: WE_CP_n ! Amount of parameters in the Cp array REAL(4), DIMENSION(:), ALLOCATABLE :: WE_CP ! Parameters that define the parameterized CP(\lambda) function @@ -119,7 +120,7 @@ MODULE DRC_Types REAL(4) :: PC_KI ! Integral gain for pitch controller at rated pitch (zero) [-]. REAL(4) :: PC_KD ! Differential gain for pitch controller at rated pitch (zero) [-]. REAL(4) :: PC_TF ! First-order filter parameter for derivative action - REAL(4) :: PC_MaxPitVar ! Maximum pitch setting in pitch controller (variable) [rad]. + REAL(4) :: PC_MaxPit ! Maximum pitch setting in pitch controller (variable) [rad]. REAL(4) :: PC_PitComT ! Total command pitch based on the sum of the proportional and integral terms [rad]. REAL(4) :: PC_PitComT_IPC(3) ! Total command pitch based on the sum of the proportional and integral terms, including IPC term [rad]. REAL(4) :: PC_PwrErr ! Power error with respect to rated power [W] @@ -128,11 +129,12 @@ MODULE DRC_Types INTEGER(4) :: PC_State ! State of the pitch control system REAL(4) :: PitCom(3) ! Commanded pitch of each blade the last time the controller was called [rad]. REAL(4) :: SS_DelOmegaF ! Filtered setpoint shifting term defined in setpoint smoother [rad/s]. - INTEGER(4) :: TestType ! Test variable, no use + REAL(4) :: TestType ! Test variable, no use REAL(4) :: VS_LastGenTrq ! Commanded electrical generator torque the last time the controller was called [Nm]. REAL(4) :: VS_MechGenPwr ! Mechanical power on the generator axis [W] - REAL(4) :: VS_SpdErrAr ! Current speed error (generator torque control) [rad/s]. - REAL(4) :: VS_SpdErrBr ! Current speed error (generator torque control) [rad/s]. + REAL(4) :: VS_SpdErrAr ! Current speed error for region 2.5 PI controller (generator torque control) [rad/s]. + REAL(4) :: VS_SpdErrBr ! Current speed error for region 1.5 PI controller (generator torque control) [rad/s]. + REAL(4) :: VS_SpdErr ! Current speed error for tip-speed-ratio tracking controller (generator torque control) [rad/s]. INTEGER(4) :: VS_State ! State of the torque control system REAL(4) :: WE_Vw ! Estimated wind speed [m/s] REAL(4) :: WE_VwI ! Integrated wind speed quantity for estimation [m/s] diff --git a/Source/Functions.f90 b/Source/Functions.f90 index 13a3d872..565904b1 100644 --- a/Source/Functions.f90 +++ b/Source/Functions.f90 @@ -47,7 +47,7 @@ REAL FUNCTION PIController(error, kp, ki, minValue, maxValue, DT, I0, reset, ins ! IMPLICIT NONE - ! Inputs + ! Allocate Inputs REAL(4), INTENT(IN) :: error REAL(4), INTENT(IN) :: kp REAL(4), INTENT(IN) :: ki @@ -58,7 +58,7 @@ REAL FUNCTION PIController(error, kp, ki, minValue, maxValue, DT, I0, reset, ins REAL(4), INTENT(IN) :: I0 LOGICAL, INTENT(IN) :: reset - ! Local + ! Allocate local variables INTEGER(4) :: i ! Counter for making arrays REAL(4) :: PTerm ! Proportional term REAL(4), DIMENSION(99), SAVE :: ITerm = (/ (real(9999.9), i = 1,99) /) ! Integral term, current. @@ -265,8 +265,8 @@ SUBROUTINE Debug(LocalVar, CntrPar, avrSWAP, RootName, size_avcOUTNAME) IF (CntrPar%LoggingLevel > 0) THEN !OPEN(unit=UnDb, FILE=TRIM(RootName)//'.dbg', STATUS='NEW') OPEN(unit=UnDb, FILE='DEBUG.dbg') - WRITE (UnDb,'(A)') ' LocalVar%Time ' //Tab//'LocalVar%FA_Acc '//Tab//'LocalVar%FA_AccHPF '//Tab//'LocalVar%FA_AccHPFI '//Tab//'LocalVar%PitCom ' - WRITE (UnDb,'(A)') ' (sec) ' //Tab//'(m/s^2) ' //Tab//'(m/s^2) ' //Tab//'(m/s) ' //Tab//'(rad) ' + WRITE (UnDb,'(A)') ' Time ' //Tab//'VS_SpdErr '//Tab//' VS_LastGenTq '//Tab//' Omega_op '//Tab//' HorWindV ' //Tab//' WE_Vw ' + WRITE (UnDb,'(A)') ' (sec) ' //Tab//'(m/s) '//Tab//' (Nm) '//Tab//' (Nm)' //Tab//' (m/s) '//Tab//' (m/s) ' !WRITE (UnDb,'(A)') ' LocalVar%Time ' //Tab//'LocalVar%PC_PitComT ' //Tab//'LocalVar%PC_SpdErr ' //Tab//'LocalVar%PC_KP ' //Tab//'LocalVar%PC_KI ' //Tab//'LocalVar%Y_M ' //Tab//'LocalVar%rootMOOP(1) '//Tab//'VS_RtPwr '//Tab//'LocalVar%GenTq' !WRITE (UnDb,'(A)') ' (sec) ' //Tab//'(rad) ' //Tab//'(rad/s) '//Tab//'(-) ' //Tab//'(-) ' //Tab//'(rad) ' //Tab//'(?) ' //Tab//'(W) '//Tab//'(Nm) ' END IF @@ -289,7 +289,7 @@ SUBROUTINE Debug(LocalVar, CntrPar, avrSWAP, RootName, size_avcOUTNAME) ! Output debugging information if requested: IF (CntrPar%LoggingLevel > 0) THEN - WRITE (UnDb,FmtDat) LocalVar%Time, LocalVar%FA_Acc, LocalVar%FA_AccHPF, LocalVar%FA_AccHPFI, LocalVar%PitCom + WRITE (UnDb,FmtDat) LocalVar%Time, LocalVar%VS_SpdErr, LocalVar%VS_LastGenTrq, LocalVar%TestType, LocalVar%HorWindV, LocalVar%WE_Vw END IF IF (CntrPar%LoggingLevel > 1) THEN diff --git a/Source/ReadSetParameters.f90 b/Source/ReadSetParameters.f90 index c4fa0567..b1e29bd8 100644 --- a/Source/ReadSetParameters.f90 +++ b/Source/ReadSetParameters.f90 @@ -1,6 +1,10 @@ MODULE ReadSetParameters USE, INTRINSIC :: ISO_C_Binding + +USE Constants +USE Functions + IMPLICIT NONE CONTAINS @@ -34,6 +38,7 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar) READ(UnControllerParameters, *) CntrPar%PC_ControlMode READ(UnControllerParameters, *) CntrPar%Y_ControlMode READ(UnControllerParameters, *) CntrPar%SS_Mode + READ(UnControllerParameters, *) CntrPar%WE_Mode READ(UnControllerParameters, *) !----------------- FILTER CONSTANTS --------------------- @@ -159,9 +164,12 @@ SUBROUTINE ComputeVariablesSetpoints(CntrPar, LocalVar) ! Allocate variables TYPE(ControlParameters), INTENT(INOUT) :: CntrPar TYPE(LocalVariables), INTENT(INOUT) :: LocalVar - REAL(4) :: VS_RefSpd ! Referece speed for variable speed torque controller. - REAL(4) :: PC_RefSpd ! Referece speed for pitch controller. - + REAL(4) :: VS_RefSpd ! Referece speed for variable speed torque controller, [rad/s] + REAL(4) :: PC_RefSpd ! Referece speed for pitch controller, [rad/s] + REAL(4) :: Omega_op ! Optimal TSR-tracking generator speed, [rad/s] + ! temp + REAL(4) :: VS_TSRop = 7.5 + ! ----- Calculate yaw misalignment error ----- LocalVar%Y_MErr = LocalVar%Y_M + CntrPar%Y_MErrSet ! Yaw-alignment error @@ -175,12 +183,24 @@ SUBROUTINE ComputeVariablesSetpoints(CntrPar, LocalVar) LocalVar%PC_SpdErr = PC_RefSpd - LocalVar%GenSpeedF ! Speed error LocalVar%PC_PwrErr = CntrPar%VS_RtPwr - LocalVar%VS_GenPwr ! Power error - ! ----- Torque controller region 2.5 reference error ----- - ! Implement setpoint smoothing - IF (LocalVar%SS_DelOmegaF > 0) THEN - VS_RefSpd = CntrPar%VS_RefSpd - LocalVar%SS_DelOmegaF + ! ----- Torque controller reference errors ----- + ! Define VS reference generator speed [rad/s] + IF (CntrPar%VS_ControlMode == 2) THEN + VS_RefSpd = (VS_TSRop * LocalVar%WE_Vw / CntrPar%WE_BladeRadius) * CntrPar%WE_GearboxRatio + VS_RefSpd = saturate(VS_RefSpd,CntrPar%VS_MinOMSpd, CntrPar%PC_RefSpd) ELSE VS_RefSpd = CntrPar%VS_RefSpd + ENDIF + + ! Implement setpoint smoothing + IF (LocalVar%SS_DelOmegaF > 0) THEN + VS_RefSpd = VS_RefSpd - LocalVar%SS_DelOmegaF + ENDIF + + ! TSR-tracking reference error + IF (CntrPar%VS_ControlMode == 2) THEN + LocalVar%VS_SpdErr = VS_RefSpd - LocalVar%GenSpeedF + LocalVar%TestType = VS_RefSpd ENDIF ! Define transition region setpoint errors