def test_fuselage_aerodynamics_optimization(): opti = asb.Opti() alpha = opti.variable(init_guess=0, lower_bound=0, upper_bound=30) beta = opti.variable(init_guess=0) fuselage = asb.Fuselage(xsecs=[ asb.FuselageXSec(xyz_c=[xi, 0, 0], radius=asb.Airfoil("naca0010").local_thickness( 0.8 * xi)) for xi in np.cosspace(0, 1, 20) ], ) aero = asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage]), op_point=asb.OperatingPoint(velocity=10, alpha=alpha, beta=beta)).run() opti.minimize(-aero["L"] / aero["D"]) sol = opti.solve(verbose=False) print(sol.value(alpha)) assert sol.value(alpha) > 10 and sol.value(alpha) < 20 assert sol.value(beta) == pytest.approx(0, abs=1e-3) opti.minimize(aero["D"]) sol = opti.solve(verbose=False) assert sol.value(alpha) == pytest.approx(0, abs=1e-2) assert sol.value(beta) == pytest.approx(0, abs=1e-2)
xsecs=[ asb.WingXSec( xyz_le=[0, 0, 0], chord=0.7, ), asb.WingXSec(xyz_le=[0.14, 1.25, 0], chord=0.42), ]), asb.Wing(name="V-stab", xyz_le=[4, 0, 0], xsecs=[ asb.WingXSec( xyz_le=[0, 0, 0], chord=0.7, ), asb.WingXSec(xyz_le=[0.14, 0, 1], chord=0.42) ]) ], fuselages=[ asb.Fuselage(name="Fuselage", xyz_le=[0, 0, 0], xsecs=[ asb.FuselageXSec( xyz_c=[xi * 5 - 0.5, 0, 0], radius=asb.Airfoil("naca0024").local_thickness( x_over_c=xi)) for xi in np.cosspace(0, 1, 30) ]) ]) if __name__ == '__main__': airplane.draw()
twist=0, airfoil=tail_airfoil, control_surface_is_symmetric=True, # Rudder control_surface_deflection=0, ), asb.WingXSec( xyz_le=[0.04, 0, 0.15], chord=0.06, twist=0, airfoil=tail_airfoil ) ] ).translate([0.6, 0, 0.07]) ], fuselages=[ asb.Fuselage( name="Fuselage", xsecs=[ asb.FuselageXSec( xyz_c=[0.8 * xi - 0.1, 0, 0.1 * xi - 0.03], radius=0.6 * asb.Airfoil("dae51").local_thickness(x_over_c=xi) ) for xi in np.cosspace(0, 1, 30) ] ) ] ) if __name__ == '__main__': airplane.draw()
# fuse_radius.extend([ # boom_diameter / 2 * blend(1 - x_nd) for x_nd in fuse_taper_x_nondim # ]) fuse_straight_resolution = 4 fuse_x_c.extend([ 0.6 * boom_length + (1 - 0.6) * boom_length * x_nd for x_nd in np.linspace(0, 1, fuse_straight_resolution)[1:] ]) fuse_z_c.extend([-boom_diameter / 2] * (fuse_straight_resolution - 1)) fuse_radius.extend([boom_diameter / 2] * (fuse_straight_resolution - 1)) fuse = asb.Fuselage(name="Fuselage", x_le=0, y_le=0, z_le=0, xsecs=[ asb.FuselageXSec(x_c=fuse_x_c[i], z_c=fuse_z_c[i], radius=fuse_radius[i]) for i in range(len(fuse_x_c)) ]) # Assemble the airplane fuses = [] hstabs = [] vstabs = [] if n_booms == 1: fuses.append(fuse) hstabs.append(hstab) vstabs.append(vstab) elif n_booms == 2: boom_location = 0.40 # as a fraction of the half-span
import aerosandbox as asb import aerosandbox.numpy as np import matplotlib.pyplot as plt import aerosandbox.tools.pretty_plots as p fuselage = asb.Fuselage(xsecs=[ asb.FuselageXSec(xyz_c=[xi, 0, 0], radius=asb.Airfoil("naca0020").local_thickness(xi) / 2) for xi in np.cosspace(0, 1, 20) ], ) fig, ax = plt.subplots(figsize=(7, 6)) V = np.linspace(10, 1000, 1001) op_point = asb.OperatingPoint(velocity=V, ) aero = asb.AeroBuildup( airplane=asb.Airplane(fuselages=[fuselage]), op_point=op_point, ).run() plt.plot(op_point.mach(), aero["CD"], label="Full Model") aero = asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage]), op_point=op_point, include_wave_drag=False).run() plt.plot(op_point.mach(), aero["CD"], zorder=1.9, label="Model without Wave Drag")
def make_airplane( n_booms, wing_span, ): # n_booms = 3 # wing # wing_span = 37.126 wing_root_chord = 2.316 wing_x_quarter_chord = -0.1 # hstab hstab_span = 2.867 hstab_chord = 1.085 hstab_twist_angle = -7 # vstab vstab_span = 2.397 vstab_chord = 1.134 # fuselage boom_length = 6.181 nose_length = 1.5 fuse_diameter = 0.6 boom_diameter = 0.2 wing = asb.Wing( name="Main Wing", # x_le=-0.05 * wing_root_chord, # Coordinates of the wing's leading edge # TODO make this a free parameter? x_le= wing_x_quarter_chord, # Coordinates of the wing's leading edge # TODO make this a free parameter? y_le=0, # Coordinates of the wing's leading edge z_le=0, # Coordinates of the wing's leading edge symmetric=True, xsecs=[ # The wing's cross ("X") sections asb.WingXSec( # Root x_le=-wing_root_chord / 4, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. y_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. z_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. chord=wing_root_chord, twist=0, # degrees airfoil= e216, # Airfoils are blended between a given XSec and the next one. control_surface_type="symmetric", # Flap # Control surfaces are applied between a given XSec and the next one. control_surface_deflection=0, # degrees spanwise_panels=30, ), asb.WingXSec( # Tip x_le=-wing_root_chord * 0.5 / 4, y_le=wing_span / 2, z_le=0, # wing_span / 2 * cas.pi / 180 * 5, chord=wing_root_chord * 0.5, twist=0, airfoil=e216, ), ], ) hstab = asb.Wing( name="Horizontal Stabilizer", x_le=boom_length - vstab_chord * 0.75 - hstab_chord, # Coordinates of the wing's leading edge y_le=0, # Coordinates of the wing's leading edge z_le=0.1, # Coordinates of the wing's leading edge symmetric=True, xsecs=[ # The wing's cross ("X") sections asb.WingXSec( # Root x_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. y_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. z_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. chord=hstab_chord, twist=-3, # degrees # TODO fix airfoil= naca0008, # Airfoils are blended between a given XSec and the next one. control_surface_type="symmetric", # Flap # Control surfaces are applied between a given XSec and the next one. control_surface_deflection=0, # degrees spanwise_panels=8, ), asb.WingXSec( # Tip x_le=0, y_le=hstab_span / 2, z_le=0, chord=hstab_chord, twist=-3, # TODO fix airfoil=naca0008, ), ], ) vstab = asb.Wing( name="Vertical Stabilizer", x_le=boom_length - vstab_chord * 0.75, # Coordinates of the wing's leading edge y_le=0, # Coordinates of the wing's leading edge z_le=-vstab_span / 2 + vstab_span * 0.15, # Coordinates of the wing's leading edge symmetric=False, xsecs=[ # The wing's cross ("X") sections asb.WingXSec( # Root x_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. y_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. z_le= 0, # Coordinates of the XSec's leading edge, relative to the wing's leading edge. chord=vstab_chord, twist=0, # degrees airfoil= naca0008, # Airfoils are blended between a given XSec and the next one. control_surface_type="symmetric", # Flap # Control surfaces are applied between a given XSec and the next one. control_surface_deflection=0, # degrees spanwise_panels=8, ), asb.WingXSec( # Tip x_le=0, y_le=0, z_le=vstab_span, chord=vstab_chord, twist=0, airfoil=naca0008, ), ], ) ### Build the fuselage geometry blend = lambda x: (1 - np.cos(np.pi * x)) / 2 fuse_x_c = [] fuse_z_c = [] fuse_radius = [] fuse_resolution = 10 # Nose geometry fuse_nose_theta = np.linspace(0, np.pi / 2, fuse_resolution) fuse_x_c.extend([(wing_x_quarter_chord - wing_root_chord / 4) - nose_length * np.cos(theta) for theta in fuse_nose_theta]) fuse_z_c.extend([-fuse_diameter / 2] * fuse_resolution) fuse_radius.extend( [fuse_diameter / 2 * np.sin(theta) for theta in fuse_nose_theta]) # Taper fuse_taper_x_nondim = np.linspace(0, 1, fuse_resolution) fuse_x_c.extend([ 0.0 * boom_length + (0.6 - 0.0) * boom_length * x_nd for x_nd in fuse_taper_x_nondim ]) fuse_z_c.extend([ -fuse_diameter / 2 * blend(1 - x_nd) - boom_diameter / 2 * blend(x_nd) for x_nd in fuse_taper_x_nondim ]) fuse_radius.extend([ fuse_diameter / 2 * blend(1 - x_nd) + boom_diameter / 2 * blend(x_nd) for x_nd in fuse_taper_x_nondim ]) # Tail # fuse_tail_x_nondim = np.linspace(0, 1, fuse_resolution)[1:] # fuse_x_c.extend([ # 0.9 * boom_length + (1 - 0.9) * boom_length * x_nd for x_nd in fuse_taper_x_nondim # ]) # fuse_z_c.extend([ # -boom_diameter / 2 * blend(1 - x_nd) for x_nd in fuse_taper_x_nondim # ]) # fuse_radius.extend([ # boom_diameter / 2 * blend(1 - x_nd) for x_nd in fuse_taper_x_nondim # ]) fuse_straight_resolution = 4 fuse_x_c.extend([ 0.6 * boom_length + (1 - 0.6) * boom_length * x_nd for x_nd in np.linspace(0, 1, fuse_straight_resolution)[1:] ]) fuse_z_c.extend([-boom_diameter / 2] * (fuse_straight_resolution - 1)) fuse_radius.extend([boom_diameter / 2] * (fuse_straight_resolution - 1)) fuse = asb.Fuselage( name="Fuselage", x_le=0, y_le=0, z_le=0, xsecs=[ asb.FuselageXSec(x_c=fuse_x_c[i], z_c=fuse_z_c[i], radius=fuse_radius[i]) for i in range(len(fuse_x_c)) ], ) # Assemble the airplane fuses = [] hstabs = [] vstabs = [] if n_booms == 1: fuses.append(fuse) hstabs.append(hstab) vstabs.append(vstab) elif n_booms == 2: boom_location = 0.40 # as a fraction of the half-span left_fuse = copy.deepcopy(fuse) right_fuse = copy.deepcopy(fuse) left_fuse.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_fuse.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) fuses.extend([left_fuse, right_fuse]) left_hstab = copy.deepcopy(hstab) right_hstab = copy.deepcopy(hstab) left_hstab.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_hstab.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) hstabs.extend([left_hstab, right_hstab]) left_vstab = copy.deepcopy(vstab) right_vstab = copy.deepcopy(vstab) left_vstab.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_vstab.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) vstabs.extend([left_vstab, right_vstab]) elif n_booms == 3: boom_location = 0.57 # as a fraction of the half-span left_fuse = copy.deepcopy(fuse) center_fuse = copy.deepcopy(fuse) right_fuse = copy.deepcopy(fuse) left_fuse.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_fuse.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) fuses.extend([left_fuse, center_fuse, right_fuse]) left_hstab = copy.deepcopy(hstab) center_hstab = copy.deepcopy(hstab) right_hstab = copy.deepcopy(hstab) left_hstab.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_hstab.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) hstabs.extend([left_hstab, center_hstab, right_hstab]) left_vstab = copy.deepcopy(vstab) center_vstab = copy.deepcopy(vstab) right_vstab = copy.deepcopy(vstab) left_vstab.xyz_le += cas.vertcat(0, -wing_span / 2 * boom_location, 0) right_vstab.xyz_le += cas.vertcat(0, wing_span / 2 * boom_location, 0) vstabs.extend([left_vstab, center_vstab, right_vstab]) else: raise ValueError("Bad value of n_booms!") airplane = asb.Airplane( name="Solar1", x_ref=0, y_ref=0, z_ref=0, wings=[wing] + hstabs + vstabs, fuselages=fuses, ) return airplane
chord=ft_to_m(3, 8), airfoil=naca0012, ), asb.WingXSec( xyz_le=[ft_to_m(0, 8), 0, ft_to_m(5)], chord=ft_to_m(2, 8), airfoil=naca0012, ), ]).translate( [ft_to_m(16, 11) - ft_to_m(3, 8), 0, ft_to_m(-2)]) ], fuselages=[ asb.Fuselage(xsecs=[ asb.FuselageXSec( xyz_c=[0, 0, ft_to_m(-1)], radius=0, ), asb.FuselageXSec(xyz_c=[0, 0, ft_to_m(-1)], radius=ft_to_m(1.5)), asb.FuselageXSec( xyz_c=[ft_to_m(3), 0, ft_to_m(-0.85)], radius=ft_to_m(1.7)), asb.FuselageXSec(xyz_c=[ft_to_m(5), 0, ft_to_m(0)], radius=ft_to_m(2.7)), asb.FuselageXSec( xyz_c=[ft_to_m(10, 4), 0, ft_to_m(0.3)], radius=ft_to_m(2.3)), asb.FuselageXSec( xyz_c=[ft_to_m(21, 11), 0, ft_to_m(0.8)], radius=ft_to_m(0.3)), ]).translate([ft_to_m(-5), 0, ft_to_m(-3)]) ])