Source code for aircraft

import pdb
import json
import numpy as np
import pandas as pd
from dataclasses import dataclass
from pyNA.src.settings import Settings
import scipy

[docs]@dataclass class Aircraft: """ Aircraft class containing vehicle constants and aerodynamics data. """ # Vehicle parameters mtow : float # Max. take-off weight [kg] n_eng : int # Number of engines installed on the aircraft [-] comp_lst : list # List of airframe components to include in noise analysis [-] # Airframe parameters af_S_h : float # Horizontal tail area (0.0 ft2) [m2] af_S_v : float # Vertical tail area (361.8 ft2) [m2] af_S_w : float # Wing area (3863.0 ft2) [m2] af_b_f : float # Flap span (25.74 ft) [m] af_b_h : float # Horizontal tail span (0. ft) [m] af_b_v : float # Vertical tail span (57.17 ft) [m] af_b_w : float # Wing span (94.43 ft) [m] # High-lift devices theta_flaps : float # Flap deflection angle [deg] theta_slats: float # Slat deflection angle [deg] af_S_f : float # Flap area (120.0 ft2) [m2] af_s : int # Number of slots for trailing-edge flaps (min. is 1) [-] # Landing gear af_d_mg : float # Tire diameter of main landing gear (3.08 ft) [m] af_d_ng : float # Tire diameter of nose landing gear (3.71 ft) [m] af_l_mg : float # Main landing-gear strut length (7.5 ft) [m] af_l_ng : float # Nose landing-gear strut length (6.0 ft) [m] af_n_mg : float # Number of wheels per main landing gear [-] af_n_ng : float # Number of wheels per nose landing gear [-] af_N_mg : float # Number of main landing gear [-] af_N_ng : float # Number of nose landing gear [-] mu_r : float # Rolling resistance coefficient [-] # Engine parameters B_fan : int # Number of fan blades [-] V_fan : int # Number of fan vanes [-] RSS_fan : float # Rotor-stator spacing [%] M_d_fan : float # Relative tip Mach number of fan at design [-] inc_F_n : float # Thrust inclination angle [deg] TS_lower : float # Min. power setting [-] TS_upper : float # Max. power setting [-] # Airframe configuration af_clean_w : bool # Clean wing (1: yes / 0: no) af_clean_h : bool # Clean horizontal tail (1: yes / 0: no) af_clean_v: bool # Clean vertical tail (1: yes / 0: no) af_delta_wing : bool # Delta wing (1: yes / 0: no) # Aerodynamics and flight performance c_l_max : float # Max. lift coefficient [-] alpha_0 : float # Wing mounting angle [deg] k_rot : float # Rotation coefficient (v_rot/v_stall) [-] v_max : float # Maximum climb-out velocity [m/s] z_max: float # Maximum climb-out altitude [m] gamma_rot : float # Initial climb angle [deg]
[docs] def __init__(self, name: str, version: str, settings: Settings) -> None: """ Initialize Aircraft class. :param name: aircraft name :type name: str :param version: aircraft version :type version: str :param settings: pyna settings :type settings: Settings :return: None """ # Initialize aircraft name self.name = name self.version = version # Initialize aerodynamics deck and flight performance parameters self.aero = dict() # self.v_stall: float # self.v_rot: float # Load aircraft parameters path = settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/' + self.name + '_' + self.version + '.json' with open(path) as f: params = json.load(f) Aircraft.set_aircraft_parameters(self, **params)
[docs] def set_aircraft_parameters(self, mtow: np.float64, n_eng: np.int64, comp_lst: list, af_S_h: np.float64, af_S_v: np.float64, af_S_w: np.float64, af_b_f: np.float64, af_b_h: np.float64, af_b_v: np.float64, af_b_w: np.float64, theta_flaps: np.float64, theta_slats: np.float64, af_S_f: np.float64, af_s: np.int64, af_d_mg: np.float64, af_d_ng: np.float64, af_l_mg: np.float64, af_l_ng: np.float64, af_n_mg: np.float64, af_n_ng: np.float64, af_N_mg: np.float64, af_N_ng: np.float64, mu_r: np.float64, B_fan: np.int64, V_fan: np.int64, RSS_fan: np.float64, M_d_fan: np.float64, inc_F_n: np.float64, TS_lower: np.float64, TS_upper: np.float64, af_clean_w: bool, af_clean_h:bool, af_clean_v: bool, af_delta_wing: bool, alpha_0: np.float64, k_rot: np.float64, v_max: np.float64, z_max: np.float64, gamma_rot: np.float64) -> None: """ Set the aircraft parameters in the aircraft class. :param mtow: Max. take-off weight [kg] :type mtow: np.float64 :param n_eng: Number of engines installed on the aircraft [-] :type n_eng: np.int64 :param comp_lst: List of airframe components to include [-] :type comp_lst: list :param af_S_h: Horizontal tail area [m2] :type af_S_h: np.float64 :param af_S_v: Vertical tail area [m2] :type af_S_v: np.float64 :param af_S_w: Wing area [m2] :type af_S_w: np.float64 :param af_b_f: Flap span [m] :type af_b_f: np.float64 :param af_b_h: Horizontal tail span [m] :type af_b_h: np.float64 :param af_b_v: Vertical tail span [m] :type af_b_v: np.float64 :param af_b_w: Wing span [m] :type af_b_w: np.float64 :param theta_flaps: Flap deflection angle [deg] :type theta_flaps: np.float64 :param theta_slats: Slat deflection angle [deg] :type theta_slats: np.float64 :param af_S_f: Flap area [m2] :type af_S_f: np.float64 :param af_s: Number of slots for trailing-edge flaps (min. is 1) [-] :type af_s: np.int64 :param af_d_mg: Tire diameter of main landing gear [m] :type af_d_mg: np.float64 :param af_d_ng: Tire diameter of nose landing gear [m] :type af_d_ng: np.float64 :param af_l_mg: Main landing-gear strut length [m] :type af_l_mg: np.float64 :param af_l_ng: Nose landing-gear strut length [m] :type af_l_ng: np.float64 :param af_n_mg: Number of wheels per main landing gear [-] :type af_n_mg: np.int64 :param af_n_ng: Number of wheels per nose landing gear [-] :type af_n_ng: np.int64 :param af_N_mg: Number of main landing gear [-] :type af_N_mg: np.int64 :param af_N_ng: Number of nose landing gear [-] :type af_N_ng: np.int64 :param mu_r: Rolling resistance coefficient [-] :type mu_r: np.float64 :param B_fan: Number of fan blades [-] :type B_fan: np.int64 :param V_fan: Number of fan vanes [-] :type V_fan: np.int64 :param RSS_fan: Rotor-stator spacing [%] :type RSS_fan: np.float64 :param M_d_fan: Relative tip Mach number of fan at design [-] :type M_d_fan: np.float64 :param inc_F_n: Thrust inclination angle [deg] :type inc_F_n: np.float64 :param TS_lower: Min. power setting [-] :type TS_lower: np.float64 :param TS_upper: Max. power setting [-] :type TS_upper: np.float64 :param af_clean_w: Flag for clean wing configuration [-] :type af_clean_w: bool :param af_clean_h: Flag for clean horizontal tail configuration [-] :type af_clean_h: bool :param af_clean_v: Flag for clean vertical tail configuration [-] :type af_clean_v: bool :param af_delta_wing: Flag for delta wing configuration [-] :type af_delta_wing: bool :param alpha_0: Wing mounting angle [deg] :type alpha_0: np.float64 :param k_rot: Rotation coefficient (v_rot/v_stall) [-] :type k_rot: np.float64 :param v_max: Maximum climb-out velocity [m/s] :type v_max: np.float64 :param z_max: Maximum climb-out altitude [m] :type z_max: np.float64 :param gamma_rot: Initial climb angle [deg] :type gamma_rot: np.float64 :return: None """ self.mtow = mtow self.n_eng = n_eng self.comp_lst = comp_lst self.af_S_h = af_S_h self.af_S_v = af_S_v self.af_S_w = af_S_w self.af_b_f = af_b_f self.af_b_h = af_b_h self.af_b_v = af_b_v self.af_b_w = af_b_w self.theta_flaps = theta_flaps self.theta_slats = theta_slats self.af_S_f = af_S_f self.af_s = af_s self.af_d_mg = af_d_mg self.af_d_ng = af_d_ng self.af_l_mg = af_l_mg self.af_l_ng = af_l_ng self.af_n_mg = af_n_mg self.af_n_ng = af_n_ng self.af_N_mg = af_N_mg self.af_N_ng = af_N_ng self.mu_r = mu_r self.B_fan = B_fan self.V_fan = V_fan self.RSS_fan = RSS_fan self.M_d_fan = M_d_fan self.inc_F_n = inc_F_n self.TS_lower = TS_lower self.TS_upper = TS_upper self.af_clean_w = af_clean_w self.af_clean_h = af_clean_h self.af_clean_v = af_clean_v self.af_delta_wing = af_delta_wing self.alpha_0 = alpha_0 self.k_rot = k_rot self.v_max = v_max self.z_max = z_max self.gamma_rot = gamma_rot return None
[docs] def load_aerodynamics(self, settings: Settings) -> None: """ Load aerodynamic data from aerodynamics deck. :param settings: pyNA settings :type settings: Settings :return: None """ # Load aerodynamics deck if settings.ac_name in ['stca', 'stca_verification']: # Load data self.aero['alpha'] = np.array([-2., 0., 2., 4., 6., 8., 10., 12., 15., 18.]) self.aero['theta_flaps'] = np.array([ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18., 20., 22., 24., 26.]) self.aero['theta_slats'] = np.array([-26., -24., -22., -20., -18., -16., -14., -12., -10., -8., -6., -4., -2., 0.]) self.aero['c_l'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_l_stca.npy') self.aero['c_l_max'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_l_max_' + settings.ac_name + '.npy') self.aero['c_d'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_d_stca.npy') elif settings.ac_name == 'a10': self.aero['alpha'] = np.array([-2., -1., 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) self.aero['theta_flaps'] = np.array([0., 2., 4., 6., 8., 10., 12., 14., 16., 18., 20., 22., 24., 26.]) self.aero['theta_slats'] = np.array([-26., -24., -22., -20., -18., -16., -14., -12., -10., -8., -6., -4., -2., 0.]) self.aero['c_l'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_l_' + settings.ac_name + '.npy') self.aero['c_l_max'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_l_max_' + settings.ac_name + '.npy') self.aero['c_d'] = np.load(settings.pyNA_directory + '/cases/' + settings.case_name + '/aircraft/c_d_' + settings.ac_name + '.npy') else: raise ValueError('Invalid aircraft name specified.') return None
[docs] @staticmethod def generate_aerodeck_from_csv(filename_c_l:str, filename_c_d:str, savename_c_l:str=None, savename_cd:str=None) -> None: """ Generate a CL-CD aerodynamics deck from a .csv data file. :param filename_c_l: File name with c_l data as function of alpha, theta_flap, theta_slat :type filename_c_l: str :param filename_cd: File name with cd data as function of alpha, theta_flap, theta_slat :type filename_cd: str :param savename_c_l: Save file name of c_l-aerodynamics deck :type savename_c_l: str :param savename_cd: Save file name of c_d-aerodynamics deck :type savename_cd: str :return: None """ # Load data data_c_l = pd.read_csv(filename_c_l) data_c_d = pd.read_csv(filename_c_d) # Extract angles alpha = data_c_l.values[2:, 0] theta_slats = np.unique(data_c_l.values[0, 1:]) theta_flaps = np.unique(data_c_l.values[1, 1:]) # Extract CL-CD in matrices c_l = np.zeros((np.size(alpha), np.size(theta_flaps), np.size(theta_slats))) c_d = np.zeros((np.size(alpha), np.size(theta_flaps), np.size(theta_slats))) for i in np.arange(np.size(alpha)): for j in np.arange(np.size(theta_slats)): c_l[i, :, j] = np.flip( data_c_l.values[2 + i, 1 + j * np.size(theta_flaps):1 + (j + 1) * np.size(theta_flaps)]) c_d[i, :, j] = np.flip( data_c_d.values[2 + i, 1 + j * np.size(theta_flaps):1 + (j + 1) * np.size(theta_flaps)]) # Save aero deck if savename_c_l is not None: np.save(savename_c_l, c_l) if savename_cd is not None: np.save(savename_cd, c_d) return None