Skip to content

Commit

Permalink
Implement pitch saturation for Cp-maximization at low wind speeds
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhar-abbas committed Nov 19, 2019
1 parent 3d713aa commit 681a1f1
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 56 deletions.
62 changes: 51 additions & 11 deletions ROSCO_toolbox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ def __init__(self, controller_params):
else:
self.max_pitch = 90*deg2rad # Default to 90 degrees max pitch

if controller_params['vs_minspd']:
self.vs_minspd = controller_params['vs_minspd']
if controller_params['pc_minspd']:
self.pc_minspd = controller_params['pc_minspd']
else:
self.vs_minspd = None
self.pc_minspd = None

if controller_params['ss_vsgain']:
self.ss_vsgain = controller_params['ss_vsgain']
Expand Down Expand Up @@ -214,11 +214,13 @@ def tune_controller(self, turbine):
self.vs_refspd = min(turbine.Cp.TSR_opt * turbine.v_rated/R, turbine.rated_rotor_speed) * Ng

# -- Define some setpoints --
# minimum rotor speed
if self.vs_minspd:
self.vs_minspd = np.maximum(self.vs_minspd, (turbine.Cp.TSR_opt * turbine.v_min / turbine.rotor_radius) * Ng)
# minimum rotor speed saturation limits
self.vs_minspd = (turbine.Cp.TSR_opt * turbine.v_min / turbine.rotor_radius) * Ng
if self.pc_minspd:
self.pc_minspd = np.maximum(self.pc_minspd, (turbine.Cp.TSR_opt * turbine.v_min / turbine.rotor_radius) * Ng)
else:
self.vs_minspd = (turbine.Cp.TSR_opt * turbine.v_min / turbine.rotor_radius) * Ng
self.pc_minspd = (turbine.Cp.TSR_opt * turbine.v_min / turbine.rotor_radius) * Ng

# max pitch angle for shutdown
if self.sd_maxpit:
self.sd_maxpit = self.sd_maxpit
Expand All @@ -227,19 +229,27 @@ def tune_controller(self, turbine):

# Store some variables
self.v = v # Wind speed (m/s)
self.v_below_rated = v_below_rated
self.pitch_op = pitch_op
self.pitch_op_pc = pitch_op[len(v_below_rated):len(v)]
self.TSR_op = TSR_op
self.A = A
self.B_beta = B_beta
self.B_tau = B_tau
# --- Might want these to debug
# - Might want these to debug -
# self.Cp_op = Cp_op
# self.v_below_rated = v_below_rated

# Peak Shaving
# --- Minimum pitch saturation ---
self.ps_min_bld_pitch = np.ones(len(self.pitch_op)) * self.min_pitch
self.ps = ControllerBlocks()
self.ps.peak_shaving(self, turbine)

if self.PS_Mode == 1: # Peak Shaving
self.ps.peak_shaving(self, turbine)
elif self.PS_Mode == 2: # Cp-maximizing minimum pitch saturation
self.ps.min_pitch_saturation(self,turbine)
elif self.PS_Mode == 3: # Peak shaving and Cp-maximizing minimum pitch saturation
self.ps.peak_shaving(self, turbine)
self.ps.min_pitch_saturation(self,turbine)

class ControllerBlocks():
'''
Expand Down Expand Up @@ -302,6 +312,8 @@ def peak_shaving(self,controller, turbine):
f_pitch_min = interpolate.interp1d(Ct_tsr, turbine.pitch_initial_rad, bounds_error=False, fill_value=(turbine.pitch_initial_rad[0],turbine.pitch_initial_rad[-1]))
pitch_min[i] = f_pitch_min(Ct_max[i])

controller.ps_min_bld_pitch = pitch_min

# save some outputs for analysis or future work
self.Tshaved = 0.5 * rho * A * controller.v**2 * Ct_op
self.pitch_min = pitch_min
Expand All @@ -310,6 +322,34 @@ def peak_shaving(self,controller, turbine):
self.Ct_op = Ct_op
self.T = T

def min_pitch_saturation(self, controller, turbine):

# Find TSR associated with minimum rotor speed
TSR_at_minspeed = controller.pc_minspd * turbine.rotor_radius / controller.v_below_rated
for i in range(len(TSR_at_minspeed)):
if TSR_at_minspeed[i] > controller.TSR_op[i]:
controller.TSR_op[i] = TSR_at_minspeed[i]

# Initialize some arrays
Cp_op = np.empty(len(turbine.pitch_initial_rad),dtype='float64')
min_pitch = np.empty(len(TSR_at_minspeed),dtype='float64')


# Find Cp-maximizing minimum pitch schedule
# for j in range(len(TSR_at_minspeed)):
# Find Cp coefficients at below-rated tip speed ratios
Cp_op = turbine.Cp.interp_surface(turbine.pitch_initial_rad,TSR_at_minspeed[i])
Cp_max = max(Cp_op)
f_pitch_min = interpolate.interp1d(Cp_op, turbine.pitch_initial_rad, bounds_error=False, fill_value=(turbine.pitch_initial_rad[0],turbine.pitch_initial_rad[-1]))
min_pitch[i] = f_pitch_min(Cp_max)

# modify existing minimum pitch schedule
# for pind, pitch in enumerate(min_itch):
controller.ps_min_bld_pitch[i] = np.maximum(controller.ps_min_bld_pitch[i], min_pitch[i])
else:
return


class ControllerTypes():
'''
Class ControllerTypes used to define any types of controllers that can be tuned.
Expand Down
10 changes: 5 additions & 5 deletions ROSCO_toolbox/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def write_param_file(self, turbine, controller, param_file='DISCON.IN', txt_file
file.write('{0:<12d} ! Y_ControlMode - Yaw control mode {{0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC}}\n'.format(controller.Y_ControlMode))
file.write('{0:<12d} ! SS_Mode - Setpoint Smoother mode {{0: no setpoint smoothing, 1: introduce setpoint smoothing}}\n'.format(controller.SS_Mode))
file.write('{0:<12d} ! WE_Mode - Wind speed estimator mode {{0: One-second low pass filtered hub height wind speed, 1: Immersion and Invariance Estimator, 2: Extended Kalman Filter}}\n'.format(controller.WE_Mode))
file.write('{0:<12d} ! PS_Mode - Peak shaving mode {{0: no peak shaving, 1: implement peak shaving}}\n'.format(controller.PS_Mode))
file.write('{0:<12d} ! PS_Mode - Pitch saturation mode {{0: no pitch saturation, 1: implement pitch saturation}}\n'.format(controller.PS_Mode > 0))
file.write('{0:<12d} ! SD_Mode - Shutdown mode {{0: no shutdown procedure, 1: pitch to max pitch at shutdown}}\n'.format(controller.SD_Mode))
file.write('\n')
file.write('!------- FILTERS ----------------------------------------------------------\n')
Expand Down Expand Up @@ -498,10 +498,10 @@ def write_param_file(self, turbine, controller, param_file='DISCON.IN', txt_file
file.write('{:<13.1f} ! FA_HPF_CornerFreq - Corner frequency (-3dB point) in the high-pass filter on the fore-aft acceleration signal [rad/s]\n'.format(0.0))
file.write('{:<13.1f} ! FA_IntSat - Integrator saturation (maximum signal amplitude contribution to pitch from FA damper), [rad]\n'.format(0.0))
file.write('\n')
file.write('!------- PEAK SHAVING -------------------------------------------\n')
file.write('{:<11d} ! PS_BldPitchMin_N - Number of values in minimum blade pitch lookup table (should equal number of values in PS_WindSpeeds and PS_BldPitchMin)\n'.format(len(controller.ps.pitch_min)))
file.write('{} ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s]\n'.format(''.join('{:<4.2f} '.format(controller.ps.v[i]) for i in range(len(controller.ps.v)))))
file.write('{} ! PS_BldPitchMin - Minimum blade pitch angles [rad]\n'.format(''.join('{:<10.8f} '.format(controller.ps.pitch_min[i]) for i in range(len(controller.ps.pitch_min)))))
file.write('!------- MINIMUM PITCH SATURATION -------------------------------------------\n')
file.write('{:<11d} ! PS_BldPitchMin_N - Number of values in minimum blade pitch lookup table (should equal number of values in PS_WindSpeeds and PS_BldPitchMin)\n'.format(len(controller.ps_min_bld_pitch)))
file.write('{} ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s]\n'.format(''.join('{:<4.2f} '.format(controller.v[i]) for i in range(len(controller.v)))))
file.write('{} ! PS_BldPitchMin - Minimum blade pitch angles [rad]\n'.format(''.join('{:<10.8f} '.format(controller.ps_min_bld_pitch[i]) for i in range(len(controller.ps_min_bld_pitch)))))
file.write('\n')
file.write('!------- SHUTDOWN -------------------------------------------\n')
file.write('{:<014.5f} ! SD_MaxPit - Maximum blade pitch angle to initiate shutdown, [rad]\n'.format(controller.sd_maxpit))
Expand Down
Loading

0 comments on commit 681a1f1

Please sign in to comment.