def get_general_regularization_function(variables): weight_sym = cas.SX.sym('weight_sym', variables.cat.shape) var_sym = cas.SX.sym('var_sym', variables.cat.shape) ref_sym = cas.SX.sym('ref_sym', variables.cat.shape) diff = (var_sym - ref_sym) weight = cas.diag(weight_sym) diff_sq = cas.mtimes(cas.diag(diff), diff) reg = cas.mtimes(weight, diff_sq) reg_fun = cas.Function('reg_fun', [var_sym, ref_sym, weight_sym], [reg]) return reg_fun
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 var_scaled_to_si(var_type, var_name, var_scaled, scaling): scaling_defined_for_variable = (var_type in scaling.keys()) and ( var_name in scaling[var_type].keys()) if scaling_defined_for_variable: scale = scaling[var_type][var_name] if scale.shape == (1, 1): use_unit_scaling = (scale == cas.DM(1.)) or (scale == 1.) if use_unit_scaling: return var_scaled else: return var_scaled * scale else: matrix_factor = cas.diag(scale) return cas.mtimes(matrix_factor, var_scaled) else: return var_scaled
def get_force_and_moment(options, parameters, vec_u_earth, kite_dcm, omega, delta, rho): # we use the vec_u_earth and the kite_dcm to give the relative orientation. # this means, that they must be in the same frame. otherwise, the frame of # the wind vector is not used in this function. alpha = indicators.get_alpha(vec_u_earth, kite_dcm) beta = indicators.get_beta(vec_u_earth, kite_dcm) airspeed = vect_op.norm(vec_u_earth) force_coeff_info, moment_coeff_info = stability_derivatives.stability_derivatives( options, alpha, beta, airspeed, omega, delta, parameters) force_info = {} moment_info = {} force_info['frame'] = force_coeff_info['frame'] moment_info['frame'] = moment_coeff_info['frame'] CF = force_coeff_info['coeffs'] CM = moment_coeff_info['coeffs'] # notice that magnitudes don't change under rotation dynamic_pressure = 1. / 2. * rho * cas.mtimes(vec_u_earth.T, vec_u_earth) planform_area = parameters['theta0', 'geometry', 's_ref'] force = CF * dynamic_pressure * planform_area force_info['vector'] = force b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] reference_lengths = cas.diag(cas.vertcat(b_ref, c_ref, b_ref)) moment = dynamic_pressure * planform_area * cas.mtimes( reference_lengths, CM) moment_info['vector'] = moment return force_info, moment_info
def get_outputs(options, atmos, wind, variables, outputs, parameters, architecture): parent_map = architecture.parent_map kite_nodes = architecture.kite_nodes xd = variables['xd'] u = variables['u'] elevation_angle = indicators.get_elevation_angle(xd) for n in kite_nodes: parent = parent_map[n] # get relevant variables for kite n q = xd['q' + str(n) + str(parent)] dq = xd['dq' + str(n) + str(parent)] r = cas.reshape(xd['r' + str(n) + str(parent)], (3, 3)) ehat_span = r[:, 1] ehat_chord = r[:, 0] # wind parameters rho_infty = atmos.get_density(q[2]) uw_infty = wind.get_velocity(q[2]) # apparent air velocity if options['induction_model'] == 'actuator': ua = actuator_disk_flow.get_kite_effective_velocity( options, variables, wind, n, parent, architecture) else: ua = uw_infty - dq # relative air speed norm_ua_squared = cas.mtimes(ua.T, ua) ua_norm = norm_ua_squared**0.5 # angle of attack and sideslip angle alpha = indicators.get_alpha(ua, r) beta = indicators.get_beta(ua, r) if int(options['surface_control']) == 0: delta = u['delta' + str(n) + str(parent)] omega = xd['omega' + str(n) + str(parent)] [CF, CM] = stability_derivatives.stability_derivatives( options, alpha, beta, ua, omega, delta, parameters) elif int(options['surface_control']) == 1: delta = xd['delta' + str(n) + str(parent)] omega = xd['omega' + str(n) + str(parent)] [CF, CM] = stability_derivatives.stability_derivatives( options, alpha, beta, ua, omega, delta, parameters) else: raise ValueError('unsupported surface_control chosen: %i', options['surface_control']) # body-_frameforcecomponents # notice that these are unusual because an apparent wind reference coordinate system is in use. # see below (get_coeffs_from_control_surfaces) for information CA = CF[0] CY = CF[1] CN = CF[2] Cl = CM[0] Cm = CM[1] Cn = CM[2] dynamic_pressure = 1. / 2. * rho_infty * norm_ua_squared planform_area = parameters['theta0', 'geometry', 's_ref'] ftilde_aero = cas.mtimes(r, CF) f_aero = dynamic_pressure * planform_area * ftilde_aero ehat_drag = vect_op.normalize(ua) f_drag = cas.mtimes(cas.mtimes(f_aero.T, ehat_drag), ehat_drag) ehat_lift = vect_op.normed_cross(ua, ehat_span) f_lift = cas.mtimes(cas.mtimes(f_aero.T, ehat_lift), ehat_lift) f_side = f_aero - f_drag - f_lift drag_cross_lift = indicators.convert_from_body_to_wind_axes( alpha, beta, CF) CD = drag_cross_lift[0] CS = drag_cross_lift[1] CL = drag_cross_lift[2] b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] reference_lengths = cas.diag(cas.vertcat(b_ref, c_ref, b_ref)) m_aero = dynamic_pressure * planform_area * cas.mtimes( reference_lengths, CM) aero_coefficients = {} aero_coefficients['CD'] = CD aero_coefficients['CS'] = CS aero_coefficients['CL'] = CL aero_coefficients['CA'] = CA aero_coefficients['CN'] = CN aero_coefficients['CY'] = CY aero_coefficients['Cl'] = Cl aero_coefficients['Cm'] = Cm aero_coefficients['Cn'] = Cn outputs = indicators.collect_kite_aerodynamics_outputs( options, atmos, ua, ua_norm, aero_coefficients, f_aero, f_lift, f_drag, f_side, m_aero, ehat_chord, ehat_span, r, q, n, outputs, parameters) outputs = indicators.collect_environmental_outputs( atmos, wind, q, n, outputs) outputs = indicators.collect_aero_validity_outputs( options, xd, ua, n, parent, outputs, parameters) outputs = indicators.collect_local_performance_outputs( options, atmos, wind, variables, CL, CD, elevation_angle, ua, n, parent, outputs, parameters) outputs = indicators.collect_power_balance_outputs( variables, n, outputs, architecture) return outputs
def get_aerodynamic_outputs(options, atmos, wind, variables, outputs, parameters, architecture): xd = variables['xd'] b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] s_ref = parameters['theta0', 'geometry', 's_ref'] reference_lengths = cas.diag(cas.vertcat(b_ref, c_ref, b_ref)) kite_nodes = architecture.kite_nodes for kite in kite_nodes: parent = architecture.parent_map[kite] q = xd['q' + str(kite) + str(parent)] dq = xd['dq' + str(kite) + str(parent)] vec_u_eff = tools.get_u_eff_in_earth_frame(options, variables, wind, kite, architecture) u_eff = vect_op.smooth_norm(vec_u_eff) rho = atmos.get_density(q[2]) q_eff = 0.5 * rho * cas.mtimes(vec_u_eff.T, vec_u_eff) if int(options['kite_dof']) == 3: kite_dcm = three_dof_kite.get_kite_dcm(options, variables, wind, kite, architecture) elif int(options['kite_dof']) == 6: kite_dcm = six_dof_kite.get_kite_dcm(kite, variables, architecture) else: message = 'unsupported kite_dof chosen in options: ' + str( options['kite_dof']) awelogger.logger.error(message) if int(options['kite_dof']) == 3: framed_forces = tools.get_framed_forces(vec_u_eff, kite_dcm, variables, kite, architecture) m_aero_body = cas.DM.zeros((3, 1)) elif int(options['kite_dof']) == 6: framed_forces = tools.get_framed_forces(vec_u_eff, kite_dcm, variables, kite, architecture) framed_moments = tools.get_framed_moments(vec_u_eff, kite_dcm, variables, kite, architecture) m_aero_body = framed_moments['body'] else: message = 'unsupported kite_dof chosen in options: ' + str( options['kite_dof']) awelogger.logger.error(message) f_aero_body = framed_forces['body'] f_aero_wind = framed_forces['wind'] f_aero_control = framed_forces['control'] f_aero_earth = framed_forces['earth'] coeff_body = f_aero_body / q_eff / s_ref CA = coeff_body[0] CY = coeff_body[1] CN = coeff_body[2] f_drag_wind = f_aero_wind[0] * vect_op.xhat() f_side_wind = f_aero_wind[1] * vect_op.yhat() f_lift_wind = f_aero_wind[2] * vect_op.zhat() f_drag_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_drag_wind) f_side_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_side_wind) f_lift_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_lift_wind) coeff_wind = f_aero_wind / q_eff / s_ref CD = coeff_wind[0] CS = coeff_wind[1] CL = coeff_wind[2] CM = cas.mtimes(cas.inv(reference_lengths), m_aero_body) / q_eff / s_ref Cl = CM[0] Cm = CM[1] Cn = CM[2] aero_coefficients = {} aero_coefficients['CD'] = CD aero_coefficients['CS'] = CS aero_coefficients['CL'] = CL aero_coefficients['CA'] = CA aero_coefficients['CY'] = CY aero_coefficients['CN'] = CN aero_coefficients['Cl'] = Cl aero_coefficients['Cm'] = Cm aero_coefficients['Cn'] = Cn aero_coefficients['LoverD'] = CL / CD base_aerodynamic_quantities = {} base_aerodynamic_quantities['kite'] = kite base_aerodynamic_quantities['air_velocity'] = vec_u_eff base_aerodynamic_quantities['airspeed'] = u_eff base_aerodynamic_quantities['aero_coefficients'] = aero_coefficients base_aerodynamic_quantities['f_aero_earth'] = f_aero_earth base_aerodynamic_quantities['f_aero_body'] = f_aero_body base_aerodynamic_quantities['f_aero_control'] = f_aero_control base_aerodynamic_quantities['f_aero_wind'] = f_aero_wind base_aerodynamic_quantities['f_lift_earth'] = f_lift_earth base_aerodynamic_quantities['f_drag_earth'] = f_drag_earth base_aerodynamic_quantities['f_side_earth'] = f_side_earth base_aerodynamic_quantities['m_aero_body'] = m_aero_body base_aerodynamic_quantities['kite_dcm'] = kite_dcm base_aerodynamic_quantities['q'] = q base_aerodynamic_quantities['dq'] = dq outputs = indicators.collect_kite_aerodynamics_outputs( options, architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs) outputs = indicators.collect_environmental_outputs( atmos, wind, base_aerodynamic_quantities, outputs) outputs = indicators.collect_aero_validity_outputs( options, base_aerodynamic_quantities, outputs) outputs = indicators.collect_local_performance_outputs( architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs) outputs = indicators.collect_power_balance_outputs( options, architecture, variables, base_aerodynamic_quantities, outputs) return outputs
def from_control_to_body(vector): rot = cas.diag(cas.DM([-1., 1., -1.])) transformed = cas.mtimes(rot, vector) return transformed