def get_initial_constraints(options, initial_variables, ref_variables, model, xi_dict): cstr_list = ocp_constraint.OcpConstraintList() # list all initial equalities ==> put SX expressions in dict if 'e' in list(model.variables_dict['xd'].keys()): init_energy_eq = make_initial_energy_equality(initial_variables, ref_variables) init_energy_cstr = cstr_op.Constraint(expr=init_energy_eq, name='initial_energy', cstr_type='eq') cstr_list.append(init_energy_cstr) _, initial_conditions, param_initial_conditions, _, _, _ = get_operation_conditions(options) if param_initial_conditions: init_param_eq = make_param_initial_conditions(initial_variables, ref_variables, xi_dict, model, options) init_param_cstr = cstr_op.Constraint(expr=init_param_eq, name='param_initial_conditions', cstr_type='eq') cstr_list.append(init_param_cstr) if initial_conditions: init_eq = make_initial_conditions(initial_variables, ref_variables, xi_dict, model, options) init_cstr = cstr_op.Constraint(expr=init_eq, name='initial_conditions', cstr_type='eq') cstr_list.append(init_cstr) return cstr_list
def generate_rotational_dynamics(variables, f_nodes, parameters, outputs, architecture): kite_nodes = architecture.kite_nodes parent_map = architecture.parent_map j_inertia = parameters['theta0', 'geometry', 'j'] xd = variables['SI']['xd'] xddot = variables['SI']['xddot'] cstr_list = mdl_constraint.MdlConstraintList() for kite in kite_nodes: parent = parent_map[kite] moment = f_nodes['m' + str(kite) + str(parent)] rlocal = cas.reshape(xd['r' + str(kite) + str(parent)], (3, 3)) drlocal = cas.reshape(xddot['dr' + str(kite) + str(parent)], (3, 3)) omega = xd['omega' + str(kite) + str(parent)] omega_skew = vect_op.skew(omega) domega = xddot['domega' + str(kite) + str(parent)] tether_moment = outputs['tether_moments']['n{}{}'.format(kite, parent)] # moment = J dot(omega) + omega x (J omega) + [tether moment which is zero if holonomic constraints do not depend on omega] J_dot_omega = cas.mtimes(j_inertia, domega) omega_cross_J_omega = vect_op.cross(omega, cas.mtimes(j_inertia, omega)) omega_derivative = moment - (J_dot_omega + omega_cross_J_omega + tether_moment) rotational_2nd_law = omega_derivative / vect_op.norm( cas.diag(j_inertia)) rotation_dynamics_cstr = cstr_op.Constraint(expr=rotational_2nd_law, name='rotation_dynamics' + str(kite), cstr_type='eq') cstr_list.append(rotation_dynamics_cstr) # Rdot = R omega_skew -> R ( kappa/2 (I - R.T R) + omega_skew ) baumgarte = parameters['theta0', 'kappa_r'] orthonormality = baumgarte / 2. * (cas.DM_eye(3) - cas.mtimes(rlocal.T, rlocal)) ref_frame_deriv_matrix = drlocal - (cas.mtimes( rlocal, orthonormality + omega_skew)) ref_frame_derivative = cas.reshape(ref_frame_deriv_matrix, (9, 1)) ortho_cstr = cstr_op.Constraint(expr=ref_frame_derivative, name='ref_frame_deriv' + str(kite), cstr_type='eq') cstr_list.append(ortho_cstr) return cstr_list, outputs
def get_force_cstr(options, variables, atmos, wind, architecture, parameters): cstr_list = mdl_constraint.MdlConstraintList() for kite in architecture.kite_nodes: parent = architecture.parent_map[kite] kite_dcm = get_kite_dcm(options, variables, wind, kite, architecture) vec_u = tools.get_local_air_velocity_in_earth_frame(options, variables, atmos, wind, kite, kite_dcm, architecture, parameters) force_found_frame = 'earth' force_found_vector = get_force_from_u_sym_in_earth_frame(vec_u, options, variables, kite, atmos, wind, architecture, parameters) forces_dict = tools.get_framed_forces(vec_u, kite_dcm, variables, kite, architecture) force_framed_variable = forces_dict[force_found_frame] f_scale = tools.get_f_scale(parameters, options) resi_f_kite = (force_framed_variable - force_found_vector) / f_scale f_kite_cstr = cstr_op.Constraint(expr=resi_f_kite, name='f_aero' + str(kite) + str(parent), cstr_type='eq') cstr_list.append(f_kite_cstr) return cstr_list
def get_terminal_constraints(options, terminal_variables, ref_variables, model, xi_dict): cstr_list = ocp_constraint.OcpConstraintList() _, _, _, param_terminal_conditions, terminal_inequalities, integral_constraints = get_operation_conditions(options) if param_terminal_conditions: terminal_param_eq = make_param_terminal_conditions(terminal_variables, ref_variables, xi_dict, model, options) terminal_param_cstr = cstr_op.Constraint(expr=terminal_param_eq, name='param_terminal_conditions', cstr_type='eq') cstr_list.append(terminal_param_cstr) if terminal_inequalities: terminal_ineq = make_terminal_position_inequality(terminal_variables, model, options) terminal_ineq_cstr = cstr_op.Constraint(expr=terminal_ineq, name='terminal_inequalities', cstr_type='ineq') cstr_list.append(terminal_ineq_cstr) return cstr_list
def get_periodic_constraints(options, initial_model_variables, terminal_model_variables): cstr_list = ocp_constraint.OcpConstraintList() periodic, _, _, _, _, _ = get_operation_conditions(options) # list all periodic equalities ==> put SX expressions in dict if periodic: periodic_eq = make_periodicity_equality(initial_model_variables, terminal_model_variables, options) cstr = cstr_op.Constraint(expr=periodic_eq, name='state_periodicity', cstr_type='eq') cstr_list.append(cstr) return cstr_list
def get_continuity_constraint(self, ms_xf, V, kdx): """Append multiple shooting continuity constraint to list of constraints @param g_list current list of constraints @param g_bounds corresponding list of constraint bounds @param ms_xf integrator output @param V nlp decision variables @param kdx interval index """ # add continuity equation to nlp g_continuity = V['xd', kdx + 1] - ms_xf[:, kdx] cont_cstr = cstr_op.Constraint(expr=g_continuity, name='ms_continuity_' + str(kdx), cstr_type='eq') return cont_cstr
def get_continuity_constraint(self, V, kdx): # get an expression for the state at the end of the finite element xf_k = 0 for ddx in range(self.__d + 1): if ddx == 0: xf_k += self.__coeff_continuity[ddx] * V['xd', kdx] else: xf_k += self.__coeff_continuity[ddx] * V['coll_var', kdx, ddx - 1, 'xd'] # pin the end of the control interval to the start of the new control interval g_continuity = V['xd', kdx + 1] - xf_k cstr = cstr_op.Constraint(expr=g_continuity, name='continuity' + str(kdx), cstr_type='eq') return cstr
def p_el_sign(options, variables_si, outputs, parameters, architecture): n_k = options['aero']['vortex']['n_k'] d = options['aero']['vortex']['d'] sign = variables_si['u']['sign'] vortex_wake_nodes = options['induction']['vortex_wake_nodes'] cstr_list = cstr_op.ConstraintList() rings = vortex_wake_nodes - 1 for ring in range(rings): wake_node = ring for ndx in range(n_k): for ddx in range(d): local_name = 'p_el_sign_' + str(ring) + '_' + str( ndx) + '_' + str(ddx) ndx_shed = n_k - 1 - wake_node ddx_shed = d - 1 already_shed = False if (ndx > ndx_shed): already_shed = True elif ((ndx == ndx_shed) and (ddx == ddx_shed)): already_shed = True if already_shed: sign_eq = sign - 1. else: sign_eq = sign + 1 print(sign_eq) sign_eq = cstr_op.Constraint(expr=sign_eq, name=local_name, cstr_type='eq') cstr_list.append(sign_eq) return cstr_list
def get_dynamics(options, atmos, wind, architecture, system_variables, system_gc, parameters, outputs): parent_map = architecture.parent_map number_of_nodes = architecture.number_of_nodes # generalized coordinates, velocities and accelerations generalized_coordinates = {} generalized_coordinates['scaled'] = generate_generalized_coordinates( system_variables['scaled'], system_gc) generalized_coordinates['SI'] = generate_generalized_coordinates( system_variables['SI'], system_gc) # ------------------------------- # mass distribution in the system # ------------------------------- node_masses_si, outputs = mass_comp.generate_m_nodes( options, system_variables['SI'], outputs, parameters, architecture) # -------------------------------- # lagrangian # -------------------------------- outputs = energy_comp.energy_outputs(options, parameters, outputs, node_masses_si, system_variables['SI'], architecture) e_kinetic = sum(outputs['e_kinetic'][nodes] for nodes in list(outputs['e_kinetic'].keys())) e_potential = sum(outputs['e_potential'][nodes] for nodes in list(outputs['e_potential'].keys())) holonomic_constraints, outputs, g, gdot, gddot = holonomic_comp.generate_holonomic_constraints( architecture, outputs, system_variables, parameters, options) # lagrangian function lag = e_kinetic - e_potential - holonomic_constraints # -------------------------------- # generalized forces in the system # -------------------------------- f_nodes, outputs = forces_comp.generate_f_nodes(options, atmos, wind, system_variables['SI'], parameters, outputs, architecture) outputs = forces_comp.generate_tether_moments(options, system_variables['SI'], system_variables['scaled'], holonomic_constraints, outputs, architecture) cstr_list = mdl_constraint.MdlConstraintList() # -------------------------------- # translational dynamics # -------------------------------- # lhs of lagrange equations dlagr_dqdot = cas.jacobian( lag, generalized_coordinates['scaled']['xgcdot'].cat).T dlagr_dqdot_dt = tools.time_derivative(dlagr_dqdot, system_variables, architecture) dlagr_dq = cas.jacobian(lag, generalized_coordinates['scaled']['xgc'].cat).T lagrangian_lhs_translation = dlagr_dqdot_dt - dlagr_dq lagrangian_lhs_constraints = holonomic_comp.get_constraint_lhs( g, gdot, gddot, parameters) # lagrangian momentum correction if options['tether']['use_wound_tether']: lagrangian_momentum_correction = 0. else: lagrangian_momentum_correction = momentum_correction( options, generalized_coordinates, system_variables, node_masses_si, outputs, architecture) # rhs of lagrange equations lagrangian_rhs_translation = cas.vertcat( *[f_nodes['f' + str(n) + str(parent_map[n])] for n in range(1, number_of_nodes)]) + \ lagrangian_momentum_correction lagrangian_rhs_constraints = np.zeros(g.shape) # scaling holonomic_scaling = holonomic_comp.generate_holonomic_scaling( options, architecture, system_variables['SI'], parameters) node_masses_scaling = mass_comp.generate_m_nodes_scaling( options, system_variables['SI'], outputs, parameters, architecture) forces_scaling = node_masses_scaling * options['scaling']['other'][ 'g'] * options['model_bounds']['acceleration']['acc_max'] dynamics_translation = (lagrangian_lhs_translation - lagrangian_rhs_translation) / forces_scaling dynamics_translation_cstr = cstr_op.Constraint(expr=dynamics_translation, cstr_type='eq', name='dynamics_translation') cstr_list.append(dynamics_translation_cstr) dynamics_constraints = (lagrangian_lhs_constraints - lagrangian_rhs_constraints) / holonomic_scaling dynamics_constraint_cstr = cstr_op.Constraint(expr=dynamics_constraints, cstr_type='eq', name='dynamics_constraint') cstr_list.append(dynamics_constraint_cstr) # -------------------------------- # rotational dynamics # -------------------------------- kite_has_6dof = (int(options['kite_dof']) == 6) if kite_has_6dof: rotation_dynamics_cstr, outputs = generate_rotational_dynamics( system_variables, f_nodes, parameters, outputs, architecture) cstr_list.append(rotation_dynamics_cstr) # -------------------------------- # trivial kinematics # -------------------------------- for name in system_variables['SI']['xddot'].keys(): name_in_xd = name in system_variables['SI']['xd'].keys() name_in_u = name in system_variables['SI']['u'].keys() if name_in_xd: trivial_dyn = cas.vertcat(*[ system_variables['scaled']['xddot', name] - system_variables['scaled']['xd', name] ]) elif name_in_u: trivial_dyn = cas.vertcat(*[ system_variables['scaled']['xddot', name] - system_variables['scaled']['u', name] ]) if name_in_xd or name_in_u: trivial_dyn_cstr = cstr_op.Constraint(expr=trivial_dyn, cstr_type='eq', name='trivial_' + name) cstr_list.append(trivial_dyn_cstr) return cstr_list, outputs
def get_tether_cstr(options, variables_si, architecture, parameters, outputs): # homotopy parameters p_dec = parameters.prefix['phi'] # initialize dictionary tether_drag_forces = {} for node in range(1, architecture.number_of_nodes): parent = architecture.parent_map[node] tether_drag_forces['f' + str(node) + str(parent)] = cas.SX.zeros( (3, 1)) for node in range(1, architecture.number_of_nodes): parent = architecture.parent_map[node] multi_upper = outputs['tether_aero']['multi_upper' + str(node)] multi_lower = outputs['tether_aero']['multi_lower' + str(node)] single_upper = outputs['tether_aero']['single_upper' + str(node)] single_lower = outputs['tether_aero']['single_lower' + str(node)] split_upper = outputs['tether_aero']['split_upper' + str(node)] split_lower = outputs['tether_aero']['split_lower' + str(node)] kite_only_upper = outputs['tether_aero']['kite_only_upper' + str(node)] kite_only_lower = outputs['tether_aero']['kite_only_lower' + str(node)] tether_model = options['tether']['tether_drag']['model_type'] if tether_model == 'multi': drag_node = p_dec['tau'] * split_upper + ( 1. - p_dec['tau']) * multi_upper drag_parent = p_dec['tau'] * split_lower + ( 1. - p_dec['tau']) * multi_lower elif tether_model == 'single': drag_node = p_dec['tau'] * split_upper + ( 1. - p_dec['tau']) * single_upper drag_parent = p_dec['tau'] * split_lower + ( 1. - p_dec['tau']) * single_lower elif tether_model == 'split': drag_node = split_upper drag_parent = split_lower elif tether_model == 'kite_only': drag_node = kite_only_upper drag_parent = kite_only_lower elif tether_model == 'not_in_use': drag_parent = cas.DM.zeros((3, 1)) drag_node = cas.DM.zeros((3, 1)) else: raise ValueError('tether drag model not supported.') # attribute portion of segment drag to parent if node > 1: grandparent = architecture.parent_map[parent] tether_drag_forces['f' + str(parent) + str(grandparent)] += drag_parent # attribute portion of segment drag to node tether_drag_forces['f' + str(node) + str(parent)] += drag_node cstr_list = mdl_constraint.MdlConstraintList() for node in range(1, architecture.number_of_nodes): parent = architecture.parent_map[node] f_tether_var = get_force_var(variables_si, node, architecture) f_tether_val = tether_drag_forces['f' + str(node) + str(parent)] local_resi_unscaled = (f_tether_var - f_tether_val) scale = options['scaling']['xl']['f_tether'] local_resi = local_resi_unscaled / scale f_cstr = cstr_op.Constraint(expr=local_resi, name='f_tether' + str(node) + str(parent), cstr_type='eq') cstr_list.append(f_cstr) return cstr_list
def get_strength_constraint(options, V, Outputs, model): n_k = options['n_k'] d = options['collocation']['d'] comparison_labels = options['induction']['comparison_labels'] wake_nodes = options['induction']['vortex_wake_nodes'] rings = wake_nodes - 1 kite_nodes = model.architecture.kite_nodes strength_scale = tools.get_strength_scale(options) Xdot = struct_op.construct_Xdot_struct(options, model.variables_dict)(0.) cstr_list = cstr_op.ConstraintList() any_vor = any(label[:3] == 'vor' for label in comparison_labels) if any_vor: for kite in kite_nodes: for ring in range(rings): wake_node = ring for ndx in range(n_k): for ddx in range(d): local_name = 'vortex_strength_' + str(kite) + '_' + str(ring) + '_' + str(ndx) + '_' + str(ddx) variables = struct_op.get_variables_at_time(options, V, Xdot, model.variables, ndx, ddx) wg_local = tools.get_ring_strength(variables, kite, ring) ndx_shed = n_k - 1 - wake_node ddx_shed = d - 1 # working out: # n_k = 3 # if ndx = 0 and ddx = 0 -> shed: wn >= n_k # wn: 0 sheds at ndx = 2, ddx = -1 : unshed, period = 0 # wn: 1 sheds at ndx = 1, ddx = -1 : unshed, period = 0 # wn: 2 sheds at ndx = 0, ddx = -1 : unshed, period = 0 # wn: 3 sheds at ndx = -1, ddx = -1 : SHED period = 1 # wn: 4 sheds at ndx = -2, period = 1 # wn: 5 sheds at ndx = -3 period = 1 # wn: 6 sheds at ndx = -4 period = 2 # if ndx = 1 and ddx = 0 -> shed: wn >= n_k - ndx # wn: 0 sheds at ndx = 2, ddx = -1 : unshed, # wn: 1 sheds at ndx = 1, ddx = -1 : unshed, # wn: 2 sheds at ndx = 0, ddx = -1 : SHED, # wn: 3 sheds at ndx = -1, ddx = -1 : SHED # if ndx = 0 and ddx = -1 -> shed: # wn: 0 sheds at ndx = 2, ddx = -1 : unshed, # wn: 1 sheds at ndx = 1, ddx = -1 : unshed, # wn: 2 sheds at ndx = 0, ddx = -1 : SHED, # wn: 3 sheds at ndx = -1, ddx = -1 : SHED already_shed = False if (ndx > ndx_shed): already_shed = True elif ((ndx == ndx_shed) and (ddx == ddx_shed)): already_shed = True if already_shed: # working out: # n_k = 3 # period_0 -> wn 0, wn 1, wn 2 -> floor(ndx_shed / n_k) # period_1 -> wn 3, wn 4, wn 5 period_number = int(np.floor(float(ndx_shed)/float(n_k))) ndx_shed_w_periodicity = ndx_shed - period_number * n_k gamma_val = Outputs['coll_outputs', ndx_shed_w_periodicity, ddx_shed, 'aerodynamics', 'circulation' + str(kite)] wg_ref = 1. * gamma_val / strength_scale else: wg_ref = 0. local_resi = (wg_local - wg_ref) local_cstr = cstr_op.Constraint(expr = local_resi, name = local_name, cstr_type='eq') cstr_list.append(local_cstr) return cstr_list
def get_force_cstr(options, variables, atmos, wind, architecture, parameters): surface_control = options['surface_control'] f_scale = tools.get_f_scale(parameters, options) m_scale = tools.get_m_scale(parameters, options) cstr_list = mdl_constraint.MdlConstraintList() for kite in architecture.kite_nodes: parent = architecture.parent_map[kite] kite_dcm = cas.reshape(variables['xd']['r' + str(kite) + str(parent)], (3, 3)) vec_u_earth = tools.get_local_air_velocity_in_earth_frame( options, variables, atmos, wind, kite, kite_dcm, architecture, parameters) if int(surface_control) == 0: delta = variables['u']['delta' + str(kite) + str(parent)] elif int(surface_control) == 1: delta = variables['xd']['delta' + str(kite) + str(parent)] omega = variables['xd']['omega' + str(kite) + str(parent)] q = variables['xd']['q' + str(kite) + str(parent)] rho = atmos.get_density(q[2]) force_info, moment_info = get_force_and_moment(options, parameters, vec_u_earth, kite_dcm, omega, delta, rho) f_found_frame = force_info['frame'] f_found_vector = force_info['vector'] m_found_frame = moment_info['frame'] m_found_vector = moment_info['vector'] forces_dict = tools.get_framed_forces(vec_u_earth, kite_dcm, variables, kite, architecture) f_var_frame = tools.force_variable_frame() f_var = forces_dict[f_var_frame] f_val = frames.from_named_frame_to_named_frame(from_name=f_found_frame, to_name=f_var_frame, vec_u=vec_u_earth, kite_dcm=kite_dcm, vector=f_found_vector) moments_dict = tools.get_framed_moments(vec_u_earth, kite_dcm, variables, kite, architecture) m_var_frame = tools.moment_variable_frame() m_var = moments_dict[m_var_frame] m_val = frames.from_named_frame_to_named_frame(from_name=m_found_frame, to_name=m_var_frame, vec_u=vec_u_earth, kite_dcm=kite_dcm, vector=m_found_vector) resi_f_kite = (f_var - f_val) / f_scale resi_m_kite = (m_var - m_val) / m_scale f_kite_cstr = cstr_op.Constraint(expr=resi_f_kite, name='f_aero' + str(kite) + str(parent), cstr_type='eq') cstr_list.append(f_kite_cstr) m_kite_cstr = cstr_op.Constraint(expr=resi_m_kite, name='m_aero' + str(kite) + str(parent), cstr_type='eq') cstr_list.append(m_kite_cstr) return cstr_list
def get_fixing_constraint(options, V, Outputs, model): n_k = options['n_k'] comparison_labels = options['induction']['comparison_labels'] wake_nodes = options['induction']['vortex_wake_nodes'] kite_nodes = model.architecture.kite_nodes wingtips = ['ext', 'int'] Xdot = struct_op.construct_Xdot_struct(options, model.variables_dict)(0.) cstr_list = cstr_op.ConstraintList() any_vor = any(label[:3] == 'vor' for label in comparison_labels) if any_vor: for kite in kite_nodes: for tip in wingtips: for wake_node in range(wake_nodes): local_name = 'wake_fixing_' + str(kite) + '_' + str(tip) + '_' + str(wake_node) if wake_node < n_k: # working out: # n_k = 3 # wn:0, n_k-1=2 # wn:1, n_k-2=1 # wn:2=n_k-1, n_k-3=0 # ... switch to periodic fixing reverse_index = n_k - 1 - wake_node variables_at_shed = struct_op.get_variables_at_time(options, V, Xdot, model.variables, reverse_index, -1) wx_local = tools.get_wake_node_position_si(options, variables_at_shed, kite, tip, wake_node) wingtip_pos = Outputs[ 'coll_outputs', reverse_index, -1, 'aerodynamics', 'wingtip_' + tip + str(kite)] local_resi = wx_local - wingtip_pos local_cstr = cstr_op.Constraint(expr = local_resi, name = local_name, cstr_type='eq') cstr_list.append(local_cstr) else: # working out: # n_k = 3 # wn:0, n_k-1=2 # wn:1, n_k-2=1 # wn:2=n_k-1, n_k-3=0 # ... switch to periodic fixing # wn:3 at ndx = 0 must be equal to -> wn:0 at ndx = -1, ddx = -1 # wn:4 at ndx = 0 must be equal to -> wn:1 at ndx = -1, ddx = -1 variables_at_initial = struct_op.get_variables_at_time(options, V, Xdot, model.variables, 0) variables_at_final = struct_op.get_variables_at_time(options, V, Xdot, model.variables, -1, -1) upstream_node = wake_node - n_k wx_local = tools.get_wake_node_position_si(options, variables_at_initial, kite, tip, wake_node) wx_upstream = tools.get_wake_node_position_si(options, variables_at_final, kite, tip, upstream_node) local_resi = wx_local - wx_upstream local_cstr = cstr_op.Constraint(expr = local_resi, name = local_name, cstr_type='eq') cstr_list.append(local_cstr) return cstr_list
def get_winch_cstr(options, atmos, wind, variables_si, parameters, outputs, architecture): cstr_list = mdl_constraint.MdlConstraintList() t_em = cas.DM(0.) if options['generator']['type'] != None and options['generator'][ 'type'] != 'experimental': if not options['tether']['use_wound_tether']: raise ValueError( 'Invalid user_options: use_wound_tether = False, when you use a generator model with ODEs it have to be True' ) if options['ground_station']['in_lag_dyn']: raise ValueError( 'Invalid user_options: in_lag_dyn = True, when you use a generator model with ODEs it have to be False or when you dont want to use the default winch' ) t_em = t_em_ode(options, variables_si, outputs, parameters, architecture) if not options['ground_station']['in_lag_dyn']: radius_winch = parameters['theta0', 'ground_station', 'r_gen'] #not optinal j_gen = parameters['theta0', 'ground_station', 'j_gen'] j_winch = parameters['theta0', 'ground_station', 'j_winch'] f_winch = parameters['theta0', 'ground_station', 'f_winch'] l_t_full = variables_si['theta']['l_t_full'] phi = (l_t_full - variables_si['xd']['l_t']) / radius_winch omega = -variables_si['xd']['dl_t'] / radius_winch domega = -variables_si['xddot']['ddl_t'] / radius_winch t_tether = -variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_frict = -f_winch * omega t_inertia = j_winch * domega t_inertia += variables_si['theta'][ 'diam_t']**2 / 4 * np.pi * parameters['theta0', 'tether', 'rho'] * radius_winch**3 * ( omega * omega + domega * phi) # rhs = t_tether + t_em + t_frict lhs = t_inertia omega = variables_si['xd']['dl_t'] / radius_winch domega = variables_si['xddot']['ddl_t'] / radius_winch phi = (l_t_full - variables_si['xd']['l_t']) / radius_winch rhs = (j_gen + j_winch) * variables_si['xddot']['ddl_t'] / radius_winch rhs += variables_si['theta']['diam_t']**2 / 4 * np.pi * parameters[ 'theta0', 'tether', 'rho'] * radius_winch**3 * (-omega * omega + domega * phi) lhs = variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch - t_em if options['generator']['gear_train']['used']: j_gen = parameters['theta0', 'ground_station', 'j_gen'] j_winch = parameters['theta0', 'ground_station', 'j_winch'] #normaly rigid body f_gen = parameters['theta0', 'ground_station', 'f_gen'] k = variables_si['theta']['k_gear'] t_win = j_winch * variables_si['xddot'][ 'ddl_t'] / radius_winch + options['scaling']['theta'][ 'diam_t']**2 / 4 * np.pi * parameters[ 'theta0', 'tether', 'rho'] * radius_winch**3 * ( -omega * omega + domega * phi) # j_gen *= k**2 t_tether = -variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_gen = j_gen * variables_si['xddot']['ddl_t'] / radius_winch lhs = -t_gen - t_win rhs = t_tether + k * t_em #+ omega*(f_winch + f_gen*k**2) if options['generator']['gear_train']['used']: k = variables_si['theta']['k_gear'] # dk = variables_si['xddot']['dk_gear'] # dk_ineq = dk # dk_ineq_cstr = cstr_op.Constraint(expr=dk_ineq, name='dk_ineq', cstr_type='eq') # cstr_list.append(dk_ineq_cstr) # len_zstl = 0.1 delta_r = 0.05 rho_zstl = 2700 j_zstl = np.pi * len_zstl * rho_zstl * ( -3 * k * radius_winch**2 * delta_r**2 + 2 * k**2 * delta_r**3 * radius_winch + 2 * delta_r * radius_winch**3 - 1 / 2 * k**3 * delta_r**4) j_gen_zstl = k**3 * j_gen + j_zstl t_tether = variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_angular_momentum = (j_gen_zstl + k * j_winch) * domega t_angular_momentum_tether = k * variables_si['theta'][ 'diam_t']**2 / 4 * np.pi * parameters['theta0', 'tether', 'rho'] t_angular_momentum_tether *= radius_winch**3 * (-omega * omega + domega * phi) rhs = t_angular_momentum + t_angular_momentum_tether rhs += omega * (f_winch * k**3) lhs = t_tether * k - k**2 * t_em if options['generator']['type'] == 'pmsm': generator = generator_ode(options, variables_si, outputs, parameters, architecture) cstr_list.append(generator) # sign = variables_si['u']['sign'] # sign_eq = sign**2 - 4*sign + 3 # sign_ineq = -variables_si['u']['v_sq']/(sign) # sign_eq = cstr_op.Constraint(expr=sign_eq, name='sign_eq', cstr_type='eq') # cstr_list.append(sign_eq) # sign_ineq = cstr_op.Constraint(expr=sign_ineq, name='sign_ineq', cstr_type='ineq') # cstr_list.append(sign_ineq) #sign = p_el_sign(options, variables_si, outputs, parameters, architecture) #cstr_list.append(sign) torque = lhs - rhs print("torque") print(torque) winch_cstr = cstr_op.Constraint(expr=torque, name='winch', cstr_type='eq') cstr_list.append(winch_cstr) return cstr_list
def generator_ode(options, variables_si, outputs, parameters, architecture): cstr_list = mdl_constraint.MdlConstraintList() if options['generator']['type'] == 'pmsm': if options['generator']['dv_sd']: # v_sd = variables_si['u']['v_sd'] v_sd_ode = variables_si['xddot']['dv_sd'] - variables_si['u'][ 'dv_sd'] v_sd_ode = cstr_op.Constraint(expr=v_sd_ode, name='v_sd_ode', cstr_type='eq') cstr_list.append(v_sd_ode) v_sd = variables_si['xd']['v_sd'] i_sd = variables_si['xd']['i_sd'] di_sd = variables_si['xddot']['di_sd'] # v_sq = variables_si['u']['v_sq'] v_sq_ode = variables_si['xddot']['dv_sq'] - variables_si['u']['dv_sq'] v_sq_ode = cstr_op.Constraint(expr=v_sq_ode, name='v_sq_ode', cstr_type='eq') cstr_list.append(v_sq_ode) v_sq = variables_si['xd']['v_sq'] i_sq = variables_si['xd']['i_sq'] di_sq = variables_si['xddot']['di_sq'] ld = parameters['theta0', 'generator', 'l_d'] lq = parameters['theta0', 'generator', 'l_q'] rs = parameters['theta0', 'generator', 'r_s'] phi_f = parameters['theta0', 'generator', 'phi_f'] p_p = parameters['theta0', 'generator', 'p_p'] omega = -variables_si['xd']['dl_t'] / parameters['theta0', 'ground_station', 'r_gen'] i_sq_ode = -v_sq + rs * i_sq + phi_f * omega * p_p + lq * di_sq if options['generator']['dv_sd']: i_sq_ode += omega * p_p * i_sd * ld i_sd_ode = -v_sd + rs * i_sd - omega * p_p * i_sq * lq + ld * di_sd if options['generator']['gear_train']['used']: k = variables_si['theta']['k_gear'] r_gen = parameters['theta0', 'ground_station', 'r_gen'] omega = k * variables_si['xd']['dl_t'] / r_gen i_sq_ode = -v_sq + rs * i_sq - phi_f * omega * p_p + lq * di_sq if options['generator']['dv_sd']: i_sq_ode += -omega * p_p * i_sd * ld i_sd_ode = -v_sd + rs * i_sd + omega * p_p * i_sq * lq + ld * di_sd print("i_sq_ode") print(i_sq_ode) i_sq_cstr = cstr_op.Constraint(expr=i_sq_ode, name='gen1', cstr_type='eq') cstr_list.append(i_sq_cstr) if options['generator']['dv_sd']: print('i_sd_ode') print(i_sd_ode) i_sd_cstr = cstr_op.Constraint(expr=i_sd_ode, name='gen0', cstr_type='eq') cstr_list.append(i_sd_cstr) return cstr_list