Skip to content

Commit

Permalink
Add discrete ballast control
Browse files Browse the repository at this point in the history
  • Loading branch information
dzalkind committed Dec 5, 2024
1 parent 12968a8 commit cf46114
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 24 deletions.
38 changes: 38 additions & 0 deletions rosco/controller/rosco_registry/rosco_types.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,31 @@ ControlParameters:
<<: *real
description: Transformation from F_Pitch (output of PID control) to StC_Force (length should match StC_Group_N), will be normalized to max of 1, must sum to 0
allocatable: True
StC_Target_Period:
<<: *real
description: Period that fill (force) target periods are updated
StC_Fill_Period:
<<: *real
description: Period that actual fill settings are updated
StC_Offset_DB:
<<: *real
description: Deadband on offset
StC_Fill_DB:
<<: *real
description: Deadband on fill amount
StC_F_Gain:
<<: *real
description: Proportional gain on force targets
n_DT_StC_Target:
<<: *integer
description: Number of timesteps until target StC force is updated
F_Roll_Target:
<<: *real
description: Target on force to zero roll offset
F_Pitch_Target:
<<: *real
description: Target on force to zero pitch offset



# Calculated
Expand Down Expand Up @@ -1312,6 +1337,19 @@ LocalVariables:
Force_Roll:
<<: *real
description: Force to roll the rotor back to even keel
StC_FR_Target:
<<: *real
description: Target force to roll the rotor back to even keel
StC_FP_Target:
<<: *real
description: Target force to roll the rotor back to even keel
StC_Fi_Target:
<<: *real
allocatable: True
StC_Fill_State:
<<: *integer
allocatable: True
description: State of ballast 0-doing nothing, -1-emptying, 1-filling
CC_DesiredL:
<<: *real
size: 12
Expand Down
60 changes: 58 additions & 2 deletions rosco/controller/src/Controllers.f90
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ SUBROUTINE StructuralControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar)


! Internal Variables
Integer(IntKi) :: I_GROUP
Integer(IntKi) :: I_GROUP, I_STC
CHARACTER(*), PARAMETER :: RoutineName = 'StructuralControl'


Expand Down Expand Up @@ -883,9 +883,65 @@ SUBROUTINE StructuralControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar)
ENDIF
ENDDO

ELSEIF (CntrPar%StC_Mode == 3) THEN
! Discrete, constant rate mode of ballast control

! Filter pitch and roll offsets
LocalVar%PtfmRDX_F = LPFilter(LocalVar%PtfmRDX, LocalVar%DT, CntrPar%StC_F_FiltFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instLPF) ! roll
LocalVar%PtfmRDY_F = LPFilter(LocalVar%PtfmRDY, LocalVar%DT, CntrPar%StC_F_FiltFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instLPF) ! pitch


! Check if it's time to update targets
IF ( MOD(LocalVar%n_DT, CntrPar%n_DT_StC_Target) == 0 ) THEN

! If filtered offset greater than deadband
IF (ABS(LocalVar%PtfmRDX_F) > CntrPar%StC_Offset_DB) THEN
LocalVar%StC_FR_Target = LocalVar%StC_FR_Target + CntrPar%StC_F_Gain * LocalVar%PtfmRDX_F
ENDIF

IF (ABS(LocalVar%PtfmRDY_F) > CntrPar%StC_Offset_DB) THEN
LocalVar%StC_FP_Target = LocalVar%StC_FP_Target + CntrPar%StC_F_Gain * LocalVar%PtfmRDY_F
ENDIF
ENDIF

! Transform roll/pitch targets into individual force targets
T = RESHAPE((/CntrPar%StC_T_Roll, CntrPar%StC_T_Pitch/),(/6,2/))
Inp = RESHAPE( (/LocalVar%StC_FR_Target, LocalVar%StC_FP_Target/) , (/2,1/))
F_Out = matmul(T,Inp)

DO I_GROUP = 1,CntrPar%StC_Group_N
LocalVar%StC_Fi_Target(I_GROUP) = F_Out(I_GROUP,1)
END DO

! Fill state machine, run this every time step

DO I_StC = 1, CntrPar%StC_Group_N ! For each StC
! Determine state
IF (LocalVar%StC_Input(I_StC) < LocalVar%StC_Fi_Target(I_StC) - CntrPar%StC_Fill_DB) THEN ! Fill < target - deadband
LocalVar%StC_Fill_State(I_StC) = 1 ! Fill
ELSEIF (LocalVar%StC_Input(I_StC) > LocalVar%StC_Fi_Target(I_StC) + CntrPar%StC_Fill_DB) THEN ! Fill > target + deadband
LocalVar%StC_Fill_State(I_StC) = -1 ! Empty
ELSE
LocalVar%StC_Fill_State(I_StC) = 0 ! Do nothing
ENDIF

! Fill/empty
IF (LocalVar%StC_Fill_State(I_StC) == 1 ) THEN
LocalVar%StC_Input(I_StC) = LocalVar%StC_Input(I_StC) + CntrPar%StC_F_Rates(2) * LocalVar%DT
ELSEIF (LocalVar%StC_Fill_State(I_StC) == -1 ) THEN
LocalVar%StC_Input(I_StC) = LocalVar%StC_Input(I_StC) + CntrPar%StC_F_Rates(1) * LocalVar%DT
ENDIF


END DO

! Helpful for debugging
! WRITE(403,*) LocalVar%Time, LocalVar%StC_Fill_State
! WRITE(404,*) LocalVar%Time, LocalVar%StC_Input


ENDIF

END IF


! Assign to avrSWAP
Expand Down
51 changes: 32 additions & 19 deletions rosco/controller/src/ROSCO_IO.f90
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ SUBROUTINE WriteRestartFile(LocalVar, CntrPar, ErrVar, objInst, RootName, size_a
WRITE( Un, IOSTAT=ErrStat) LocalVar%PtfmRDY_F
WRITE( Un, IOSTAT=ErrStat) LocalVar%Force_Pitch
WRITE( Un, IOSTAT=ErrStat) LocalVar%Force_Roll
WRITE( Un, IOSTAT=ErrStat) LocalVar%StC_FR_Target
WRITE( Un, IOSTAT=ErrStat) LocalVar%StC_FP_Target
WRITE( Un, IOSTAT=ErrStat) LocalVar%StC_Fi_Target
WRITE( Un, IOSTAT=ErrStat) LocalVar%StC_Fill_State
WRITE( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(1)
WRITE( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(2)
WRITE( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(3)
Expand Down Expand Up @@ -479,6 +483,10 @@ SUBROUTINE ReadRestartFile(avrSWAP, LocalVar, CntrPar, objInst, PerfData, RootNa
READ( Un, IOSTAT=ErrStat) LocalVar%PtfmRDY_F
READ( Un, IOSTAT=ErrStat) LocalVar%Force_Pitch
READ( Un, IOSTAT=ErrStat) LocalVar%Force_Roll
READ( Un, IOSTAT=ErrStat) LocalVar%StC_FR_Target
READ( Un, IOSTAT=ErrStat) LocalVar%StC_FP_Target
READ( Un, IOSTAT=ErrStat) LocalVar%StC_Fi_Target
READ( Un, IOSTAT=ErrStat) LocalVar%StC_Fill_State
READ( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(1)
READ( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(2)
READ( Un, IOSTAT=ErrStat) LocalVar%CC_DesiredL(3)
Expand Down Expand Up @@ -700,7 +708,7 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av
'[N/A]', '[N/A]', '[N/A]', '[N/A]', '[rad/s]', &
'[deg]', '[deg]', '[deg]', '[N/A]', '[rad/s]', &
'[rad/s]']
nLocalVars = 128
nLocalVars = 132
Allocate(LocalVarOutData(nLocalVars))
Allocate(LocalVarOutStrings(nLocalVars))
LocalVarOutData(1) = LocalVar%iStatus
Expand Down Expand Up @@ -819,18 +827,22 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av
LocalVarOutData(114) = LocalVar%PtfmRDY_F
LocalVarOutData(115) = LocalVar%Force_Pitch
LocalVarOutData(116) = LocalVar%Force_Roll
LocalVarOutData(117) = LocalVar%CC_DesiredL(1)
LocalVarOutData(118) = LocalVar%CC_ActuatedL(1)
LocalVarOutData(119) = LocalVar%CC_ActuatedDL(1)
LocalVarOutData(120) = LocalVar%StC_Input(1)
LocalVarOutData(121) = LocalVar%Flp_Angle(1)
LocalVarOutData(122) = LocalVar%RootMyb_Last(1)
LocalVarOutData(123) = LocalVar%ACC_INFILE_SIZE
LocalVarOutData(124) = LocalVar%AWC_complexangle(1)
LocalVarOutData(125) = LocalVar%ZMQ_ID
LocalVarOutData(126) = LocalVar%ZMQ_YawOffset
LocalVarOutData(127) = LocalVar%ZMQ_TorqueOffset
LocalVarOutData(128) = LocalVar%ZMQ_PitOffset(1)
LocalVarOutData(117) = LocalVar%StC_FR_Target
LocalVarOutData(118) = LocalVar%StC_FP_Target
LocalVarOutData(119) = LocalVar%StC_Fi_Target(1)
LocalVarOutData(120) = LocalVar%StC_Fill_State(1)
LocalVarOutData(121) = LocalVar%CC_DesiredL(1)
LocalVarOutData(122) = LocalVar%CC_ActuatedL(1)
LocalVarOutData(123) = LocalVar%CC_ActuatedDL(1)
LocalVarOutData(124) = LocalVar%StC_Input(1)
LocalVarOutData(125) = LocalVar%Flp_Angle(1)
LocalVarOutData(126) = LocalVar%RootMyb_Last(1)
LocalVarOutData(127) = LocalVar%ACC_INFILE_SIZE
LocalVarOutData(128) = LocalVar%AWC_complexangle(1)
LocalVarOutData(129) = LocalVar%ZMQ_ID
LocalVarOutData(130) = LocalVar%ZMQ_YawOffset
LocalVarOutData(131) = LocalVar%ZMQ_TorqueOffset
LocalVarOutData(132) = LocalVar%ZMQ_PitOffset(1)
LocalVarOutStrings = [CHARACTER(15) :: 'iStatus', 'Time', 'DT', 'n_DT', 'Time_Last', &
'VS_GenPwr', 'VS_GenPwrF', 'GenSpeed', 'RotSpeed', 'NacHeading', &
'NacVane', 'HorWindV', 'rootMOOP', 'rootMOOPF', 'BlPitch', &
Expand All @@ -854,9 +866,10 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av
'PtfmTVX', 'PtfmTVY', 'PtfmTVZ', 'PtfmRVX', 'PtfmRVY', &
'PtfmRVZ', 'PtfmTAX', 'PtfmTAY', 'PtfmTAZ', 'PtfmRAX', &
'PtfmRAY', 'PtfmRAZ', 'PtfmRDX_F', 'PtfmRDY_F', 'Force_Pitch', &
'Force_Roll', 'CC_DesiredL', 'CC_ActuatedL', 'CC_ActuatedDL', 'StC_Input', &
'Flp_Angle', 'RootMyb_Last', 'ACC_INFILE_SIZE', 'AWC_complexangle', 'ZMQ_ID', &
'ZMQ_YawOffset', 'ZMQ_TorqueOffset', 'ZMQ_PitOffset']
'Force_Roll', 'StC_FR_Target', 'StC_FP_Target', 'StC_Fi_Target', 'StC_Fill_State', &
'CC_DesiredL', 'CC_ActuatedL', 'CC_ActuatedDL', 'StC_Input', 'Flp_Angle', &
'RootMyb_Last', 'ACC_INFILE_SIZE', 'AWC_complexangle', 'ZMQ_ID', 'ZMQ_YawOffset', &
'ZMQ_TorqueOffset', 'ZMQ_PitOffset']
! Initialize debug file
IF ((LocalVar%iStatus == 0) .OR. (LocalVar%iStatus == -9)) THEN ! .TRUE. if we're on the first call to the DLL
IF (CntrPar%LoggingLevel > 0) THEN
Expand All @@ -871,8 +884,8 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av
CALL GetNewUnit(UnDb2, ErrVar)
OPEN(unit=UnDb2, FILE=TRIM(RootName)//'.RO.dbg2')
WRITE(UnDb2, *) 'Generated on '//CurDate()//' at '//CurTime()//' using ROSCO-'//TRIM(rosco_version)
WRITE(UnDb2, '(129(a20,TR5:))') 'Time', LocalVarOutStrings
WRITE(UnDb2, '(129(a20,TR5:))')
WRITE(UnDb2, '(133(a20,TR5:))') 'Time', LocalVarOutStrings
WRITE(UnDb2, '(133(a20,TR5:))')
END IF

IF (CntrPar%LoggingLevel > 2) THEN
Expand Down Expand Up @@ -935,7 +948,7 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av
END DO

! Write debug files
FmtDat = "(F20.5,TR5,128(ES20.5E2,TR5:))" ! The format of the debugging data
FmtDat = "(F20.5,TR5,132(ES20.5E2,TR5:))" ! The format of the debugging data
IF ( MOD(LocalVar%n_DT, CntrPar%n_DT_Out) == 0) THEN
IF(CntrPar%LoggingLevel > 0) THEN
WRITE (UnDb, TRIM(FmtDat)) LocalVar%Time, DebugOutData
Expand Down
12 changes: 12 additions & 0 deletions rosco/controller/src/ROSCO_Types.f90
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ MODULE ROSCO_Types
REAL(DbKi), DIMENSION(:), ALLOCATABLE :: StC_F_Rates ! Min and max force rates (at each leg?)
REAL(DbKi), DIMENSION(:), ALLOCATABLE :: StC_T_Roll ! Transformation from F_Roll (output of PID control) to StC_Force (length should match StC_Group_N), will be normalized to max of 1, must sum to 0
REAL(DbKi), DIMENSION(:), ALLOCATABLE :: StC_T_Pitch ! Transformation from F_Pitch (output of PID control) to StC_Force (length should match StC_Group_N), will be normalized to max of 1, must sum to 0
REAL(DbKi) :: StC_Target_Period ! Period that fill (force) target periods are updated
REAL(DbKi) :: StC_Fill_Period ! Period that actual fill settings are updated
REAL(DbKi) :: StC_Offset_DB ! Deadband on offset
REAL(DbKi) :: StC_Fill_DB ! Deadband on fill amount
REAL(DbKi) :: StC_F_Gain ! Proportional gain on force targets
INTEGER(IntKi) :: n_DT_StC_Target ! Number of timesteps until target StC force is updated
REAL(DbKi) :: F_Roll_Target ! Target on force to zero roll offset
REAL(DbKi) :: F_Pitch_Target ! Target on force to zero pitch offset
REAL(DbKi) :: PC_RtTq99 ! 99% of the rated torque value, using for switching between pitch and torque control, [Nm].
REAL(DbKi) :: VS_MaxOMTq ! Maximum torque at the end of the below-rated region 2, [Nm]
REAL(DbKi) :: VS_MinOMTq ! Minimum torque at the beginning of the below-rated region 2, [Nm]
Expand Down Expand Up @@ -371,6 +379,10 @@ MODULE ROSCO_Types
REAL(DbKi) :: PtfmRDY_F ! Filtered Platform motion -- Displacement RDY (rad)')
REAL(DbKi) :: Force_Pitch ! Force to pitch the rotor back to even keel
REAL(DbKi) :: Force_Roll ! Force to roll the rotor back to even keel
REAL(DbKi) :: StC_FR_Target ! Target force to roll the rotor back to even keel
REAL(DbKi) :: StC_FP_Target ! Target force to roll the rotor back to even keel
REAL(DbKi), DIMENSION(:), ALLOCATABLE :: StC_Fi_Target ! None
INTEGER(IntKi), DIMENSION(:), ALLOCATABLE :: StC_Fill_State ! State of ballast 0-doing nothing, -1-emptying, 1-filling
REAL(DbKi) :: CC_DesiredL(12) ! None
REAL(DbKi) :: CC_ActuatedL(12) ! None
REAL(DbKi) :: CC_ActuatedDL(12) ! None
Expand Down
13 changes: 13 additions & 0 deletions rosco/controller/src/ReadSetParameters.f90
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ SUBROUTINE SetParameters(avrSWAP, accINFILE, size_avcMSG, CntrPar, LocalVar, obj
ErrVar%ErrMsg = RoutineName//':'//TRIM(ErrVar%ErrMsg)
ENDIF

! Structural control allocations, intitializations
ALLOCATE(LocalVar%StC_Fi_Target(CntrPar%StC_Group_N))
ALLOCATE(LocalVar%StC_Fill_State(CntrPar%StC_Group_N))

LocalVar%StC_FR_Target = 0
LocalVar%StC_FP_Target = 0


ENDIF
END SUBROUTINE SetParameters
Expand Down Expand Up @@ -562,6 +569,11 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s
CALL ParseAry(FileLines, 'StC_F_Rates', CntrPar%StC_F_Rates, 2, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 1, UnEc)
CALL ParseAry(FileLines, 'StC_T_Roll', CntrPar%StC_T_Roll, CntrPar%StC_Group_N, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 1, UnEc)
CALL ParseAry(FileLines, 'StC_T_Pitch', CntrPar%StC_T_Pitch, CntrPar%StC_Group_N, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 1, UnEc)
CALL ParseInput(FileLines, 'StC_Target_Period', CntrPar%StC_Target_Period, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 3, UnEc)
CALL ParseInput(FileLines, 'StC_Fill_Period', CntrPar%StC_Fill_Period, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 3, UnEc)
CALL ParseInput(FileLines, 'StC_Offset_DB', CntrPar%StC_Offset_DB, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 3, UnEc)
CALL ParseInput(FileLines, 'StC_Fill_DB', CntrPar%StC_Fill_DB, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 3, UnEc)
CALL ParseInput(FileLines, 'StC_F_Gain', CntrPar%StC_F_Gain, accINFILE(1), ErrVar, CntrPar%StC_Mode .NE. 3, UnEc)

IF (ErrVar%aviFAIL < 0) RETURN

Expand All @@ -584,6 +596,7 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s
! DT_Out
CntrPar%n_DT_Out = NINT(CntrPar%DT_Out / LocalVar%DT)
CntrPar%n_DT_ZMQ = NINT(CntrPar%ZMQ_UpdatePeriod / LocalVar%DT)
CntrPar%n_DT_StC_Target = NINT(CntrPar%StC_Target_Period / LocalVar%DT)


! Fix Paths (add relative paths if called from another dir, UnEc)
Expand Down
20 changes: 20 additions & 0 deletions rosco/toolbox/inputs/toolbox_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,26 @@ properties:
type: number
description: Transformation from F_Pitch (output of PID control) to StC_Force (length should match StC_Group_N), will be normalized to max of 1, must sum to 0
default: [0,0,0,0,0,0]
StC_Target_Period:
type: number
description: Period that fill (force) target periods are updated
default: 50.
StC_Fill_Period:
type: number
description: Period that actual fill settings are updated
default: 50.
StC_Offset_DB:
type: number
description: Deadband on offset
default: 1
StC_Fill_DB:
type: number
description: Deadband on fill amount
default: 1e3
StC_F_Gain:
type: number
description: Gain on F_*_Target, from pitch/roll (rad) to F_Pitch/Roll_Target, only used in StC_Mode = 3
default: 1e3

linmodel_tuning:
type: object
Expand Down
8 changes: 5 additions & 3 deletions rosco/toolbox/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,11 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C
file.write('{:<11s} ! StC_F_Rates - {}\n'.format(write_array(rosco_vt['StC_F_Rates'], '<6e'), input_descriptions['StC_F_Rates']))
file.write('{:<11s} ! StC_T_Roll - {}\n'.format(write_array(rosco_vt['StC_T_Roll'], '<6f'), input_descriptions['StC_T_Roll']))
file.write('{:<11s} ! StC_T_Pitch - {}\n'.format(write_array(rosco_vt['StC_T_Pitch'], '<6f'), input_descriptions['StC_T_Pitch']))



file.write('{:<11f} ! StC_Target_Period - {}\n'.format(rosco_vt['StC_Target_Period'], input_descriptions['StC_Target_Period']))
file.write('{:<11f} ! StC_Fill_Period - {}\n'.format(rosco_vt['StC_Fill_Period'], input_descriptions['StC_Fill_Period']))
file.write('{:<11f} ! StC_Offset_DB - {}\n'.format(rosco_vt['StC_Offset_DB'], input_descriptions['StC_Offset_DB']))
file.write('{:<11f} ! StC_Fill_DB - {}\n'.format(rosco_vt['StC_Fill_DB'], input_descriptions['StC_Fill_DB']))
file.write('{:<11f} ! StC_F_Gain - {}\n'.format(rosco_vt['StC_F_Gain'], input_descriptions['StC_F_Gain']))
file.close()

# Write Open loop input
Expand Down

0 comments on commit cf46114

Please sign in to comment.