diff --git a/.github/workflows/Publish_ROSCO.yml b/.github/workflows/Publish_ROSCO.yml index ef017d940..697a50c73 100644 --- a/.github/workflows/Publish_ROSCO.yml +++ b/.github/workflows/Publish_ROSCO.yml @@ -25,8 +25,10 @@ jobs: if: false == contains( matrix.os, 'windows') uses: fortran-lang/setup-fortran@v1 + # macOS runners already ship Apple clang; installing llvm via Homebrew + # builds from source on untiered images (e.g. macos-14) and breaks. - name: Install compiler - if: false == contains( matrix.os, 'windows') + if: contains( matrix.os, 'ubuntu') id: install_cc uses: rlalik/setup-cpp-compiler@master with: @@ -68,16 +70,16 @@ jobs: if: contains( matrix.os, 'macos-14') uses: pypa/cibuildwheel@v2.23.3 env: - CC: ${{ steps.install_cc.outputs.cc }} - CXX: ${{ steps.install_cc.outputs.cxx }} + CC: clang + CXX: clang++ CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET="14.0" - name: Build wheels mac-15 if: contains( matrix.os, 'macos-15') uses: pypa/cibuildwheel@v2.23.3 env: - CC: ${{ steps.install_cc.outputs.cc }} - CXX: ${{ steps.install_cc.outputs.cxx }} + CC: clang + CXX: clang++ CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET="15.0" - name: Build wheels windows diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 09e3b92fc..c9a39adfe 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,8 +13,7 @@ build: jobs: # Read the docs needs a couple packages not in the environment file pre_install: - - conda install -y cmake compilers sphinx sphinxcontrib-bibtex sphinx-jsonschema - - conda install sphinx_rtd_theme>=1.3 + - mamba install -y compilers sphinx sphinxcontrib-bibtex sphinx-jsonschema - pip install json-schema-for-humans pre_build: - pwd diff --git a/Examples/26_marine_hydro.py b/Examples/26_marine_hydro.py index 874e2696b..61ef7427b 100644 --- a/Examples/26_marine_hydro.py +++ b/Examples/26_marine_hydro.py @@ -1,7 +1,7 @@ """ 26_marine_hydro --------------- -Run MHK turbine in OpenFAST with ROSCO torque controller +Run MHK turbine in OpenFAST with ROSCO pitch and torque controller """ import os diff --git a/Examples/31_fixed_pitch_mhk.py b/Examples/31_fixed_pitch_mhk.py index 8fd572f96..ad77eb59a 100644 --- a/Examples/31_fixed_pitch_mhk.py +++ b/Examples/31_fixed_pitch_mhk.py @@ -5,14 +5,19 @@ This example demonstrates the fixed-pitch control of a marine hydrodkinetic (MHK) turbine. There are several ways to control the power output of a turbine in above-rated conditions. -In this example we demonstrate the following control configurations: +The first three configurations demonstrated here are the case studies verified against +simulation in :ref:`marine_hydro`: -#. Constant power underspeed (should be the default) -#. Constant power overspeed -#. Linear increasing power -#. Linear increasing power, leveling out -#. Generic numeric function -#. Constant power overspeed, nonlinear lookup table control +#. Example 1: Constant power overspeed, nonlinear control law +#. Example 2: Linear increasing power, underspeed with torque-lookup reference +#. Example 3: Generic user-defined power curve, underspeed with WSE-lookup reference + +The remaining three are experimental. They exercise the rest of the fixed-pitch input +space and are not part of that verification campaign: + +* Constant power underspeed +* Constant power overspeed, via WSE-lookup reference tracking +* Linear increasing power, leveling out below cut-out More details about the controller methods can be found in :ref:`marine_hydro`. @@ -20,18 +25,22 @@ .. image:: ../images/examples/31_fixed_pitch_mhk_sched.png -In the first case, the reference generator speed is decreased (underspeed) to maintain a constant rated power above rated. -To slow down the generator, a higher torque must be used: +In the first case, the reference generator speed is increased (overspeed) to maintain a constant +rated power above rated, following the fixed control law tau = min(P_rated/omega, K*omega^2): .. image:: ../images/examples/31_fixed_pitch_mhk_sim.png +All configurations are started softly: an open loop input ramps the torque rating +(``R_Torque``) from ``SOFT_START_R0`` to 1.0 with a sigma function over ``SOFT_START_DUR`` +seconds, de-rating the generator torque limit while the turbine spins up. + ''' # Copying images, from docs/: -# cp ../Examples/examples_out/30_fixed_pitch_mhk_sched.png images/ -# cp ../Examples/examples_out/30_fixed_pitch_mhk_sim.png images/ +# cp ../Examples/examples_out/31_fixed_pitch_mhk_sched.png images/examples/ +# cp ../Examples/examples_out/31_fixed_pitch_mhk_sim.png images/examples/ import os from rosco.toolbox.ofTools.case_gen.run_FAST import run_FAST_ROSCO @@ -53,10 +62,13 @@ example_out_dir = os.path.join(this_dir, 'examples_out') os.makedirs(example_out_dir,exist_ok=True) +# Soft start up: R_Torque is ramped from SOFT_START_R0 to 1.0 over SOFT_START_DUR seconds +SOFT_START_R0 = 0.5 +SOFT_START_DUR = 100. + def main(): FULL_TEST = False # Run a full test locally (True) or a shorter one for CI - sim_config = 1 # Choose which simulation configuration (1-6) # Input yaml and output directory parameter_filename = os.path.join(this_dir, 'Tune_Cases/RM1_MHK_FBP.yaml') @@ -80,78 +92,74 @@ def main(): ) + ### Control configurations: overrides applied to the tuning yaml controller_params + # The first three are the verified case studies of :ref:`marine_hydro`; the rest + # demonstrate the rest of the FBP input space and are not part of that campaign. + # Each config states VS_FBP and its paired VS_ControlMode explicitly, rather than + # inheriting either from the tuning yaml. + control_configs = { + 'Example 1: Constant Power Overspeed': { # marine_hydro Example 1 + 'VS_FBP': 1, # Constant power overspeed, nonlinear control law + 'VS_ControlMode': 1, # Region 2 mode paired with VS_FBP = 1 + 'VS_FBP_speed_mode': 1, + 'VS_FBP_U': [2.0, 4.0], + 'VS_FBP_P': [1.0, 1.0], + }, + 'Example 2: Linear Increasing Power': { # marine_hydro Example 2 + 'VS_FBP': 3, # Torque-lookup reference + 'VS_ControlMode': 4, # Region 2 mode paired with VS_FBP = 3 + 'VS_FBP_speed_mode': 0, + 'VS_FBP_U': [2.0, 4.0], + 'VS_FBP_P': [1.0, 2.0], + }, + 'Example 3: Generic User-Defined': { # marine_hydro Example 3 + 'VS_FBP': 2, # WSE-lookup reference + 'VS_ControlMode': 2, # Region 2 mode paired with VS_FBP = 2 + 'VS_FBP_speed_mode': 0, + 'VS_FBP_U': [2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0], + 'VS_FBP_P': [1.0, 1.3, 1.6, 1.8, 1.9, 2.0, 1.9, 1.8, 1.7, 1.6, 1.5], + }, + 'Experimental: Constant Power Underspeed': { # Example 2 held at rated power + 'VS_FBP': 3, # Torque-lookup reference + 'VS_ControlMode': 4, # Region 2 mode paired with VS_FBP = 3 + 'VS_FBP_speed_mode': 0, + 'VS_FBP_U': [2.0, 4.0], + 'VS_FBP_P': [1.0, 1.0], + }, + 'Experimental: Constant Power Overspeed (WSE)': { # Example 1 schedule via reference tracking + 'VS_FBP': 2, # WSE-lookup reference + 'VS_ControlMode': 2, # Region 2 mode paired with VS_FBP = 2 + 'VS_FBP_speed_mode': 1, # Overspeed: check against the cavitation limit, exceeded for the RM1 + 'VS_FBP_U': [2.0, 4.0], + 'VS_FBP_P': [1.0, 1.0], + }, + 'Experimental: Increasing Leveled Power': { # Example 2 leveling out below cut-out + 'VS_FBP': 3, # Torque-lookup reference + 'VS_ControlMode': 4, # Region 2 mode paired with VS_FBP = 3 + 'VS_FBP_speed_mode': 0, + 'VS_FBP_U': [2.0, 3.0], + 'VS_FBP_P': [1.0, 2.0], + }, + } + ### Tune controller cases - # Constant power underspeed (should be the default) - controller_params_1 = controller_params.copy() - controller_params_1['VS_FBP'] = 3 # Power reference - controller_params_1['VS_FBP_speed_mode'] = 0 - controller_params_1['VS_FBP_U'] = [2.0, 4.0] - controller_params_1['VS_FBP_P'] = [1.0, 1.0] - controller_1 = ROSCO_controller.Controller(controller_params_1) - controller_1.tune_controller(turbine) - - # Constant power overspeed - controller_params_2 = controller_params.copy() - controller_params_2['VS_FBP'] = 2 # Switch to WSE reference - controller_params_2['VS_FBP_speed_mode'] = 1 - controller_params_2['VS_FBP_U'] = [2.0, 4.0] - controller_params_2['VS_FBP_P'] = [1.0, 1.0] - controller_2 = ROSCO_controller.Controller(controller_params_2) - controller_2.tune_controller(turbine) - - # Linear increasing power - controller_params_3 = controller_params.copy() - controller_params_3['VS_FBP_speed_mode'] = 0 - controller_params_2['VS_FBP_U'] = [2.0, 4.0] - controller_params_3['VS_FBP_P'] = [1.0, 2.0] - controller_3 = ROSCO_controller.Controller(controller_params_3) - controller_3.tune_controller(turbine) - - # Linear increasing power, leveling out - controller_params_4 = controller_params.copy() - controller_params_4['VS_FBP_U'] = [2.0, 3.0] - controller_params_4['VS_FBP_P'] = [1.0, 2.0] - controller_4 = ROSCO_controller.Controller(controller_params_4) - controller_4.tune_controller(turbine) - - # Generic numeric function - controller_params_5 = controller_params.copy() - controller_params_5['VS_FBP'] = 2 # WSE reference - controller_params_5['VS_FBP_U'] = [2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0] - controller_params_5['VS_FBP_P'] = [1.0, 1.3, 1.6, 1.8, 1.9, 2.0, 1.9, 1.8, 1.7, 1.6, 1.5] - controller_5 = ROSCO_controller.Controller(controller_params_5) - controller_5.tune_controller(turbine) - - # Constant power overspeed, nonlinear lookup table control - controller_params_6 = controller_params.copy() - controller_params_6['VS_FBP'] = 1 # Constant power overspeed - controller_params_6['VS_FBP_speed_mode'] = 1 - controller_params_6['VS_FBP_U'] = [2.0, 4.0] - controller_params_6['VS_FBP_P'] = [1.0, 1.0] - controller_params_6['VS_ControlMode'] = 1 - controller_6 = ROSCO_controller.Controller(controller_params_6) - controller_6.tune_controller(turbine) - - - plot_labels = ['Constant Power Underspeed', 'Constant Power Overspeed', 'Linear Increasing Power', 'Increasing Leveled Power', 'Generic User-Defined'] + controllers = [] + for overrides in control_configs.values(): + controller = ROSCO_controller.Controller({**controller_params, **overrides}) + controller.tune_controller(turbine) + controllers.append(controller) + + # The WSE overspeed config tracks the same schedule as Example 1, so dash it to keep both visible + line_styles = {'Experimental: Constant Power Overspeed (WSE)': '--'} + fig, axs = plt.subplots(3,1) - axs[0].plot(controller_1.v, controller_1.power_op, label=plot_labels[0]) - axs[0].plot(controller_2.v, controller_2.power_op, label=plot_labels[1], linestyle='--') - axs[0].plot(controller_3.v, controller_3.power_op, label=plot_labels[2]) - axs[0].plot(controller_4.v, controller_4.power_op, label=plot_labels[3]) - axs[0].plot(controller_5.v, controller_5.power_op, label=plot_labels[4]) + for label, cont in zip(control_configs, controllers): + line_style = line_styles.get(label, '-') + axs[0].plot(cont.v, cont.power_op, label=label, linestyle=line_style) + axs[1].plot(cont.v, cont.omega_gen_op, label=label, linestyle=line_style) + axs[2].plot(cont.v, cont.tau_op, label=label, linestyle=line_style) axs[0].set_ylabel('Gen Power [W]') - axs[1].plot(controller_1.v, controller_1.omega_gen_op, label=plot_labels[0]) - axs[1].plot(controller_2.v, controller_2.omega_gen_op, label=plot_labels[1], linestyle='--') - axs[1].plot(controller_3.v, controller_3.omega_gen_op, label=plot_labels[2]) - axs[1].plot(controller_4.v, controller_4.omega_gen_op, label=plot_labels[3]) - axs[1].plot(controller_5.v, controller_5.omega_gen_op, label=plot_labels[4]) axs[1].set_ylabel('Gen Speed [rad/s]') - axs[2].plot(controller_1.v, controller_1.tau_op, label=plot_labels[0]) - axs[2].plot(controller_2.v, controller_2.tau_op, label=plot_labels[1], linestyle='--') - axs[2].plot(controller_3.v, controller_3.tau_op, label=plot_labels[2]) - axs[2].plot(controller_4.v, controller_4.tau_op, label=plot_labels[3]) - axs[2].plot(controller_5.v, controller_5.tau_op, label=plot_labels[4]) axs[2].set_ylabel('Gen Torque [N m]') axs[2].set_xlabel('Flow Speed [m/s]') axs[0].legend(loc='upper left', bbox_to_anchor=(.2, 2.35)) @@ -163,60 +171,66 @@ def main(): if False: plt.show() else: - fig_fname = os.path.join(example_out_dir, '30_fixed_pitch_mhk_sched.png') + fig_fname = os.path.join(example_out_dir, '31_fixed_pitch_mhk_sched.png') print('Saving figure ' + fig_fname) plt.savefig(fig_fname,bbox_inches='tight',) - # Write parameter input file for constant power underspeed controller - run_dir = os.path.join(example_out_dir, f'31_MHK/{sim_config}_config') + # Simulate all control configurations, in parallel + run_dir = os.path.join(example_out_dir, '31_MHK') os.makedirs(run_dir,exist_ok=True) # simulation set up if FULL_TEST: - TMax = 60 + TMax = SOFT_START_DUR + 100 else: TMax = 5 - all_controller_params = [ - controller_params_1, - controller_params_2, - controller_params_3, - controller_params_4, - controller_params_5, - controller_params_6, - ] - - if sim_config in range(1,len(all_controller_params)+1): - controller_params = all_controller_params[sim_config-1] - else: - raise Exception(f'Invalid sim_config of {sim_config}. Note the 1-indexing.') + # Soft start up: phase in the torque rating with an open loop input + olc = ROSCO_controller.OpenLoopControl(t_max=SOFT_START_DUR) + olc.interp_series('R_torque', [0, SOFT_START_DUR], [SOFT_START_R0, 1.0], 'sigma') + ol_dict = olc.write_input(os.path.join(run_dir, '31_OL_Input.dat')) r = run_FAST_ROSCO() r.tuning_yaml = parameter_filename + r.controller_params = { + 'PRC_Mode': 2, # power reference control + 'OL_Mode': 1, + 'open_loop': ol_dict, + 'DISCON': { + 'PRC_Comm': 1, # open loop inputs + }, + } r.wind_case_fcn = cl.power_curve r.wind_case_opts = { 'U': [3.0], 'TMax': TMax, } r.case_inputs = {} - r.controller_params = controller_params + r.control_sweep_fcn = cl.sweep_yaml_input + r.control_sweep_opts = {'param_sweeps': list(control_configs.values())} r.save_dir = run_dir r.rosco_dir = rosco_dir + r.n_cores = min(len(control_configs), os.cpu_count()) r.run_FAST() op = output_processing.output_processing() - fast_out = op.load_fast_out([os.path.join(run_dir,'RM1_MHK_FBP_0.out')], tmin=0) + out_files = [os.path.join(run_dir,f'RM1_MHK_FBP_{i}.out') for i in range(len(control_configs))] + fast_out = op.load_fast_out(out_files, tmin=0) + assert len(fast_out) == len(control_configs) + fig, axs = plt.subplots(4,1) - axs[0].plot(fast_out[0]['Time'], fast_out[0]['Wind1VelX'], label='Constant Power Underspeed') + for label, fo in zip(control_configs, fast_out): + axs[0].plot(fo['Time'], fo['Wind1VelX'], label=label) + axs[1].plot(fo['Time'], fo['GenSpeed'] * 2*np.pi/60, label=label) + axs[2].plot(fo['Time'], fo['GenTq'] * 1e3, label=label) + axs[3].plot(fo['Time'], fo['GenPwr'] * 1e3, label=label) axs[0].set_ylabel('Flow Speed [m/s]',rotation=0, labelpad=50) - axs[1].plot(fast_out[0]['Time'], fast_out[0]['GenSpeed'] * 2*np.pi/60, label='Constant Power Underspeed') axs[1].set_ylabel('Gen Speed [rad/s]',rotation=0, labelpad=50) - axs[2].plot(fast_out[0]['Time'], fast_out[0]['GenTq'] * 1e3, label='Constant Power Underspeed') axs[2].set_ylabel('Gen Torque [N m]',rotation=0, labelpad=50) - axs[3].plot(fast_out[0]['Time'], fast_out[0]['GenPwr'] * 1e3, label='Constant Power Underspeed') axs[3].set_ylabel('Gen Power [W]',rotation=0, labelpad=50) axs[3].set_xlabel('Time [s]') + axs[0].legend(loc='upper left', bbox_to_anchor=(.2, 1.9)) plt.subplots_adjust(hspace=0.5) fig.align_ylabels() @@ -227,7 +241,7 @@ def main(): if False: plt.show() else: - fig_fname = os.path.join(example_out_dir, '30_fixed_pitch_mhk_sim.png') + fig_fname = os.path.join(example_out_dir, '31_fixed_pitch_mhk_sim.png') print('Saving figure ' + fig_fname) plt.savefig(fig_fname, bbox_inches='tight') diff --git a/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN b/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN index 49be8061b..0b19297f6 100644 --- a/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN +++ b/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the BAR_10 wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 1 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,7 +10,7 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 2 ! 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 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -2 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +2 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 0 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 1 ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control) @@ -114,7 +114,7 @@ 2 ! PRC_n - Number of elements in PRC_WindSpeeds and PRC_GenSpeeds array 0.07854 ! PRC_LPF_Freq - Frequency of the low pass filter on the wind speed estimate used to set PRC_GenSpeeds [rad/s] 3.0000 25.0000 ! PRC_WindSpeeds - Array of wind speeds used in rotor speed vs. wind speed lookup table [m/s] -7.9168e-01 7.9168e-01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] +7.9853e+01 7.9853e+01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] !------- WIND SPEED ESTIMATOR --------------------------------------------- 102.996 ! WE_BladeRadius - Blade length (distance from hub center to blade tip), [m] diff --git a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_DISCON.IN b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_DISCON.IN index 4cc22b597..40657985d 100644 --- a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_DISCON.IN +++ b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the IEA-15-240-RWT-Monopile wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 1 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,7 +10,7 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 2 ! 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 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -2 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +2 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 0 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 1 ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control) diff --git a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_ROSCO.yaml b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_ROSCO.yaml index cc64b97dd..7357aa8ef 100644 --- a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_ROSCO.yaml +++ b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile_ROSCO.yaml @@ -28,7 +28,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_DISCON.IN b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_DISCON.IN index 05b0219d8..6ee57f407 100644 --- a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_DISCON.IN +++ b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the IEA-15-240-RWT-UMaineSemi wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 2 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,7 +10,7 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 2 ! 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 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -2 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +2 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 0 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 1 ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control) diff --git a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ROSCO.yaml b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ROSCO.yaml index 274e1b897..d1ae2a79e 100644 --- a/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ROSCO.yaml +++ b/Examples/Test_Cases/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ROSCO.yaml @@ -28,7 +28,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN b/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN index 8b47be58a..ea7135476 100644 --- a/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN +++ b/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the MHK_RM1_Floating wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 2 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,14 +10,14 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 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 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -3 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +3 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 1 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 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 ! PRC_Mode - Power reference tracking mode (0: power control disabled, 1: lookup table from wind speed to generator speed setpoints, 2: change speed, torque, pitch to control power) -0 ! 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) +2 ! 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) 1 ! PS_Mode - Pitch saturation mode (0: no pitch saturation, 1: implement pitch saturation) 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) @@ -55,9 +55,9 @@ !------- BLADE PITCH CONTROL ---------------------------------------------- 30 ! PC_GS_n - Amount of gain-scheduling table entries -0.030 0.049 0.064 0.076 0.087 0.097 0.107 0.115 0.124 0.131 0.139 0.146 0.153 0.160 0.166 0.173 0.179 0.185 0.191 0.197 0.202 0.208 0.214 0.219 0.224 0.230 0.235 0.240 0.245 0.250 ! PC_GS_angles - Gain-schedule table: pitch angles [rad]. --2.407e-02 -2.136e-02 -1.912e-02 -1.724e-02 -1.563e-02 -1.424e-02 -1.304e-02 -1.197e-02 -1.103e-02 -1.020e-02 -9.442e-03 -8.763e-03 -8.146e-03 -7.584e-03 -7.070e-03 -6.597e-03 -6.162e-03 -5.760e-03 -5.386e-03 -5.039e-03 -4.715e-03 -4.413e-03 -4.130e-03 -3.864e-03 -3.614e-03 -3.378e-03 -3.156e-03 -2.946e-03 -2.747e-03 -2.558e-03 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. --3.864e-03 -3.498e-03 -3.195e-03 -2.940e-03 -2.723e-03 -2.536e-03 -2.372e-03 -2.229e-03 -2.102e-03 -1.989e-03 -1.887e-03 -1.795e-03 -1.712e-03 -1.636e-03 -1.566e-03 -1.503e-03 -1.444e-03 -1.389e-03 -1.339e-03 -1.292e-03 -1.248e-03 -1.207e-03 -1.169e-03 -1.133e-03 -1.099e-03 -1.068e-03 -1.038e-03 -1.009e-03 -9.822e-04 -9.568e-04 ! PC_GS_KI - Gain-schedule table: pitch controller ki gains [-]. +0.049 0.076 0.097 0.115 0.131 0.146 0.160 0.173 0.185 0.197 0.208 0.219 0.230 0.240 0.250 0.260 0.269 0.279 0.288 0.297 0.306 0.315 0.324 0.332 0.341 0.349 0.357 0.365 0.373 0.381 ! PC_GS_angles - Gain-schedule table: pitch angles [rad]. +-1.813e-02 -1.538e-02 -1.318e-02 -1.138e-02 -9.887e-03 -8.625e-03 -7.545e-03 -6.610e-03 -5.793e-03 -5.072e-03 -4.432e-03 -3.860e-03 -3.345e-03 -2.880e-03 -2.457e-03 -2.071e-03 -1.717e-03 -1.392e-03 -1.092e-03 -8.142e-04 -5.563e-04 -3.163e-04 -9.232e-05 1.171e-04 3.135e-04 4.978e-04 6.713e-04 8.349e-04 9.893e-04 1.135e-03 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. +-2.846e-03 -2.526e-03 -2.270e-03 -2.062e-03 -1.889e-03 -1.742e-03 -1.617e-03 -1.508e-03 -1.413e-03 -1.330e-03 -1.255e-03 -1.189e-03 -1.129e-03 -1.075e-03 -1.026e-03 -9.810e-04 -9.400e-04 -9.022e-04 -8.674e-04 -8.351e-04 -8.052e-04 -7.773e-04 -7.513e-04 -7.270e-04 -7.042e-04 -6.828e-04 -6.626e-04 -6.436e-04 -6.257e-04 -6.087e-04 ! PC_GS_KI - Gain-schedule table: pitch controller ki gains [-]. 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 ! PC_GS_KD - Gain-schedule table: pitch controller kd gains 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 ! PC_GS_TF - Gain-schedule table: pitch controller tf gains (derivative filter) 1.570000000000 ! PC_MaxPit - Maximum physical pitch limit, [rad]. @@ -95,7 +95,7 @@ !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries -0.5000 0.5517 0.6034 0.6552 0.7069 0.7586 0.8103 0.8621 0.9138 0.9655 1.0172 1.0690 1.1207 1.1724 1.2241 1.2759 1.3276 1.3793 1.4310 1.4828 1.5345 1.5862 1.6379 1.6897 1.7414 1.7931 1.8448 1.8966 1.9483 2.0000 2.0333 2.0667 2.1000 2.1333 2.1667 2.2000 2.2333 2.2667 2.3000 2.3333 2.3667 2.4000 2.4333 2.4667 2.5000 2.5333 2.5667 2.6000 2.6333 2.6667 2.7000 2.7333 2.7667 2.8000 2.8333 2.8667 2.9000 2.9333 2.9667 3.0000 ! VS_FBP_U - Operating schedule table: Wind speeds [m/s]. +0.5000 0.5517 0.6034 0.6552 0.7069 0.7586 0.8103 0.8621 0.9138 0.9655 1.0172 1.0690 1.1207 1.1724 1.2241 1.2759 1.3276 1.3793 1.4310 1.4828 1.5345 1.5862 1.6379 1.6897 1.7414 1.7931 1.8448 1.8966 1.9483 2.0000 2.0667 2.1333 2.2000 2.2667 2.3333 2.4000 2.4667 2.5333 2.6000 2.6667 2.7333 2.8000 2.8667 2.9333 3.0000 3.0667 3.1333 3.2000 3.2667 3.3333 3.4000 3.4667 3.5333 3.6000 3.6667 3.7333 3.8000 3.8667 3.9333 4.0000 ! VS_FBP_U - Operating schedule table: Wind speeds [m/s]. 1.8550e+01 2.0469e+01 2.2388e+01 2.4307e+01 2.6226e+01 2.8145e+01 3.0064e+01 3.1983e+01 3.3902e+01 3.5821e+01 3.7740e+01 3.9659e+01 4.1578e+01 4.3497e+01 4.5416e+01 4.7334e+01 4.9253e+01 5.1172e+01 5.3091e+01 5.5010e+01 5.6929e+01 5.8848e+01 6.0767e+01 6.2686e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 6.3812e+01 ! VS_FBP_Omega - Operating schedule table: Generator speeds [rad/s]. 4.4631e+02 5.4342e+02 6.5009e+02 7.6631e+02 8.9208e+02 1.0274e+03 1.1723e+03 1.3267e+03 1.4907e+03 1.6642e+03 1.8473e+03 2.0400e+03 2.2422e+03 2.4539e+03 2.6752e+03 2.9060e+03 3.1464e+03 3.3964e+03 3.6559e+03 3.9250e+03 4.2036e+03 4.4917e+03 4.7894e+03 5.0967e+03 5.4773e+03 5.9648e+03 6.4710e+03 6.9951e+03 7.5363e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 8.0937e+03 ! VS_FBP_Tau - Operating schedule table: Generator torques [N m]. @@ -113,8 +113,8 @@ 0.1752 0.1702 0.1651 0.1601 0.1547 0.1492 0.1437 0.1377 0.1316 0.1253 0.1184 0.1116 0.1038 0.0960 0.0869 0.0774 0.0663 0.0530 0.0360 0.0000 ! PRC_Pitch_Table - Table of fine pitch versus PRC_R_Table, length should be PRC_Table_n [rad]. Used if PRC_Mode = 1. 2 ! PRC_n - Number of elements in PRC_WindSpeeds and PRC_GenSpeeds array 0.07854 ! PRC_LPF_Freq - Frequency of the low pass filter on the wind speed estimate used to set PRC_GenSpeeds [rad/s] -3.0000 25.0000 ! PRC_WindSpeeds - Array of wind speeds used in rotor speed vs. wind speed lookup table [m/s] -7.9168e-01 7.9168e-01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] +0.5000 4.0000 ! PRC_WindSpeeds - Array of wind speeds used in rotor speed vs. wind speed lookup table [m/s] +6.3812e+01 6.3812e+01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] !------- WIND SPEED ESTIMATOR --------------------------------------------- 10.000 ! WE_BladeRadius - Blade length (distance from hub center to blade tip), [m] @@ -127,8 +127,8 @@ "MHK_RM1_Cp_Ct_Cq.txt" ! PerfFileName - File containing rotor performance tables (Cp,Ct,Cq) (absolute path or relative to this file) 36 49 ! PerfTableSize - Size of rotor performance tables, first number refers to number of blade pitch angles, second number referse to number of tip-speed ratios 60 ! WE_FOPoles_N - Number of first-order system poles used in EKF -0.500 0.552 0.603 0.655 0.707 0.759 0.810 0.862 0.914 0.966 1.017 1.069 1.121 1.172 1.224 1.276 1.328 1.379 1.431 1.483 1.534 1.586 1.638 1.690 1.741 1.793 1.845 1.897 1.948 2.000 2.033 2.067 2.100 2.133 2.167 2.200 2.233 2.267 2.300 2.333 2.367 2.400 2.433 2.467 2.500 2.533 2.567 2.600 2.633 2.667 2.700 2.733 2.767 2.800 2.833 2.867 2.900 2.933 2.967 3.000 ! WE_FOPoles_v - Wind speeds corresponding to first-order system poles [m/s] --2.996e-02 -3.306e-02 -3.616e-02 -3.926e-02 -4.236e-02 -4.546e-02 -4.856e-02 -5.166e-02 -5.475e-02 -5.785e-02 -6.095e-02 -6.405e-02 -6.715e-02 -7.025e-02 -7.335e-02 -7.645e-02 -7.955e-02 -8.265e-02 -8.575e-02 -8.885e-02 -9.195e-02 -9.505e-02 -9.814e-02 -1.012e-01 -1.045e-01 -1.078e-01 -1.105e-01 -1.126e-01 -1.141e-01 -1.148e-01 3.763e-02 3.168e-02 2.301e-02 1.259e-02 5.960e-04 -1.099e-02 -2.403e-02 -3.679e-02 -5.073e-02 -6.410e-02 -7.882e-02 -9.271e-02 -1.075e-01 -1.226e-01 -1.375e-01 -1.533e-01 -1.687e-01 -1.843e-01 -2.009e-01 -2.166e-01 -2.329e-01 -2.499e-01 -2.663e-01 -2.830e-01 -3.004e-01 -3.175e-01 -3.344e-01 -3.520e-01 -3.701e-01 -3.872e-01 ! WE_FOPoles - First order system poles [1/s] +0.500 0.552 0.603 0.655 0.707 0.759 0.810 0.862 0.914 0.966 1.017 1.069 1.121 1.172 1.224 1.276 1.328 1.379 1.431 1.483 1.534 1.586 1.638 1.690 1.741 1.793 1.845 1.897 1.948 2.000 2.067 2.133 2.200 2.267 2.333 2.400 2.467 2.533 2.600 2.667 2.733 2.800 2.867 2.933 3.000 3.067 3.133 3.200 3.267 3.333 3.400 3.467 3.533 3.600 3.667 3.733 3.800 3.867 3.933 4.000 ! WE_FOPoles_v - Wind speeds corresponding to first-order system poles [m/s] +-2.996e-02 -3.306e-02 -3.616e-02 -3.926e-02 -4.236e-02 -4.546e-02 -4.856e-02 -5.166e-02 -5.475e-02 -5.785e-02 -6.095e-02 -6.405e-02 -6.715e-02 -7.025e-02 -7.335e-02 -7.645e-02 -7.955e-02 -8.265e-02 -8.575e-02 -8.885e-02 -9.195e-02 -9.505e-02 -9.814e-02 -1.012e-01 -1.045e-01 -1.078e-01 -1.105e-01 -1.126e-01 -1.141e-01 -1.148e-01 3.168e-02 1.259e-02 -1.099e-02 -3.679e-02 -6.410e-02 -9.271e-02 -1.226e-01 -1.533e-01 -1.843e-01 -2.166e-01 -2.499e-01 -2.830e-01 -3.175e-01 -3.520e-01 -3.872e-01 -4.233e-01 -4.590e-01 -4.963e-01 -5.326e-01 -5.705e-01 -6.075e-01 -6.460e-01 -6.837e-01 -7.226e-01 -7.607e-01 -8.000e-01 -8.386e-01 -8.782e-01 -9.174e-01 -9.570e-01 ! WE_FOPoles - First order system poles [1/s] !------- YAW CONTROL ------------------------------------------------------ 0.00000 ! Y_uSwitch - Wind speed to switch between Y_ErrThresh. If zero, only the second value of Y_ErrThresh is used [m/s] @@ -149,8 +149,8 @@ !------- MINIMUM PITCH SATURATION ------------------------------------------- 60 ! PS_BldPitchMin_N - Number of values in minimum blade pitch lookup table (should equal number of values in PS_WindSpeeds and PS_BldPitchMin) -0.5000 0.5517 0.6034 0.6552 0.7069 0.7586 0.8103 0.8621 0.9138 0.9655 1.0172 1.0690 1.1207 1.1724 1.2241 1.2759 1.3276 1.3793 1.4310 1.4828 1.5345 1.5862 1.6379 1.6897 1.7414 1.7931 1.8448 1.8966 1.9483 2.0000 2.0333 2.0667 2.1000 2.1333 2.1667 2.2000 2.2333 2.2667 2.3000 2.3333 2.3667 2.4000 2.4333 2.4667 2.5000 2.5333 2.5667 2.6000 2.6333 2.6667 2.7000 2.7333 2.7667 2.8000 2.8333 2.8667 2.9000 2.9333 2.9667 3.0000 ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s] -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0077 0.0181 0.0276 0.0368 0.0456 0.0543 0.0597 0.0650 0.0703 0.0754 0.0805 0.0857 0.0906 0.0955 0.1004 0.1053 0.1100 0.1148 0.1195 0.1242 0.1288 0.1334 0.1380 0.1425 0.1470 0.1515 0.1560 0.1604 0.1648 0.1691 0.1736 0.1778 0.1821 0.1864 0.1907 0.1950 ! PS_BldPitchMin - Minimum blade pitch angles [rad] +0.5000 0.5517 0.6034 0.6552 0.7069 0.7586 0.8103 0.8621 0.9138 0.9655 1.0172 1.0690 1.1207 1.1724 1.2241 1.2759 1.3276 1.3793 1.4310 1.4828 1.5345 1.5862 1.6379 1.6897 1.7414 1.7931 1.8448 1.8966 1.9483 2.0000 2.0667 2.1333 2.2000 2.2667 2.3333 2.4000 2.4667 2.5333 2.6000 2.6667 2.7333 2.8000 2.8667 2.9333 3.0000 3.0667 3.1333 3.2000 3.2667 3.3333 3.4000 3.4667 3.5333 3.6000 3.6667 3.7333 3.8000 3.8667 3.9333 4.0000 ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s] +0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0077 0.0181 0.0276 0.0368 0.0456 0.0543 0.0650 0.0754 0.0857 0.0955 0.1053 0.1148 0.1242 0.1334 0.1425 0.1515 0.1604 0.1691 0.1778 0.1864 0.1950 0.2033 0.2117 0.2200 0.2282 0.2363 0.2444 0.2524 0.2604 0.2682 0.2760 0.2838 0.2915 0.2991 0.3067 0.3143 ! PS_BldPitchMin - Minimum blade pitch angles [rad] !------- STARTUP ----------------------------------------------------------- 120.0000000000 ! SU_StartTime - Time to start startup routine [s] @@ -168,7 +168,7 @@ 0 ! SD_EnableYawError - Shutdown when yaw error exceeds a threshold, [-] 0 ! SD_EnableGenSpeed - Shutdown when generator speed exceeds a threshold, [-] 0 ! SD_EnableTime - Shutdown at a predefined time, [-] -0.249980000000 ! SD_MaxPit - Maximum blade pitch angle to initiate shutdown, [rad] +0.381260000000 ! SD_MaxPit - Maximum blade pitch angle to initiate shutdown, [rad] 0.418880000000 ! SD_PitchCornerFreq - Cutoff Frequency for first order low-pass filter for blade pitch angle for shutdown, [rad/s] 30.00000000000 ! SD_MaxYawError - Maximum yaw error to initiate shutdown, [deg] 0.418880000000 ! SD_YawErrorCornerFreq - Cutoff Frequency for first order low-pass filter for yaw error for shutdown, [rad/s] @@ -184,7 +184,7 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 --0.4002 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +-0.4160 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] 2.1000 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] !------- FLAP ACTUATION ----------------------------------------------------- diff --git a/Examples/Test_Cases/NREL-5MW/DISCON.IN b/Examples/Test_Cases/NREL-5MW/DISCON.IN index 0a74b9c94..93a7c1dde 100644 --- a/Examples/Test_Cases/NREL-5MW/DISCON.IN +++ b/Examples/Test_Cases/NREL-5MW/DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the NREL-5MW wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 1 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,7 +10,7 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 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 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -2 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +2 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 1 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 1 ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control) @@ -114,7 +114,7 @@ 2 ! PRC_n - Number of elements in PRC_WindSpeeds and PRC_GenSpeeds array 0.07854 ! PRC_LPF_Freq - Frequency of the low pass filter on the wind speed estimate used to set PRC_GenSpeeds [rad/s] 3.0000 25.0000 ! PRC_WindSpeeds - Array of wind speeds used in rotor speed vs. wind speed lookup table [m/s] -7.9168e-01 7.9168e-01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] +1.2291e+02 1.2291e+02 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] !------- WIND SPEED ESTIMATOR --------------------------------------------- 63.000 ! WE_BladeRadius - Blade length (distance from hub center to blade tip), [m] diff --git a/Examples/Test_Cases/NREL_2p8_127/NREL-2p8-127_DISCON.IN b/Examples/Test_Cases/NREL_2p8_127/NREL-2p8-127_DISCON.IN index e50f61bd8..6b3369022 100644 --- a/Examples/Test_Cases/NREL_2p8_127/NREL-2p8-127_DISCON.IN +++ b/Examples/Test_Cases/NREL_2p8_127/NREL-2p8-127_DISCON.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the NREL-2p8-127 wind turbine -! - File written using ROSCO version 2.10.6 controller tuning logic on 06/09/26 +! - File written using ROSCO version 2.10.6 controller tuning logic on 09/16/26 !------- SIMULATION CONTROL ------------------------------------------------------------ 2 ! LoggingLevel - 0: write no debug files, 1: write standard output .dbg-file, 2: LoggingLevel 1 + ROSCO LocalVars (.dbg2) 3: LoggingLevel 2 + complete avrSWAP-array (.dbg3) @@ -10,7 +10,7 @@ !------- CONTROLLER FLAGS ------------------------------------------------- 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 1 ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions) -3 ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) +3 ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) 0 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) 0 ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking) 1 ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control) @@ -114,7 +114,7 @@ 2 ! PRC_n - Number of elements in PRC_WindSpeeds and PRC_GenSpeeds array 0.07854 ! PRC_LPF_Freq - Frequency of the low pass filter on the wind speed estimate used to set PRC_GenSpeeds [rad/s] 3.0000 25.0000 ! PRC_WindSpeeds - Array of wind speeds used in rotor speed vs. wind speed lookup table [m/s] -7.9168e-01 7.9168e-01 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] +1.2291e+02 1.2291e+02 ! PRC_GenSpeeds - Array of generator speeds corresponding to PRC_WindSpeeds [rad/s] !------- WIND SPEED ESTIMATOR --------------------------------------------- 63.457 ! WE_BladeRadius - Blade length (distance from hub center to blade tip), [m] diff --git a/Examples/Tune_Cases/BAR.yaml b/Examples/Tune_Cases/BAR.yaml index bdf96e066..3fcf7de7f 100644 --- a/Examples/Tune_Cases/BAR.yaml +++ b/Examples/Tune_Cases/BAR.yaml @@ -27,7 +27,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW.yaml b/Examples/Tune_Cases/IEA15MW.yaml index c12112b0e..62c146122 100644 --- a/Examples/Tune_Cases/IEA15MW.yaml +++ b/Examples/Tune_Cases/IEA15MW.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml b/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml index 30a8f783a..b52b1510f 100644 --- a/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml +++ b/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_FOCAL.yaml b/Examples/Tune_Cases/IEA15MW_FOCAL.yaml index 1785f77b0..915b58c0e 100644 --- a/Examples/Tune_Cases/IEA15MW_FOCAL.yaml +++ b/Examples/Tune_Cases/IEA15MW_FOCAL.yaml @@ -30,7 +30,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml b/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml index 8b5b6577d..8152e67eb 100644 --- a/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml +++ b/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_OL.yaml b/Examples/Tune_Cases/IEA15MW_OL.yaml index 8bd515a2c..699730839 100644 --- a/Examples/Tune_Cases/IEA15MW_OL.yaml +++ b/Examples/Tune_Cases/IEA15MW_OL.yaml @@ -32,7 +32,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 1 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_PRC.yaml b/Examples/Tune_Cases/IEA15MW_PRC.yaml index 2a0faacba..abb78c150 100644 --- a/Examples/Tune_Cases/IEA15MW_PRC.yaml +++ b/Examples/Tune_Cases/IEA15MW_PRC.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_ballast.yaml b/Examples/Tune_Cases/IEA15MW_ballast.yaml index 95013c483..c34e6e4de 100644 --- a/Examples/Tune_Cases/IEA15MW_ballast.yaml +++ b/Examples/Tune_Cases/IEA15MW_ballast.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_cable.yaml b/Examples/Tune_Cases/IEA15MW_cable.yaml index 8b67b82bc..2ef1b13e1 100644 --- a/Examples/Tune_Cases/IEA15MW_cable.yaml +++ b/Examples/Tune_Cases/IEA15MW_cable.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/IEA15MW_robust.yaml b/Examples/Tune_Cases/IEA15MW_robust.yaml index ea2ab70ad..55bf71155 100644 --- a/Examples/Tune_Cases/IEA15MW_robust.yaml +++ b/Examples/Tune_Cases/IEA15MW_robust.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 2 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch on the measured generator speed {0: disable, 1: enable} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/NREL5MW.yaml b/Examples/Tune_Cases/NREL5MW.yaml index 69f78982c..62d57dbe6 100644 --- a/Examples/Tune_Cases/NREL5MW.yaml +++ b/Examples/Tune_Cases/NREL5MW.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 1 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch filter on generator speed and/or tower fore-aft motion (for floating) {0: disable, 1: generator speed, 2: tower-top fore-aft motion, 3: generator speed and tower-top fore-aft motion} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} VS_ConstPower: 1 # Use constant power PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} diff --git a/Examples/Tune_Cases/NREL5MW_PassThrough.yaml b/Examples/Tune_Cases/NREL5MW_PassThrough.yaml index 2db0472e9..1ce3c5a01 100644 --- a/Examples/Tune_Cases/NREL5MW_PassThrough.yaml +++ b/Examples/Tune_Cases/NREL5MW_PassThrough.yaml @@ -31,7 +31,7 @@ controller_params: F_LPFType: 1 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 0 # Notch filter on generator speed and/or tower fore-aft motion (for floating) {0: disable, 1: generator speed, 2: tower-top fore-aft motion, 3: generator speed and tower-top fore-aft motion} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} VS_ConstPower: 1 # Use constant power PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} diff --git a/Examples/Tune_Cases/RM1_MHK.yaml b/Examples/Tune_Cases/RM1_MHK.yaml index 4262abc46..2fef67ef0 100644 --- a/Examples/Tune_Cases/RM1_MHK.yaml +++ b/Examples/Tune_Cases/RM1_MHK.yaml @@ -16,7 +16,7 @@ turbine_params: rated_rotor_speed: 1.204 # 11.5 rpm # Rated rotor speed [rad/s] v_min: 0.5 # Cut-in wind speed [m/s] v_rated: 2.0 # Rated wind speed [m/s] - v_max: 3.0 # Cut-out wind speed [m/s], -- Does not need to be exact (JUST ASSUME FOR NOW) + v_max: 4.0 # Cut-out wind speed [m/s], -- Does not need to be exact (JUST ASSUME FOR NOW) max_pitch_rate: 0.1745 # Maximum blade pitch rate [rad/s] max_torque_rate: 7800. # Maximum torque rate [Nm/s], {~1/4 VS_RtTq/s} rated_power: 500000 # Rated Power [W] @@ -32,12 +32,12 @@ controller_params: F_LPFType: 1 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 1 # Notch filter on generator speed and/or tower fore-aft motion (for floating) {0: disable, 1: generator speed, 2: tower-top fore-aft motion, 3: generator speed and tower-top fore-aft motion} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 3 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} - VS_ConstPower: 1 # Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control} + VS_ControlMode: 3 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} + VS_ConstPower: 1 # Generator torque control mode in above rated conditions with variable blade pitch {0: constant torque, 1: constant power} PC_ControlMode: 1 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} SS_Mode: 1 # Setpoint Smoother mode {0: no setpoint smoothing, 1: introduce setpoint smoothing} - WE_Mode: 0 # Wind speed estimator mode {0: One-second low pass filtered hub height wind speed, 1: Immersion and Invariance Estimator (Ortega et al.)} + WE_Mode: 2 # Wind speed estimator mode {0: One-second low pass filtered hub height wind speed, 1: Immersion and Invariance Estimator (Ortega et al.), 2: Extended Kalman Filter} PS_Mode: 1 # Pitch saturation mode {0: no pitch saturation, 1: peak shaving, 2: Cp-maximizing pitch saturation, 3: peak shaving and Cp-maximizing pitch saturation} SD_Mode: 0 # Shutdown mode {0: no shutdown procedure, 1: pitch to max pitch at shutdown} Fl_Mode: 1 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} diff --git a/Examples/Tune_Cases/RM1_MHK_FBP.yaml b/Examples/Tune_Cases/RM1_MHK_FBP.yaml index de6bca870..4a688a068 100644 --- a/Examples/Tune_Cases/RM1_MHK_FBP.yaml +++ b/Examples/Tune_Cases/RM1_MHK_FBP.yaml @@ -15,7 +15,9 @@ turbine_params: rotor_inertia: 92169 # Rotor inertia [kg m^2], {Available in Elastodyn .sum file} rated_rotor_speed: 1.204 # 11.5 rpm # Rated rotor speed [rad/s] v_min: 0.5 # Cut-in wind speed [m/s] - v_rated: 2.0 # Rated wind speed [m/s] + # Rated SPEED point, not rated power: rotor hits 1.204 rad/s at TSR 7, and ROSCO starts the + # FBP lookup here. Does not cap speed; see the MHK docs on the rated transition. + v_rated: 1.72 v_max: 4.0 # Cut-out wind speed [m/s], -- Does not need to be exact (JUST ASSUME FOR NOW) max_pitch_rate: 0.1745 # Maximum blade pitch rate [rad/s] max_torque_rate: 1500000. # Maximum torque rate [Nm/s], {~1/4 VS_RtTq/s} @@ -32,7 +34,7 @@ controller_params: F_LPFType: 1 # {1: first-order low-pass filter, 2: second-order low-pass filter}, [rad/s] (currently filters generator speed and pitch control signals) F_NotchType: 1 # Notch filter on generator speed and/or tower fore-aft motion (for floating) {0: disable, 1: generator speed, 2: tower-top fore-aft motion, 3: generator speed and tower-top fore-aft motion} IPC_ControlMode: 0 # Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0: off, 1: 1P reductions, 2: 1P+2P reductions} - VS_ControlMode: 2 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control} + VS_ControlMode: 4 # Generator torque control mode in below rated conditions {0: torque control disabled, 1: K*Omega^2, 2: WSE TSR-tracking PI control, 3: power TSR-tracking PI control, 4: Torque TSR-tracking PI control}, paired with VS_FBP = 3 below VS_ConstPower: 0 # Generator torque control mode in above rated conditions with variable blade pitch {0: constant torque, 1: constant power} PC_ControlMode: 0 # Blade pitch control mode {0: No pitch, fix to fine pitch, 1: active PI blade pitch control} Y_ControlMode: 0 # Yaw control mode {0: no yaw control, 1: yaw rate control, 2: yaw-by-IPC} diff --git a/docs/index.rst b/docs/index.rst index fe11ca996..fa3047a35 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,6 +21,17 @@ The toolbox has other capabilities like simple 1-DOF turbine simulations for qui Source code for ROSCO toolset can be found in this `github repository `_ and it can be installed following the instructions provided in :ref:`install`. +Building the Documentation +-------------------------- + +To build these docs locally, navigate to the :code:`docs` directory and run: + +.. code-block:: bash + + sphinx-build . ./_build/ + +This generates HTML documentation in the :code:`_build` folder. + **Documentation Directory** .. toctree:: diff --git a/docs/source/marine_hydro.rst b/docs/source/marine_hydro.rst index cbde54968..2015ec492 100644 --- a/docs/source/marine_hydro.rst +++ b/docs/source/marine_hydro.rst @@ -3,15 +3,43 @@ ROSCO Control of Marine Hydrokinetic Turbines (MHKs) ==================================================== +.. note:: + The fixed-blade-pitch (FBP) control method, its implementation in ROSCO and the + ROSCO toolbox, and the verification study documented here were developed by + **David Stockhouse** (University of Colorado). + This page is adapted from his presentation *Fixed-Blade-Pitch Control in ROSCO + for MHK Turbines* [Stockhouse2025]_. + + Introduction --------------- -Here, we detail the control of MHK turbines in above rated flow speeds. -In below rated flow speeds, torque control is used to operate the turbine at it's maximum tip speed ratio (TSR) and pitch angle. - -For MHK turbines equipped with pitch actuators, those turbine can can use control schemes similar to those used by wind turbines, which reduce the Cp surface by increasing the pitch angle (black). -For MHK turbines without pitch actuation, we provide a few control methods for controlling the power of the turbine using only torque control. -Overspeed control increases the TSR along the fixed pitch line on the Cp surface below (blue circle) by decreasing the generator torque. +Here, we detail the control of MHK turbines in above-rated flow speeds. +In below-rated flow speeds, torque control is used to operate the turbine at its +maximum tip speed ratio (TSR) and pitch angle, as it is for wind turbines +[Johnson2006]_. + +The ROSCO baseline for marine turbines is adapted from the variable-pitch wind +turbine controller [Abbas2022]_. +Many marine turbine designs, however, do not have pitch actuators, because the +cost, complexity, and reliability burden of a submerged pitch system is often +prohibitive. +Assuming a fixed (optimal) blade pitch, we instead redefine the operating schedule +of TSR to find the equilibrium between hydrodynamic and generator torque. +This trades pitch actuation for trade-offs in blade loads, rotor speed, generator +sizing, and environmental impact, which are discussed throughout this page. + +Regulating power above rated requires a means of reducing the power coefficient +:math:`C_p`. +For MHK turbines equipped with pitch actuators, those turbines can use control +schemes similar to those used by wind turbines, which reduce the :math:`C_p` +surface by increasing the pitch angle and decreasing TSR (black). +For MHK turbines without pitch actuation, we provide a few control methods for +controlling the power of the turbine using only torque control. +Any such controller is constrained by the requirement that the steady state +operating points be in equilibrium with the inflow torque. +Overspeed control increases the TSR along the fixed pitch line on the :math:`C_p` +surface below (blue circle) by decreasing the generator torque. Underspeed control decreases the TSR (red circle) by increasing the torque. .. _cp_surface_annotated: @@ -19,18 +47,294 @@ Underspeed control decreases the TSR (red circle) by increasing the torque. :align: center :width: 90% +The feature set added to ROSCO consists of an FBP generator torque controller that +is configurable to automatically generate an overspeed or underspeed operating +schedule, a configurable control approach for realizing that operating schedule, +and automatically tuned feedback gains. + + +.. _variable_pitch_mhk: + +Variable-Pitch MHK Control +--------------------------- + +Nothing in the ROSCO controller changes for an MHK turbine that does have pitch +actuators. +The same collective pitch PI controller, gain scheduling, peak shaving, and +setpoint smoothing are used as for a wind turbine. +Only the tuning inputs change, and a few of them change enough to be worth noting. +A worked example is provided in :code:`Examples/26_marine_hydro.py`, tuned from +:code:`Examples/Tune_Cases/RM1_MHK.yaml`. +The comparisons below are against the NREL 2.8 MW land-based reference turbine +(:code:`Examples/Tune_Cases/NREL2p8.yaml`). + +Fluid Density +^^^^^^^^^^^^^^ + +Density selection is the only MHK-specific branch in the tuning toolbox. +When the OpenFAST model sets :code:`MHK > 0`, the toolbox uses the water density +:code:`WtrDens` in place of :code:`AirDens`. +The sensitivities used for gain scheduling +(:math:`\partial\tau/\partial\beta`, :math:`\partial\tau/\partial\lambda`) and the +thrust used for peak shaving all scale linearly with :math:`\rho`, so the rotor +performance tables and the density must describe the same fluid. +Otherwise the gains are wrong by nearly three orders of magnitude. +In the generated DISCON file this value appears as :code:`WE_RhoAir`, which is +1025 kg/m³ for the RM1, despite the parameter name. + +A Compressed Region 3 +^^^^^^^^^^^^^^^^^^^^^^ -Over/Underspeed Reference Setpoints ------------------------------------ +Tidal flow speeds span a much narrower range than wind speeds, which compresses +everything the above-rated controller has to work with. -The steady state generator-speed setpoints are determined by the Cp contour. -Overspeed achieves up to 3x rated speed, which has additional consequences for blade loads (e.g., cavitation) +.. list-table:: + :header-rows: 1 + :widths: auto + + * - + - NREL 2.8 MW (wind) + - RM1 (MHK) + * - Cut-in / rated / cut-out + - 3 / 11.4 / 25 m/s + - 0.5 / 2.0 / 4.0 m/s + * - Cut-out / rated ratio + - 2.2 + - 2.0 + * - Gain-schedule pitch range + - 4.4° to 25.6° + - 1.7° to 14.3° + * - Rotor performance table + - 30 x 30, TSR 2–12 + - 36 x 49, TSR 0.5–24.5 + +The entire above-rated pitch travel is roughly 12°, so the pitch resolution of the +:math:`C_p` table limits the quality of the gain schedule in a way it does not for +a wind turbine. +The RM1 table is generated at 1° pitch resolution for this reason. +The pitch rate limit :code:`PC_MaxRat` is rarely the binding constraint: the RM1 +keeps the wind default of 0.1745 rad/s (10°/s), which traverses the full Region 3 +range in about a second. + +Pitch Bandwidth and Filtering +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The RM1 is tuned at :code:`omega_pc` = 0.35 rad/s with :code:`zeta_pc` = 1.0, +against 0.137 rad/s and 2.0 for the 2.8 MW wind turbine, so the pitch loop is +roughly 2.5x faster. +Rated rotor speed is nearly the same for both machines (1.20 versus 1.27 rad/s), +so the faster loop sits closer to the rotor-periodic disturbances. How much +closer depends on the blade count. + +Summing the per-blade loads of a :math:`B`-bladed rotor cancels every harmonic +except multiples of :math:`B\Omega`, so only those reach rotor torque and, in +turn, the generator speed the pitch controller acts on. A three-bladed rotor +passes 3P, 6P, ...; a two-bladed rotor passes 2P, 4P, .... Both rotors average, +but a two-bladed rotor begins averaging one harmonic lower, and 1P survives on +neither except through blade-to-blade imbalance. The relevant comparison is each +machine's lowest surviving harmonic: + +.. list-table:: + :header-rows: 1 + :widths: auto + + * - + - NREL 2.8 MW (wind) + - RM1 (MHK) + * - Blades + - 3 + - 2 + * - Lowest surviving harmonic + - 3P = 3.80 rad/s + - 2P = 2.41 rad/s + * - Separation from :code:`omega_pc` + - 28x + - 7x + +The margin is roughly four times tighter, from the combination of a faster loop +and a lower first harmonic. This advantage belongs to the blade count only at a +given rotor speed: a three-bladed rotor of the same diameter typically runs +slower, which moves 3P back down. + +Two blades carry a second penalty. The in-plane inertia of a three-bladed rotor is +isotropic about the hub, while a two-bladed rotor's varies with azimuth, so even a +perfectly balanced two-bladed rotor couples to the support structure at 2P through +rotor anisotropy alone. + +The MHK tuning case therefore enables filtering that the wind cases leave off: + +.. code-block:: yaml + + DISCON: + F_NumNotchFilts: 2 + F_NotchFreqs: [1.0, 2.42] # 2.42 rad/s is 2P + F_NotchBetaNum: [0.0, 0.0] + F_NotchBetaDen: [0.25, 0.25] + F_GenSpdNotch_N: 2 + F_GenSpdNotch_Ind: [1, 2] + F_TwrTopNotch_N: 2 + F_TwrTopNotch_Ind: [1, 2] + +Both notches are applied twice: :code:`F_GenSpdNotch_Ind` filters the generator +speed used by the pitch and torque loops, and :code:`F_TwrTopNotch_Ind` filters +the nacelle fore-aft IMU acceleration used by the floating feedback term. + +.. TODO(DS): the second notch at 2.42 rad/s matches 2P at rated speed + (2 x 1.204 = 2.408). The first, at 1.0 rad/s, does not correspond to 1P + (1.204 rad/s), the platform frequency (0.4 rad/s), or the tower frequency + (3.34 rad/s), and with ``F_NotchBetaDen`` = 0.25 the notch is narrow enough + that the 17% offset from 1P is unlikely to be incidental. Please confirm what + this notch targets so it can be documented. + +The low-pass corner frequency moves the other way. +:code:`F_LPFCornerFreq` is derived from the blade edgewise frequency, and +hydrokinetic blades are short and stiff: 60.3 rad/s for the RM1 against 8.3 rad/s +for the 2.8 MW rotor. +The resulting corner frequency is 15.1 rad/s rather than 2.07 rad/s, well above +the control bandwidth, so the notch filters, rather than the low-pass filter, +limit the achievable bandwidth. + +Setpoint smoothing is also more aggressive on the pitch side, +:code:`SS_PCGain` = 0.05 against 0.001, because the Region 2.5 transition is +compressed into a narrow band of flow speed. + +Minimum Pitch and Peak Shaving +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The RM1 uses :code:`PC_MinPit` = 0, whereas the wind cases allow pitch to go +negative (-10° for the 2.8 MW) to recover a small amount of :math:`C_p` below +rated. +Peak shaving is enabled with :code:`ps_percent` = 0.8, which produces a minimum +pitch schedule that peaks near 11°, compared with about 20° for the wind turbine +over its much wider speed range. + +Peak shaving limits rotor thrust in the same way it does for a wind turbine. +Whether it also provides useful margin against cavitation depends on the rotor. +As shown in :ref:`speed_limits_cavitation`, the cavitation criterion is driven by +rotor speed and blade section :math:`-C_{p,min}`, and a pitch schedule is not a +substitute for evaluating it. +ROSCO performs no cavitation check at runtime, so a marginal variable-pitch MHK +schedule should be verified with an AeroDyn cavitation check +(:code:`CavitCheck = True`), which evaluates the full criterion at every blade node. + +.. TODO(DS): the RM1 tuning case sets ``PC_MinPit = 0`` rather than a negative + fine pitch. Please confirm whether this is a deliberate constraint (cavitation + or load-driven) or simply the default, so this can be stated rather than + described. + +Torque Control and Wind Speed Estimation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Above rated, the RM1 case uses constant power (:code:`VS_ConstPower` = 1) rather +than the constant torque used by the wind cases, with +:code:`max_torque_factor` = 1.5 sizing the torque saturation limit above rated +torque. +Individual pitch control is disabled, as the rotor has two blades. + +Note that :code:`VS_ControlMode` selects the *below*-rated torque control +strategy; :code:`VS_ConstPower` selects constant-torque versus constant-power +behavior above rated. +The RM1 case uses :code:`VS_ControlMode` = 3 (power-based TSR tracking) below +rated. + +The wind speed estimator is used as it is for wind turbines +(:code:`WE_Mode` = 2, the extended Kalman filter). +The estimate drives gain scheduling, the peak shaving minimum pitch lookup, and +setpoint smoothing, so degrading it to the filtered measurement +(:code:`WE_Mode` = 0) affects all three. + +Floating MHK +^^^^^^^^^^^^^ + +For a floating MHK turbine (:code:`MHK = 2`), the platform feedback term behaves +as it does for floating wind, but with much less frequency separation to work +with. +The RM1 floating case has a platform frequency of 0.4 rad/s against a pitch +control bandwidth of 0.35 rad/s, roughly a factor of 1.15. +The negative damping problem therefore cannot be avoided by detuning the pitch +controller, and is instead handled by the floating feedback term +(:code:`Fl_Mode` = 1, :code:`Kp_float` = -0.4). +Restoring stiffness comes from the mooring system rather than from waterplane +area, and wave excitation is attenuated with depth but not eliminated. + + +Over/Underspeed Reference Setpoints for Fixed-Pitch Control +----------------------------------------------------------- + +The steady state generator-speed setpoints are determined by the :math:`C_p` +contours intersecting with the fine-pitch line. +For the RM1, the constant-power overspeed schedule reaches roughly 5.7x rated +rotor speed at cut-out. +How much of that range a given rotor can use is limited by cavitation, discussed +in :ref:`speed_limits_cavitation`; on the RM1 the limit binds at about 1.9x, well +before the schedule gets there. +Rotor speed also has consequences for blade loads (high thrust). .. _cp_wg_sched: .. figure:: /images/mhk/03_cp_wg_sched.png :align: center :width: 90% +.. _fbp_rated_speed_overshoot: + +Rotor Speed Through the Rated Transition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Fixed-pitch control has no rated-speed saturation. +A variable-pitch controller holds the rotor at :math:`\Omega_{rated}` through +Region 2.5, letting the TSR slide below :math:`TSR_{operational}` as the flow +speed rises to rated; with the blade pitch fixed there is no second actuator to +do this, so the schedule stays on the :math:`TSR_{operational}` line until the +Region 3 power curve binds. + +Whenever the rotor reaches rated speed before the power curve binds, the schedule +therefore overshoots rated rotor speed in the band between the two. +For the RM1, the rotor reaches its rated 1.204 rad/s (11.5 rpm) at 1.72 m/s while +running at :math:`TSR_{operational} = 7`, but MPPT does not reach the 500 kW +rating until 2.0 m/s. +Across that band the schedule continues along the TSR line and peaks at +1.364 rad/s, or 13.0 rpm, about 1.13x rated, before the constant-power curve pulls +it back down. + +This is a deliberate trade in the shipped RM1 configuration, not an oversight: + +* The overshoot is well inside the cavitation limit of 2.26 rad/s + (:ref:`speed_limits_cavitation`), and generator torque within that band peaks at + about 6.8 kNm against a rated 8.3 kNm, so it is purely a question of drivetrain + and generator speed rating. + Verify that the machine tolerates a 13% speed excursion near rated before + reusing this configuration. +* The alternative is to set :code:`TSR_operational` to the design TSR rather than + the :math:`C_p`-maximizing one. + The RM1 rates at :math:`TSR = 6.02` (1.204 rad/s at 2.0 m/s), and pinning + :code:`TSR_operational` there removes the overshoot entirely, at the cost of + about 2.5% in below-rated :math:`C_p` (0.4358 against 0.4471). + The variable-pitch RM1 case reaches this same operating point on its own, + through rated-speed saturation. + +Note that :code:`v_rated` means different things to the two control paths, so the +two RM1 tuning cases set it differently. +For variable pitch it is the rated *power* speed, which is where pitch regulation +and the pitch gain schedule begin, and +:code:`Examples/Tune_Cases/RM1_MHK.yaml` sets 2.0 m/s. +For fixed pitch, power regulation is set by :code:`VS_FBP_U` and +:code:`VS_FBP_P` instead, so :code:`v_rated` is the rated *speed* point: the flow +speed at which the rotor reaches :code:`rated_rotor_speed` while tracking +:code:`TSR_operational`. +:code:`Examples/Tune_Cases/RM1_MHK_FBP.yaml` sets 1.72 m/s, which makes it agree +with :code:`VS_RefSpd`, the speed at which ROSCO begins using the FBP lookup +table. + +Setting :code:`v_rated` here does not cap the rotor speed, which is the easy +misreading. +It is where the toolbox stops holding the TSR at :code:`TSR_operational` and +begins solving for it from the :math:`C_p` inversion, and where ROSCO switches to +the lookup table. +Until the power curve binds, that solved TSR is still :code:`TSR_operational`, so +the schedule continues up the same line and the rotor keeps accelerating past +rated speed. +The lookup table contains that overshoot, and ROSCO tracks it deliberately. + Torque setpoints (:math:`\bar{\tau}`) determined by constant-power relationship :math:`\bar{\tau} = \frac{P_{rated}}{{\bar{\omega}}}`, where :math:`P_{rated}` is the rated power and :math:`\bar{\omega}` is the steady state generator speed. .. _cp_tg_sched: @@ -38,7 +342,7 @@ Torque setpoints (:math:`\bar{\tau}`) determined by constant-power relationship :align: center :width: 90% -In Region 3, the relationship between torque and speed are nonmonotic. +In Region 3, the relationship between torque and speed is nonmonotonic. Thus, more careful reference control design is required for managing the transition region. There are examples in the literature for saturation/smoothing during the transition region. @@ -56,9 +360,18 @@ Over/Underspeed Dynamics .. :align: center .. :width: 90% -At each operating point, the sensitivity is computed using the gradients of the Cp surface. +At each operating point, the sensitivity is computed using the gradients of the +:math:`C_p` surface, in the same manner as the Region 2 controller. The first-order system decay rate is represented by a single pole on the real axis: more negative means more rapidly stable (positive means unstable). Underspeed set points are open-loop unstable at high flow speeds. +The sign follows from what each set point asks the rotor to do. +Underspeed set points sit below :math:`TSR_{opt}`, where hydrodynamic torque still +grows with speed and generator torque is the only thing holding the speed down. +A small speed perturbation grows rather than decays, so losing torque control lets +the rotor run away. +Overspeed set points are past :math:`TSR_{opt}`, where hydrodynamic torque falls +off with speed, so the operating point is self-limiting and any speed perturbation +decays on its own. .. _cp_Agen_sched_annotated: .. figure:: /images/mhk/07_cp_Agen_sched_annotated.png @@ -70,7 +383,16 @@ Underspeed set points are open-loop unstable at high flow speeds. .. :align: center .. :width: 90% -@DS: what is shown here? +The same result can be viewed in the flow-speed/generator-speed plane. +Contours of constant hydrodynamic rotor torque intersect the constant-power +generator torque schedule at the equilibrium operating points. +The overspeed and underspeed branches are the two intersections available at each +flow speed. +The local slope of the torque surface across each intersection determines whether +that equilibrium is open-loop stable. + +.. TODO(DS): please confirm the description above matches what is plotted in + 09_cp_wg_Ta_contour_annotated.png (slide 11 carried no bullets). .. _cp_wg_Ta_contour_annotated: .. figure:: /images/mhk/09_cp_wg_Ta_contour_annotated.png @@ -81,7 +403,7 @@ Underspeed set points are open-loop unstable at high flow speeds. Fixed-Blade-Pitch (FBP) Control -------------------------------- -At each setpoint, the torque controller gains are determined using the process as the normal torque control in ROSCO. +At each setpoint, the torque controller gains are determined using the same process as the normal torque control in ROSCO. High magnitude gains are required to compensate for the open-loop instability of the underspeed system (red). .. _cp_kp_ki_sched: @@ -94,13 +416,59 @@ Alternate Region 3 Operating Schedules --------------------------------------- Using the ROSCO toolbox, we enable the user to determine their own operational power curve, besides a constant rated power. +Throughout this section, the *power requirement* is the generator power that the +selected Region 3 power curve demands at a given flow speed, that is, the +:code:`VS_FBP_P` input evaluated at that speed. +It is an upper bound on what is asked of the machine, not on what is available. +The toolbox clips it to the power the inflow can supply at fine pitch, so the MPPT +curve is the ceiling and no request can exceed it. +Relaxing the constant-power constraint in Region 3 raises the peak of the power +requirement, and with it the sustained power the generator must be sized for. +The five power curves studied, with their peak power requirement at cut-out +relative to rated power (equivalently, the generator resizing factor), are: + +.. list-table:: + :header-rows: 1 + :widths: auto + + * - Region 3 power curve + - Peak power requirement (x rated) + * - Extended Region 2 (MPPT) + - 8x + * - Quadratic extrapolation from tangent + - 7x + * - Linear extrapolation from tangent + - 4x + * - Linear to 2x rated power at cut-out + - 2x + * - Constant power + - 1x + +These multipliers follow from the RM1 :math:`C_p` surface and its +:math:`v_{rated}` to :math:`v_{cut-out}` range, and are reported to show the +relative spread between the curves. +They are not general: the same five curve definitions applied to another rotor +will produce different factors. .. _ext_P: .. figure:: /images/mhk/11_ext_P.png :align: center :width: 90% -The alternative power curves result in different speed and torque set points (dashed lines represent underspeed, solid overspeed). +Each non-MPPT option can follow either the overspeed or the underspeed +equilibrium trajectory. +The alternative power curves result in different speed and torque set points +(dashed lines represent underspeed, solid overspeed). +Speed setpoints always lie within the envelope bounded by the over- and +underspeed constant-power trajectories. +Constant power has the lowest power requirement of the five, so it departs +furthest from :math:`TSR_{opt}` and produces the widest speed excursion in either +direction. +The MPPT curve has the highest requirement and does not depart at all, tracking +:math:`\Omega \propto v` straight through rated. +The constant-power schedule is therefore the bounding case for rotor overspeed and +cavitation margin on the overspeed branch, and for generator torque headroom on +the underspeed branch. .. _ext_wg_sched_annotated: .. figure:: /images/mhk/16_ext_wg_sched_annotated.png @@ -118,6 +486,28 @@ The alternative power curves result in different speed and torque set points (da :align: center :width: 90% +Contours in the :math:`C_p` surface intersect with the equilibrium points in the +hydrodynamic torque surface, which is what constrains the speed and torque +schedule generated from a generic power curve input. +Plotted in the generator torque/speed plane below, with contours of constant +generator power behind them, the equilibrium trajectories run nearly *along* the +power contours rather than across them. +A small reduction in the power requirement therefore produces a large change in +the equilibrium speed and torque. +Note that the schedule above is plotted against rotor speed :math:`\Omega`, while +the torque/speed plane below is plotted against generator speed +:math:`\Omega_g = N_g \Omega`; for the RM1 the gearbox ratio is +:math:`N_g = 53`, so the two speed axes differ by that factor. +Dropping from the MPPT curve to the quadratic curve reduces the peak power +requirement from 8x to 7x rated, and moves the overspeed setpoint at cut-out from +roughly 2.5 to 3.5 rad/s rotor speed in the schedule above (about 130 to 185 rad/s +at the generator). +A 12% reduction in power buys a 40% change in speed. +These values are specific to the RM1. +The two branches also look very different in this plane: the underspeed branches +are nearly vertical (large torque change for small speed change), the overspeed +branches nearly horizontal (large speed change for small torque change). + .. _ext_wg_tg_P_contour: .. figure:: /images/mhk/13_ext_wg_tg_P_contour.png :align: center @@ -128,8 +518,11 @@ The alternative power curves result in different speed and torque set points (da .. :align: center .. :width: 90% -The stability can be represented by the sensitivity :math:`\frac{d\tau}{d\Omega}`. -Values less than 0 are open-loop stable. +The stability of the FBP set points can be represented by the sensitivity +:math:`\frac{d\tau}{d\Omega}`, following the same over/underspeed argument as +above. +Values less than 0 are open-loop stable; positive values must be stabilized by the +torque controller. .. _ext_Agen_sched: .. figure:: /images/mhk/18_ext_Agen_sched.png @@ -137,30 +530,132 @@ Values less than 0 are open-loop stable. :width: 90% The power curve selection also impacts the rotor thrust (F). -Underspeed control and lower power generally results in lower thrust. +Underspeed control and lower power generally result in lower thrust. +Overspeed trajectories approach substantially higher rotor thrust. +The overspeed MPPT trajectory in particular reaches thrust levels that are likely +unacceptable for the structure, and should be checked against the design loads +before being selected. .. _ext_wg_thrust_contour: .. figure:: /images/mhk/19_ext_wg_thrust_contour.png :align: center :width: 90% -.. .. _ext_wg_thrust_sched: -.. .. figure:: /images/mhk/20_ext_wg_thrust_sched.png -.. :align: center -.. :width: 90% +.. _ext_wg_thrust_sched: +.. figure:: /images/mhk/20_ext_wg_thrust_sched.png + :align: center + :width: 90% + + +.. _speed_limits_cavitation: + +Rotor Speed Limits and Cavitation +---------------------------------- + +Power and thrust are not the only constraints on an FBP operating schedule. +For a marine turbine, the rotor speed is also bounded by cavitation, and this +bound usually decides whether the overspeed branch is available at all. + +Cavitation occurs where the local pressure on the blade falls below the vapour +pressure of water. +Writing the suction peak in terms of the section's minimum pressure coefficient +:math:`C_{p,min}`, + +.. math:: + + p_{min} = p_{atm} + \rho g h + C_{p,min}\left(\tfrac{1}{2}\rho W^2\right) < p_{vap} + +which rearranges into the usual cavitation number criterion, + +.. math:: + + \sigma = \frac{p_{atm} + \rho g h - p_{vap}}{\tfrac{1}{2}\rho W^2} > -C_{p,min} + +Two results follow for control design. + +Depth enters only as hydrostatic head. +The submergence :math:`h` appears nowhere except in :math:`\rho g h`, which sets +the pressure budget available to be spent on suction. +Seawater is dense enough that 10 m of depth adds about 101 kPa, roughly one +additional atmosphere, so submergence is a strong lever on the available margin. +The relevant depth is the *shallowest* point the blade reaches, so the binding +condition is the blade tip at the top of its rotation. + +The criterion also collapses to a rotor speed limit. +The relative velocity at the tip is dominated by :math:`\Omega R`, so substituting +:math:`W^2 = (\Omega R)^2 + v^2` and solving for :math:`\Omega` gives a maximum +usable rotor speed: + +.. math:: + + \Omega_{cav} = \frac{1}{R}\sqrt{\frac{2\left(p_{atm} + \rho g h_{tip} - p_{vap}\right)}{\rho\,\sigma_v} - v^2} + +where :math:`\sigma_v = -C_{p,min}` for the outboard blade sections and +:math:`h_{tip}` is the tip depth at the top of its rotation. +Neither the power curve nor the choice of over/underspeed branch appears in this +expression. +Cavitation constrains rotor speed directly, and any operating schedule that +exceeds :math:`\Omega_{cav}` is affected regardless of how it was generated. + +The ROSCO toolbox evaluates this limit and warns if the generated speed schedule +violates it (see :ref:`the toolbox schedule checks `). + +Selecting Over- vs Underspeed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Comparing :math:`\Omega_{cav}` against the speed schedule a given power curve +requires is the practical way to decide whether overspeed is usable for a +particular rotor: + +* If the overspeed schedule stays below :math:`\Omega_{cav}` across Region 3, + overspeed is available, and the thrust and drivetrain-speed considerations + discussed above govern the choice. +* If it does not, the overspeed branch is unavailable for that rotor at that + submergence, and the underspeed branch should be selected + (:code:`VS_FBP_speed_mode = 0`). + +Because :math:`\Omega_{cav}` scales with :math:`\sqrt{\rho g h_{tip}}`, machines +that are deeply submerged, or that use low design tip speeds, retain more of the +overspeed range than shallow, high-tip-speed rotors. + +For the RM1 at its nominal 24 m hub depth, :math:`\Omega_{cav}` is approximately +2.26 rad/s, or about 1.9x rated rotor speed, whereas the constant-power overspeed +schedule requires roughly 5.7x rated speed at cut-out. +Overspeed is therefore not available for this rotor, and the underspeed +configurations (Examples 2 and 3) are the applicable ones. +This is a property of the RM1 and its submergence, not a general result. + +.. note:: + For a floating MHK turbine (:code:`MHK = 2`), the hub depth is not constant: + platform heave and tidal range move the rotor vertically and change + :math:`h_{tip}` directly. A speed limit computed at nominal depth will be + optimistic at the shallow end of that excursion, so the limit should be + evaluated at the shallowest expected submergence rather than the mean. + +The expression above is a tip, attached-flow estimate. +It suits the high-TSR overspeed regime, where the outboard sections operate near +zero lift and :math:`-C_{p,min}` is close to its minimum value. +It is optimistic for deeply stalled underspeed setpoints, whose larger +:math:`-C_{p,min}` it does not capture, though those setpoints have much lower +relative velocity and correspondingly large margin. +A schedule that is marginal against this estimate should be verified with an +AeroDyn cavitation check (:code:`CavitCheck = True`), which evaluates the full +criterion at every blade node using the angle-of-attack-dependent +:math:`C_{p,min}` from the polars. Toolbox Implementation ----------------------- -The ROSCO toolbox works by determining the speed and torque set points required to operate at a TSR and Cp for the desired power. +The ROSCO toolbox works by determining the speed and torque set points required to operate at a TSR and Cp for the desired power across flow speeds. .. _fbp_flow_chart: .. figure:: /images/mhk/14_fbp_flow_chart.png :align: center :width: 90% -The following inputs to the ROSCO tuning yaml will generate DISCON inputs to ROSCO. +The following inputs to the ROSCO tuning yaml, under :code:`controller_params`, +will generate DISCON inputs to ROSCO. .. list-table:: :header-rows: 1 @@ -169,19 +664,112 @@ The following inputs to the ROSCO tuning yaml will generate DISCON inputs to ROS * - Parameter - Description * - VS_FBP - - FBP Control Mode (0 = variable pitch, 1 = constant power overspeed (nonlinear), 2 = WSE-lookup reference tracking, 3 = torque-lookup reference tracking) - * - FBP_speed_mode - - Over/underspeed mode (0 = underspeed, 1 = overspeed) - * - FBP_power_mode - - Normalized or exact power curve values (0 = relative to rated, 1 = exact) - * - FBP_U - - Flow speed setpoints for power curve lookup table - * - FBP_P - - Power curve lookup table + - FBP Control Mode: + + - 0 = variable pitch (disabled) + - 1 = constant power overspeed (nonlinear) + - 2 = WSE-lookup reference tracking + - 3 = torque-lookup reference tracking + * - VS_FBP_speed_mode + - Over/underspeed mode: + + - 0 = underspeed + - 1 = overspeed + * - VS_FBP_power_mode + - Normalized or exact power curve values: + + - 0 = relative to rated + - 1 = exact + * - VS_FBP_U + - Flow speed setpoints for power curve lookup table [m/s] + * - VS_FBP_P + - Power curve lookup table, interpreted per :code:`VS_FBP_power_mode` + +The following constraints apply when FBP control is enabled: + +* :code:`PC_ControlMode` and :code:`VS_ConstPower` must both be 0 whenever + :code:`VS_FBP > 0`. + Blade pitch is fixed to fine pitch, so constant-power torque control may not run + concurrently. + :code:`PRC_Mode` must not be 1, since its speed setpoint lookup would override + the FBP speed reference. + ROSCO aborts on any of these at runtime, and the toolbox raises an exception + rather than write a configuration that cannot run. +* :code:`PRC_Mode = 2` is allowed with FBP control. + :code:`R_Torque` de-rates the generator torque limit (:code:`VS_MaxTq`) and the + Region 3 constant-power torque, which is how + :code:`Examples/31_fixed_pitch_mhk.py` ramps the rating in for a soft start up. + :code:`R_Pitch` has no effect, since the blade pitch is fixed. +* :code:`VS_FBP = 1` is the fixed control law + :math:`\tau = \min(P_{rated}/\Omega_g,\ K\Omega_g^2)`, which is inherently + constant-power and inherently overspeed. + ROSCO ignores :code:`VS_FBP_speed_mode`, :code:`VS_FBP_power_mode`, and + :code:`VS_FBP_P` in this mode, so the toolbox overrides them to the + constant-power overspeed schedule and warns if they were set otherwise. + The generated operating schedule is still used, both to seed the initial + generator torque and to tune the torque gains, so it must match the law ROSCO + will actually run. +* For :code:`VS_FBP = 3` (torque-lookup reference tracking), the generator torque + schedule must be strictly increasing, since ROSCO inverts it to look up the + speed reference. + The toolbox checks the computed schedule and raises an exception otherwise. + A nondecreasing power curve on the *underspeed* branch + (:code:`VS_FBP_speed_mode = 0`) is sufficient to guarantee this, because + generator speed falls with flow speed there, so :math:`\tau = P/\Omega_g` rises + on both counts. + Overspeed generally is not sufficient: generator speed rises with flow speed, so + the torque falls unless the power curve rises faster than the speed, which in + practice only holds near the MPPT curve. + +.. _cavitation_warning: + +The toolbox also screens the generated schedule against two limits that it warns +about rather than enforces, since both depend on hardware choices outside the +controller: + +* If the generator torque schedule exceeds :code:`max_torque_factor` times rated + torque, the toolbox warns that the schedule may not be realizable within + saturation limits. +* For MHK turbines (:code:`MHK > 0`), if the rotor speed schedule exceeds the + estimated tip cavitation limit :math:`\Omega_{cav}` from + :ref:`speed_limits_cavitation`, the toolbox warns and reports the worst + offending operating point. + The limit is computed from the water density, atmospheric and vapour pressures, + and hub submergence in the OpenFAST model, together with :math:`-C_{p,min}` + taken from the outboard AeroDyn polars. + The check is skipped if the polars carry no :math:`C_{p,min}` column + (:code:`InCol_Cpmin = 0`). + +The torque check alone will not catch an overspeed schedule. +Overspeed *reduces* generator torque while raising speed, so an overspeed +configuration can sit far above the cavitation limit while the torque schedule +stays well within bounds. +The two checks are complementary. + +The Region 2 torque control mode should be chosen to match the Region 3 FBP mode, +so that the two controllers hand off consistently through the transition region: +.. list-table:: + :header-rows: 1 + :widths: auto + + * - :code:`VS_FBP` + - Recommended :code:`VS_ControlMode` + * - 1 (constant power overspeed, nonlinear) + - 1 (:math:`k\Omega^2`) + * - 2 (WSE-lookup reference tracking) + - 2 (WSE TSR-tracking) + * - 3 (torque-lookup reference tracking) + - 4 (torque TSR-tracking) Note that the ROSCO input schema (:ref:`rt_tuning_yaml`) contains the latest input definitions. +The three case studies verified below are provided as worked examples in +:code:`Examples/31_fixed_pitch_mhk.py`, which tunes against the RM1 marine turbine +tuning case :code:`Examples/Tune_Cases/RM1_MHK_FBP.yaml`. +That script also ships three experimental configurations covering the rest of the +input space; see :ref:`fbp_experimental_configs`. + ROSCO Implementation ----------------------- @@ -195,7 +783,12 @@ The following DISCON parameters are generated using the ROSCO toolbox, or can be * - Parameter - Description * - VS_FBP - - FBP Control Mode (0 = variable pitch, 1 = constant power overspeed (nonlinear), 2 = WSE-lookup reference tracking, 3 = torque-lookup reference tracking) + - FBP Control Mode: + + - 0 = variable pitch + - 1 = constant power overspeed (nonlinear) + - 2 = WSE-lookup reference tracking + - 3 = torque-lookup reference tracking * - VS_FBP_n - Number of values in operating schedule lookup table * - VS_FBP_U @@ -203,7 +796,7 @@ The following DISCON parameters are generated using the ROSCO toolbox, or can be * - VS_FBP_Omega - Generator speed operating points in lookup table * - VS_FBP_Tau - - Generator torque operating points in lookup table + - Generator torque operating points in lookup table (must be monotonic for :code:`VS_FBP = 3`) Note that the ROSCO input schema (:ref:`rt_tuning_yaml`) contains the latest input definitions (under :code:`controller_params`, :code:`DISCON`). @@ -212,8 +805,8 @@ Simulation Verification ----------------------- A handful of example controller case studies have been developed using the RM1 -marine turbine to showcase the implemented features of FBP control. These -configurations are +marine turbine [Neary2014]_ to showcase the implemented features of FBP control. +These configurations are * Example 1: Overspeed, constant power * Example 2: Underspeed, torque-based reference tracking @@ -223,40 +816,68 @@ For each example, a power curve is defined and input to the ROSCO toolbox to generate operating schedules and auto-tune the gains used by the torque controller. The operating schedules for generator power, speed, and torque for each example -test case are shown in the following figure. +test case are shown in the following figure. .. _cases_P_wg_tg_sched: .. figure:: /images/mhk/21_cases_P_wg_tg_sched.png :align: center :width: 90% -Each example controller is then simulated with the RM1 marine turbine model -using OpenFAST in both steady and turbulent inflow. The steady-state performance -of each controller is compared to the operating schedules generated by the ROSCO -toolbox. The turbulent inflow uses the intensity shown in the following figure. +Each example controller is then simulated with the RM1 marine turbine model using +OpenFAST in both steady and turbulent inflow. +The steady state performance of each controller is compared to the operating +schedules generated by the ROSCO toolbox. +The turbulent inflow uses the intensity shown in the following figure. .. _turb_intensity: .. figure:: /images/mhk/25_turb_intensity.png :align: center :width: 90% +Tidal flow design load cases differ from their wind counterparts in ways that +matter for controller verification. +Turbulence characteristics are not those typically encountered in atmospheric +flow, the mean probability distribution is more closely isolated by environmental +condition, and turbulence intensity varies heavily with site conditions. +The better tidal sites are generally lower in turbulence intensity than wind sites +[Milne2013]_. +The turbulence intensity and wave statistics used here were varied to mimic buoy +data collected in the Orkney Islands, Scotland. +Design requirements for tidal current converters are given in [IEC62600-2]_. + +.. TODO(DS): please supply the citation or dataset identifier for the Orkney buoy + data so it can be referenced properly. + Example 1 ^^^^^^^^^ The first example test case uses the naturally stable nonlinear feedback control -law. This controller is confined to operating in the constant power, overspeed -configuration. The explicit (non-reference-tracking) control law is analogous to -the `k\Omega^2` control law sometimes used in Region 2 for wind and marine -turbines. +law. +This controller is confined to operating in the constant power, overspeed +configuration. +The explicit (non-reference-tracking) control law is analogous to the +:math:`k\Omega^2` control law sometimes used in Region 2 for wind and marine +turbines [Johnson2006]_, and is best paired with a :math:`k\Omega^2` Region 2 +controller (:code:`VS_ControlMode = 1`). +It is easy to design and requires no tuning, but is rigid and inflexible, and its +overspeed operating points carry high tip speed and blade thrust. + +.. note:: + Because this mode is inherently overspeed, it should be screened against the + cavitation speed limit of :ref:`speed_limits_cavitation` before selection. For + the RM1 the required speeds exceed that limit, so this example is included to + demonstrate and verify the control law rather than as a recommended + configuration for this rotor. It remains appropriate for rotors whose + overspeed schedule stays within :math:`\Omega_{cav}`. .. _case1_P_wg_tg_ss: .. figure:: /images/mhk/22_case1_P_wg_tg_ss.png :align: center :width: 90% -This controller has the best power tracking in Region 3, but it only allows constant power. -The power-focused feedback approach accommodates offsets in equilibrium speed and torque made by inaccuracies in the simplified tuning model. +This controller has the best power tracking in Region 3, but it only allows constant power. +The power-focused feedback approach accommodates offsets in equilibrium speed and torque made by inaccuracies in the simplified tuning model. .. _case1_P_wg_tg_turb: .. figure:: /images/mhk/26_case1_P_wg_tg_turb.png @@ -267,12 +888,31 @@ The power-focused feedback approach accommodates offsets in equilibrium speed an Example 2 ^^^^^^^^^ -The second example test case +The second example test case uses underspeed operation with a torque-based +reference and a semi-arbitrary power curve: -* Region-2 mode: TSR-tracking with torque-based reference -* Region-3 FBP mode: reference tracking with torque lookup +* Region-2 mode: TSR-tracking with torque-based reference (:code:`VS_ControlMode = 4`) +* Region-3 FBP mode: reference tracking with torque lookup (:code:`VS_FBP = 3`) * The power curve may be arbitrarily specified, but should be a nondecreasing function so that the torque schedule is monotonically increasing +This configuration is highly general, but requires an aggressive torque controller +to stabilize the open-loop-unstable underspeed setpoints, and therefore requires a +high maximum torque signal (see :code:`max_torque_factor` in the tuning yaml). + +.. warning:: + Sizing the torque limit is a safety consideration, not only a tracking one. + Every underspeed setpoint sits where hydrodynamic torque *increases* with rotor + speed, so if the commanded torque saturates below what the inflow demands, the + rotor accelerates rather than settling. The aerodynamic torque curve only turns + over past :math:`TSR_{opt}`, so the nearest stable equilibrium is on the + *overspeed* side of the :math:`C_p` peak. Insufficient torque authority on an + underspeed schedule therefore does not stall the rotor to a stop: the rotor + accelerates through the :math:`C_p` peak and settles at high speed, in the + high-thrust and cavitation-prone regime that the underspeed schedule was chosen + to avoid. The same applies to any fault that removes generator torque. Size + :code:`max_torque_factor` above the peak hydrodynamic torque over the operating + range, and ensure the shutdown path can arrest the rotor without it. + .. _case2_P_wg_tg_ss: .. figure:: /images/mhk/23_case2_P_wg_tg_ss.png :align: center @@ -294,12 +934,17 @@ The second example test case Example 3 ^^^^^^^^^ -The third example test case +The third example test case uses underspeed operation with a wind speed estimator +(WSE) reference [Ortega2013]_ and a fully arbitrary power curve: -* Region-2 mode: TSR-tracking with WSE-based reference -* Region-3 FBP mode: reference tracking with WSE lookup +* Region-2 mode: TSR-tracking with WSE-based reference (:code:`VS_ControlMode = 2`) +* Region-3 FBP mode: reference tracking with WSE lookup (:code:`VS_FBP = 2`) * The power curve can be completely arbitrarily specified +This is the most general configuration and the easiest to combine with a Region 2 +controller or with alternate references. +It is less robust to errors in the tuning model than the torque lookup, and shares +the torque lookup's need for an aggressive controller and high torque headroom. .. _case3_P_wg_tg_ss: .. figure:: /images/mhk/24_case3_P_wg_tg_ss.png @@ -318,25 +963,98 @@ The third example test case :width: 90% +.. _fbp_experimental_configs: + +Additional Configurations +^^^^^^^^^^^^^^^^^^^^^^^^^ + +:code:`Examples/31_fixed_pitch_mhk.py` ships three further configurations beyond +the three examples above: + +* Constant power underspeed: the Example 2 configuration + (:code:`VS_FBP = 3`, :code:`VS_ControlMode = 4`) with the power curve held flat at + rated rather than increasing. +* Constant power overspeed via reference tracking: the Example 1 operating schedule + reached through the WSE lookup (:code:`VS_FBP = 2`, :code:`VS_ControlMode = 2`) + instead of the fixed control law. +* Linear increasing power, leveling out: the Example 2 power curve reaching 2x rated + below cut-out and flat thereafter. + +These are experimental. +They demonstrate the range of power curves and mode pairings the toolbox accepts, +and have not been through the steady and turbulent verification campaign that +Examples 1 through 3 have. +Their operating schedules should be treated as illustrative rather than validated. + +The cavitation caveat attached to Example 1 applies to the overspeed +reference-tracking configuration as well. +For the RM1 rotor, both exceed the tip cavitation limit of +:ref:`speed_limits_cavitation`, and the toolbox warns accordingly when they are +tuned. + + Recommendations ----------------------- -FBP control is well suited to marine turbines without blade pitch actuators. +FBP control is well suited to marine turbines without blade pitch actuators. In certain applications, the ability to follow a generic power curve with a -limit actuation capability is more advantageous than using variable-blade-pitch -(VBP) control. +limited actuation capability is more advantageous than using variable-blade-pitch +(VBP) control. VBP control allows constant-power operation in Region 3 matched with constant -speed and torque for a flat operating schedule. Pitch-actuated turbines also -experience smaller blade loads in Region 3. The FBP approach satisfies -applications in which the cost and complexity of the actuators themselves are -prohibitive. +speed and torque for a flat operating schedule, and pitch-actuated turbines also +experience smaller blade loads in Region 3. +The FBP approach satisfies applications in which the cost and complexity of the +actuators themselves are prohibitive. -Generic user input allows flexibility for variety of applications. +Generic user input allows flexibility for variety of applications. FBP controller implementation in ROSCO with auto-tuning and automatic generation of operating schedule to follow power curve. -Because the Region-2 and Region-3 controllers utilize the same actuator, the +Because the Region 2 and Region 3 controllers utilize the same actuator, the transition region is markedly different than what is required for a VBP -Region-3 controller. +Region 3 controller. +Future Work +----------------------- + +* Enhanced multi-constraint configuration, including constraining Region 3 rotor + thrust to a constant level rather than only constraining power. +* Explicit power reference tracking. + + +References +----------------------- + +.. [Stockhouse2025] Stockhouse, D. *Fixed-Blade-Pitch Control in ROSCO for MHK + Turbines.* National Renewable Energy Laboratory presentation, 2025. + (Source material for this page.) + +.. [Abbas2022] Abbas, N. J., Zalkind, D. S., Pao, L., and Wright, A. *A reference + open-source controller for fixed and floating offshore wind turbines.* + Wind Energy Science, 7(1), 53–73, 2022. https://doi.org/10.5194/wes-7-53-2022 + +.. [Johnson2006] Johnson, K. E., Pao, L. Y., Balas, M. J., and Fingersh, L. J. + *Control of variable-speed wind turbines: standard and adaptive techniques for + maximizing energy capture.* IEEE Control Systems Magazine, 26(3), 70–81, 2006. + https://doi.org/10.1109/MCS.2006.1636311 + +.. [Ortega2013] Ortega, R., Mancilla-David, F., and Jaramillo, F. *A globally + convergent wind speed estimator for wind turbine systems.* International + Journal of Adaptive Control and Signal Processing, 27(5), 413–425, 2013. + https://doi.org/10.1002/acs.2319 + +.. [Neary2014] Neary, V. S., Previsic, M., Jepsen, R. A., Lawson, M. J., Yu, Y.-H., + Copping, A. E., Fontaine, A. A., Hallett, K. C., and Murray, D. K. *Methodology + for Design and Economic Analysis of Marine Energy Conversion (MEC) + Technologies.* SAND2014-9040, Sandia National Laboratories, 2014. + (Source of the RM1 reference marine turbine model.) + +.. [Milne2013] Milne, I. A., Sharma, R. N., Flay, R. G. J., and Bickerton, S. + *Characteristics of the turbulence in the flow at a tidal stream power site.* + Philosophical Transactions of the Royal Society A, 371:20120196, 2013. + https://doi.org/10.1098/rsta.2012.0196 + +.. [IEC62600-2] IEC TS 62600-2:2019, *Marine energy – Wave, tidal and other water + current converters – Part 2: Marine energy systems – Design requirements.* + International Electrotechnical Commission, 2019. diff --git a/rosco/controller/src/Controllers.f90 b/rosco/controller/src/Controllers.f90 index b1e40c96f..08651d11c 100644 --- a/rosco/controller/src/Controllers.f90 +++ b/rosco/controller/src/Controllers.f90 @@ -245,8 +245,8 @@ SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) LocalVar%VS_MaxTq = CntrPar%VS_RtTq * LocalVar%PRC_R_Torque END IF ELSE - ! Constant pitch, max torque is control parameter - LocalVar%VS_MaxTq = CntrPar%VS_MaxTq + ! Constant pitch, max torque is control parameter, de-rated by the torque rating + LocalVar%VS_MaxTq = CntrPar%VS_MaxTq * LocalVar%PRC_R_Torque ENDIF ! Optimal Tip-Speed-Ratio tracking controller (reference generated in subroutine ComputeVariablesSetpoints) diff --git a/rosco/controller/src/ReadSetParameters.f90 b/rosco/controller/src/ReadSetParameters.f90 index 626adaac4..3f1939cd5 100644 --- a/rosco/controller/src/ReadSetParameters.f90 +++ b/rosco/controller/src/ReadSetParameters.f90 @@ -1032,9 +1032,9 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG) ErrVar%ErrMsg = 'VS_FBP and PC_ControlMode cannot both be greater than 0.' ENDIF - IF ((CntrPar%VS_FBP > 0) .AND. (CntrPar%PRC_Mode > 0)) THEN + IF ((CntrPar%VS_FBP > 0) .AND. (CntrPar%PRC_Mode == 1)) THEN ErrVar%aviFAIL = -1 - ErrVar%ErrMsg = 'Fixed blade pitch control (VS_FBP) and power reference control (PRC_Mode) cannot both be enabled.' + ErrVar%ErrMsg = 'Fixed blade pitch control (VS_FBP) and the PRC_Mode = 1 speed setpoint lookup cannot both be enabled.' ENDIF IF ((CntrPar%VS_FBP > 0) .AND. (CntrPar%VS_ConstPower > 0)) THEN diff --git a/rosco/toolbox/controller.py b/rosco/toolbox/controller.py index 189221c4e..5951243b0 100644 --- a/rosco/toolbox/controller.py +++ b/rosco/toolbox/controller.py @@ -112,11 +112,33 @@ def __init__(self, controller_params): self.min_pitch = controller_params['min_pitch'] if self.VS_FBP > 0: - - # Fail if generator torque enabled in Region 3 but pitch control not disabled (may enable these modes to operate together in the future) - if self.PC_ControlMode != 0: + + # Mode conflicts asserted in ReadSetParameters.f90; ROSCO aborts on these at runtime, so fail here instead of writing a config that cannot run + for mode_name in ['PC_ControlMode', 'VS_ConstPower']: + if getattr(self, mode_name) != 0: + raise Exception( + f'rosco.toolbox:controller: {mode_name} must be 0 if VS_FBP > 0') + + # PRC_Mode = 1 overrides the FBP speed reference with its own lookup; PRC_Mode = 2 only de-rates and is allowed + if self.PRC_Mode == 1: raise Exception( - 'rosco.toolbox:controller: PC_ControlMode must be 0 if VS_FBP > 0') + 'rosco.toolbox:controller: PRC_Mode must not be 1 if VS_FBP > 0') + + # Region 2 and Region 3 use the same actuator, so the torque controllers must hand off consistently + recommended_vs_mode = {1: 1, 2: 2, 3: 4}[self.VS_FBP] + if self.VS_ControlMode != recommended_vs_mode: + print(f'WARNING: VS_ControlMode = {self.VS_ControlMode} is not the recommended Region 2 ' + f'mode for VS_FBP = {self.VS_FBP}; use VS_ControlMode = {recommended_vs_mode} so the ' + 'Region 2 and Region 3 references agree through the transition.') + + # VS_FBP = 1 runs the fixed control law tau = min(P_rated/omega, K*omega^2), so ROSCO ignores the power curve and speed mode. + # Generate the schedule it will actually follow: the table still sets the initial generator torque and the tuned gain schedule. + if self.VS_FBP == 1: + if self.fbp_speed_mode != 1 or self.fbp_power_mode != 0 or np.any(np.atleast_1d(self.fbp_P) != 1.0): + print('WARNING: VS_FBP = 1 always follows a constant rated power, overspeed schedule. Ignoring VS_FBP_speed_mode, VS_FBP_power_mode, and VS_FBP_P.') + self.fbp_speed_mode = 1 + self.fbp_power_mode = 0 + self.fbp_P = np.ones(len(np.atleast_1d(self.fbp_U))) if self.Flp_Mode > 0: if 'flp_kp_norm' in controller_params and 'flp_tau' in controller_params: @@ -234,6 +256,54 @@ def __init__(self, controller_params): 'U_pc, omega_pc, and zeta_pc are all list-like and are not of equal length') + def cavitation_speed_limit(self, turbine, v): + """ + Estimate the rotor speed at which tip cavitation begins, for each inflow speed. + + Cavitation occurs where the local pressure falls below the vapour pressure: + + p_min = p_atm + rho*g*h + Cp_min*(0.5*rho*W^2) < p_vap + + which rearranges to a cavitation number criterion, sigma > -Cp_min, with + + sigma = (p_atm + rho*g*h - p_vap) / (0.5*rho*W^2) + + Depth enters only through the hydrostatic head rho*g*h. The worst case is the + blade tip at the top of its rotation, where h is smallest and W is largest. + Setting sigma = sigma_v and W^2 = (Omega*R)^2 + v^2 gives Omega directly. + + This is a tip, attached-flow screening estimate. It is accurate in the high-TSR + (overspeed) regime where the tip sits near zero lift, and optimistic for + deeply-stalled underspeed setpoints, whose higher -Cp_min it does not capture. + It also assumes a fixed hub depth; for a floating MHK turbine, heave and tide + move the tip shallower and reduce the true limit. Verify a marginal schedule + with an AeroDyn CavitCheck run. + + Parameters: + ----------- + turbine : Turbine + Turbine object, must carry MHK cavitation properties. + v : array_like + Inflow speeds of the operating schedule, m/s. + + Returns: + -------- + omega_cav : ndarray or None + Rotor speed limit at each inflow speed, rad/s. None if the turbine + is not an MHK turbine or the polars carry no Cp_min data. + """ + if not getattr(turbine, 'MHK', 0) or getattr(turbine, 'cavit_sigma_v', None) is None: + return None + + # Available pressure budget at the tip's shallowest point + dp = turbine.Patm + turbine.rho * 9.80665 * turbine.tip_depth - turbine.Pvap + if dp <= 0: + return None + + w_max_sq = 2 * dp / (turbine.rho * turbine.cavit_sigma_v) + return np.sqrt(np.maximum(w_max_sq - np.asarray(v)**2, 0.0)) / turbine.rotor_radius + + def tune_controller(self, turbine): """ Given a turbine model, tune a controller based on the NREL generic controller tuning process @@ -258,6 +328,13 @@ def tune_controller(self, turbine): self.min_pitch = turbine.Cp.pitch_opt turbine.min_pitch = self.min_pitch + # minimum rotor speed saturation limits, set before the operating schedule saturates against them + if self.vs_minspd: + self.vs_minspd = np.maximum(self.vs_minspd, (turbine.TSR_operational * turbine.v_min / turbine.rotor_radius)) + else: + self.vs_minspd = (turbine.TSR_operational * turbine.v_min / turbine.rotor_radius) + self.pc_minspd = self.vs_minspd + # -------------Define Operation Points ------------- # TSR_rated = rated_rotor_speed*R/turbine.v_rated # TSR at rated @@ -270,10 +347,6 @@ def tune_controller(self, turbine): # Construct power schedule differently based on pitch control configuration if self.VS_FBP > 0: # If using torque control in Region 3 - # Check if constant power control disabled (may be implemented to work concurrently in the future) - if self.VS_ConstPower != 0: - raise Exception("VS_ConstPower must be 0 when VS_FBP > 0") - # Begin with user-defined power curve from input yaml (default constant rated power) f_P_user_defined = interpolate.interp1d(self.fbp_U, self.fbp_P, fill_value=(self.fbp_P[0], self.fbp_P[-1]), bounds_error=False) P_user_defined = f_P_user_defined(v) @@ -287,8 +360,6 @@ def tune_controller(self, turbine): P_op = np.min([P_user_defined, P_max], axis=0) # Operation along Cp surface (with fixed pitch) Cp_op = (P_op / P_max) * Cp_operational - Cp_op_br = Cp_op[:len(v_below_rated)] - Cp_op_ar = Cp_op[len(v_below_rated):] # Identify TSR matching the Cp values (similar to variable pitch angle interpolation below) Cp_FBP = np.ndarray.flatten(turbine.Cp.interp_surface(self.min_pitch, turbine.TSR_initial)) # all Cp values for fine blade pitch @@ -304,7 +375,16 @@ def tune_controller(self, turbine): f_cp_TSR = interpolate.interp1d(Cp_FBP[:Cp_maxidx+1], turbine.TSR_initial[:Cp_maxidx+1]) # interpolate function for Cp(tsr) values TSR_op = f_cp_TSR(Cp_op) # Defer to operational TSR for below rated, even if other optimum (should keep Cp the same, but may lead to discontinuities in operating schedule if min_pitch is not optimal) - TSR_op[v < turbine.v_rated] = turbine.TSR_operational + below_rated = v < turbine.v_rated + TSR_op[below_rated] = turbine.TSR_operational + # FBP only engages once the Region 2 speed reference exceeds rated, so below rated the + # turbine tracks TSR_operational regardless of what the power curve asks for. Hold Cp on + # the surface at that TSR: otherwise the (Cp, TSR) pair is not an equilibrium and the + # resulting speed and torque setpoints are not reachable. + if np.any(P_user_defined[below_rated] < P_max[below_rated] * (1 - 1e-6)): + print('WARNING: FBP control cannot curtail below rated. The power curve is ignored ' + 'below v_rated, where the turbine tracks TSR_operational.') + Cp_op[below_rated] = Cp_operational TSR_below_rated = TSR_op[:len(v_below_rated)] # Should be constant at TSR_operational TSR_above_rated = TSR_op[len(v_below_rated):] @@ -380,11 +460,23 @@ def tune_controller(self, turbine): print('WARNING: Torque operating schedule is above maximum generator torque and may not be realizable within saturation limits.') # DBS: Future - add input constraints to satisfy maximum torque, speed, and thrust (peak shaving) in addition to power + # Check the speed schedule against tip cavitation for MHK turbines. Overspeed + # schedules reduce torque while raising speed, so the torque check above cannot + # catch them. + omega_cav = self.cavitation_speed_limit(turbine, v) + if omega_cav is not None and np.any(omega_op > omega_cav): + i = np.argmax(omega_op - omega_cav) + print('WARNING: Rotor speed operating schedule exceeds the estimated tip ' + 'cavitation limit. Worst point is {:.2f} rad/s at {:.1f} m/s inflow, ' + 'against a limit of {:.2f} rad/s. Verify with an AeroDyn CavitCheck ' + 'run; see the MHK documentation on rotor speed limits.'.format( + omega_op[i], v[i], omega_cav[i])) + # Check if options allow a nonmonotonic torque schedule if self.VS_FBP == 3: # The simulation will crash if we have a nonmonotonic schedule, so fail to generate the config and alert the user if np.any(np.diff(tau_op) <= 0): - raise Exception("VS controller reference torque interpolation is selected (VS_FBP_ref_mode == 1), but computed generator torque schedule is not monotonically increasing. Reconfigure power curve, ensure VS_FBP_speed_mode == 0, or switch VS_FBP to 2.") + raise Exception("VS_FBP = 3 (torque-lookup reference tracking) is selected, but the computed generator torque schedule is not strictly increasing, so it cannot be inverted. Set VS_FBP_speed_mode = 0 (underspeed) with a nondecreasing power curve, or switch VS_FBP to 2.") # Full Cx surface gradients @@ -459,13 +551,6 @@ def tune_controller(self, turbine): self.vs_refspd = min(turbine.TSR_operational * turbine.v_rated/R, turbine.rated_rotor_speed) * Ng # -- Define some setpoints -- - # minimum rotor speed saturation limits - if self.vs_minspd: - self.vs_minspd = np.maximum(self.vs_minspd, (turbine.TSR_operational * turbine.v_min / turbine.rotor_radius)) - else: - self.vs_minspd = (turbine.TSR_operational * turbine.v_min / turbine.rotor_radius) - self.pc_minspd = self.vs_minspd - # Set IPC ramp inputs if not already defined if max(self.IPC_Vramp) == 0.0: self.IPC_Vramp = [turbine.v_rated*0.8, turbine.v_rated] diff --git a/rosco/toolbox/inputs/toolbox_schema.yaml b/rosco/toolbox/inputs/toolbox_schema.yaml index 84c601289..27297b7dd 100644 --- a/rosco/toolbox/inputs/toolbox_schema.yaml +++ b/rosco/toolbox/inputs/toolbox_schema.yaml @@ -130,7 +130,7 @@ properties: minimum: 0 maximum: 4 default: 2 - description: Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) + description: Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) VS_ConstPower: type: number minimum: 0 @@ -647,7 +647,7 @@ properties: type: number minimum: 0 maximum: 4 - description: Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) + description: Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking) VS_ConstPower: type: number minimum: 0 diff --git a/rosco/toolbox/ofTools/case_gen/CaseLibrary.py b/rosco/toolbox/ofTools/case_gen/CaseLibrary.py index d5fb3a62a..8c74169ac 100644 --- a/rosco/toolbox/ofTools/case_gen/CaseLibrary.py +++ b/rosco/toolbox/ofTools/case_gen/CaseLibrary.py @@ -547,16 +547,19 @@ def test_pitch_offset(start_group, **control_sweep_opts): def sweep_yaml_input(start_group, **control_sweep_opts): ''' - Sweep any single tuning yaml input + Sweep any single tuning yaml input, or a list of full controller configurations control_sweep_opts: control_param: name of parameter param_values: values of parameter (1D array) + or + param_sweeps: list of controller_params overrides, one dict per case ''' - required_inputs = [('control_param','discon_param'), 'param_values'] - check_inputs(control_sweep_opts,required_inputs) + if 'param_sweeps' not in control_sweep_opts: + required_inputs = [('control_param','discon_param'), 'param_values'] + check_inputs(control_sweep_opts,required_inputs) # load default params control_param_yaml = control_sweep_opts['tuning_yaml'] @@ -573,14 +576,26 @@ def sweep_yaml_input(start_group, **control_sweep_opts): case_inputs = {} discon_lists = {} - for param_value in control_sweep_opts['param_values']: - controller_params = control_sweep_opts['controller_params'].copy() + base_params = control_sweep_opts['controller_params'] - if 'control_param' in control_sweep_opts: - controller_params[control_sweep_opts['control_param']] = param_value - elif 'discon_param' in control_sweep_opts: - controller_params.setdefault('DISCON', {}) - controller_params['DISCON'][control_sweep_opts['discon_param']] = param_value + if 'param_sweeps' in control_sweep_opts: + # NOTE: shallow merge, a nested override (e.g. DISCON) replaces the whole sub-dict + param_sweeps = [{**base_params, **overrides} for overrides in control_sweep_opts['param_sweeps']] + else: + param_sweeps = [] + for param_value in control_sweep_opts['param_values']: + controller_params = base_params.copy() + + if 'control_param' in control_sweep_opts: + controller_params[control_sweep_opts['control_param']] = param_value + elif 'discon_param' in control_sweep_opts: + controller_params['DISCON'] = { + **base_params.get('DISCON', {}), + control_sweep_opts['discon_param']: param_value, + } + param_sweeps.append(controller_params) + + for controller_params in param_sweeps: controller = ROSCO_controller.Controller(controller_params) # tune default controller diff --git a/rosco/toolbox/turbine.py b/rosco/toolbox/turbine.py index d37790740..042ea89e6 100644 --- a/rosco/toolbox/turbine.py +++ b/rosco/toolbox/turbine.py @@ -224,6 +224,20 @@ def load_from_fast( self.rated_torque = self.rated_power/(self.GenEff/100*self.rated_rotor_speed*self.Ng) self.rotor_radius = self.TipRad + # MHK cavitation properties (used to screen the operating schedule) + self.MHK = fast.fst_vt['Fst']['MHK'] + if self.MHK: + self.Patm = fast.fst_vt['Fst']['Patm'] + self.Pvap = fast.fst_vt['Fst']['Pvap'] + self.MSL2SWL = fast.fst_vt['Fst']['MSL2SWL'] + # Shallowest depth reached by the blade tip, at the top of its rotation. + # hubHt is negative below MSL for an MHK turbine. + self.tip_depth = abs(self.hubHt + self.MSL2SWL) - self.TipRad + self.cavit_sigma_v = self.load_cavitation_number(fast) + else: + self.Patm = self.Pvap = self.MSL2SWL = None + self.tip_depth = self.cavit_sigma_v = None + # Load blade information self.load_blade_info() @@ -256,6 +270,35 @@ def load_from_fast( # Compute operational Cp (may not be optimal if TSR_operational set by user) self.Cp_operational = self.Cp.interp_surface(self.Cp.pitch_opt, self.TSR_operational) + def load_cavitation_number(self, fast): + ''' + Smallest cavitation number the blade sections can tolerate, sigma_v = -Cp_min. + + Taken as the minimum of -Cp_min over the outboard airfoil polars, i.e. the most + permissive (thinnest suction peak) condition the blade ever presents. Used to + screen the operating schedule for tip cavitation in + :code:`Controller.tune_controller`. + + Returns None if the AeroDyn polars carry no Cp_min column. + ''' + if not fast.fst_vt['AeroDyn'].get('InCol_Cpmin', 0): + return None + + # Airfoils used outboard of 70% span, where relative velocity is highest + blade = fast.fst_vt['AeroDynBlade'] + span = np.array(blade['BlSpn']) + afid = np.array(blade['BlAFID'], dtype=int) + outboard = set(afid[span >= 0.7 * span[-1]]) + + sigma_v = [] + for af in outboard: + for tab in fast.fst_vt['AeroDyn']['af_data'][af - 1]: + cpmin = np.array([c for c in tab['Cpmin'] if c is not None], dtype=float) + if cpmin.size: + sigma_v.append(-cpmin.max()) # max Cp_min -> min -Cp_min + + return min(sigma_v) if sigma_v else None + # Load rotor performance data from CCBlade def load_from_ccblade(self): ''' diff --git a/rosco/toolbox/utilities.py b/rosco/toolbox/utilities.py index c2f91f078..c53d82b65 100644 --- a/rosco/toolbox/utilities.py +++ b/rosco/toolbox/utilities.py @@ -98,7 +98,7 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C file.write('!------- CONTROLLER FLAGS -------------------------------------------------\n') file.write('{0:<12d} ! F_LPFType - 1: first-order low-pass filter, 2: second-order low-pass filter, [rad/s] (currently filters generator speed and pitch control signals\n'.format(int(rosco_vt['F_LPFType']))) file.write('{0:<12d} ! IPC_ControlMode - Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) (0: off, 1: 1P reductions, 2: 1P+2P reductions)\n'.format(int(rosco_vt['IPC_ControlMode']))) - file.write('{0:<12d} ! VS_ControlMode - Generator torque control mode in above rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking)\n'.format(int(rosco_vt['VS_ControlMode']))) + file.write('{0:<12d} ! VS_ControlMode - Generator torque control mode in below rated conditions (0- no torque control, 1- k*omega^2 with PI transitions, 2- WSE TSR Tracking, 3- Power-based TSR Tracking, 4- Torque-based TSR Tracking)\n'.format(int(rosco_vt['VS_ControlMode']))) file.write('{0:<12d} ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque)\n'.format(int(rosco_vt['VS_ConstPower']))) file.write('{0:<12d} ! VS_FBP - Fixed blade pitch configuration mode (0- variable pitch (disabled), 1- constant power overspeed, 2- WSE-lookup reference tracking, 3- torque-lookup reference tracking)\n'.format(int(rosco_vt['VS_FBP']))) file.write('{0:<12d} ! PC_ControlMode - Blade pitch control mode (0: No pitch, fix to fine pitch, 1: active PI blade pitch control)\n'.format(int(rosco_vt['PC_ControlMode']))) @@ -614,8 +614,8 @@ def DISCON_dict(turbine, controller, txt_filename=None): DISCON_dict['SS_PCGain'] = controller.ss_pcgain # -------- POWER REFERENCE TRACKING ------ DISCON_dict['PRC_n'] = 2 - DISCON_dict['PRC_WindSpeeds'] = [3,25] - DISCON_dict['PRC_GenSpeeds'] = [rpm2RadSec * 7.56] * 2 + DISCON_dict['PRC_WindSpeeds'] = [turbine.v_min, turbine.v_max] + DISCON_dict['PRC_GenSpeeds'] = [DISCON_dict['PC_RefSpd']] * 2 # ------- WIND SPEED ESTIMATOR ------- DISCON_dict['WE_BladeRadius'] = turbine.rotor_radius