def from_earth_to_body(kite_dcm, vector): # kite frame conversion (earth to body) involves a matrix inversion. div-by-zero errors are possible. # therefore: avoid using this conversion in critical-path dcm_inv = cas.inv(kite_dcm) transformed = cas.mtimes(dcm_inv, vector) return transformed
def from_earth_to_wind(vec_u, kite_dcm, vector): # kite frame conversion (earth to wind) involves a matrix inversion. div-by-zero errors are possible. # therefore: avoid using this conversion in critical-path wind_dcm = get_wind_dcm(vec_u, kite_dcm) wind_dcm_inv = cas.inv(wind_dcm) transformed = cas.mtimes(wind_dcm_inv, vector) return transformed
def from_earth_to_body(vector, q_upper, q_lower): [ehat_x, ehat_y, ehat_z] = get_body_axes(q_upper, q_lower) r_from_body_to_ef = cas.horzcat(ehat_x, ehat_y, ehat_z) r_from_ef_to_body = cas.inv(r_from_body_to_ef) transformed = cas.mtimes(r_from_ef_to_body, vector) return transformed
def time_derivative(expr, variables, architecture): # notice that the the chain rule # df/dt = partial f/partial t # + (partial f/partial x1)(partial x1/partial t) # + (partial f/partial x2)(partial x2/partial t)... # doesn't care about the scaling of the component functions, as long as # the units of (partial xi) will cancel # it is here assumed that (partial f/partial t) = 0. vars_scaled = variables['scaled'] deriv = 0. # (partial f/partial xi) for variables with trivial derivatives deriv_vars = struct_op.subkeys(vars_scaled, 'xddot') for deriv_name in deriv_vars: deriv_type = struct_op.get_variable_type(variables['SI'], deriv_name) var_name = deriv_name[1:] var_type = struct_op.get_variable_type(variables['SI'], var_name) q_sym = vars_scaled[var_type, var_name] dq_sym = vars_scaled[deriv_type, deriv_name] deriv += cas.mtimes(cas.jacobian(expr, q_sym), dq_sym) # (partial f/partial xi) for kite rotation matrices kite_nodes = architecture.kite_nodes for kite in kite_nodes: parent = architecture.parent_map[kite] r_name = 'r{}{}'.format(kite, parent) kite_has_6dof = r_name in struct_op.subkeys(vars_scaled, 'xd') if kite_has_6dof: r_kite = vars_scaled['xd', r_name] dcm_kite = cas.reshape(r_kite, (3, 3)) omega = vars_scaled['xd', 'omega{}{}'.format(kite, parent)] dexpr_dr = cas.jacobian(expr, r_kite) dr_dt = cas.reshape( cas.mtimes(vect_op.skew(omega), cas.inv(dcm_kite.T)), (9, 1)) deriv += cas.mtimes(dexpr_dr, dr_dt) return deriv
def var_si_to_scaled(var_type, var_name, var_si, 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_si else: return var_si / scale else: matrix_factor = cas.inv(cas.diag(scale)) return cas.mtimes(matrix_factor, var_si) else: return var_si
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