diff --git a/Examples/34_floating_feedback_torque.py b/Examples/34_floating_feedback_torque.py new file mode 100644 index 00000000..1b327321 --- /dev/null +++ b/Examples/34_floating_feedback_torque.py @@ -0,0 +1,365 @@ +''' +----------- 29_floating_feedback_torque ------------------------ +Run openfast with ROSCO and torque floating feedback +----------------------------------------------- + +Floating feedback methods available in ROSCO/ROSCO_Toolbox + +1. Automated tuning, constant for all wind speeds +2. Automated tuning, varies with wind speed +3. Direct tuning, constant for all wind speeds +4. Direct tuning, varies with wind speeds + +''' + +import os +from rosco.toolbox.ofTools.case_gen.run_FAST import run_FAST_ROSCO +from rosco.toolbox.ofTools.case_gen import CaseLibrary as cl +import numpy as np +#from rosco.toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST +#from rosco.toolbox.inputs.validation import load_rosco_yaml +#from rosco.toolbox.controller import OpenLoopControl +from rosco.toolbox.tune import yaml_to_objs +from rosco.toolbox.utilities import DISCON_dict, write_DISCON, read_DISCON +from rosco.toolbox import controller as ROSCO_controller +from rosco.toolbox.ofTools.fast_io import output_processing +import matplotlib.pyplot as plt + + + +#directories +this_dir = os.path.dirname(os.path.abspath(__file__)) +rosco_dir = os.path.dirname(this_dir) +example_out_dir = os.path.join(this_dir,'examples_out') +os.makedirs(example_out_dir,exist_ok=True) + +def main(): + + # Input yaml and output directory + parameter_filename = os.path.join(this_dir,'Tune_Cases/IEA15MW.yaml') + run_dir = os.path.join(example_out_dir,'29_floating_feedback_torque') + os.makedirs(run_dir,exist_ok=True) + + controller, turbine, path_params = yaml_to_objs(parameter_filename) + + # # First, let's write the DISCONs for each method + # param_files = [] + + # # Method 1: Automated tuning, constant for all wind speeds (default param = 0.5) + # controller_params_1 = controller.controller_params # numbers correspond to methods above + # controller_params_1['Fl_Mode'] = 0 + # controller_params_1['FlTq_Mode'] = 2 + # controller_params_1['U_Fl'] = 'all' + # controller_params_1['tune_Fl'] = True + # controller_params_1['tune_FlTq'] = True + # controller_params_1['FlTq_alpha'] = [0.2] # Low tuning + # controller_new = ROSCO_controller.Controller(controller_params_1) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_1.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # # Automated tuning, constant for all wind speeds, with smaller scaling param + # controller_params_2 = controller.controller_params # numbers correspond to methods above + # controller_params_2['Fl_Mode'] = 0 + # controller_params_2['FlTq_Mode'] = 2 + # controller_params_2['U_Fl'] = 'all' + # controller_params_2['tune_Fl'] = True + # controller_params_2['tune_FlTq'] = True + # controller_params_2['FlTq_alpha'] = [0.5] # Moderate tuning + # controller_new = ROSCO_controller.Controller(controller_params_2) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_2.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # # Automated tuning, constant for all wind speeds, with smaller scaling param + # controller_params_3 = controller_new.controller_params # numbers correspond to methods above + # controller_params_3['Fl_Mode'] = 0 + # controller_params_3['FlTq_Mode'] = 2 + # controller_params_3['U_Fl'] = 'all' + # controller_params_3['tune_Fl'] = True + # controller_params_3['tune_FlTq'] = True + # controller_params_3['FlTq_alpha'] = [0.8] # Aggressive tuning + # controller_new = ROSCO_controller.Controller(controller_params_3) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_3.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + + # # Read all DISCONs and make into case_inputs + # case_inputs = {} + # discon_lists = {} + # for discon in param_files: + # discon_vt = read_DISCON(discon) + # for discon_input in discon_vt: + # if discon_input not in discon_lists: # initialize + # discon_lists[discon_input] = [] + # discon_lists[discon_input].append(discon_vt[discon_input]) + + # for discon_input, input in discon_lists.items(): + # case_inputs[('DISCON_in',discon_input)] = {'vals': input, 'group': 2} + + + # # Additional config for the torque controller + # case_inputs[('DISCON_in', 'VS_MaxTq')] = {'vals': [turbine.rated_torque * 1.5], 'group': 0} # 29436069.9996 + # case_inputs[('ElastoDyn', 'RotSpeed')] = {'vals': [7.56], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch1')] = {'vals': [10], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch2')] = {'vals': [10], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch3')] = {'vals': [10], 'group': 0} + + # # simulation set up + # r = run_FAST_ROSCO() + # r.tuning_yaml = parameter_filename + # r.wind_case_fcn = cl.simp_step # single step wind input + # r.wind_case_opts = { + # 'U_start': [13], + # 'U_end': [16], + # 'TMax': 800, + # 'TStep': 400, + # } + # r.case_inputs = case_inputs + # r.save_dir = run_dir + # r.rosco_dir = rosco_dir + # r.n_cores = 4 + # r.run_FAST() + + # op = output_processing.output_processing() + # op_dbg = output_processing.output_processing() + # op_dbg2 = output_processing.output_processing() + + # out_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.outb') for i_case in range(len(param_files))] + # dbg_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg') for i_case in range(len(param_files))] + # dbg2_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg2') for i_case in range(len(param_files))] + + # fst_out = op.load_fast_out(out_files, tmin=0) + # debug_vars = op_dbg.load_fast_out(dbg_files, tmin=0) + # local_vars = op_dbg2.load_fast_out(dbg2_files, tmin=0) + + # comb_out = [None] * len(fst_out) + # for i, (r_out, f_out) in enumerate(zip(debug_vars,fst_out)): + # r_out.update(f_out) + # comb_out[i] = r_out + # for i, (r_out2, f_out) in enumerate(zip(local_vars,comb_out)): + # r_out2.update(f_out) + # comb_out[i] = r_out2 + + # cases = {} + # cases['Fl Sigs.'] = ['Wind1VelX', 'GenSpeed', 'GenPwr', 'BldPitch1', 'PtfmPitch', 'NacIMU_FA_AccF', 'NacIMU_FA_AccFT', 'Fl_TqCom', 'GenTq'] # , 'NcIMURAys']#,'PtfmPitch','PtfmYaw','NacYaw'] + # fig, ax = op.plot_fast_out(comb_out, cases, showplot=False) + + # if False: + # plt.show() + # else: + # plt.savefig(os.path.join(run_dir,'29_floating_feedback_torque.png')) + + + # More comprehensive parameter sweep test + param_files = [] + + DISCON_i = 0 + + # # Baseline (zero FF) + # controller_params_new = controller.controller_params + # controller_params_new['Fl_Mode'] = 0 + # controller_params_new['FlTq_Mode'] = 0 + # controller_params_new['U_Fl'] = [] + # controller_params_new['tune_Fl'] = 0 + # controller_params_new['tune_FlTq'] = 0 + # controller_new = ROSCO_controller.Controller(controller_params_new) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_{}.IN'.format(DISCON_i)) + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # DISCON_i += 1 + + alpha_tq_cases = np.arange(0, 2.2, .2) + # alpha_bp_cases = np.arange(0, 2.2, .2) + alpha_bp_cases = np.arange(0, 1.1, .1) + alpha_case_matrix_indices = np.zeros([len(alpha_tq_cases), len(alpha_bp_cases)]) + + for alpha_tq_ii in range(len(alpha_tq_cases)): + + for alpha_bp_ii in range(len(alpha_bp_cases)): + + controller_params_new = controller.controller_params + controller_params_new['Fl_Mode'] = 2 + controller_params_new['FlTq_Mode'] = 2 + controller_params_new['U_Fl'] = [] + controller_params_new['tune_Fl'] = 2 + controller_params_new['tune_FlTq'] = 1 + # controller_params_new['Fl_alpha'] = [alpha_bp_cases[alpha_bp_ii]] + controller_params_new['Fl_Dzeta'] = [alpha_bp_cases[alpha_bp_ii]] + controller_params_new['FlTq_alpha'] = [alpha_tq_cases[alpha_tq_ii]] + controller_new = ROSCO_controller.Controller(controller_params_new) + controller_new.tune_controller(turbine) + param_file = os.path.join(run_dir,'DISCON_Fl_{}.IN'.format(DISCON_i)) + param_files.append(param_file) + # Adjust filter frequency manually + rosco_vt = DISCON_dict(turbine, controller_new, txt_filename=path_params['rotor_performance_filename']) + rosco_vt['F_FlCornerFreq'] = rosco_vt['F_FlTqCornerFreq'] + write_DISCON(turbine,controller_new, + param_file=param_file, + txt_filename=path_params['rotor_performance_filename']) + + # Record index in case matrix + alpha_case_matrix_indices[alpha_tq_ii, alpha_bp_ii] = DISCON_i + + DISCON_i += 1 + + # Dzeta_select = np.arange(.1, .5, .1) + # for Dzeta in Dzeta_select: + + # controller_params_new = controller.controller_params + # controller_params_new['Fl_Mode'] = 2 + # controller_params_new['FlTq_Mode'] = 0 + # controller_params_new['U_Fl'] = [] + # controller_params_new['tune_Fl'] = 2 + # controller_params_new['tune_FlTq'] = 0 + # controller_params_new['Fl_Dzeta'] = [Dzeta] + # controller_new = ROSCO_controller.Controller(controller_params_new) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_{}.IN'.format(DISCON_i)) + # param_files.append(param_file) + # # Adjust filter frequency manually + # rosco_vt = DISCON_dict(turbine, controller_new, txt_filename=path_params['rotor_performance_filename']) + # rosco_vt['F_FlCornerFreq'] = rosco_vt['F_FlTqCornerFreq'] + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # DISCON_i += 1 + + + # Read all DISCONs and make into case_inputs + case_inputs = {} + discon_lists = {} + for discon in param_files: + discon_vt = read_DISCON(discon) + for discon_input in discon_vt: + if discon_input not in discon_lists: # initialize + discon_lists[discon_input] = [] + discon_lists[discon_input].append(discon_vt[discon_input]) + + for discon_input, input in discon_lists.items(): + case_inputs[('DISCON_in',discon_input)] = {'vals': input, 'group': 2} + + + # Additional config for the torque controller + case_inputs[('DISCON_in', 'VS_MaxTq')] = {'vals': [turbine.rated_torque * 1.5], 'group': 0} # 29436069.9996 + # case_inputs[('DISCON_in', 'F_FlCornerFreq')] = {'vals': [], 'group': 0} + case_inputs[('ElastoDyn', 'RotSpeed')] = {'vals': [7.56], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch1')] = {'vals': [10], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch2')] = {'vals': [10], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch3')] = {'vals': [10], 'group': 0} + + # simulation set up + r = run_FAST_ROSCO() + r.tuning_yaml = parameter_filename + r.wind_case_fcn = cl.turb_bts # single step wind input + r.wind_case_opts = { + 'TMax': 720, + 'wind_filenames': ['/home/david/WEIS_clean/ROSCO_fork/rosco/test/testing/wind/IEA-15MW_NTM_U15.000000_Seed971231.0.bts'] + } + r.case_inputs = case_inputs + r.save_dir = run_dir + r.rosco_dir = rosco_dir + r.n_cores = 48 + r.run_FAST() + + op = output_processing.output_processing() + op_dbg = output_processing.output_processing() + op_dbg2 = output_processing.output_processing() + + out_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:03}.outb') for i_case in range(len(param_files))] + dbg_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:03}.RO.dbg') for i_case in range(len(param_files))] + dbg2_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:03}.RO.dbg2') for i_case in range(len(param_files))] + + fst_out = op.load_fast_out(out_files, tmin=0) + debug_vars = op_dbg.load_fast_out(dbg_files, tmin=0) + local_vars = op_dbg2.load_fast_out(dbg2_files, tmin=0) + + comb_out = [None] * len(fst_out) + for i, (r_out, f_out) in enumerate(zip(debug_vars,fst_out)): + r_out.update(f_out) + comb_out[i] = r_out + for i, (r_out2, f_out) in enumerate(zip(local_vars,comb_out)): + r_out2.update(f_out) + comb_out[i] = r_out2 + + cases = {} + cases['Fl Sigs.'] = ['Wind1VelX', 'GenSpeed', 'GenPwr', 'BldPitch1', 'PtfmPitch', 'Fl_PitCom', 'Fl_TqCom', 'GenTq'] # 'NacIMU_FA_AccF', 'NacIMU_FA_AccFT', 'NcIMURAys']#,'PtfmPitch','PtfmYaw','NacYaw'] + fig, ax = op.plot_fast_out(comb_out, cases, showplot=False) + + if False: + plt.show() + else: + plt.savefig(os.path.join(run_dir,'29_floating_feedback_torque_sweep.png')) + + # Compute performance statistics + # tau_comp_genspeed_data = [comb_out[i]['GenSpeed'] for i in range(6)] + # tau_comp_power_data = [comb_out[i]['GenPwr'] for i in range(6)] + # tau_comp_pitch_data = [comb_out[i]['PtfmPitch'] for i in range(6)] + # tau_comp_genspeed_std = np.std(tau_comp_genspeed_data, axis=1) + # tau_comp_power_std = np.std(tau_comp_power_data, axis=1) + # tau_comp_pitch_std = np.std(tau_comp_pitch_data, axis=1) + # beta_comp_genspeed_data = [comb_out[i]['GenSpeed'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_power_data = [comb_out[i]['GenPwr'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_pitch_data = [comb_out[i]['PtfmPitch'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_genspeed_std = np.std(beta_comp_genspeed_data, axis=1) + # beta_comp_power_std = np.std(beta_comp_power_data, axis=1) + # beta_comp_pitch_std = np.std(beta_comp_pitch_data, axis=1) + # Combined data + genspeed_data = [comb_out[i]['GenSpeed'] for i in range(len(comb_out))] + genpower_data = [comb_out[i]['GenPwr'] for i in range(len(comb_out))] + ptfmpitch_data = [comb_out[i]['PtfmPitch'] for i in range(len(comb_out))] + genspeed_std = np.std(genspeed_data, axis=1) + genpower_std = np.std(genpower_data, axis=1) + ptfmpitch_std = np.std(ptfmpitch_data, axis=1) + + plt.figure() + plt.subplot(3, 1, 1) + plt.grid() + # plt.plot(np.concatenate(([0], alpha_tq_cases)), tau_comp_genspeed_std) + # plt.plot(np.concatenate(([0], alpha_bp_cases)), beta_comp_genspeed_std) + plt.contourf(alpha_bp_cases, alpha_tq_cases, genspeed_std[np.int32(alpha_case_matrix_indices)] / (turbine.rated_rotor_speed * turbine.Ng * 60/(2*np.pi))) + plt.colorbar() + plt.title('Gen Speed STD') + plt.ylabel(r'$\alpha_{\tau,comp}$') + + plt.subplot(3, 1, 2) + plt.grid() + # plt.plot(np.concatenate(([0], alpha_tq_cases)), tau_comp_power_std) + # plt.plot(np.concatenate(([0], alpha_bp_cases)), beta_comp_power_std) + plt.contourf(alpha_bp_cases, alpha_tq_cases, genpower_std[np.int32(alpha_case_matrix_indices)] / (turbine.rated_power/1.0e3)) + plt.colorbar() + plt.title('Gen Power STD') + plt.ylabel(r'$\alpha_{\tau,comp}$') + + plt.subplot(3, 1, 3) + plt.grid() + # plt.plot(np.concatenate(([0], alpha_tq_cases)), tau_comp_pitch_std) + # plt.plot(np.concatenate(([0], alpha_bp_cases)), beta_comp_pitch_std) + plt.contourf(alpha_bp_cases, alpha_tq_cases, ptfmpitch_std[np.int32(alpha_case_matrix_indices)]) + plt.colorbar() + plt.title('Ptfm Pitch STD') + plt.ylabel(r'$\alpha_{\tau,comp}$') + plt.xlabel(r'$\alpha_{\beta,comp}$') + + plt.savefig(os.path.join(run_dir,'29_floating_feedback_torque_sweep_stats.png')) + + plt.show(block=False) + 0 + +if __name__=="__main__": + main() diff --git a/Examples/35_constant_power_detuned.py b/Examples/35_constant_power_detuned.py new file mode 100644 index 00000000..e966935b --- /dev/null +++ b/Examples/35_constant_power_detuned.py @@ -0,0 +1,354 @@ +''' +----------- 29_constant_power_detuned ------------------------ +Run openfast with ROSCO and detuned constant power control loop +----------------------------------------------- + +''' + +import os +from rosco.toolbox.ofTools.case_gen.run_FAST import run_FAST_ROSCO +from rosco.toolbox.ofTools.case_gen import CaseLibrary as cl +import numpy as np +#from rosco.toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST +#from rosco.toolbox.inputs.validation import load_rosco_yaml +#from rosco.toolbox.controller import OpenLoopControl +from rosco.toolbox.tune import yaml_to_objs +from rosco.toolbox.utilities import DISCON_dict, write_DISCON, read_DISCON +from rosco.toolbox import controller as ROSCO_controller +from rosco.toolbox.ofTools.fast_io import output_processing +import matplotlib.pyplot as plt + + + +#directories +this_dir = os.path.dirname(os.path.abspath(__file__)) +rosco_dir = os.path.dirname(this_dir) +example_out_dir = os.path.join(this_dir,'examples_out') +os.makedirs(example_out_dir,exist_ok=True) + +def main(): + + # Input yaml and output directory + parameter_filename = os.path.join(this_dir,'Tune_Cases/IEA15MW.yaml') + run_dir = os.path.join(example_out_dir,'29_constant_power_detuned') + os.makedirs(run_dir,exist_ok=True) + + controller, turbine, path_params = yaml_to_objs(parameter_filename) + + # # First, let's write the DISCONs for each method + # param_files = [] + + # # Method 1: Automated tuning, constant for all wind speeds (default param = 0.5) + # controller_params_1 = controller.controller_params # numbers correspond to methods above + # controller_params_1['Fl_Mode'] = 0 + # controller_params_1['FlTq_Mode'] = 2 + # controller_params_1['U_Fl'] = 'all' + # controller_params_1['tune_Fl'] = True + # controller_params_1['tune_FlTq'] = True + # controller_params_1['FlTq_alpha'] = [0.2] # Low tuning + # controller_new = ROSCO_controller.Controller(controller_params_1) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_1.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # # Automated tuning, constant for all wind speeds, with smaller scaling param + # controller_params_2 = controller.controller_params # numbers correspond to methods above + # controller_params_2['Fl_Mode'] = 0 + # controller_params_2['FlTq_Mode'] = 2 + # controller_params_2['U_Fl'] = 'all' + # controller_params_2['tune_Fl'] = True + # controller_params_2['tune_FlTq'] = True + # controller_params_2['FlTq_alpha'] = [0.5] # Moderate tuning + # controller_new = ROSCO_controller.Controller(controller_params_2) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_2.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # # Automated tuning, constant for all wind speeds, with smaller scaling param + # controller_params_3 = controller_new.controller_params # numbers correspond to methods above + # controller_params_3['Fl_Mode'] = 0 + # controller_params_3['FlTq_Mode'] = 2 + # controller_params_3['U_Fl'] = 'all' + # controller_params_3['tune_Fl'] = True + # controller_params_3['tune_FlTq'] = True + # controller_params_3['FlTq_alpha'] = [0.8] # Aggressive tuning + # controller_new = ROSCO_controller.Controller(controller_params_3) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_3.IN') + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + + # # Read all DISCONs and make into case_inputs + # case_inputs = {} + # discon_lists = {} + # for discon in param_files: + # discon_vt = read_DISCON(discon) + # for discon_input in discon_vt: + # if discon_input not in discon_lists: # initialize + # discon_lists[discon_input] = [] + # discon_lists[discon_input].append(discon_vt[discon_input]) + + # for discon_input, input in discon_lists.items(): + # case_inputs[('DISCON_in',discon_input)] = {'vals': input, 'group': 2} + + + # # Additional config for the torque controller + # case_inputs[('DISCON_in', 'VS_MaxTq')] = {'vals': [turbine.rated_torque * 1.5], 'group': 0} # 29436069.9996 + # case_inputs[('ElastoDyn', 'RotSpeed')] = {'vals': [7.56], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch1')] = {'vals': [10], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch2')] = {'vals': [10], 'group': 0} + # case_inputs[('ElastoDyn', 'BlPitch3')] = {'vals': [10], 'group': 0} + + # # simulation set up + # r = run_FAST_ROSCO() + # r.tuning_yaml = parameter_filename + # r.wind_case_fcn = cl.simp_step # single step wind input + # r.wind_case_opts = { + # 'U_start': [13], + # 'U_end': [16], + # 'TMax': 800, + # 'TStep': 400, + # } + # r.case_inputs = case_inputs + # r.save_dir = run_dir + # r.rosco_dir = rosco_dir + # r.n_cores = 4 + # r.run_FAST() + + # op = output_processing.output_processing() + # op_dbg = output_processing.output_processing() + # op_dbg2 = output_processing.output_processing() + + # out_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.outb') for i_case in range(len(param_files))] + # dbg_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg') for i_case in range(len(param_files))] + # dbg2_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg2') for i_case in range(len(param_files))] + + # fst_out = op.load_fast_out(out_files, tmin=0) + # debug_vars = op_dbg.load_fast_out(dbg_files, tmin=0) + # local_vars = op_dbg2.load_fast_out(dbg2_files, tmin=0) + + # comb_out = [None] * len(fst_out) + # for i, (r_out, f_out) in enumerate(zip(debug_vars,fst_out)): + # r_out.update(f_out) + # comb_out[i] = r_out + # for i, (r_out2, f_out) in enumerate(zip(local_vars,comb_out)): + # r_out2.update(f_out) + # comb_out[i] = r_out2 + + # cases = {} + # cases['Fl Sigs.'] = ['Wind1VelX', 'GenSpeed', 'GenPwr', 'BldPitch1', 'PtfmPitch', 'NacIMU_FA_AccF', 'NacIMU_FA_AccFT', 'Fl_TqCom', 'GenTq'] # , 'NcIMURAys']#,'PtfmPitch','PtfmYaw','NacYaw'] + # fig, ax = op.plot_fast_out(comb_out, cases, showplot=False) + + # if False: + # plt.show() + # else: + # plt.savefig(os.path.join(run_dir,'29_floating_feedback_torque.png')) + + + # More comprehensive parameter sweep test + param_files = [] + + DISCON_i = 0 + + # # Baseline (zero FF) + # controller_params_new = controller.controller_params + # controller_params_new['Fl_Mode'] = 0 + # controller_params_new['FlTq_Mode'] = 0 + # controller_params_new['U_Fl'] = [] + # controller_params_new['tune_Fl'] = 0 + # controller_params_new['tune_FlTq'] = 0 + # controller_new = ROSCO_controller.Controller(controller_params_new) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_{}.IN'.format(DISCON_i)) + # param_files.append(param_file) + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # DISCON_i += 1 + + # alpha_tq_cases = np.arange(0, 2.2, .2) + # # alpha_bp_cases = np.arange(0, 2.2, .2) + # alpha_bp_cases = np.arange(0, 1.1, .1) + # alpha_case_matrix_indices = np.zeros([len(alpha_tq_cases), len(alpha_bp_cases)]) + + # for alpha_tq_ii in range(len(alpha_tq_cases)): + + # for alpha_bp_ii in range(len(alpha_bp_cases)): + + # controller_params_new = controller.controller_params + # controller_params_new['Fl_Mode'] = 2 + # controller_params_new['FlTq_Mode'] = 2 + # controller_params_new['U_Fl'] = [] + # controller_params_new['tune_Fl'] = 2 + # controller_params_new['tune_FlTq'] = 1 + # # controller_params_new['Fl_alpha'] = [alpha_bp_cases[alpha_bp_ii]] + # controller_params_new['Fl_Dzeta'] = [alpha_bp_cases[alpha_bp_ii]] + # controller_params_new['FlTq_alpha'] = [alpha_tq_cases[alpha_tq_ii]] + # controller_new = ROSCO_controller.Controller(controller_params_new) + # controller_new.tune_controller(turbine) + # param_file = os.path.join(run_dir,'DISCON_Fl_{}.IN'.format(DISCON_i)) + # param_files.append(param_file) + # # Adjust filter frequency manually + # rosco_vt = DISCON_dict(turbine, controller_new, txt_filename=path_params['rotor_performance_filename']) + # rosco_vt['F_FlCornerFreq'] = rosco_vt['F_FlTqCornerFreq'] + # write_DISCON(turbine,controller_new, + # param_file=param_file, + # txt_filename=path_params['rotor_performance_filename']) + + # # Record index in case matrix + # alpha_case_matrix_indices[alpha_tq_ii, alpha_bp_ii] = DISCON_i + + # DISCON_i += 1 + + alpha_cases = np.arange(0., 1.1, .1) + for alpha in alpha_cases: + + controller_params_new = controller.controller_params + controller_params_new['Fl_Mode'] = 0 + controller_params_new['FlTq_Mode'] = 0 + controller_params_new['U_Fl'] = [] + controller_params_new['tune_Fl'] = 0 + controller_params_new['tune_FlTq'] = 0 + controller_params_new['VS_ConstPower'] = 1 + # controller_params_new['VS_ConstPower_alpha'] = alpha + controller_params_new['VS_ConstPower_alpha'] = np.array([0.0, 0.5, 1.0]) * alpha + controller_params_new['VS_ConstPower_U'] = np.array([12, 18, 24]) + controller_new = ROSCO_controller.Controller(controller_params_new) + controller_new.tune_controller(turbine) + param_file = os.path.join(run_dir,'DISCON_CP_{}.IN'.format(DISCON_i)) + param_files.append(param_file) + # Adjust filter frequency manually + rosco_vt = DISCON_dict(turbine, controller_new, txt_filename=path_params['rotor_performance_filename']) + # rosco_vt['F_FlCornerFreq'] = rosco_vt['F_FlTqCornerFreq'] + write_DISCON(turbine,controller_new, + param_file=param_file, + txt_filename=path_params['rotor_performance_filename']) + + DISCON_i += 1 + + + # Read all DISCONs and make into case_inputs + case_inputs = {} + discon_lists = {} + for discon in param_files: + discon_vt = read_DISCON(discon) + for discon_input in discon_vt: + if discon_input not in discon_lists: # initialize + discon_lists[discon_input] = [] + discon_lists[discon_input].append(discon_vt[discon_input]) + + for discon_input, input in discon_lists.items(): + case_inputs[('DISCON_in',discon_input)] = {'vals': input, 'group': 2} + + + # Additional config for the torque controller + case_inputs[('DISCON_in', 'VS_MaxTq')] = {'vals': [turbine.rated_torque * 1.5], 'group': 0} # 29436069.9996 + # case_inputs[('DISCON_in', 'F_FlCornerFreq')] = {'vals': [], 'group': 0} + case_inputs[('ElastoDyn', 'RotSpeed')] = {'vals': [7.56], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch1')] = {'vals': [10], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch2')] = {'vals': [10], 'group': 0} + case_inputs[('ElastoDyn', 'BlPitch3')] = {'vals': [10], 'group': 0} + + # simulation set up + r = run_FAST_ROSCO() + r.tuning_yaml = parameter_filename + r.wind_case_fcn = cl.turb_bts # single step wind input + r.wind_case_opts = { + 'TMax': 720, + # 'wind_filenames': ['/home/david/WEIS_clean/ROSCO_fork/rosco/test/testing/wind/IEA-15MW_NTM_U15.000000_Seed971231.0.bts'] + 'wind_filenames': ['/home/david/WEIS_clean/WEIS/outputs/02_control_blopt_del_pi_ff_blp/rank_0/wind/IEA15_0_NTM_U20.000000_Seed839901364.0.bts'] + } + r.case_inputs = case_inputs + r.save_dir = run_dir + r.rosco_dir = rosco_dir + r.n_cores = 48 + r.run_FAST() + + op = output_processing.output_processing() + op_dbg = output_processing.output_processing() + op_dbg2 = output_processing.output_processing() + + out_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:01}.outb') for i_case in range(len(param_files))] + dbg_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:01}.RO.dbg') for i_case in range(len(param_files))] + dbg2_files = [os.path.join(run_dir,f'IEA15MW/turb_bts/base/IEA15MW_{i_case:01}.RO.dbg2') for i_case in range(len(param_files))] + + fst_out = op.load_fast_out(out_files, tmin=0) + debug_vars = op_dbg.load_fast_out(dbg_files, tmin=0) + local_vars = op_dbg2.load_fast_out(dbg2_files, tmin=0) + + comb_out = [None] * len(fst_out) + for i, (r_out, f_out) in enumerate(zip(debug_vars,fst_out)): + r_out.update(f_out) + comb_out[i] = r_out + for i, (r_out2, f_out) in enumerate(zip(local_vars,comb_out)): + r_out2.update(f_out) + comb_out[i] = r_out2 + + cases = {} + cases['Fl Sigs.'] = ['Wind1VelX', 'GenSpeed', 'GenPwr', 'GenTq', 'BldPitch1', 'PtfmPitch'] # 'NacIMU_FA_AccF', 'NacIMU_FA_AccFT', 'NcIMURAys']#,'PtfmPitch','PtfmYaw','NacYaw'] + fig, ax = op.plot_fast_out(comb_out, cases, showplot=False) + + if False: + plt.show() + else: + plt.savefig(os.path.join(run_dir,'29_constant_power_detuned_sweep.png')) + + # Compute performance statistics + # tau_comp_genspeed_data = [comb_out[i]['GenSpeed'] for i in range(6)] + # tau_comp_power_data = [comb_out[i]['GenPwr'] for i in range(6)] + # tau_comp_pitch_data = [comb_out[i]['PtfmPitch'] for i in range(6)] + # tau_comp_genspeed_std = np.std(tau_comp_genspeed_data, axis=1) + # tau_comp_power_std = np.std(tau_comp_power_data, axis=1) + # tau_comp_pitch_std = np.std(tau_comp_pitch_data, axis=1) + # beta_comp_genspeed_data = [comb_out[i]['GenSpeed'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_power_data = [comb_out[i]['GenPwr'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_pitch_data = [comb_out[i]['PtfmPitch'] for i in [0, 6, 7, 8, 9, 10]] + # beta_comp_genspeed_std = np.std(beta_comp_genspeed_data, axis=1) + # beta_comp_power_std = np.std(beta_comp_power_data, axis=1) + # beta_comp_pitch_std = np.std(beta_comp_pitch_data, axis=1) + # Combined data + genspeed_data = [comb_out[i]['GenSpeed'] for i in range(len(comb_out))] + genpower_data = [comb_out[i]['GenPwr'] for i in range(len(comb_out))] + ptfmpitch_data = [comb_out[i]['PtfmPitch'] for i in range(len(comb_out))] + genspeed_std = np.std(genspeed_data, axis=1) + genpower_std = np.std(genpower_data, axis=1) + ptfmpitch_std = np.std(ptfmpitch_data, axis=1) + + plt.figure() + plt.subplot(3, 1, 1) + plt.grid() + # plt.plot(alpha_cases, genspeed_std / (turbine.rated_rotor_speed * turbine.Ng * 60/(2*np.pi))) + plt.plot(alpha_cases, genspeed_std) + plt.ylabel('Gen Speed\nSTD [RPM]') + # plt.xlabel(r'$\alpha_{cp}$') + + plt.subplot(3, 1, 2) + plt.grid() + # plt.plot(alpha_cases, genpower_std / (turbine.rated_power/1.0e3)) + plt.plot(alpha_cases, genpower_std / 1.0e3) + plt.ylabel('Gen Power\nSTD [MW]') + # plt.xlabel(r'$\alpha_{cp}$') + + plt.subplot(3, 1, 3) + plt.grid() + plt.plot(alpha_cases, ptfmpitch_std) + plt.ylabel('Ptfm Pitch\nSTD [deg]') + plt.xlabel(r'$\alpha_{cp}$') + + plt.savefig(os.path.join(run_dir,'29_constant_power_detuned_sweep_stats.png')) + + plt.show(block=False) + 0 + +if __name__=="__main__": + main() diff --git a/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN b/Examples/Test_Cases/BAR_10/BAR_10_DISCON.IN index 1490ea64..ccf0e6c0 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 0 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 2 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.0000 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +0.0000 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 0.01042 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 7.8480 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -92,6 +94,9 @@ -2.41226e+03 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -3.32357e+02 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 10.00000 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -184,7 +189,8 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 -0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle velocity proportional feedback gain to generator torque [s] 0.0000 ! 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/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 19692bb2..28f0dd27 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 0 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 0 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.0000 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +0.0000 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 0.01042 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 10.4616 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -92,6 +94,9 @@ -3.61179e+07 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -4.49937e+06 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 9.00000 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -184,7 +189,8 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 -0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle velocity proportional feedback gain to generator torque [s] 0.0000 ! 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/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 94f9632f..6b303057 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 2 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 0 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.2130 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +0.6390 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 0.01042 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 10.4616 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -92,6 +94,9 @@ -3.57306e+07 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -4.49937e+06 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 9.00000 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -184,8 +189,9 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 --9.1984 ! Fl_Kp - Nacelle pitching proportional feedback gain [s] -11.2770 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] +-6.1823 ! Fl_Kp - Nacelle pitching proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle pitching proportional feedback gain to generator torque [s] +12.0000 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] !------- FLAP ACTUATION ----------------------------------------------------- 0.000000000000 ! Flp_Angle - Initial or steady state flap angle [rad] diff --git a/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN b/Examples/Test_Cases/MHK_RM1/MHK_RM1_DISCON.IN index b651db66..5398769c 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 1 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 0 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.6613 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +1.9839 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 1.50000 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 0.0000 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -92,6 +94,9 @@ -7.38377e+01 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -8.44329e+01 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 7.00000 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -184,8 +189,9 @@ !------- 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] -2.1000 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] +-0.1491 ! Fl_Kp - Nacelle velocity proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle velocity proportional feedback gain to generator torque [s] +12.0000 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] !------- FLAP ACTUATION ----------------------------------------------------- 0.000000000000 ! Flp_Angle - Initial or steady state flap angle [rad] diff --git a/Examples/Test_Cases/NREL-5MW/DISCON.IN b/Examples/Test_Cases/NREL-5MW/DISCON.IN index 67bddf55..c3f7dd8f 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 0 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 0 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.0000 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +0.0000 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 0.01042 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 0.0000 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -92,6 +94,9 @@ -6.97771e+02 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -1.04507e+02 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 7.50000 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -184,7 +189,8 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 -0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle velocity proportional feedback gain to generator torque [s] 0.0000 ! 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_2p8_127/NREL-2p8-127_DISCON.IN b/Examples/Test_Cases/NREL_2p8_127/NREL-2p8-127_DISCON.IN index 6fe57878..2056dfcb 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.0 controller tuning logic on 09/08/25 +! - File written using ROSCO version 2.11.0 controller tuning logic on 09/22/25 !------- 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,8 +10,8 @@ !------- 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) -0 ! VS_ConstPower - Do constant power torque control, where above rated torque varies, 0 for constant torque) +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) +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) @@ -22,6 +22,7 @@ 0 ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled) 0 ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled) 0 ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity) +0 ! FlTq_Mode - Floating specific feedback mode to generator torque {0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty} 0 ! TD_Mode - Tower damper mode (0- no tower damper, 1- feed back translational nacelle accelleration to pitch angle 0 ! TRA_Mode - Tower resonance avoidance mode (0- no tower resonsnace avoidance, 1- use torque control setpoints to avoid a specific frequency 0 ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control) @@ -49,6 +50,7 @@ 0.20944 ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s]. 0.17952 ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s]. 0.0000 1.0000 ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -]. +0.0000 1.0000 ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -]. 0.01042 ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]. 0.0000 1.0000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control 0.20944 ! F_VSRefSpdCornerFreq - Corner frequency (-3dB point) in the first order low pass filter of the generator speed reference used for TSR tracking torque control [rad/s]. @@ -56,7 +58,7 @@ !------- BLADE PITCH CONTROL ---------------------------------------------- 30 ! PC_GS_n - Amount of gain-scheduling table entries 0.076 0.105 0.127 0.148 0.165 0.182 0.197 0.212 0.226 0.239 0.252 0.264 0.277 0.288 0.300 0.311 0.322 0.332 0.343 0.353 0.363 0.373 0.383 0.392 0.402 0.411 0.421 0.429 0.438 0.446 ! PC_GS_angles - Gain-schedule table: pitch angles [rad]. --2.324e-02 -2.087e-02 -1.888e-02 -1.720e-02 -1.575e-02 -1.449e-02 -1.339e-02 -1.241e-02 -1.154e-02 -1.076e-02 -1.006e-02 -9.426e-03 -8.848e-03 -8.320e-03 -7.835e-03 -7.388e-03 -6.976e-03 -6.594e-03 -6.238e-03 -5.908e-03 -5.599e-03 -5.310e-03 -5.038e-03 -4.783e-03 -4.543e-03 -4.317e-03 -4.103e-03 -3.901e-03 -3.709e-03 -3.527e-03 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. +-2.437e-02 -2.190e-02 -1.983e-02 -1.807e-02 -1.656e-02 -1.525e-02 -1.410e-02 -1.308e-02 -1.218e-02 -1.137e-02 -1.063e-02 -9.971e-03 -9.369e-03 -8.818e-03 -8.312e-03 -7.847e-03 -7.417e-03 -7.019e-03 -6.648e-03 -6.304e-03 -5.982e-03 -5.680e-03 -5.397e-03 -5.132e-03 -4.882e-03 -4.646e-03 -4.423e-03 -4.212e-03 -4.012e-03 -3.822e-03 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. -8.020e-04 -7.307e-04 -6.710e-04 -6.203e-04 -5.767e-04 -5.389e-04 -5.057e-04 -4.764e-04 -4.503e-04 -4.269e-04 -4.058e-04 -3.867e-04 -3.693e-04 -3.534e-04 -3.388e-04 -3.254e-04 -3.130e-04 -3.015e-04 -2.908e-04 -2.809e-04 -2.716e-04 -2.629e-04 -2.547e-04 -2.471e-04 -2.399e-04 -2.331e-04 -2.266e-04 -2.205e-04 -2.148e-04 -2.093e-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) @@ -92,6 +94,9 @@ -5.99592e+02 ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) -8.53230e+01 ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2) 8.20700 ! VS_TSRopt - Power-maximizing region 2 tip-speed-ratio. Only used in VS_ControlMode = 2. +1 ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1 +1.0000 ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1) +12.0000 ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s] !------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------ 60 ! VS_FBP_n - Number of gain-scheduling table entries @@ -128,7 +133,7 @@ 30 30 ! 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 3.000 3.290 3.579 3.869 4.159 4.448 4.738 5.028 5.317 5.607 5.897 6.186 6.476 6.766 7.055 7.345 7.634 7.924 8.214 8.503 8.793 9.083 9.372 9.662 9.952 10.241 10.531 10.821 11.110 11.400 11.853 12.307 12.760 13.213 13.667 14.120 14.573 15.027 15.480 15.933 16.387 16.840 17.293 17.747 18.200 18.653 19.107 19.560 20.013 20.467 20.920 21.373 21.827 22.280 22.733 23.187 23.640 24.093 24.547 25.000 ! WE_FOPoles_v - Wind speeds corresponding to first-order system poles [m/s] --1.232e-02 -1.351e-02 -1.469e-02 -1.588e-02 -1.707e-02 -1.826e-02 -1.945e-02 -2.064e-02 -2.183e-02 -2.302e-02 -2.421e-02 -2.540e-02 -2.659e-02 -2.777e-02 -2.896e-02 -3.015e-02 -3.134e-02 -3.253e-02 -3.372e-02 -3.491e-02 -3.610e-02 -3.729e-02 -3.848e-02 -3.967e-02 -3.891e-02 -3.499e-02 -2.999e-02 -2.413e-02 -1.727e-02 -8.985e-03 -2.245e-02 -2.706e-02 -3.109e-02 -3.713e-02 -4.210e-02 -4.857e-02 -5.396e-02 -6.079e-02 -6.631e-02 -7.261e-02 -7.985e-02 -8.612e-02 -9.375e-02 -1.015e-01 -1.090e-01 -1.168e-01 -1.240e-01 -1.323e-01 -1.413e-01 -1.498e-01 -1.587e-01 -1.693e-01 -1.784e-01 -1.869e-01 -1.968e-01 -2.078e-01 -2.180e-01 -2.267e-01 -2.362e-01 -2.452e-01 ! WE_FOPoles - First order system poles [1/s] +-1.232e-02 -1.351e-02 -1.469e-02 -1.588e-02 -1.707e-02 -1.826e-02 -1.945e-02 -2.064e-02 -2.183e-02 -2.302e-02 -2.421e-02 -2.540e-02 -2.659e-02 -2.777e-02 -2.896e-02 -3.015e-02 -3.134e-02 -3.253e-02 -3.372e-02 -3.491e-02 -3.610e-02 -3.729e-02 -3.848e-02 -3.967e-02 -3.891e-02 -3.499e-02 -2.999e-02 -2.413e-02 -1.727e-02 -8.985e-03 3.834e-03 -7.758e-04 -4.804e-03 -1.084e-02 -1.581e-02 -2.229e-02 -2.767e-02 -3.451e-02 -4.002e-02 -4.633e-02 -5.357e-02 -5.984e-02 -6.746e-02 -7.523e-02 -8.267e-02 -9.052e-02 -9.773e-02 -1.060e-01 -1.150e-01 -1.235e-01 -1.324e-01 -1.430e-01 -1.521e-01 -1.606e-01 -1.705e-01 -1.815e-01 -1.917e-01 -2.004e-01 -2.099e-01 -2.189e-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] @@ -184,7 +189,8 @@ !------- Floating ----------------------------------------------------------- 1 ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1 -0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +0.0000 ! Fl_Kp - Nacelle velocity proportional feedback gain to blade pitch [s] +0.0000 ! FlTq_Kp - Nacelle velocity proportional feedback gain to generator torque [s] 0.0000 ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s] !------- FLAP ACTUATION ----------------------------------------------------- diff --git a/Examples/Tune_Cases/BAR.yaml b/Examples/Tune_Cases/BAR.yaml index bdf96e06..e8a136b6 100644 --- a/Examples/Tune_Cases/BAR.yaml +++ b/Examples/Tune_Cases/BAR.yaml @@ -35,6 +35,7 @@ controller_params: PS_Mode: 1 # Peak shaving mode {0: no peak shaving, 1: implement peak shaving} SD_Mode: 0 # Shutdown mode {0: no shutdown procedure, 1: pitch to max pitch at shutdown} Fl_Mode: 0 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 2 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters U_pc: [12] @@ -47,4 +48,4 @@ controller_params: flp_tau: 10 # Flap controller integral gain time constant [s] ps_percent: 0.8 IPC_Kp1p: 2.05e-08 - IPC_Ki1p: 1.45e-09 \ No newline at end of file + IPC_Ki1p: 1.45e-09 diff --git a/Examples/Tune_Cases/IEA15MW.yaml b/Examples/Tune_Cases/IEA15MW.yaml index c12112b0..b4f49853 100644 --- a/Examples/Tune_Cases/IEA15MW.yaml +++ b/Examples/Tune_Cases/IEA15MW.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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: 2 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} PA_Mode: 2 # Pitch actuator mode {0 - not used, 1 - first order filter, 2 - second order filter} # Controller parameters diff --git a/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml b/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml index 30a8f783..a61cc151 100644 --- a/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml +++ b/Examples/Tune_Cases/IEA15MW_ExtInterface.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} Ext_Mode: 1 # Use external controller # Controller parameters diff --git a/Examples/Tune_Cases/IEA15MW_FOCAL.yaml b/Examples/Tune_Cases/IEA15MW_FOCAL.yaml index 1785f77b..2544469b 100644 --- a/Examples/Tune_Cases/IEA15MW_FOCAL.yaml +++ b/Examples/Tune_Cases/IEA15MW_FOCAL.yaml @@ -38,6 +38,7 @@ controller_params: PS_Mode: 0 # 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: 2 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters # U_pc: [14] diff --git a/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml b/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml index 8b5b6577..6451e116 100644 --- a/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml +++ b/Examples/Tune_Cases/IEA15MW_MultiOmega.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters U_pc: [14,20] diff --git a/Examples/Tune_Cases/IEA15MW_OL.yaml b/Examples/Tune_Cases/IEA15MW_OL.yaml index 8bd515a2..93cf353e 100644 --- a/Examples/Tune_Cases/IEA15MW_OL.yaml +++ b/Examples/Tune_Cases/IEA15MW_OL.yaml @@ -40,6 +40,7 @@ controller_params: PS_Mode: 2 # 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} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} OL_Mode: 1 # Controller parameters @@ -70,4 +71,4 @@ controller_params: # sine: # amplitude: 0.0524 # period: 20 - # filename: '/Users/dzalkind/Tools/ROSCO/Examples/ol_test.dat' \ No newline at end of file + # filename: '/Users/dzalkind/Tools/ROSCO/Examples/ol_test.dat' diff --git a/Examples/Tune_Cases/IEA15MW_PRC.yaml b/Examples/Tune_Cases/IEA15MW_PRC.yaml index 2a0faacb..644b871d 100644 --- a/Examples/Tune_Cases/IEA15MW_PRC.yaml +++ b/Examples/Tune_Cases/IEA15MW_PRC.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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: 2 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} PA_Mode: 2 # Pitch actuator mode {0 - not used, 1 - first order filter, 2 - second order filter} # Controller parameters diff --git a/Examples/Tune_Cases/IEA15MW_ballast.yaml b/Examples/Tune_Cases/IEA15MW_ballast.yaml index 95013c48..d21bada2 100644 --- a/Examples/Tune_Cases/IEA15MW_ballast.yaml +++ b/Examples/Tune_Cases/IEA15MW_ballast.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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: 2 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} PA_Mode: 2 # Pitch actuator mode {0 - not used, 1 - first order filter, 2 - second order filter} StC_Mode: 2 diff --git a/Examples/Tune_Cases/IEA15MW_cable.yaml b/Examples/Tune_Cases/IEA15MW_cable.yaml index 8b67b82b..3111f977 100644 --- a/Examples/Tune_Cases/IEA15MW_cable.yaml +++ b/Examples/Tune_Cases/IEA15MW_cable.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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: 2 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} PA_Mode: 2 # Pitch actuator mode {0 - not used, 1 - first order filter, 2 - second order filter} CC_Mode: 2 diff --git a/Examples/Tune_Cases/IEA15MW_robust.yaml b/Examples/Tune_Cases/IEA15MW_robust.yaml index ea2ab70a..c6eb5be6 100644 --- a/Examples/Tune_Cases/IEA15MW_robust.yaml +++ b/Examples/Tune_Cases/IEA15MW_robust.yaml @@ -39,6 +39,7 @@ controller_params: PS_Mode: 3 # 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} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters U_pc: [12,14, 15, 18, 20] diff --git a/Examples/Tune_Cases/NREL2p8.yaml b/Examples/Tune_Cases/NREL2p8.yaml index 3d0af809..163c9f42 100644 --- a/Examples/Tune_Cases/NREL2p8.yaml +++ b/Examples/Tune_Cases/NREL2p8.yaml @@ -4,7 +4,8 @@ controller_params: F_LPFType: 1 F_NotchType: 0 IPC_ControlMode: 1 - VS_ControlMode: 3 + VS_ControlMode: 2 + VS_ConstPower: 1 PC_ControlMode: 1 Y_ControlMode: 0 SS_Mode: 1 @@ -12,6 +13,7 @@ controller_params: PS_Mode: 1 SD_Mode: 0 Fl_Mode: 0 + FlTq_Mode: 0 Flp_Mode: 0 zeta_pc: [2.0062413749856227] omega_pc: [0.13653659182284006] @@ -38,7 +40,7 @@ controller_params: flp_maxpit: 0.1745 WS_GS_n: 60 PC_GS_n: 30 - tune_Fl: true + tune_Fl: 0 max_torque_factor: 1.1 IPC_Kp1p: 0.0 IPC_Kp2p: 0.0 diff --git a/Examples/Tune_Cases/NREL5MW.yaml b/Examples/Tune_Cases/NREL5MW.yaml index 69f78982..7829b9a6 100644 --- a/Examples/Tune_Cases/NREL5MW.yaml +++ b/Examples/Tune_Cases/NREL5MW.yaml @@ -40,6 +40,7 @@ controller_params: 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: 0 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters zeta_pc: 0.7 # Pitch controller desired damping ratio [-] diff --git a/Examples/Tune_Cases/NREL5MW_PassThrough.yaml b/Examples/Tune_Cases/NREL5MW_PassThrough.yaml index 2db0472e..daf958ab 100644 --- a/Examples/Tune_Cases/NREL5MW_PassThrough.yaml +++ b/Examples/Tune_Cases/NREL5MW_PassThrough.yaml @@ -39,6 +39,7 @@ controller_params: 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: 0 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters zeta_pc: 0.7 # Pitch controller desired damping ratio [-] diff --git a/Examples/Tune_Cases/RM1_MHK.yaml b/Examples/Tune_Cases/RM1_MHK.yaml index b0cbfde3..ee83e2df 100644 --- a/Examples/Tune_Cases/RM1_MHK.yaml +++ b/Examples/Tune_Cases/RM1_MHK.yaml @@ -40,7 +40,8 @@ controller_params: 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.)} PS_Mode: 0 # 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} + Fl_Mode: 1 # Floating specific feedback mode {0: no nacelle velocity feedback, 1: nacelle velocity feedback} + FlTq_Mode: 0 # Floating specific feedback mode to torque {0: no nacelle velocity feedback to torque, 1: nacelle velocity feedback to torque} Flp_Mode: 0 # Flap control mode {0: no flap control, 1: steady state flap angle, 2: Proportional flap control} # Controller parameters U_pc: [2.3,2.5] diff --git a/pyproject.toml b/pyproject.toml index 84e8c831..1b6c4729 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "rosco" -version = "2.10.1" +version = "2.11.0" description = "A reference open source controller toolset for wind turbine applications." readme = "README.md" requires-python = ">=3.9" diff --git a/rosco/controller/rosco_registry/rosco_types.yaml b/rosco/controller/rosco_registry/rosco_types.yaml index 0e5f13d2..b45d9c50 100644 --- a/rosco/controller/rosco_registry/rosco_types.yaml +++ b/rosco/controller/rosco_registry/rosco_types.yaml @@ -146,7 +146,11 @@ ControlParameters: description: Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s] F_FlCornerFreq: <<: *real - description: Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s]. + description: Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for blade pitch floating feedback control [rad/s]. + allocatable: True + F_FlTqCornerFreq: + <<: *real + description: Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s]. allocatable: True F_FlHighPassFreq: <<: *real @@ -187,7 +191,7 @@ ControlParameters: FA_KI: <<: *real description: Integral gain for the fore-aft tower damper controller, -1 = off / >0 = on [rad s/m] - + # Individual Pitch Control IPC_ControlMode: <<: *integer @@ -201,7 +205,7 @@ ControlParameters: description: Integrator saturation (maximum signal amplitude contrbution to pitch from IPC) IPC_SatMode: <<: *integer - description: IPC Saturation method IPC Saturation method (0 - no saturation (except by PC_MinPit), 1 - saturate by PS_BldPitchMin, 2 - saturate sotfly (full IPC cycle) by PC_MinPit, 3 - saturate softly by PS_BldPitchMin) + description: IPC Saturation method IPC Saturation method (0 - no saturation (except by PC_MinPit), 1 - saturate by PS_BldPitchMin, 2 - saturate softly (full IPC cycle) by PC_MinPit, 3 - saturate softly by PS_BldPitchMin) IPC_KP: <<: *real description: Integral gain for the individual pitch controller, [-]. @@ -217,7 +221,7 @@ ControlParameters: IPC_CornerFreqAct: <<: *real description: Corner frequency of the first-order actuators model, to induce a phase lag in the IPC signal {0 - Disable}, [rad/s] - + # Collective Pitch Controller PC_ControlMode: <<: *integer @@ -266,7 +270,7 @@ ControlParameters: PC_Switch: <<: *real description: Angle above lowest minimum pitch angle for switch [rad] - + # Generator Torque Controller VS_ControlMode: <<: *integer @@ -336,6 +340,17 @@ ControlParameters: <<: *real description: Operating schedule for fixed blade pitch control - Generator torque allocatable: True + VS_ConstPower_n: + <<: *integer + description: Number of VS_ConstPower_alpha for gain scheduling + VS_ConstPower_alpha: + <<: *real + description: Detuning parameter for the constant power feedback loop + allocatable: True + VS_ConstPower_U: + <<: *real + description: Wind speeds for scheduling VS_ConstPower_alpha [m/s] + allocatable: True # Setpoint Smoother SS_Mode: @@ -576,13 +591,20 @@ ControlParameters: # Floating Fl_Mode: <<: *integer - description: Floating specific feedback mode {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} + description: Floating specific feedback mode for blade pitch {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} + FlTq_Mode: + <<: *integer + description: Floating specific feedback mode for generator torque {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} Fl_n: <<: *integer description: Number of Fl_Kp for gain scheduling Fl_Kp: <<: *real - description: Nacelle velocity proportional feedback gain [s] + description: Nacelle velocity proportional feedback gain to blade pitch [s] + allocatable: True + FlTq_Kp: + <<: *real + description: Nacelle velocity proportional feedback gain to generator torque [s] allocatable: True Fl_U: <<: *real @@ -1361,9 +1383,18 @@ LocalVariables: TestType: <<: *real description: Test variable, no use + Alpha_ConstPower: + <<: *real + description: Local instantaneous constant power gain scheduled on wind speed + VS_ConstPwr_GenTq: + <<: *real + description: Calculation of generator torque signal used by the constant power mode Kp_Float: <<: *real description: Local, instantaneous Kp_Float, scheduled on wind speed, if desired + Kp_FloatTq: + <<: *real + description: Local, instantaneous Kp_FloatTq, scheduled on wind speed, if desired VS_MaxTq: <<: *real description: Maximum allowable generator torque [Nm]. @@ -1474,12 +1505,19 @@ LocalVariables: description: Electrical generator torque command for shutdown, [Nm]. Fl_PitCom: <<: *real - description: Shutdown, .FALSE. if inactive, .TRUE. if active + description: Floating feedback signal from nacelle fore-aft velocity to blade pitch + Fl_TqCom: + <<: *real + description: Floating feedback signal from nacelle fore-aft velocity to generator torque NACIMU_FA_AccF: <<: *real FA_AccF: <<: *real description: Filtered fore-aft acceleration in rotation frame, ready for control + NACIMU_FA_AccFTq: + <<: *real + FA_AccFTq: + <<: *real FA_Hist: <<: *integer description: Hysteresis state for tower resonance avoidance. @@ -1717,13 +1755,22 @@ DebugVariables: description: Filtered rotor speed [rad/s] NacIMU_FA_AccF: <<: *real - description: Filtered NacIMU_FA_RAcc [rad/s] + description: Filtered NacIMU_FA_RAcc for blade pitch FF [rad/s] FA_AccF: <<: *real - description: Filtered FA_Acc [m/s] + description: Filtered FA_Acc for blade pitch FF [m/s] + NacIMU_FA_AccFTq: + <<: *real + description: Filtered NacIMU_FA_Acc for generator torque FF [rad/s] + FA_AccFTq: + <<: *real + description: Filtered FA_Acc for generator torque FF [m/s] Fl_PitCom: <<: *real description: Floating contribution to the pitch command [rad] + Fl_TqCom: + <<: *real + description: Floating contribution to the generator torque command [Nm] PC_MinPit: <<: *real description: Minimum blade pitch angle [rad] diff --git a/rosco/controller/src/Controllers.f90 b/rosco/controller/src/Controllers.f90 index b1e40c96..367ba506 100644 --- a/rosco/controller/src/Controllers.f90 +++ b/rosco/controller/src/Controllers.f90 @@ -209,7 +209,7 @@ SUBROUTINE PitchControl(avrSWAP, CntrPar, LocalVar, objInst, DebugVar, ErrVar) ENDIF END SUBROUTINE PitchControl !------------------------------------------------------------------------------------------------------------------------------- - SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) + SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, DebugVar, ErrVar) ! Generator torque controller ! VS_State = VS_State_Error (0), Error state, for debugging purposes, GenTq = VS_RtTq ! VS_State = VS_State_Region_1_5 (1), Region 1(.5) operation, torque control to keep the rotor at cut-in speed towards the Cp-max operational curve @@ -224,6 +224,7 @@ SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) TYPE(ControlParameters), INTENT(INOUT) :: CntrPar TYPE(LocalVariables), INTENT(INOUT) :: LocalVar TYPE(ObjectInstances), INTENT(INOUT) :: objInst + TYPE(DebugVariables), INTENT(INOUT) :: DebugVar TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar CHARACTER(*), PARAMETER :: RoutineName = 'VariableSpeedControl' @@ -234,7 +235,8 @@ SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) ! Pre-compute generator torque values for K*Omega^2 and constant power LocalVar%VS_KOmega2_GenTq = CntrPar%VS_Rgn2K*LocalVar%GenSpeedF*LocalVar%GenSpeedF - LocalVar%VS_ConstPwr_GenTq = (CntrPar%VS_RtPwr/(CntrPar%VS_GenEff/100.0))/LocalVar%GenSpeedF * LocalVar%PRC_R_Torque + LocalVar%Alpha_ConstPower = interp1d(CntrPar%VS_ConstPower_U, CntrPar%VS_ConstPower_alpha, LocalVar%WE_Vw_F, ErrVar) ! Schedule based on WSE (could use filtered blade pitch instead) + LocalVar%VS_ConstPwr_GenTq = (CntrPar%VS_RtPwr/(CntrPar%VS_GenEff/100.0)) / (CntrPar%PC_RefSpd + LocalVar%Alpha_ConstPower * (LocalVar%GenSpeedF - CntrPar%PC_RefSpd)) * LocalVar%PRC_R_Torque ! Determine maximum torque saturation limit, VS_MaxTq IF (CntrPar%VS_FBP == VS_FBP_Variable_Pitch) THEN @@ -312,6 +314,13 @@ SUBROUTINE VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) LocalVar%GenTq = LocalVar%GenTq_SD ENDIF + ! Add floating feedback to torque signal + IF (CntrPar%FlTq_Mode > 0) THEN + LocalVar%Fl_TqCom = FloatingFeedbackTq(LocalVar, CntrPar, objInst, ErrVar) + DebugVar%FL_TqCom = LocalVar%Fl_TqCom + LocalVar%GenTq = LocalVar%GenTq + LocalVar%Fl_TqCom + ENDIF + ! Saturate based on most stringent defined maximum LocalVar%GenTq = saturate(LocalVar%GenTq, CntrPar%VS_MinTq, MIN(CntrPar%VS_MaxTq, LocalVar%VS_MaxTq)) @@ -587,26 +596,26 @@ SUBROUTINE ForeAftDamping(CntrPar, LocalVar, objInst) ! Fore-aft damping controller, reducing the tower fore-aft vibrations using pitch USE ROSCO_Types, ONLY : ControlParameters, LocalVariables, ObjectInstances - + ! Local variables INTEGER(IntKi) :: K ! Integer used to loop through turbine blades TYPE(ControlParameters), INTENT(INOUT) :: CntrPar TYPE(LocalVariables), INTENT(INOUT) :: LocalVar TYPE(ObjectInstances), INTENT(INOUT) :: objInst - + ! Body LocalVar%FA_AccHPFI = PIController(LocalVar%FA_AccHPF, 0.0_DbKi, CntrPar%FA_KI, -CntrPar%FA_IntSat, CntrPar%FA_IntSat, LocalVar%DT, 0.0_DbKi, LocalVar%piP, LocalVar%restart, objInst%instPI) - + ! Store the fore-aft pitch contribution to LocalVar data type DO K = 1,LocalVar%NumBl LocalVar%FA_PitCom(K) = LocalVar%FA_AccHPFI END DO - + END SUBROUTINE ForeAftDamping !------------------------------------------------------------------------------------------------------------------------------- REAL(DbKi) FUNCTION FloatingFeedback(LocalVar, CntrPar, objInst, ErrVar) - ! FloatingFeedback defines a minimum blade pitch angle based on a lookup table provided by DISON.IN + ! FloatingFeedback computes a feedback signal from nacelle fore-aft velocity to blade pitch ! Fl_Mode = 0, No feedback ! Fl_Mode = 1, Proportional feedback of nacelle velocity (translational) ! Fl_Mode = 2, Proportional feedback of nacelle velocity (rotational) @@ -635,6 +644,41 @@ REAL(DbKi) FUNCTION FloatingFeedback(LocalVar, CntrPar, objInst, ErrVar) END IF END FUNCTION FloatingFeedback +!------------------------------------------------------------------------------------------------------------------------------- + REAL(DbKi) FUNCTION FloatingFeedbackTq(LocalVar, CntrPar, objInst, ErrVar) + ! FloatingFeedbackGenTq computes a feedback signal from nacelle fore-aft velocity to generator torque + ! Fl_Mode = 0, No feedback + ! Fl_Mode = 1, Proportional feedback of nacelle velocity (translational) + ! Fl_Mode = 2, Proportional feedback of nacelle velocity (rotational) + USE ROSCO_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances, ErrorVariables + IMPLICIT NONE + ! Inputs + TYPE(ControlParameters), INTENT(IN) :: CntrPar + TYPE(LocalVariables), INTENT(INOUT) :: LocalVar + TYPE(ObjectInstances), INTENT(INOUT) :: objInst + TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar + ! Allocate Variables + REAL(DbKi) :: FA_vel ! Tower fore-aft velocity [m/s] + REAL(DbKi) :: NacIMU_FA_vel ! Tower fore-aft pitching velocity [rad/s] + REAL(DbKi) :: FlTq_sat_lim ! +/- saturation limit for torque floating feedback signal + + ! Gain scheduling + LocalVar%Kp_FloatTq = interp1d(CntrPar%Fl_U,CntrPar%FlTq_Kp,LocalVar%WE_Vw_F,ErrVar) ! Schedule based on WSE + + ! Define FlTq saturation limit (TODO make this based on the actual parameter) + FlTq_sat_lim = CntrPar%VS_RtTq * 2.0_DbKi + + ! Calculate floating contribution to pitch command + FA_vel = PIController(LocalVar%FA_AccFTq, 0.0_DbKi, 1.0_DbKi, -FlTq_sat_lim, FlTq_sat_lim, LocalVar%DT, 0.0_DbKi, LocalVar%piP, LocalVar%restart, objInst%instPI) + NacIMU_FA_vel = PIController(LocalVar%NacIMU_FA_AccFTq, 0.0_DbKi, 1.0_DbKi, -FlTq_sat_lim, FlTq_sat_lim, LocalVar%DT, 0.0_DbKi, LocalVar%piP, LocalVar%restart, objInst%instPI) +! Mod made by A. Wright: use the gain scheduled value of KPfloat in the floating fb equ's below (instead of the old value of CntrPar%Fl_Kp), for either value of CntrPar%Fl_Mode... + if (CntrPar%FlTq_Mode == 1) THEN + FloatingFeedbackTq = (0.0_DbKi - FA_vel) * LocalVar%Kp_FloatTq ! Mod made by A. Wright: use the gain scheduled value of KPfloat in the floating fb equ's below (instead of the old value of CntrPar%Fl_Kp), for either value of CntrPar%Fl_Mode... + ELSEIF (CntrPar%FlTq_Mode == 2) THEN + FloatingFeedbackTq = (0.0_DbKi - NacIMU_FA_vel) * LocalVar%Kp_FloatTq ! Mod made by A. Wright: use the gain scheduled value of KPfloat in the floating fb equ's below (instead of the old value of CntrPar%Fl_Kp), for either value of CntrPar%Fl_Mode... + END IF + + END FUNCTION FloatingFeedbackTq !------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE FlapControl(avrSWAP, CntrPar, LocalVar, objInst) ! Yaw rate controller diff --git a/rosco/controller/src/DISCON.F90 b/rosco/controller/src/DISCON.F90 index e96a7c17..6c71b446 100644 --- a/rosco/controller/src/DISCON.F90 +++ b/rosco/controller/src/DISCON.F90 @@ -114,7 +114,7 @@ SUBROUTINE DISCON(avrSWAP, aviFAIL, accINFILE, avcOUTNAME, avcMSG) BIND (C, NAME CALL ComputeVariablesSetpoints(CntrPar, LocalVar, objInst, DebugVar, ErrVar) CALL StateMachine(CntrPar, LocalVar) CALL SetpointSmoother(LocalVar, CntrPar, objInst) - CALL VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, ErrVar) + CALL VariableSpeedControl(avrSWAP, CntrPar, LocalVar, objInst, DebugVar, ErrVar) IF (CntrPar%PC_ControlMode > 0) THEN CALL PitchControl(avrSWAP, CntrPar, LocalVar, objInst, DebugVar, ErrVar) END IF diff --git a/rosco/controller/src/Filters.f90 b/rosco/controller/src/Filters.f90 index 6027f488..beb045f6 100644 --- a/rosco/controller/src/Filters.f90 +++ b/rosco/controller/src/Filters.f90 @@ -370,11 +370,17 @@ SUBROUTINE PreFilterMeasuredSignals(CntrPar, LocalVar, DebugVar, objInst, ErrVar ! Low pass LocalVar%NacIMU_FA_AccF = SecLPFilter(LocalVar%NacIMU_FA_RAcc, LocalVar%DT, CntrPar%F_FlCornerFreq(1), CntrPar%F_FlCornerFreq(2), LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instSecLPF) ! Fixed Damping LocalVar%FA_AccF = SecLPFilter(LocalVar%FA_Acc_Nac, LocalVar%DT, CntrPar%F_FlCornerFreq(1), CntrPar%F_FlCornerFreq(2), LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instSecLPF) ! Fixed Damping - + + LocalVar%NacIMU_FA_AccFTq = SecLPFilter(LocalVar%NacIMU_FA_RAcc, LocalVar%DT, CntrPar%F_FlTqCornerFreq(1), CntrPar%F_FlTqCornerFreq(2), LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instSecLPF) ! Fixed Damping + LocalVar%FA_AccFTq = SecLPFilter(LocalVar%FA_Acc_Nac, LocalVar%DT, CntrPar%F_FlTqCornerFreq(1), CntrPar%F_FlTqCornerFreq(2), LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instSecLPF) ! Fixed Damping + ! High pass - LocalVar%NacIMU_FA_AccF = HPFilter(LocalVar%NacIMU_FA_AccF, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) - LocalVar%FA_AccF = HPFilter(LocalVar%FA_AccF, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) - + LocalVar%NacIMU_FA_AccF = HPFilter(LocalVar%NacIMU_FA_AccF, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) + LocalVar%FA_AccF = HPFilter(LocalVar%FA_AccF, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) + + LocalVar%NacIMU_FA_AccFTq = HPFilter(LocalVar%NacIMU_FA_AccFTq, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) + LocalVar%FA_AccFTq = HPFilter(LocalVar%FA_AccFTq, LocalVar%DT, CntrPar%F_FlHighPassFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) + ! Notch filters DO n = 1,CntrPar%F_TwrTopNotch_N LocalVar%NACIMU_FA_AccF = NotchFilter(LocalVar%NacIMU_FA_AccF, LocalVar%DT, & @@ -382,19 +388,31 @@ SUBROUTINE PreFilterMeasuredSignals(CntrPar, LocalVar, DebugVar, objInst, ErrVar CntrPar%F_NotchBetaNum(CntrPar%F_TwrTopNotch_Ind(n)), & CntrPar%F_NotchBetaDen(CntrPar%F_TwrTopNotch_Ind(n)), & LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instNotch) - + LocalVar%FA_AccF = NotchFilter(LocalVar%FA_AccF, LocalVar%DT, & CntrPar%F_NotchFreqs(CntrPar%F_TwrTopNotch_Ind(n)), & CntrPar%F_NotchBetaNum(CntrPar%F_TwrTopNotch_Ind(n)), & CntrPar%F_NotchBetaDen(CntrPar%F_TwrTopNotch_Ind(n)), & LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instNotch) + + LocalVar%NACIMU_FA_AccFTq = NotchFilter(LocalVar%NacIMU_FA_AccFTq, LocalVar%DT, & + CntrPar%F_NotchFreqs(CntrPar%F_TwrTopNotch_Ind(n)), & + CntrPar%F_NotchBetaNum(CntrPar%F_TwrTopNotch_Ind(n)), & + CntrPar%F_NotchBetaDen(CntrPar%F_TwrTopNotch_Ind(n)), & + LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instNotch) + + LocalVar%FA_AccFTq = NotchFilter(LocalVar%FA_AccFTq, LocalVar%DT, & + CntrPar%F_NotchFreqs(CntrPar%F_TwrTopNotch_Ind(n)), & + CntrPar%F_NotchBetaNum(CntrPar%F_TwrTopNotch_Ind(n)), & + CntrPar%F_NotchBetaDen(CntrPar%F_TwrTopNotch_Ind(n)), & + LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instNotch) END DO - + ! FA acc for ForeAft damping, condition matches whether it's used in Controllers.f90 IF (CntrPar%TD_Mode > 0) THEN LocalVar%FA_AccHPF = HPFilter(LocalVar%FA_Acc_Nac, LocalVar%DT, CntrPar%FA_HPFCornerFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instHPF) ENDIF - + ! Filter Wind Speed Estimator Signal LocalVar%We_Vw_F = LPFilter(LocalVar%WE_Vw, LocalVar%DT,CntrPar%F_WECornerFreq, LocalVar%FP, LocalVar%iStatus, LocalVar%restart, objInst%instLPF) @@ -434,5 +452,7 @@ SUBROUTINE PreFilterMeasuredSignals(CntrPar, LocalVar, DebugVar, objInst, ErrVar DebugVar%RotSpeedF = LocalVar%RotSpeedF DebugVar%NacIMU_FA_AccF = LocalVar%NacIMU_FA_AccF DebugVar%FA_AccF = LocalVar%FA_AccF + DebugVar%NacIMU_FA_AccFTq = LocalVar%NacIMU_FA_AccFTq + DebugVar%FA_AccFTq = LocalVar%FA_AccFTq END SUBROUTINE PreFilterMeasuredSignals END MODULE Filters diff --git a/rosco/controller/src/ROSCO_IO.f90 b/rosco/controller/src/ROSCO_IO.f90 index 73e57df3..97467dcf 100644 --- a/rosco/controller/src/ROSCO_IO.f90 +++ b/rosco/controller/src/ROSCO_IO.f90 @@ -1,5 +1,5 @@ ! ROSCO IO -! This file is automatically generated by write_registry.py using ROSCO v2.10.1 +! This file is automatically generated by write_registry.py using ROSCO v2.11.0 ! For any modification to the registry, please edit the rosco_types.yaml accordingly MODULE ROSCO_IO @@ -139,7 +139,9 @@ SUBROUTINE WriteRestartFile(LocalVar, CntrPar, ErrVar, objInst, RootName, size_a WRITE( Un, IOSTAT=ErrStat) LocalVar%PitComAct(3) WRITE( Un, IOSTAT=ErrStat) LocalVar%SS_DelOmegaF WRITE( Un, IOSTAT=ErrStat) LocalVar%TestType + WRITE( Un, IOSTAT=ErrStat) LocalVar%Alpha_ConstPower WRITE( Un, IOSTAT=ErrStat) LocalVar%Kp_Float + WRITE( Un, IOSTAT=ErrStat) LocalVar%Kp_FloatTq WRITE( Un, IOSTAT=ErrStat) LocalVar%VS_MaxTq WRITE( Un, IOSTAT=ErrStat) LocalVar%VS_LastGenTrq WRITE( Un, IOSTAT=ErrStat) LocalVar%VS_LastGenPwr @@ -177,8 +179,11 @@ SUBROUTINE WriteRestartFile(LocalVar, CntrPar, ErrVar, objInst, RootName, size_a WRITE( Un, IOSTAT=ErrStat) LocalVar%SD_MaxTorqueRate WRITE( Un, IOSTAT=ErrStat) LocalVar%GenTq_SD WRITE( Un, IOSTAT=ErrStat) LocalVar%Fl_PitCom + WRITE( Un, IOSTAT=ErrStat) LocalVar%Fl_TqCom WRITE( Un, IOSTAT=ErrStat) LocalVar%NACIMU_FA_AccF WRITE( Un, IOSTAT=ErrStat) LocalVar%FA_AccF + WRITE( Un, IOSTAT=ErrStat) LocalVar%NACIMU_FA_AccFTq + WRITE( Un, IOSTAT=ErrStat) LocalVar%FA_AccFTq WRITE( Un, IOSTAT=ErrStat) LocalVar%FA_Hist WRITE( Un, IOSTAT=ErrStat) LocalVar%TRA_LastRefSpd WRITE( Un, IOSTAT=ErrStat) LocalVar%VS_RefSpeed @@ -482,7 +487,9 @@ SUBROUTINE ReadRestartFile(avrSWAP, LocalVar, CntrPar, objInst, PerfData, RootNa READ( Un, IOSTAT=ErrStat) LocalVar%PitComAct(3) READ( Un, IOSTAT=ErrStat) LocalVar%SS_DelOmegaF READ( Un, IOSTAT=ErrStat) LocalVar%TestType + READ( Un, IOSTAT=ErrStat) LocalVar%Alpha_ConstPower READ( Un, IOSTAT=ErrStat) LocalVar%Kp_Float + READ( Un, IOSTAT=ErrStat) LocalVar%Kp_FloatTq READ( Un, IOSTAT=ErrStat) LocalVar%VS_MaxTq READ( Un, IOSTAT=ErrStat) LocalVar%VS_LastGenTrq READ( Un, IOSTAT=ErrStat) LocalVar%VS_LastGenPwr @@ -520,8 +527,11 @@ SUBROUTINE ReadRestartFile(avrSWAP, LocalVar, CntrPar, objInst, PerfData, RootNa READ( Un, IOSTAT=ErrStat) LocalVar%SD_MaxTorqueRate READ( Un, IOSTAT=ErrStat) LocalVar%GenTq_SD READ( Un, IOSTAT=ErrStat) LocalVar%Fl_PitCom + READ( Un, IOSTAT=ErrStat) LocalVar%Fl_TqCom READ( Un, IOSTAT=ErrStat) LocalVar%NACIMU_FA_AccF READ( Un, IOSTAT=ErrStat) LocalVar%FA_AccF + READ( Un, IOSTAT=ErrStat) LocalVar%NACIMU_FA_AccFTq + READ( Un, IOSTAT=ErrStat) LocalVar%FA_AccFTq READ( Un, IOSTAT=ErrStat) LocalVar%FA_Hist READ( Un, IOSTAT=ErrStat) LocalVar%TRA_LastRefSpd READ( Un, IOSTAT=ErrStat) LocalVar%VS_RefSpeed @@ -729,10 +739,10 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av REAL(DbKi), ALLOCATABLE :: DebugOutData(:) - CHARACTER(15), DIMENSION(159) :: LocalVarOutStrings + CHARACTER(15), DIMENSION(164) :: LocalVarOutStrings REAL(DbKi), ALLOCATABLE :: LocalVarOutData(:) - nDebugOuts = 26 + nDebugOuts = 29 Allocate(DebugOutData(nDebugOuts)) Allocate(DebugOutStrings(nDebugOuts)) Allocate(DebugOutUnits(nDebugOuts)) @@ -749,32 +759,35 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av DebugOutData(11) = DebugVar%RotSpeedF DebugOutData(12) = DebugVar%NacIMU_FA_AccF DebugOutData(13) = DebugVar%FA_AccF - DebugOutData(14) = DebugVar%Fl_PitCom - DebugOutData(15) = DebugVar%PC_MinPit - DebugOutData(16) = DebugVar%axisTilt_1P - DebugOutData(17) = DebugVar%axisYaw_1P - DebugOutData(18) = DebugVar%axisTilt_2P - DebugOutData(19) = DebugVar%axisYaw_2P - DebugOutData(20) = DebugVar%YawRateCom - DebugOutData(21) = DebugVar%NacHeadingTarget - DebugOutData(22) = DebugVar%NacVaneOffset - DebugOutData(23) = DebugVar%Yaw_Err - DebugOutData(24) = DebugVar%YawState - DebugOutData(25) = DebugVar%VS_RefSpd - DebugOutData(26) = DebugVar%PC_RefSpd + DebugOutData(14) = DebugVar%NacIMU_FA_AccFTq + DebugOutData(15) = DebugVar%FA_AccFTq + DebugOutData(16) = DebugVar%Fl_PitCom + DebugOutData(17) = DebugVar%Fl_TqCom + DebugOutData(18) = DebugVar%PC_MinPit + DebugOutData(19) = DebugVar%axisTilt_1P + DebugOutData(20) = DebugVar%axisYaw_1P + DebugOutData(21) = DebugVar%axisTilt_2P + DebugOutData(22) = DebugVar%axisYaw_2P + DebugOutData(23) = DebugVar%YawRateCom + DebugOutData(24) = DebugVar%NacHeadingTarget + DebugOutData(25) = DebugVar%NacVaneOffset + DebugOutData(26) = DebugVar%Yaw_Err + DebugOutData(27) = DebugVar%YawState + DebugOutData(28) = DebugVar%VS_RefSpd + DebugOutData(29) = DebugVar%PC_RefSpd DebugOutStrings = [CHARACTER(15) :: 'WE_Cp', 'WE_b', 'WE_w', 'WE_t', 'WE_Vm', & 'WE_Vt', 'WE_Vw', 'WE_lambda', 'PC_PICommand', 'GenSpeedF', & - 'RotSpeedF', 'NacIMU_FA_AccF', 'FA_AccF', 'Fl_PitCom', 'PC_MinPit', & - 'axisTilt_1P', 'axisYaw_1P', 'axisTilt_2P', 'axisYaw_2P', 'YawRateCom', & - 'NacHeadingTarget', 'NacVaneOffset', 'Yaw_Err', 'YawState', 'VS_RefSpd', & - 'PC_RefSpd'] + 'RotSpeedF', 'NacIMU_FA_AccF', 'FA_AccF', 'NacIMU_FA_AccFTq', 'FA_AccFTq', & + 'Fl_PitCom', 'Fl_TqCom', 'PC_MinPit', 'axisTilt_1P', 'axisYaw_1P', & + 'axisTilt_2P', 'axisYaw_2P', 'YawRateCom', 'NacHeadingTarget', 'NacVaneOffset', & + 'Yaw_Err', 'YawState', 'VS_RefSpd', 'PC_RefSpd'] DebugOutUnits = [CHARACTER(15) :: '[-]', '[-]', '[-]', '[-]', '[m/s]', & '[m/s]', '[m/s]', '[rad]', '[rad]', '[rad/s]', & - '[rad/s]', '[rad/s]', '[m/s]', '[rad]', '[rad]', & - '[N/A]', '[N/A]', '[N/A]', '[N/A]', '[rad/s]', & - '[deg]', '[deg]', '[deg]', '[N/A]', '[rad/s]', & - '[rad/s]'] - nLocalVars = 159 + '[rad/s]', '[rad/s]', '[m/s]', '[rad/s]', '[m/s]', & + '[rad]', '[Nm]', '[rad]', '[N/A]', '[N/A]', & + '[N/A]', '[N/A]', '[rad/s]', '[deg]', '[deg]', & + '[deg]', '[N/A]', '[rad/s]', '[rad/s]'] + nLocalVars = 164 Allocate(LocalVarOutData(nLocalVars)) LocalVarOutData(1) = LocalVar%iStatus LocalVarOutData(2) = LocalVar%AlreadyInitialized @@ -857,84 +870,89 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av LocalVarOutData(79) = LocalVar%PitComAct(1) LocalVarOutData(80) = LocalVar%SS_DelOmegaF LocalVarOutData(81) = LocalVar%TestType - LocalVarOutData(82) = LocalVar%Kp_Float - LocalVarOutData(83) = LocalVar%VS_MaxTq - LocalVarOutData(84) = LocalVar%VS_LastGenTrq - LocalVarOutData(85) = LocalVar%VS_LastGenPwr - LocalVarOutData(86) = LocalVar%VS_MechGenPwr - LocalVarOutData(87) = LocalVar%VS_SpdErrAr - LocalVarOutData(88) = LocalVar%VS_SpdErrBr - LocalVarOutData(89) = LocalVar%VS_SpdErr - LocalVarOutData(90) = LocalVar%VS_State - LocalVarOutData(91) = LocalVar%VS_Rgn3Pitch - LocalVarOutData(92) = LocalVar%WE_Vw - LocalVarOutData(93) = LocalVar%WE_Vw_F - LocalVarOutData(94) = LocalVar%WE_VwI - LocalVarOutData(95) = LocalVar%WE_VwIdot - LocalVarOutData(96) = LocalVar%WE_Op - LocalVarOutData(97) = LocalVar%WE_Op_Last - LocalVarOutData(98) = LocalVar%VS_LastGenTrqF - LocalVarOutData(99) = LocalVar%PRC_WSE_F - LocalVarOutData(100) = LocalVar%PRC_R_Speed - LocalVarOutData(101) = LocalVar%PRC_R_Torque - LocalVarOutData(102) = LocalVar%PRC_R_Pitch - LocalVarOutData(103) = LocalVar%PRC_R_Total - LocalVarOutData(104) = LocalVar%PRC_Min_Pitch - LocalVarOutData(105) = LocalVar%PS_Min_Pitch - LocalVarOutData(106) = LocalVar%OL_Index - LocalVarOutData(107) = LocalVar%SU_Stage - LocalVarOutData(108) = LocalVar%SU_LoadStageStartTime - LocalVarOutData(109) = LocalVar%SU_RotSpeedF - LocalVarOutData(110) = LocalVar%SD_Trigger - LocalVarOutData(111) = LocalVar%SD_BlPitchF - LocalVarOutData(112) = LocalVar%SD_NacVaneF - LocalVarOutData(113) = LocalVar%SD_GenSpeedF - LocalVarOutData(114) = LocalVar%SD_Stage - LocalVarOutData(115) = LocalVar%SD_StageStartTime - LocalVarOutData(116) = LocalVar%SD_MaxPitchRate - LocalVarOutData(117) = LocalVar%SD_MaxTorqueRate - LocalVarOutData(118) = LocalVar%GenTq_SD - LocalVarOutData(119) = LocalVar%Fl_PitCom - LocalVarOutData(120) = LocalVar%NACIMU_FA_AccF - LocalVarOutData(121) = LocalVar%FA_AccF - LocalVarOutData(122) = LocalVar%FA_Hist - LocalVarOutData(123) = LocalVar%TRA_LastRefSpd - LocalVarOutData(124) = LocalVar%VS_RefSpeed - LocalVarOutData(125) = LocalVar%PtfmTDX - LocalVarOutData(126) = LocalVar%PtfmTDY - LocalVarOutData(127) = LocalVar%PtfmTDZ - LocalVarOutData(128) = LocalVar%PtfmRDX - LocalVarOutData(129) = LocalVar%PtfmRDY - LocalVarOutData(130) = LocalVar%PtfmRDZ - LocalVarOutData(131) = LocalVar%PtfmTVX - LocalVarOutData(132) = LocalVar%PtfmTVY - LocalVarOutData(133) = LocalVar%PtfmTVZ - LocalVarOutData(134) = LocalVar%PtfmRVX - LocalVarOutData(135) = LocalVar%PtfmRVY - LocalVarOutData(136) = LocalVar%PtfmRVZ - LocalVarOutData(137) = LocalVar%PtfmTAX - LocalVarOutData(138) = LocalVar%PtfmTAY - LocalVarOutData(139) = LocalVar%PtfmTAZ - LocalVarOutData(140) = LocalVar%PtfmRAX - LocalVarOutData(141) = LocalVar%PtfmRAY - LocalVarOutData(142) = LocalVar%PtfmRAZ - LocalVarOutData(143) = LocalVar%CC_DesiredL(1) - LocalVarOutData(144) = LocalVar%CC_ActuatedL(1) - LocalVarOutData(145) = LocalVar%CC_ActuatedDL(1) - LocalVarOutData(146) = LocalVar%StC_Input(1) - LocalVarOutData(147) = LocalVar%Flp_Angle(1) - LocalVarOutData(148) = LocalVar%RootMyb_Last(1) - LocalVarOutData(149) = LocalVar%ACC_INFILE_SIZE - LocalVarOutData(150) = LocalVar%AWC_complexangle(1) - LocalVarOutData(151) = LocalVar%TiltMean - LocalVarOutData(152) = LocalVar%YawMean - LocalVarOutData(153) = LocalVar%ZMQ_ID - LocalVarOutData(154) = LocalVar%ZMQ_YawOffset - LocalVarOutData(155) = LocalVar%ZMQ_TorqueOffset - LocalVarOutData(156) = LocalVar%ZMQ_PitOffset(1) - LocalVarOutData(157) = LocalVar%ZMQ_R_Speed - LocalVarOutData(158) = LocalVar%ZMQ_R_Torque - LocalVarOutData(159) = LocalVar%ZMQ_R_Pitch + LocalVarOutData(82) = LocalVar%Alpha_ConstPower + LocalVarOutData(83) = LocalVar%Kp_Float + LocalVarOutData(84) = LocalVar%Kp_FloatTq + LocalVarOutData(85) = LocalVar%VS_MaxTq + LocalVarOutData(86) = LocalVar%VS_LastGenTrq + LocalVarOutData(87) = LocalVar%VS_LastGenPwr + LocalVarOutData(88) = LocalVar%VS_MechGenPwr + LocalVarOutData(89) = LocalVar%VS_SpdErrAr + LocalVarOutData(90) = LocalVar%VS_SpdErrBr + LocalVarOutData(91) = LocalVar%VS_SpdErr + LocalVarOutData(92) = LocalVar%VS_State + LocalVarOutData(93) = LocalVar%VS_Rgn3Pitch + LocalVarOutData(94) = LocalVar%WE_Vw + LocalVarOutData(95) = LocalVar%WE_Vw_F + LocalVarOutData(96) = LocalVar%WE_VwI + LocalVarOutData(97) = LocalVar%WE_VwIdot + LocalVarOutData(98) = LocalVar%WE_Op + LocalVarOutData(99) = LocalVar%WE_Op_Last + LocalVarOutData(100) = LocalVar%VS_LastGenTrqF + LocalVarOutData(101) = LocalVar%PRC_WSE_F + LocalVarOutData(102) = LocalVar%PRC_R_Speed + LocalVarOutData(103) = LocalVar%PRC_R_Torque + LocalVarOutData(104) = LocalVar%PRC_R_Pitch + LocalVarOutData(105) = LocalVar%PRC_R_Total + LocalVarOutData(106) = LocalVar%PRC_Min_Pitch + LocalVarOutData(107) = LocalVar%PS_Min_Pitch + LocalVarOutData(108) = LocalVar%OL_Index + LocalVarOutData(109) = LocalVar%SU_Stage + LocalVarOutData(110) = LocalVar%SU_LoadStageStartTime + LocalVarOutData(111) = LocalVar%SU_RotSpeedF + LocalVarOutData(112) = LocalVar%SD_Trigger + LocalVarOutData(113) = LocalVar%SD_BlPitchF + LocalVarOutData(114) = LocalVar%SD_NacVaneF + LocalVarOutData(115) = LocalVar%SD_GenSpeedF + LocalVarOutData(116) = LocalVar%SD_Stage + LocalVarOutData(117) = LocalVar%SD_StageStartTime + LocalVarOutData(118) = LocalVar%SD_MaxPitchRate + LocalVarOutData(119) = LocalVar%SD_MaxTorqueRate + LocalVarOutData(120) = LocalVar%GenTq_SD + LocalVarOutData(121) = LocalVar%Fl_PitCom + LocalVarOutData(122) = LocalVar%Fl_TqCom + LocalVarOutData(123) = LocalVar%NACIMU_FA_AccF + LocalVarOutData(124) = LocalVar%FA_AccF + LocalVarOutData(125) = LocalVar%NACIMU_FA_AccFTq + LocalVarOutData(126) = LocalVar%FA_AccFTq + LocalVarOutData(127) = LocalVar%FA_Hist + LocalVarOutData(128) = LocalVar%TRA_LastRefSpd + LocalVarOutData(129) = LocalVar%VS_RefSpeed + LocalVarOutData(130) = LocalVar%PtfmTDX + LocalVarOutData(131) = LocalVar%PtfmTDY + LocalVarOutData(132) = LocalVar%PtfmTDZ + LocalVarOutData(133) = LocalVar%PtfmRDX + LocalVarOutData(134) = LocalVar%PtfmRDY + LocalVarOutData(135) = LocalVar%PtfmRDZ + LocalVarOutData(136) = LocalVar%PtfmTVX + LocalVarOutData(137) = LocalVar%PtfmTVY + LocalVarOutData(138) = LocalVar%PtfmTVZ + LocalVarOutData(139) = LocalVar%PtfmRVX + LocalVarOutData(140) = LocalVar%PtfmRVY + LocalVarOutData(141) = LocalVar%PtfmRVZ + LocalVarOutData(142) = LocalVar%PtfmTAX + LocalVarOutData(143) = LocalVar%PtfmTAY + LocalVarOutData(144) = LocalVar%PtfmTAZ + LocalVarOutData(145) = LocalVar%PtfmRAX + LocalVarOutData(146) = LocalVar%PtfmRAY + LocalVarOutData(147) = LocalVar%PtfmRAZ + LocalVarOutData(148) = LocalVar%CC_DesiredL(1) + LocalVarOutData(149) = LocalVar%CC_ActuatedL(1) + LocalVarOutData(150) = LocalVar%CC_ActuatedDL(1) + LocalVarOutData(151) = LocalVar%StC_Input(1) + LocalVarOutData(152) = LocalVar%Flp_Angle(1) + LocalVarOutData(153) = LocalVar%RootMyb_Last(1) + LocalVarOutData(154) = LocalVar%ACC_INFILE_SIZE + LocalVarOutData(155) = LocalVar%AWC_complexangle(1) + LocalVarOutData(156) = LocalVar%TiltMean + LocalVarOutData(157) = LocalVar%YawMean + LocalVarOutData(158) = LocalVar%ZMQ_ID + LocalVarOutData(159) = LocalVar%ZMQ_YawOffset + LocalVarOutData(160) = LocalVar%ZMQ_TorqueOffset + LocalVarOutData(161) = LocalVar%ZMQ_PitOffset(1) + LocalVarOutData(162) = LocalVar%ZMQ_R_Speed + LocalVarOutData(163) = LocalVar%ZMQ_R_Torque + LocalVarOutData(164) = LocalVar%ZMQ_R_Pitch LocalVarOutStrings(1) = 'iStatus' LocalVarOutStrings(2) = 'AlreadyInitialized' @@ -1017,84 +1035,89 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av LocalVarOutStrings(79) = 'PitComAct' LocalVarOutStrings(80) = 'SS_DelOmegaF' LocalVarOutStrings(81) = 'TestType' - LocalVarOutStrings(82) = 'Kp_Float' - LocalVarOutStrings(83) = 'VS_MaxTq' - LocalVarOutStrings(84) = 'VS_LastGenTrq' - LocalVarOutStrings(85) = 'VS_LastGenPwr' - LocalVarOutStrings(86) = 'VS_MechGenPwr' - LocalVarOutStrings(87) = 'VS_SpdErrAr' - LocalVarOutStrings(88) = 'VS_SpdErrBr' - LocalVarOutStrings(89) = 'VS_SpdErr' - LocalVarOutStrings(90) = 'VS_State' - LocalVarOutStrings(91) = 'VS_Rgn3Pitch' - LocalVarOutStrings(92) = 'WE_Vw' - LocalVarOutStrings(93) = 'WE_Vw_F' - LocalVarOutStrings(94) = 'WE_VwI' - LocalVarOutStrings(95) = 'WE_VwIdot' - LocalVarOutStrings(96) = 'WE_Op' - LocalVarOutStrings(97) = 'WE_Op_Last' - LocalVarOutStrings(98) = 'VS_LastGenTrqF' - LocalVarOutStrings(99) = 'PRC_WSE_F' - LocalVarOutStrings(100) = 'PRC_R_Speed' - LocalVarOutStrings(101) = 'PRC_R_Torque' - LocalVarOutStrings(102) = 'PRC_R_Pitch' - LocalVarOutStrings(103) = 'PRC_R_Total' - LocalVarOutStrings(104) = 'PRC_Min_Pitch' - LocalVarOutStrings(105) = 'PS_Min_Pitch' - LocalVarOutStrings(106) = 'OL_Index' - LocalVarOutStrings(107) = 'SU_Stage' - LocalVarOutStrings(108) = 'SU_LoadStageStartTime' - LocalVarOutStrings(109) = 'SU_RotSpeedF' - LocalVarOutStrings(110) = 'SD_Trigger' - LocalVarOutStrings(111) = 'SD_BlPitchF' - LocalVarOutStrings(112) = 'SD_NacVaneF' - LocalVarOutStrings(113) = 'SD_GenSpeedF' - LocalVarOutStrings(114) = 'SD_Stage' - LocalVarOutStrings(115) = 'SD_StageStartTime' - LocalVarOutStrings(116) = 'SD_MaxPitchRate' - LocalVarOutStrings(117) = 'SD_MaxTorqueRate' - LocalVarOutStrings(118) = 'GenTq_SD' - LocalVarOutStrings(119) = 'Fl_PitCom' - LocalVarOutStrings(120) = 'NACIMU_FA_AccF' - LocalVarOutStrings(121) = 'FA_AccF' - LocalVarOutStrings(122) = 'FA_Hist' - LocalVarOutStrings(123) = 'TRA_LastRefSpd' - LocalVarOutStrings(124) = 'VS_RefSpeed' - LocalVarOutStrings(125) = 'PtfmTDX' - LocalVarOutStrings(126) = 'PtfmTDY' - LocalVarOutStrings(127) = 'PtfmTDZ' - LocalVarOutStrings(128) = 'PtfmRDX' - LocalVarOutStrings(129) = 'PtfmRDY' - LocalVarOutStrings(130) = 'PtfmRDZ' - LocalVarOutStrings(131) = 'PtfmTVX' - LocalVarOutStrings(132) = 'PtfmTVY' - LocalVarOutStrings(133) = 'PtfmTVZ' - LocalVarOutStrings(134) = 'PtfmRVX' - LocalVarOutStrings(135) = 'PtfmRVY' - LocalVarOutStrings(136) = 'PtfmRVZ' - LocalVarOutStrings(137) = 'PtfmTAX' - LocalVarOutStrings(138) = 'PtfmTAY' - LocalVarOutStrings(139) = 'PtfmTAZ' - LocalVarOutStrings(140) = 'PtfmRAX' - LocalVarOutStrings(141) = 'PtfmRAY' - LocalVarOutStrings(142) = 'PtfmRAZ' - LocalVarOutStrings(143) = 'CC_DesiredL' - LocalVarOutStrings(144) = 'CC_ActuatedL' - LocalVarOutStrings(145) = 'CC_ActuatedDL' - LocalVarOutStrings(146) = 'StC_Input' - LocalVarOutStrings(147) = 'Flp_Angle' - LocalVarOutStrings(148) = 'RootMyb_Last' - LocalVarOutStrings(149) = 'ACC_INFILE_SIZE' - LocalVarOutStrings(150) = 'AWC_complexangle' - LocalVarOutStrings(151) = 'TiltMean' - LocalVarOutStrings(152) = 'YawMean' - LocalVarOutStrings(153) = 'ZMQ_ID' - LocalVarOutStrings(154) = 'ZMQ_YawOffset' - LocalVarOutStrings(155) = 'ZMQ_TorqueOffset' - LocalVarOutStrings(156) = 'ZMQ_PitOffset' - LocalVarOutStrings(157) = 'ZMQ_R_Speed' - LocalVarOutStrings(158) = 'ZMQ_R_Torque' - LocalVarOutStrings(159) = 'ZMQ_R_Pitch' + LocalVarOutStrings(82) = 'Alpha_ConstPower' + LocalVarOutStrings(83) = 'Kp_Float' + LocalVarOutStrings(84) = 'Kp_FloatTq' + LocalVarOutStrings(85) = 'VS_MaxTq' + LocalVarOutStrings(86) = 'VS_LastGenTrq' + LocalVarOutStrings(87) = 'VS_LastGenPwr' + LocalVarOutStrings(88) = 'VS_MechGenPwr' + LocalVarOutStrings(89) = 'VS_SpdErrAr' + LocalVarOutStrings(90) = 'VS_SpdErrBr' + LocalVarOutStrings(91) = 'VS_SpdErr' + LocalVarOutStrings(92) = 'VS_State' + LocalVarOutStrings(93) = 'VS_Rgn3Pitch' + LocalVarOutStrings(94) = 'WE_Vw' + LocalVarOutStrings(95) = 'WE_Vw_F' + LocalVarOutStrings(96) = 'WE_VwI' + LocalVarOutStrings(97) = 'WE_VwIdot' + LocalVarOutStrings(98) = 'WE_Op' + LocalVarOutStrings(99) = 'WE_Op_Last' + LocalVarOutStrings(100) = 'VS_LastGenTrqF' + LocalVarOutStrings(101) = 'PRC_WSE_F' + LocalVarOutStrings(102) = 'PRC_R_Speed' + LocalVarOutStrings(103) = 'PRC_R_Torque' + LocalVarOutStrings(104) = 'PRC_R_Pitch' + LocalVarOutStrings(105) = 'PRC_R_Total' + LocalVarOutStrings(106) = 'PRC_Min_Pitch' + LocalVarOutStrings(107) = 'PS_Min_Pitch' + LocalVarOutStrings(108) = 'OL_Index' + LocalVarOutStrings(109) = 'SU_Stage' + LocalVarOutStrings(110) = 'SU_LoadStageStartTime' + LocalVarOutStrings(111) = 'SU_RotSpeedF' + LocalVarOutStrings(112) = 'SD_Trigger' + LocalVarOutStrings(113) = 'SD_BlPitchF' + LocalVarOutStrings(114) = 'SD_NacVaneF' + LocalVarOutStrings(115) = 'SD_GenSpeedF' + LocalVarOutStrings(116) = 'SD_Stage' + LocalVarOutStrings(117) = 'SD_StageStartTime' + LocalVarOutStrings(118) = 'SD_MaxPitchRate' + LocalVarOutStrings(119) = 'SD_MaxTorqueRate' + LocalVarOutStrings(120) = 'GenTq_SD' + LocalVarOutStrings(121) = 'Fl_PitCom' + LocalVarOutStrings(122) = 'Fl_TqCom' + LocalVarOutStrings(123) = 'NACIMU_FA_AccF' + LocalVarOutStrings(124) = 'FA_AccF' + LocalVarOutStrings(125) = 'NACIMU_FA_AccFTq' + LocalVarOutStrings(126) = 'FA_AccFTq' + LocalVarOutStrings(127) = 'FA_Hist' + LocalVarOutStrings(128) = 'TRA_LastRefSpd' + LocalVarOutStrings(129) = 'VS_RefSpeed' + LocalVarOutStrings(130) = 'PtfmTDX' + LocalVarOutStrings(131) = 'PtfmTDY' + LocalVarOutStrings(132) = 'PtfmTDZ' + LocalVarOutStrings(133) = 'PtfmRDX' + LocalVarOutStrings(134) = 'PtfmRDY' + LocalVarOutStrings(135) = 'PtfmRDZ' + LocalVarOutStrings(136) = 'PtfmTVX' + LocalVarOutStrings(137) = 'PtfmTVY' + LocalVarOutStrings(138) = 'PtfmTVZ' + LocalVarOutStrings(139) = 'PtfmRVX' + LocalVarOutStrings(140) = 'PtfmRVY' + LocalVarOutStrings(141) = 'PtfmRVZ' + LocalVarOutStrings(142) = 'PtfmTAX' + LocalVarOutStrings(143) = 'PtfmTAY' + LocalVarOutStrings(144) = 'PtfmTAZ' + LocalVarOutStrings(145) = 'PtfmRAX' + LocalVarOutStrings(146) = 'PtfmRAY' + LocalVarOutStrings(147) = 'PtfmRAZ' + LocalVarOutStrings(148) = 'CC_DesiredL' + LocalVarOutStrings(149) = 'CC_ActuatedL' + LocalVarOutStrings(150) = 'CC_ActuatedDL' + LocalVarOutStrings(151) = 'StC_Input' + LocalVarOutStrings(152) = 'Flp_Angle' + LocalVarOutStrings(153) = 'RootMyb_Last' + LocalVarOutStrings(154) = 'ACC_INFILE_SIZE' + LocalVarOutStrings(155) = 'AWC_complexangle' + LocalVarOutStrings(156) = 'TiltMean' + LocalVarOutStrings(157) = 'YawMean' + LocalVarOutStrings(158) = 'ZMQ_ID' + LocalVarOutStrings(159) = 'ZMQ_YawOffset' + LocalVarOutStrings(160) = 'ZMQ_TorqueOffset' + LocalVarOutStrings(161) = 'ZMQ_PitOffset' + LocalVarOutStrings(162) = 'ZMQ_R_Speed' + LocalVarOutStrings(163) = 'ZMQ_R_Torque' + LocalVarOutStrings(164) = 'ZMQ_R_Pitch' ! Initialize debug file IF ((LocalVar%iStatus == 0) .OR. (LocalVar%iStatus == -9)) THEN ! .TRUE. if we're on the first call to the DLL IF (CntrPar%LoggingLevel > 0) THEN @@ -1109,8 +1132,8 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av CALL GetNewUnit(UnDb2, ErrVar) OPEN(unit=UnDb2, FILE=TRIM(RootName)//'.RO.dbg2') WRITE(UnDb2, *) 'Generated on '//CurDate()//' at '//CurTime()//' using ROSCO-'//TRIM(rosco_version) - WRITE(UnDb2, '(160(a20,TR5:))') 'Time', LocalVarOutStrings - WRITE(UnDb2, '(160(a20,TR5:))') + WRITE(UnDb2, '(165(a20,TR5:))') 'Time', LocalVarOutStrings + WRITE(UnDb2, '(165(a20,TR5:))') END IF IF (CntrPar%LoggingLevel > 2) THEN @@ -1173,7 +1196,7 @@ SUBROUTINE Debug(LocalVar, CntrPar, DebugVar, ErrVar, avrSWAP, RootName, size_av END DO ! Write debug files - FmtDat = "(F20.5,TR5,159(ES20.5E2,TR5:))" ! The format of the debugging data + FmtDat = "(F20.5,TR5,164(ES20.5E2,TR5:))" ! The format of the debugging data IF ( MOD(LocalVar%n_DT, CntrPar%n_DT_Out) == 0) THEN IF((CntrPar%LoggingLevel > 0) .AND. (LocalVar%iStatus .ge. 0)) THEN WRITE (UnDb, TRIM(FmtDat)) LocalVar%Time, DebugOutData diff --git a/rosco/controller/src/ROSCO_Types.f90 b/rosco/controller/src/ROSCO_Types.f90 index 3407f602..0aeaef94 100644 --- a/rosco/controller/src/ROSCO_Types.f90 +++ b/rosco/controller/src/ROSCO_Types.f90 @@ -1,5 +1,5 @@ ! ROSCO Registry -! This file is automatically generated by write_registry.py using ROSCO v2.10.1 +! This file is automatically generated by write_registry.py using ROSCO v2.11.0 ! For any modification to the registry, please edit the rosco_types.yaml accordingly MODULE ROSCO_Types @@ -7,7 +7,7 @@ MODULE ROSCO_Types USE Constants IMPLICIT NONE -Character(*), PARAMETER :: rosco_version = '2.10.1' ! ROSCO version +Character(*), PARAMETER :: rosco_version = '2.11.0' ! ROSCO version TYPE, PUBLIC :: ControlParameters INTEGER(IntKi) :: ZMQ_ID ! 0000 - 9999, Identifier of the rosco, used for zeromq interface only @@ -30,7 +30,8 @@ MODULE ROSCO_Types REAL(DbKi), DIMENSION(:), ALLOCATABLE :: F_NotchBetaDen ! Notch Filter Numerator damping (determines depth?) REAL(DbKi) :: F_SSCornerFreq ! Corner frequency (-3dB point) in the first order low pass filter for the setpoint smoother [rad/s] REAL(DbKi) :: F_WECornerFreq ! Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s] - REAL(DbKi), DIMENSION(:), ALLOCATABLE :: F_FlCornerFreq ! Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s]. + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: F_FlCornerFreq ! Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for blade pitch floating feedback control [rad/s]. + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: F_FlTqCornerFreq ! Corner frequency (-3dB point) in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s]. REAL(DbKi) :: F_FlHighPassFreq ! Natural frequency of first-roder high-pass filter for nacelle fore-aft motion [rad/s]. REAL(DbKi) :: F_YawErr ! Corner low pass filter corner frequency for yaw controller [rad/s]. REAL(DbKi), DIMENSION(:), ALLOCATABLE :: F_FlpCornerFreq ! Corner frequency (-3dB point) in the second order low pass filter of the blade root bending moment for flap control [rad/s]. @@ -46,7 +47,7 @@ MODULE ROSCO_Types INTEGER(IntKi) :: IPC_ControlMode ! Turn Individual Pitch Control (IPC) for fatigue load reductions (pitch contribution) {0 - off, 1 - 1P reductions, 2 - 1P+2P reductions} REAL(DbKi), DIMENSION(:), ALLOCATABLE :: IPC_Vramp ! Wind speeds for IPC cut-in sigma function [m/s] REAL(DbKi) :: IPC_IntSat ! Integrator saturation (maximum signal amplitude contrbution to pitch from IPC) - INTEGER(IntKi) :: IPC_SatMode ! IPC Saturation method IPC Saturation method (0 - no saturation (except by PC_MinPit), 1 - saturate by PS_BldPitchMin, 2 - saturate sotfly (full IPC cycle) by PC_MinPit, 3 - saturate softly by PS_BldPitchMin) + INTEGER(IntKi) :: IPC_SatMode ! IPC Saturation method IPC Saturation method (0 - no saturation (except by PC_MinPit), 1 - saturate by PS_BldPitchMin, 2 - saturate softly (full IPC cycle) by PC_MinPit, 3 - saturate softly by PS_BldPitchMin) REAL(DbKi), DIMENSION(:), ALLOCATABLE :: IPC_KP ! Integral gain for the individual pitch controller, [-]. REAL(DbKi), DIMENSION(:), ALLOCATABLE :: IPC_KI ! Integral gain for the individual pitch controller, [-]. REAL(DbKi), DIMENSION(:), ALLOCATABLE :: IPC_aziOffset ! Phase offset added to the azimuth angle for the individual pitch controller, [rad]. @@ -86,6 +87,9 @@ MODULE ROSCO_Types REAL(DbKi), DIMENSION(:), ALLOCATABLE :: VS_FBP_U ! Operating schedule for fixed blade pitch control - Wind speed REAL(DbKi), DIMENSION(:), ALLOCATABLE :: VS_FBP_Omega ! Operating schedule for fixed blade pitch control - Generator speed REAL(DbKi), DIMENSION(:), ALLOCATABLE :: VS_FBP_Tau ! Operating schedule for fixed blade pitch control - Generator torque + INTEGER(IntKi) :: VS_ConstPower_n ! Number of VS_ConstPower_alpha for gain scheduling + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: VS_ConstPower_alpha ! Detuning parameter for the constant power feedback loop + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: VS_ConstPower_U ! Wind speeds for scheduling VS_ConstPower_alpha [m/s] INTEGER(IntKi) :: SS_Mode ! Setpoint Smoother mode {0 - no setpoint smoothing, 1 - introduce setpoint smoothing} REAL(DbKi) :: SS_VSGain ! Variable speed torque controller setpoint smoother gain, [-]. REAL(DbKi) :: SS_PCGain ! Collective pitch controller setpoint smoother gain, [-]. @@ -154,9 +158,11 @@ MODULE ROSCO_Types REAL(DbKi), DIMENSION(:), ALLOCATABLE :: SD_StagePitch ! Array containing the pitch angle to reach in each shutdown stage [rad] REAL(DbKi), DIMENSION(:), ALLOCATABLE :: SD_StageTime ! Array containing the time to spend in each shutdown stage [s] INTEGER(IntKi) :: SD_Stage_N ! Number of shutdown stages (should equal number of values in SD_MaxPitchRate and SD_MaxTorqueRate) [-] - INTEGER(IntKi) :: Fl_Mode ! Floating specific feedback mode {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} + INTEGER(IntKi) :: Fl_Mode ! Floating specific feedback mode for blade pitch {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} + INTEGER(IntKi) :: FlTq_Mode ! Floating specific feedback mode for generator torque {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback} INTEGER(IntKi) :: Fl_n ! Number of Fl_Kp for gain scheduling - REAL(DbKi), DIMENSION(:), ALLOCATABLE :: Fl_Kp ! Nacelle velocity proportional feedback gain [s] + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: Fl_Kp ! Nacelle velocity proportional feedback gain to blade pitch [s] + REAL(DbKi), DIMENSION(:), ALLOCATABLE :: FlTq_Kp ! Nacelle velocity proportional feedback gain to generator torque [s] REAL(DbKi), DIMENSION(:), ALLOCATABLE :: Fl_U ! Wind speeds for scheduling Fl_Kp [m/s] INTEGER(IntKi) :: Flp_Mode ! Flap actuator mode {0 - off, 1 - fixed flap position, 2 - PI flap control} REAL(DbKi) :: Flp_Angle ! Fixed flap angle (degrees) @@ -353,7 +359,7 @@ MODULE ROSCO_Types REAL(DbKi) :: GenArTq ! Electrical generator torque, for above-rated PI-control [Nm]. REAL(DbKi) :: GenBrTq ! Electrical generator torque, for below-rated PI-control [Nm]. REAL(DbKi) :: VS_KOmega2_GenTq ! Calculation of torque signal used by K*Omega^2 controller - REAL(DbKi) :: VS_ConstPwr_GenTq ! Calculation of constant-power torque signal + REAL(DbKi) :: VS_ConstPwr_GenTq ! Calculation of generator torque signal used by the constant power mode REAL(DbKi) :: IPC_PitComF(3) ! Commanded pitch of each blade as calculated by the individual pitch controller, F stands for low-pass filtered [rad]. REAL(DbKi) :: PC_KP ! Proportional gain for pitch controller at rated pitch (zero) [s]. REAL(DbKi) :: PC_KI ! Integral gain for pitch controller at rated pitch (zero) [-]. @@ -386,7 +392,9 @@ MODULE ROSCO_Types REAL(DbKi) :: PitComAct(3) ! Actuated pitch command of each blade [rad]. REAL(DbKi) :: SS_DelOmegaF ! Filtered setpoint shifting term defined in setpoint smoother [rad/s]. REAL(DbKi) :: TestType ! Test variable, no use + REAL(DbKi) :: Alpha_ConstPower ! Local instantaneous constant power gain scheduled on wind speed REAL(DbKi) :: Kp_Float ! Local, instantaneous Kp_Float, scheduled on wind speed, if desired + REAL(DbKi) :: Kp_FloatTq ! Local, instantaneous Kp_FloatTq, scheduled on wind speed, if desired REAL(DbKi) :: VS_MaxTq ! Maximum allowable generator torque [Nm]. REAL(DbKi) :: VS_LastGenTrq ! Commanded electrical generator torque the last time the controller was called [Nm]. REAL(DbKi) :: VS_LastGenPwr ! Commanded electrical generator torque the last time the controller was called [Nm]. @@ -423,9 +431,12 @@ MODULE ROSCO_Types REAL(DbKi) :: SD_MaxPitchRate ! Maximum pitch rate during current shutdown stage [rad/s] REAL(DbKi) :: SD_MaxTorqueRate ! Maximum torque rate during current shutdown stage [Nm/s] REAL(DbKi) :: GenTq_SD ! Electrical generator torque command for shutdown, [Nm]. - REAL(DbKi) :: Fl_PitCom ! Shutdown, .FALSE. if inactive, .TRUE. if active + REAL(DbKi) :: Fl_PitCom ! Floating feedback signal from nacelle fore-aft velocity to blade pitch + REAL(DbKi) :: Fl_TqCom ! Floating feedback signal from nacelle fore-aft velocity to generator torque REAL(DbKi) :: NACIMU_FA_AccF ! None REAL(DbKi) :: FA_AccF ! Filtered fore-aft acceleration in rotation frame, ready for control + REAL(DbKi) :: NACIMU_FA_AccFTq ! None + REAL(DbKi) :: FA_AccFTq ! None INTEGER(IntKi) :: FA_Hist ! Hysteresis state for tower resonance avoidance. REAL(DbKi) :: TRA_LastRefSpd ! Last reference generator speed REAL(DbKi) :: VS_RefSpeed ! Torque controller reference speed @@ -505,9 +516,12 @@ MODULE ROSCO_Types REAL(DbKi) :: PC_PICommand ! Commanded collective pitch from pitch PI controller [rad] REAL(DbKi) :: GenSpeedF ! Filtered generator speed [rad/s] REAL(DbKi) :: RotSpeedF ! Filtered rotor speed [rad/s] - REAL(DbKi) :: NacIMU_FA_AccF ! Filtered NacIMU_FA_RAcc [rad/s] - REAL(DbKi) :: FA_AccF ! Filtered FA_Acc [m/s] + REAL(DbKi) :: NacIMU_FA_AccF ! Filtered NacIMU_FA_RAcc for blade pitch FF [rad/s] + REAL(DbKi) :: FA_AccF ! Filtered FA_Acc for blade pitch FF [m/s] + REAL(DbKi) :: NacIMU_FA_AccFTq ! Filtered NacIMU_FA_Acc for generator torque FF [rad/s] + REAL(DbKi) :: FA_AccFTq ! Filtered FA_Acc for generator torque FF [m/s] REAL(DbKi) :: Fl_PitCom ! Floating contribution to the pitch command [rad] + REAL(DbKi) :: Fl_TqCom ! Floating contribution to the generator torque command [Nm] REAL(DbKi) :: PC_MinPit ! Minimum blade pitch angle [rad] REAL(DbKi) :: axisTilt_1P ! Tilt component of coleman transformation, 1P REAL(DbKi) :: axisYaw_1P ! Yaw component of coleman transformation, 1P diff --git a/rosco/controller/src/ReadSetParameters.f90 b/rosco/controller/src/ReadSetParameters.f90 index 4977696c..e1a2cdda 100644 --- a/rosco/controller/src/ReadSetParameters.f90 +++ b/rosco/controller/src/ReadSetParameters.f90 @@ -392,7 +392,8 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s CALL ParseInput(FileLines,'PS_Mode', CntrPar%PS_Mode, accINFILE(1), ErrVar, UnEc=UnEc) CALL ParseInput(FileLines,'SU_Mode', CntrPar%SU_Mode, accINFILE(1), ErrVar, UnEc=UnEc) CALL ParseInput(FileLines,'SD_Mode', CntrPar%SD_Mode, accINFILE(1), ErrVar, UnEc=UnEc) - CALL ParseInput(FileLines,'FL_Mode', CntrPar%FL_Mode, accINFILE(1), ErrVar, UnEc=UnEc) + CALL ParseInput(FileLines,'Fl_Mode', CntrPar%Fl_Mode, accINFILE(1), ErrVar, UnEc=UnEc) + CALL ParseInput(FileLines,'FlTq_Mode', CntrPar%FlTq_Mode, accINFILE(1), ErrVar, UnEc=UnEc) CALL ParseInput(FileLines,'TD_Mode', CntrPar%TD_Mode, accINFILE(1), ErrVar, UnEc=UnEc) CALL ParseInput(FileLines,'TRA_Mode', CntrPar%TRA_Mode, accINFILE(1), ErrVar, UnEc=UnEc) CALL ParseInput(FileLines,'Flp_Mode', CntrPar%Flp_Mode, accINFILE(1), ErrVar, UnEc=UnEc) @@ -418,8 +419,9 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s CALL ParseInput(FileLines, 'F_SSCornerFreq', CntrPar%F_SSCornerFreq, accINFILE(1), ErrVar, CntrPar%SS_Mode == 0, UnEc) CALL ParseInput(FileLines, 'F_WECornerFreq', CntrPar%F_WECornerFreq, accINFILE(1), ErrVar, .FALSE., UnEc) CALL ParseInput(FileLines, 'F_YawErr', CntrPar%F_YawErr, accINFILE(1), ErrVar, CntrPar%Y_ControlMode == 0, UnEc) - CALL ParseAry( FileLines, 'F_FlCornerFreq', CntrPar%F_FlCornerFreq, 2, accINFILE(1), ErrVar, CntrPar%FL_Mode == 0, UnEc) - CALL ParseInput(FileLines, 'F_FlHighPassFreq', CntrPar%F_FlHighPassFreq, accINFILE(1), ErrVar, CntrPar%FL_Mode == 0, UnEc) + CALL ParseAry( FileLines, 'F_FlCornerFreq', CntrPar%F_FlCornerFreq, 2, accINFILE(1), ErrVar, CntrPar%Fl_Mode == 0, UnEc) + CALL ParseAry( FileLines, 'F_FlTqCornerFreq', CntrPar%F_FlTqCornerFreq, 2, accINFILE(1), ErrVar, CntrPar%FlTq_Mode == 0, UnEc) + CALL ParseInput(FileLines, 'F_FlHighPassFreq', CntrPar%F_FlHighPassFreq, accINFILE(1), ErrVar, CntrPar%Fl_Mode == 0 .AND. CntrPar%FlTq_Mode == 0, UnEc) CALL ParseAry( FileLines, 'F_FlpCornerFreq', CntrPar%F_FlpCornerFreq, 2, accINFILE(1), ErrVar, CntrPar%Flp_Mode == 0, UnEc) CALL ParseInput(FileLines, 'F_VSRefSpdCornerFreq', CntrPar%F_VSRefSpdCornerFreq, accINFILE(1), ErrVar, CntrPar%VS_ControlMode < 2, UnEc) @@ -474,6 +476,14 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s CALL ParseAry( FileLines, 'VS_KP', CntrPar%VS_KP, CntrPar%VS_n, accINFILE(1), ErrVar, .FALSE., UnEc) CALL ParseAry( FileLines, 'VS_KI', CntrPar%VS_KI, CntrPar%VS_n, accINFILE(1), ErrVar, .FALSE., UnEc) CALL ParseInput(FileLines, 'VS_TSRopt', CntrPar%VS_TSRopt, accINFILE(1), ErrVar, CntrPar%VS_ControlMode < 2, UnEc) + CALL ParseInput(FileLines, 'VS_ConstPower_n', CntrPar%VS_ConstPower_n, accINFILE(1), ErrVar, .TRUE., UnEc) + IF (CntrPar%VS_ConstPower_n == 0) CntrPar%VS_ConstPower_n = 1 ! Default is 1 + CALL ParseAry(FileLines, 'VS_ConstPower_alpha', CntrPar%VS_ConstPower_alpha, CntrPar%VS_ConstPower_n, accINFILE(1), ErrVar, .TRUE., UnEc) + IF (SUM(ABS(CntrPar%VS_ConstPower_alpha)) == 0) THEN + PRINT *, 'ROSCO Warning: Setting VS_ConstPower_alpha to default of 1.0 for all entries.' + CntrPar%VS_ConstPower_alpha = 1.0 + ENDIF + CALL ParseAry(FileLines, 'VS_ConstPower_U', CntrPar%VS_ConstPower_U, CntrPar%VS_ConstPower_n, accINFILE(1), ErrVar, CntrPar%VS_ConstPower_n == 1, UnEc) ! Allow default if only one parameter IF (ErrVar%aviFAIL < 0) RETURN !------------ Fixed-Pitch Region 3 Control ------------ @@ -578,6 +588,7 @@ SUBROUTINE ReadControlParameterFileSub(CntrPar, LocalVar, accINFILE, accINFILE_s CALL ParseInput(FileLines, 'Fl_n', CntrPar%Fl_n, accINFILE(1), ErrVar, .TRUE., UnEc) IF (CntrPar%Fl_n == 0) CntrPar%Fl_n = 1 ! Default is 1 CALL ParseAry(FileLines, 'Fl_Kp', CntrPar%Fl_Kp, CntrPar%Fl_n, accINFILE(1), ErrVar, CntrPar%FL_Mode == 0, UnEc) + CALL ParseAry(FileLines, 'FlTq_Kp', CntrPar%FlTq_Kp, CntrPar%Fl_n, accINFILE(1), ErrVar, CntrPar%FLTq_Mode == 0, UnEc) CALL ParseAry(FileLines, 'Fl_U', CntrPar%Fl_U, CntrPar%Fl_n, accINFILE(1), ErrVar, CntrPar%Fl_n == 1, UnEc) ! Allow default if only one Fl_Kp IF (ErrVar%aviFAIL < 0) RETURN @@ -1095,6 +1106,12 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG) ErrVar%ErrMsg = 'Fl_Mode must be 0, 1, or 2.' ENDIF + ! FlTq_Mode + IF ((CntrPar%FlTq_Mode < 0) .OR. (CntrPar%FlTq_Mode > 2)) THEN + ErrVar%aviFAIL = -1 + ErrVar%ErrMsg = 'FlTq_Mode must be 0, 1, or 2.' + ENDIF + ! Flp_Mode IF ((CntrPar%Flp_Mode < 0) .OR. (CntrPar%Flp_Mode > 3)) THEN ErrVar%aviFAIL = -1 @@ -1149,6 +1166,14 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG) ErrVar%ErrMsg = 'F_WECornerFreq must be greater than zero.' ENDIF + IF ((CntrPar%Fl_Mode > 0) .OR. (CntrPar%FlTq_Mode > 0)) THEN + ! F_FlHighPassFreq + IF (CntrPar%F_FlHighPassFreq <= 0.0) THEN + ErrVar%aviFAIL = -1 + ErrVar%ErrMsg = 'F_FlHighPassFreq must be greater than zero.' + ENDIF + ENDIF + IF (CntrPar%Fl_Mode > 0) THEN ! F_FlCornerFreq(1) (frequency) IF (CntrPar%F_FlCornerFreq(1) <= 0.0) THEN @@ -1161,11 +1186,19 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG) ErrVar%aviFAIL = -1 ErrVar%ErrMsg = 'F_FlCornerFreq(2) must be greater than zero.' ENDIF + ENDIF + + IF (CntrPar%FlTq_Mode > 0) THEN + ! F_FlTqCornerFreq(1) (frequency) + IF (CntrPar%F_FlTqCornerFreq(1) <= 0.0) THEN + ErrVar%aviFAIL = -1 + ErrVar%ErrMsg = 'F_FlTqCornerFreq(1) must be greater than zero.' + ENDIF - ! F_FlHighPassFreq - IF (CntrPar%F_FlHighPassFreq <= 0.0) THEN + ! F_FlTqCornerFreq(2) (damping) + IF (CntrPar%F_FlTqCornerFreq(2) <= 0.0) THEN ErrVar%aviFAIL = -1 - ErrVar%ErrMsg = 'F_FlHighPassFreq must be greater than zero.' + ErrVar%ErrMsg = 'F_FlTqCornerFreq(2) must be greater than zero.' ENDIF ENDIF @@ -1307,7 +1340,12 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG) ErrVar%aviFAIL = -1 ErrVar%ErrMsg = 'VS_TSRopt must be greater than zero.' ENDIF - + + IF ((MINVAL(CntrPar%VS_ConstPower_alpha) < 0.0) .OR. (MAXVAL(CntrPar%VS_ConstPower_alpha) > 1.0)) THEN + ErrVar%aviFAIL = -1 + ErrVar%ErrMsg = 'VS_ConstPower_alpha must be between 0.0 and 1.0.' + ENDIF + !------- SETPOINT SMOOTHER --------------------------------------------- ! SS_VSGain diff --git a/rosco/test/ROSCO_testing.py b/rosco/test/ROSCO_testing.py index 019ddddc..404a5690 100644 --- a/rosco/test/ROSCO_testing.py +++ b/rosco/test/ROSCO_testing.py @@ -77,7 +77,7 @@ def __init__(self, **kwargs): 'Wind1VelX', 'Wind1VelY', 'Wind1VelZ', 'RtVAvgxh', 'RtVAvgyh', 'RtVAvgzh' ] - + if self.cores > mp.cpu_count(): self.parallel_cores = mp.cpu_count() @@ -574,7 +574,7 @@ def print_results(self,outfiles): # Additional inputs # ---- DT for this test! ---- case_inputs={} - case_inputs[('Fst', 'TMax')] = {'vals': [60], 'group': 0} + case_inputs[('Fst', 'TMax')] = {'vals': [420], 'group': 0} case_inputs[('Fst', 'DT')] = {'vals': [0.01], 'group': 0} case_inputs[('Fst', 'CompElast')] = {'vals': [1], 'group': 0} @@ -584,7 +584,7 @@ def print_results(self,outfiles): case_inputs[('DISCON_in', 'WE_Mode')] = {'vals': [2], 'group': 0} # Wind Speeds - U = [5] + U = [5, 15] # Run test rt.ROSCO_Test_lite(more_case_inputs=case_inputs, U=U) diff --git a/rosco/toolbox/controller.py b/rosco/toolbox/controller.py index 189221c4..925c7132 100644 --- a/rosco/toolbox/controller.py +++ b/rosco/toolbox/controller.py @@ -64,6 +64,7 @@ def __init__(self, controller_params): self.SU_Mode = controller_params['SU_Mode'] self.SD_Mode = controller_params['SD_Mode'] self.Fl_Mode = controller_params['Fl_Mode'] + self.FlTq_Mode = controller_params['FlTq_Mode'] self.TD_Mode = controller_params['TD_Mode'] self.TRA_Mode = controller_params['TRA_Mode'] self.Flp_Mode = controller_params['Flp_Mode'] @@ -92,6 +93,8 @@ def __init__(self, controller_params): self.ps_percent = controller_params['ps_percent'] self.WS_GS_n = controller_params['WS_GS_n'] self.PC_GS_n = controller_params['PC_GS_n'] + self.VS_ConstPower_alpha = controller_params['VS_ConstPower_alpha'] + self.VS_ConstPower_U = controller_params['VS_ConstPower_U'] self.flp_maxpit = controller_params['flp_maxpit'] self.Kp_ipc1p = controller_params['IPC_Kp1p'] self.Ki_ipc1p = controller_params['IPC_Ki1p'] @@ -126,7 +129,7 @@ def __init__(self, controller_params): raise Exception( 'rosco.toolbox:controller: flp_kp_norm and flp_tau must be set if Flp_Mode > 0') - if self.Fl_Mode > 0: + if self.Fl_Mode > 0 or self.FlTq_Mode > 0: if 'twr_freq' in controller_params and 'ptfm_freq' in controller_params: self.twr_freq = controller_params['twr_freq'] self.ptfm_freq = controller_params['ptfm_freq'] @@ -139,12 +142,20 @@ def __init__(self, controller_params): else: self.Kp_float = np.array([0]) + if 'Kp_floatTq' in controller_params: + self.Kp_floatTq = controller_params['Kp_floatTq'] + else: + self.Kp_floatTq = np.array([0]) + self.tune_Fl = controller_params['tune_Fl'] + self.tune_FlTq = controller_params['tune_FlTq'] else: self.twr_freq = 0 self.ptfm_freq = 0 + self.ptfm_inertia = 0 + # Use critical damping if LPFType = 2 if controller_params['F_LPFType'] == 2: @@ -409,12 +420,18 @@ def tune_controller(self, turbine): A = dtau_domega/J else: # Constant power above rated A = dtau_domega/J - A[-len(v_above_rated)+1:] += Ng**2/J * turbine.rated_power/(Ng**2*rated_rotor_speed**2) + # A[-len(v_above_rated)+1:] += Ng**2/J * turbine.rated_power/(Ng**2*rated_rotor_speed**2) + if self.interp_type == 'sigma': # sigma interpolation + alpha_cp = multi_sigma(v_above_rated[1:], self.VS_ConstPower_U, self.VS_ConstPower_alpha) + else: # standard scipy interpolation types + interp_alpha_cp = interpolate.interp1d(self.VS_ConstPower_U, self.VS_ConstPower_alpha, kind=self.interp_type, bounds_error=False, fill_value='extrapolate') + alpha_cp = interp_alpha_cp(v_above_rated[1:]) + A[-len(v_above_rated)+1:] += alpha_cp * Ng**2/J * turbine.rated_power/(Ng**2*rated_rotor_speed**2) B_tau = -Ng**2/J # Torque input B_beta = dtau_dbeta/J # Blade pitch input # Wind Disturbance Input - dtau_dv = (0.5 * rho * Ar * 1/rated_rotor_speed) * (dCp_dTSR*dlambda_dv*v**3 + Cp_op*3*v**2) + dtau_dv = (0.5 * rho * Ar * 1/(TSR_op*v/R)) * (dCp_dTSR*dlambda_dv*v**3 + Cp_op*3*v**2) B_wind = dtau_dv/J # wind speed input - currently unused @@ -474,8 +491,6 @@ def tune_controller(self, turbine): self.v = v # Wind speed (m/s) self.v_above_rated = v_above_rated self.v_below_rated = v_below_rated - # Mod by A. Wright - self.v_for_gs = v[-len(v_above_rated)+1:] # end self.pitch_op = pitch_op self.pitch_op_pc = pitch_op[-len(v_above_rated)+1:] @@ -525,6 +540,8 @@ def tune_controller(self, turbine): self.controller_params['DISCON']['PRC_Pitch_Table'] = pitch_R # --- Floating feedback term --- + self.U_Fl = np.array([0.0]) # Will be overwritten if either floating feedback mode is active + self.U_FlTq = np.array([0.0]) # Will be overwritten if either floating feedback mode is active if self.Fl_Mode >= 1: # Floating feedback @@ -533,33 +550,121 @@ def tune_controller(self, turbine): if self.U_Fl: # default is [], only have one Fl_Kp if type(self.U_Fl) == str: if self.U_Fl == 'all': - # Mod by A. Wright: get the array of Kp_float values at the values of v-above rated (see self.v_for_gs calculated around line 344). - self.U_Fl = self.v_for_gs + self.U_Fl = self.v_above_rated + + # Make Fl_alpha the same size if only one value given + if len(self.controller_params['Fl_alpha']) == 1: + self.controller_params['Fl_alpha'] = [self.controller_params['Fl_alpha'][0]] * len(self.U_Fl) else: raise Exception("Invalid entry in controller_params for U_Fl, please see schema") else: - self.U_Fl = np.array([turbine.v_rated * (1.05)]) - + self.U_Fl = np.array([turbine.v_rated * (1.05)]) # Default value is what is scheduled at v_rated + 5% # If we haven't set Kp_float as a control parameter, we tune it automatically here if self.tune_Fl: - Kp_float = (dtau_dv/dtau_dbeta) * Ng - if self.Fl_Mode == 2: - Kp_float *= turbine.TowerHt - f_kp = interpolate.interp1d(v,Kp_float) - self.Kp_float = f_kp(self.U_Fl) # get Kp at v_rated + 0.5 m/s + if self.tune_Fl == 1: # "Parallel" compensation tuning + self.Fl_alpha = self.controller_params['Fl_alpha'] + if len(self.Fl_alpha) != len(self.U_Fl): + raise Exception('The sizes of Fl_alpha and U_Fl are not equal, please check your controller_params') + + f_alpha_comp = interpolate.interp1d(self.U_Fl, self.Fl_alpha, fill_value=(self.Fl_alpha[0], self.Fl_alpha[-1]), bounds_error=False) + Kp_float = (dtau_dv/dtau_dbeta) * Ng + Kp_float *= f_alpha_comp(v) + + if self.Fl_Mode == 2: + Kp_float *= turbine.TowerHt # Multiply by tower height because we are compensating for torque from fore-aft rotation + + elif self.tune_Fl == 2: + self.Fl_Dzeta = self.controller_params['Fl_Dzeta'] + if len(self.Fl_Dzeta) != len(self.U_Fl): + raise Exception('The sizes of Fl_Dzeta and U_Fl are not equal, please check your controller_params') + + try: + self.ptfm_inertia = self.controller_params['ptfm_inertia'] + # if self.Fl_Mode == 1: + # self.ptfm_inertia = self.controller_params['ptfm_inertia'] + # elif self.Fl_Mode == 2: + # self.ptfm_inertia = self.controller_params['ptfm_mass'] + except: + try: + if self.Fl_Mode == 1: + self.ptfm_inertia = turbine.ED_mass + elif self.Fl_Mode == 2: + self.ptfm_inertia = turbine.ED_pitch_inertia + + if self.ptfm_inertia == 0.0: + raise Exception('rosco.toolbox:controller: ptfm_inertia found to be zero, either set nonzero value in toolbox input or check ElastoDyn') + except: + raise Exception('rosco.toolbox:controller: ptfm_inertia must be set if Fl_Mode > 0 and tune_Fl == 2') + f_Dzeta = interpolate.interp1d(self.U_Fl, self.Fl_Dzeta, fill_value=(self.Fl_Dzeta[0], self.Fl_Dzeta[-1]), bounds_error=False) + Kp_float = (2 * self.ptfm_freq * self.ptfm_inertia / Pi_beta) * f_Dzeta(v) + + if self.Fl_Mode == 2: + Kp_float /= turbine.TowerHt # Divide by tower length because we are adding thrust moment + + f_kp = interpolate.interp1d(v, Kp_float, bounds_error=False, fill_value=(Kp_float[0], Kp_float[-1])) + self.Kp_float = f_kp(self.U_Fl) # get Kp at scheduled wind speeds # Make arrays if not if not np.shape(self.Kp_float): self.Kp_float = np.array([self.Kp_float]) if not np.shape(self.U_Fl): self.U_Fl = np.array([self.U_Fl]) - + # Check size of Kp_float and U_Fl if len(self.Kp_float) != len(self.U_Fl): raise Exception('The sizes of Kp_float and U_Fl are not equal, please check your controller_params') + # Turn on the notch filter if floating and not already on + if not self.F_NotchType: + self.F_NotchType = 2 + + # And check for .yaml input inconsistencies + if self.twr_freq == 0.0 or self.ptfm_freq == 0.0: + print('WARNING: twr_freq and ptfm_freq should be defined for floating turbine control!!') + + else: + self.Kp_float = np.array([0.0]) + + if self.FlTq_Mode >= 1: # Generator torque floating feedback + + # Wind speed gain scheduling + self.U_FlTq = self.controller_params['U_FlTq'] + if self.U_FlTq: # default is [], only have one Fl_Kp + if type(self.U_FlTq) == str: + if self.U_FlTq == 'all': + self.U_FlTq = self.v_above_rated + # Make FlTq_alpha the same size if only one value given + if len(self.controller_params['FlTq_alpha']) == 1: + self.controller_params['FlTq_alpha'] = [self.controller_params['FlTq_alpha'][0]] * len(self.U_Fl) + else: + raise Exception("Invalid entry in controller_params for U_FlTq, please see schema") + else: + self.U_FlTq = np.array([turbine.v_rated * (1.05)]) + + self.FlTq_alpha = self.controller_params['FlTq_alpha'] + if len(self.FlTq_alpha) != len(self.U_FlTq): + raise Exception('The sizes of FlTq_alpha and U_FlTq are not equal, please check your controller_params') + + # If we haven't set Kp_floatTq as a control parameter, we tune it automatically here + if self.tune_FlTq: + f_alpha_comp = interpolate.interp1d(self.U_FlTq, self.FlTq_alpha, fill_value=(self.FlTq_alpha[0], self.FlTq_alpha[-1]), bounds_error=False) + Kp_floatTq = dtau_dv # * Ng / Ng + Kp_floatTq *= f_alpha_comp(v) + if self.FlTq_Mode == 2: + Kp_floatTq *= turbine.TowerHt + f_kp = interpolate.interp1d(v,Kp_floatTq) + self.Kp_floatTq = f_kp(self.U_FlTq) + + # Make arrays if not + if not np.shape(self.Kp_floatTq): + self.Kp_floatTq = np.array([self.Kp_floatTq]) + if not np.shape(self.U_FlTq): + self.U_FlTq = np.array([self.U_FlTq]) + # Check size of Kp_floatTq and U_FlTq + if len(self.Kp_floatTq) != len(self.U_FlTq): + raise Exception('The sizes of Kp_floatTq and U_FlTq are not equal, please check your controller_params') # Turn on the notch filter if floating and not already on if not self.F_NotchType: @@ -570,8 +675,20 @@ def tune_controller(self, turbine): print('WARNING: twr_freq and ptfm_freq should be defined for floating turbine control!!') else: - self.Kp_float = np.array([0.0]) - self.U_Fl = np.array([0.0]) + self.Kp_floatTq = np.array([0.0]) + + # Ensure lengths are correct, if not then repeat the last value until they are + if len(self.Kp_float) < len(self.U_Fl): + self.Kp_float = np.append(self.Kp_float, np.repeat(self.Kp_float[-1], len(self.U_Fl) - len(self.Kp_float))) + if len(self.Kp_floatTq) < len(self.U_FlTq): + self.Kp_floatTq = np.append(self.Kp_floatTq, np.repeat(self.Kp_floatTq[-1], len(self.U_FlTq) - len(self.Kp_floatTq))) + + + # # If using both blade pitch and generator torque for parallel compensation, then share the load equally + # # DBS: In future work, have tuning options to allow the user to choose how to manage this exchange + # if self.Fl_Mode > 0 and self.FlTq_Mode > 0: + # self.Kp_float = self.Kp_float / 2.0 + # self.KpTq_float = self.KpTq_float / 2.0 # Flap actuation if self.Flp_Mode >= 1: diff --git a/rosco/toolbox/inputs/toolbox_schema.yaml b/rosco/toolbox/inputs/toolbox_schema.yaml index c52b5a70..aea18107 100644 --- a/rosco/toolbox/inputs/toolbox_schema.yaml +++ b/rosco/toolbox/inputs/toolbox_schema.yaml @@ -202,7 +202,13 @@ properties: minimum: 0 maximum: 2 default: 0 - description: Floating specific feedback mode (0- no nacelle velocity feedback, 1 - nacelle velocity feedback, 2 - nacelle pitching acceleration feedback) + description: Floating specific feedback mode to blade pitch (0- no nacelle velocity feedback, 1 - nacelle velocity feedback, 2 - nacelle pitching acceleration feedback) + FlTq_Mode: + type: number + minimum: 0 + maximum: 2 + default: 0 + description: Floating specific feedback mode to generator torque (0- no nacelle velocity feedback, 1 - nacelle velocity feedback, 2 - nacelle pitching acceleration feedback) Flp_Mode: type: number minimum: 0 @@ -355,6 +361,11 @@ properties: description: Platform natural frequency, for floating only unit: rad/s minimum: 0 + ptfm_inertia: + type: number + description: Platform inertia (if Fl_Mode == 2) or mass (if Fl_Mode == 1), for floating only + unit: rad/s + minimum: 0 WS_GS_n: type: number description: Number of wind speed breakpoints @@ -367,40 +378,81 @@ properties: default: 30 Kp_float: type: [number, array] - description: Gain(s) of floating feedback control + description: Gain(s) of blade pitch floating feedback control + unit: s + items: + type: number + Kp_floatTq: + type: [number, array] + description: Gain(s) of generator floating feedback control unit: s items: type: number tune_Fl: - type: boolean - description: Whether to automatically tune Kp_float - default: True + type: number + description: Configuration to automatically tune Kp_float (0 - Disable auto-tuning, 1 - Auto-tune based on "parallel" compensation, 2 - Auto-tune based on platform pitch damping) + minimum: 0 + maximum: 2 + default: 1 + tune_FlTq: + type: number + description: Configuration to automatically tune Kp_floatTq (0 - Disable auto-tuning, 1 - Auto-tune based on parallel compensation) + minimum: 0 + maximum: 1 + default: 1 U_Fl: type: [array, string, number] description: List of wind speeds for tuning floating feedback, or "all" for all above-rated wind speeds - default: [] + default: [12] items: type: number - zeta_flp: + U_FlTq: + type: [array,number] + description: List of wind speeds for tuning torque floating feedback + default: [12] + items: + type: number + Fl_alpha: + type: [array,number] + description: List of scale parameters for detuning blade pitch floating feedback, when acting as a compensator (alpha_beta in https://onlinelibrary.wiley.com/doi/10.1002/we.2864) + unit: none + items: + type: number + default: [1.0] + Fl_Dzeta: + type: [array,number] + description: List of parameters for tuning blade pitch platform damper (Delta zeta in https://doi.org/10.23919/ACC55779.2023.10156143) + unit: none + items: + type: number + default: [0.2] + FlTq_alpha: + type: [array,number] + description: List of scale parameters for detuning generator torque floating feedback (alpha_tau in https://onlinelibrary.wiley.com/doi/10.1002/we.2864, or alpha_comp in https://doi.org/10.23919/ACC55779.2023.10156143) + unit: none + items: + type: number + default: [0.5] + zeta_flp: type: number minimum: 0 description: Flap controller desired damping ratio [-] unit: none - omega_flp: + omega_flp: type: number minimum: 0 description: Flap controller desired natural frequency [rad/s] unit: rad/s - flp_kp_norm: + flp_kp_norm: type: number minimum: 0 description: Flap controller normalization term for DC gain (kappa) - flp_tau: + flp_tau: type: number minimum: 0 description: Flap controller time constant for integral gain unit: s - max_torque_factor: + max_torque_factor: type: number minimum: 0 default: 1.1 @@ -440,6 +492,21 @@ properties: description: Factor on VS_Rgn2K to increase/decrease optimal torque control gain, default is 1. Sometimes environmental conditions or differences in BEM solvers necessitate this change. default: 1 minimum: 0 + VS_ConstPower_U: + type: [array,number] + description: List of wind speeds for tuning torque constant power feedback + default: [12] + items: + type: number + VS_ConstPower_alpha: + type: [array,number] + description: List of scale parameters for detuning constant power torque control, only used when VS_ConstPower = 1, defaults to fully tuned (1.0) + unit: none + items: + type: number + minimum: 0.0 + maximum: 1.0 + default: [1.0] VS_FBP_power_mode: type: number description: Interpretation mode for VS_FBP_P (0- scale relative to rated power, 1- absolute power) @@ -683,7 +750,10 @@ properties: description: Shutdown mode (0- no shutdown procedure, 1- enable shutdown) Fl_Mode: type: number - description: Floating specific feedback mode (0- no nacelle velocity feedback, 1- feed back translational velocity, 2- feed back rotational veloicty) + description: Floating specific feedback mode to blade pitch (0- no nacelle velocity feedback, 1- feed back translational velocity, 2- feed back rotational veloicty) + FlTq_Mode: + type: number + description: Floating specific feedback mode to generator torque (0- no nacelle velocity feedback, 1- feed back translational velocity, 2- feed back rotational veloicty) Flp_Mode: type: number description: Flap control mode (0- no flap control, 1- steady state flap angle, 2- Proportional flap control) @@ -746,6 +816,12 @@ properties: type: number description: Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control units: rad/s + F_FlTqCornerFreq: + type: array + items: + type: number + description: Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control + units: rad/s F_FlHighPassFreq: type: number description: Natural frequency of first-order high-pass filter for nacelle fore-aft motion @@ -1227,7 +1303,13 @@ properties: units: s Fl_Kp: type: array - description: Nacelle velocity proportional feedback gain + description: Nacelle velocity proportional feedback gain to blade pitch + units: s + items: + type: number + FlTq_Kp: + type: array + description: Nacelle velocity proportional feedback gain to generator torque units: s items: type: number diff --git a/rosco/toolbox/turbine.py b/rosco/toolbox/turbine.py index d2a7ea5c..ff51b8c9 100644 --- a/rosco/toolbox/turbine.py +++ b/rosco/toolbox/turbine.py @@ -236,6 +236,11 @@ def load_from_fast( self.rated_torque = self.rated_power/(self.GenEff/100*self.rated_rotor_speed*self.Ng) self.rotor_radius = self.TipRad + # Platform parameters + self.ED_mass = fast.fst_vt['ElastoDyn']['HubMass'] + fast.fst_vt['ElastoDyn']['NacMass'] + fast.fst_vt['ElastoDyn']['YawBrMass'] + fast.fst_vt['ElastoDyn']['PtfmMass'] + # DBS: Add tip-brake mass components? + self.ED_pitch_inertia = fast.fst_vt['ElastoDyn']['PtfmPIner'] + # Load blade information self.load_blade_info() diff --git a/rosco/toolbox/utilities.py b/rosco/toolbox/utilities.py index 65c77e90..75bc76bc 100644 --- a/rosco/toolbox/utilities.py +++ b/rosco/toolbox/utilities.py @@ -110,6 +110,7 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C file.write('{0:<12d} ! SU_Mode - Startup mode (0: no startup procedure, 1: startup enabled)\n'.format(int(rosco_vt['SU_Mode']))) file.write('{0:<12d} ! SD_Mode - Shutdown mode (0: no shutdown procedure, 1: shutdown enabled)\n'.format(int(rosco_vt['SD_Mode']))) file.write('{0:<12d} ! Fl_Mode - Floating specific feedback mode (0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational velocity)\n'.format(int(rosco_vt['Fl_Mode']))) + file.write('{0:<12d} ! FlTq_Mode - Floating specific feedback mode to generator torque {{0: no nacelle velocity feedback, 1: feed back translational velocity, 2: feed back rotational veloicty}}\n'.format(int(rosco_vt['FlTq_Mode']))) file.write('{:<12d} ! TD_Mode - {}\n'.format(int(rosco_vt['TD_Mode']),mode_descriptions['TD_Mode'])) file.write('{:<12d} ! TRA_Mode - {}\n'.format(int(rosco_vt['TRA_Mode']),mode_descriptions['TRA_Mode'])) file.write('{0:<12d} ! Flp_Mode - Flap control mode (0: no flap control, 1: steady state flap angle, 2: Proportional flap control, 2: Cyclic (1P) flap control)\n'.format(int(rosco_vt['Flp_Mode']))) @@ -138,6 +139,7 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C file.write('{:<13.5f} ! F_WECornerFreq - Corner frequency (-3dB point) in the first order low pass filter for the wind speed estimate [rad/s].\n'.format(rosco_vt['F_WECornerFreq'])) file.write('{:<13.5f} ! F_YawErr - Low pass filter corner frequency for yaw controller [rad/s].\n'.format(rosco_vt['F_YawErr'])) file.write('{} ! F_FlCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for floating feedback control [rad/s, -].\n'.format(write_array(rosco_vt['F_FlCornerFreq'],'<8.4f'))) + file.write('{} ! F_FlTqCornerFreq - Natural frequency and damping in the second order low pass filter of the tower-top fore-aft motion for generator torque floating feedback control [rad/s, -].\n'.format(write_array(rosco_vt['F_FlTqCornerFreq'],'<8.4f'))) file.write('{:<13.5f} ! F_FlHighPassFreq - Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s].\n'.format(rosco_vt['F_FlHighPassFreq'])) file.write('{} ! F_FlpCornerFreq - {}\n'.format(write_array(rosco_vt["F_FlpCornerFreq"], '<7.4f'), input_descriptions["F_FlpCornerFreq"])) file.write('{:<13.5f} ! F_VSRefSpdCornerFreq - {}\n'.format(float(rosco_vt['F_VSRefSpdCornerFreq']),input_descriptions['F_VSRefSpdCornerFreq'])) @@ -182,6 +184,9 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C file.write('{:<14.5e} ! VS_KP - Proportional gain for generator PI torque controller [-]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2)\n'.format(rosco_vt['VS_KP'])) file.write('{:<14.5e} ! VS_KI - Integral gain for generator PI torque controller [s]. (Only used in the transitional 2.5 region if VS_ControlMode =/ 2)\n'.format(rosco_vt['VS_KI'])) file.write('{:<14.5f} ! VS_TSRopt - {}\n'.format(float(rosco_vt['VS_TSRopt']),input_descriptions['VS_TSRopt'])) + file.write('{:<11d} ! VS_ConstPower_n - Number of VS_ConstPower_alpha gains in gain scheduling, optional with default of 1\n'.format(int(rosco_vt['VS_ConstPower_n']))) + file.write('{} ! VS_ConstPower_alpha - Detuning parameter for the constant power feedback loop [-]. (Only used if VS_ConstPower = 1)\n'.format(write_array(rosco_vt['VS_ConstPower_alpha'],'<12.4f'))) + file.write('{} ! VS_ConstPower_U - Wind speeds for scheduling VS_ConstPower_alpha, optional if VS_ConstPower_alpha is single value [m/s]\n'.format(write_array(rosco_vt['VS_ConstPower_U'],'<12.4f'))) file.write('\n') file.write('!------- FIXED PITCH REGION 3 TORQUE CONTROL ------------------------------------------------\n') file.write('{:<11d} ! VS_FBP_n - Number of gain-scheduling table entries\n'.format(int(rosco_vt['VS_FBP_n']))) @@ -278,7 +283,8 @@ def write_DISCON(turbine, controller, param_file='DISCON.IN', txt_filename='Cp_C else: floatstr = 'velocity' file.write('{:<11d} ! Fl_n - Number of Fl_Kp gains in gain scheduling, optional with default of 1\n'.format(int(rosco_vt['Fl_n']))) - file.write('{} ! Fl_Kp - Nacelle {} proportional feedback gain [s]\n'.format(write_array(rosco_vt['Fl_Kp'],'<6.4f'), floatstr)) + file.write('{} ! Fl_Kp - Nacelle {} proportional feedback gain to blade pitch [s]\n'.format(write_array(rosco_vt['Fl_Kp'],'<6.4f'), floatstr)) + file.write('{} ! FlTq_Kp - Nacelle {} proportional feedback gain to generator torque [s]\n'.format(write_array(rosco_vt['FlTq_Kp'],'<6.4f'), floatstr)) file.write('{} ! Fl_U - Wind speeds for scheduling Fl_Kp, optional if Fl_Kp is single value [m/s]\n'.format(write_array(rosco_vt['Fl_U'],'<6.4f'))) file.write('\n') file.write('!------- FLAP ACTUATION -----------------------------------------------------\n') @@ -532,6 +538,7 @@ def DISCON_dict(turbine, controller, txt_filename=None): DISCON_dict['SU_Mode'] = int(controller.SU_Mode) DISCON_dict['SD_Mode'] = int(controller.SD_Mode) DISCON_dict['Fl_Mode'] = int(controller.Fl_Mode) + DISCON_dict['FlTq_Mode'] = int(controller.FlTq_Mode) DISCON_dict['TD_Mode'] = int(controller.TD_Mode) DISCON_dict['TRA_Mode'] = int(controller.TRA_Mode) DISCON_dict['Flp_Mode'] = int(controller.Flp_Mode) @@ -542,9 +549,9 @@ def DISCON_dict(turbine, controller, txt_filename=None): DISCON_dict['Ext_Mode'] = int(controller.Ext_Mode) DISCON_dict['ZMQ_Mode'] = int(controller.ZMQ_Mode) DISCON_dict['CC_Mode'] = int(controller.CC_Mode) - DISCON_dict['StC_Mode'] = int(controller.StC_Mode) + DISCON_dict['StC_Mode'] = int(controller.StC_Mode) # ------- FILTERS ------- - DISCON_dict['F_LPFCornerFreq'] = turbine.bld_edgewise_freq * 1/4 + DISCON_dict['F_LPFCornerFreq'] = turbine.bld_edgewise_freq * 0.25 DISCON_dict['F_LPFDamping'] = controller.F_LPFDamping DISCON_dict['F_NumNotchFilts'] = len(controller.f_notch_freqs) DISCON_dict['F_NotchFreqs'] = controller.f_notch_freqs if controller.f_notch_freqs else [0.0] @@ -554,16 +561,16 @@ def DISCON_dict(turbine, controller, txt_filename=None): DISCON_dict['F_GenSpdNotch_Ind'] = controller.f_notch_gen_inds if controller.f_notch_gen_inds else [0] DISCON_dict['F_TwrTopNotch_N'] = len(controller.f_notch_twr_inds) DISCON_dict['F_TwrTopNotch_Ind'] = controller.f_notch_twr_inds if controller.f_notch_twr_inds else [0] - DISCON_dict['F_WECornerFreq'] = controller.f_we_cornerfreq - DISCON_dict['F_SSCornerFreq'] = controller.f_ss_cornerfreq - DISCON_dict['F_FlHighPassFreq'] = controller.f_fl_highpassfreq - DISCON_dict['F_FlCornerFreq'] = [controller.ptfm_freq, 1.0] - DISCON_dict['F_FlpCornerFreq'] = [turbine.bld_flapwise_freq*3, 1.0] + DISCON_dict['F_WECornerFreq'] = controller.f_we_cornerfreq + DISCON_dict['F_SSCornerFreq'] = controller.f_ss_cornerfreq + DISCON_dict['F_FlHighPassFreq'] = controller.f_fl_highpassfreq + DISCON_dict['F_FlpCornerFreq'] = [turbine.bld_flapwise_freq*3, 1.0] DISCON_dict['F_WECornerFreq'] = controller.f_we_cornerfreq DISCON_dict['F_SSCornerFreq'] = controller.f_ss_cornerfreq DISCON_dict['F_YawErr'] = controller.f_yawerr DISCON_dict['F_FlHighPassFreq'] = controller.f_fl_highpassfreq DISCON_dict['F_FlCornerFreq'] = [controller.ptfm_freq, 1.0] + DISCON_dict['F_FlTqCornerFreq'] = [controller.ptfm_freq*3, 1.0] DISCON_dict['F_VSRefSpdCornerFreq'] = controller.f_vs_refspd_cornerfreq # ------- BLADE PITCH CONTROL ------- DISCON_dict['PC_GS_n'] = len(controller.pitch_op_pc) @@ -604,6 +611,9 @@ def DISCON_dict(turbine, controller, txt_filename=None): DISCON_dict['VS_KP'] = controller.vs_gain_schedule.Kp[-1] DISCON_dict['VS_KI'] = controller.vs_gain_schedule.Ki[-1] DISCON_dict['VS_TSRopt'] = turbine.TSR_operational + DISCON_dict['VS_ConstPower_n'] = len(controller.VS_ConstPower_alpha) + DISCON_dict['VS_ConstPower_alpha'] = controller.VS_ConstPower_alpha + DISCON_dict['VS_ConstPower_U'] = controller.VS_ConstPower_U # ------- FIXED BLADE PITCH TORQUE CONTROL ------- DISCON_dict['VS_FBP_n'] = len(controller.v) DISCON_dict['VS_FBP_U'] = controller.v @@ -667,6 +677,7 @@ def DISCON_dict(turbine, controller, txt_filename=None): # ------- Floating ------- DISCON_dict['Fl_n'] = len(controller.Kp_float) DISCON_dict['Fl_Kp'] = controller.Kp_float + DISCON_dict['FlTq_Kp'] = controller.Kp_floatTq DISCON_dict['Fl_U'] = controller.U_Fl # ------- FLAP ACTUATION ------- DISCON_dict['Flp_Angle'] = controller.flp_angle