diff --git a/B737_AVL_Tutorial/tut_mission_B737_AVL.py b/B737_AVL_Tutorial/tut_mission_B737_AVL.py index be4bfe9..0321500 100644 --- a/B737_AVL_Tutorial/tut_mission_B737_AVL.py +++ b/B737_AVL_Tutorial/tut_mission_B737_AVL.py @@ -6,13 +6,10 @@ # Imports # ---------------------------------------------------------------------- -# Python Imports -import numpy as np -import pylab as plt - # SUAVE Imports import SUAVE from SUAVE.Core import Data, Units +from SUAVE.Plots.Mission_Plots import * from SUAVE.Methods.Propulsion.turbofan_sizing import turbofan_sizing from SUAVE.Methods.Geometry.Two_Dimensional.Cross_Section.Propulsion import compute_turbofan_geometry from SUAVE.Input_Output.Results import print_parasite_drag, \ @@ -21,6 +18,10 @@ print_mission_breakdown, \ print_weight_breakdown +# Python Imports +import numpy as np +import pylab as plt + # ---------------------------------------------------------------------- # Main # ---------------------------------------------------------------------- @@ -100,13 +101,14 @@ def base_analysis(vehicle): # ------------------------------------------------------------------ # Weights - weights = SUAVE.Analyses.Weights.Weights_Tube_Wing() + weights = SUAVE.Analyses.Weights.Weights_Transport() weights.vehicle = vehicle analyses.append(weights) # ------------------------------------------------------------------ # Aerodynamics Analysis aerodynamics = SUAVE.Analyses.Aerodynamics.AVL() + aerodynamics.process.compute.lift.inviscid.settings.filenames.avl_bin_name = 'CHANGE ME TO YOUR DIRECTORY' #aerodynamics.process.compute.lift.inviscid.settings.spanwise_vortex_density = 3 aerodynamics.geometry = vehicle analyses.append(aerodynamics) @@ -114,6 +116,7 @@ def base_analysis(vehicle): # ------------------------------------------------------------------ # Stability Analysis stability = SUAVE.Analyses.Stability.AVL() + stability.settings.filenames.avl_bin_name = 'CHANGE ME TO YOUR DIRECTORY' #stability.settings.spanwise_vortex_density = 3 stability.geometry = vehicle analyses.append(stability) @@ -200,7 +203,6 @@ def vehicle_setup(): wing.sweeps.quarter_chord = 25 * Units.deg wing.thickness_to_chord = 0.1 wing.taper = 0.1 - wing.span_efficiency = 0.9 wing.spans.projected = 34.32 * Units.meter wing.chords.root = 7.760 * Units.meter wing.chords.tip = 0.782 * Units.meter @@ -208,34 +210,34 @@ def vehicle_setup(): wing.areas.reference = 124.862 * Units['meters**2'] wing.twists.root = 4.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [13.61,0,-1.27] # meters + wing.origin = [[13.61 * Units.meter, 0, -1.27 * Units.meter]] wing.vertical = False wing.symmetric = True wing.high_lift = True wing.dynamic_pressure_ratio = 1.0 + # add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Horizontal Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Horizontal_Tail() wing.tag = 'horizontal_stabilizer' wing.aspect_ratio = 6.16 wing.sweeps.quarter_chord = 40 * Units.deg wing.thickness_to_chord = 0.08 wing.taper = 0.2 - wing.span_efficiency = 0.9 wing.spans.projected = 14.2 * Units.meter wing.chords.root = 4.7 * Units.meter wing.chords.tip = .955 * Units.meter - wing.chords.mean_aerodynamic = 8.0 * Units.meter + wing.chords.mean_aerodynamic = 3.0 * Units.meter wing.areas.reference = 32.488 * Units['meters**2'] wing.twists.root = 3.0 * Units.degrees wing.twists.tip = 3.0 * Units.degrees - wing.origin = [32.83,0,1.14] # meters + wing.origin = [[32.83 * Units.meter, 0 , 1.14 * Units.meter]] wing.vertical = False wing.symmetric = True wing.dynamic_pressure_ratio = 0.9 @@ -247,14 +249,13 @@ def vehicle_setup(): # Vertical Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Vertical_Tail() wing.tag = 'vertical_stabilizer' wing.aspect_ratio = 1.91 wing.sweeps.quarter_chord = 25. * Units.deg wing.thickness_to_chord = 0.08 wing.taper = 0.25 - wing.span_efficiency = 0.9 wing.spans.projected = 7.777 * Units.meter wing.chords.root = 8.19 * Units.meter wing.chords.tip = 0.95 * Units.meter @@ -262,7 +263,7 @@ def vehicle_setup(): wing.areas.reference = 27.316 * Units['meters**2'] wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [28.79,0,1.54] # meters + wing.origin = [[28.79 * Units.meter, 0, 1.54 * Units.meter]] # meters wing.vertical = True wing.symmetric = False wing.t_tail = False @@ -317,7 +318,7 @@ def vehicle_setup(): turbofan.bypass_ratio = 5.4 turbofan.engine_length = 2.71 * Units.meter turbofan.nacelle_diameter = 2.05 * Units.meter - turbofan.origin = [[13.72, 4.86,-1.9],[13.72, -4.86,-1.9]] # meters + turbofan.origin = [[13.72, 4.86,-1.9],[13.72, -4.86,-1.9]] #compute engine areas turbofan.areas.wetted = 1.1*np.pi*turbofan.nacelle_diameter*turbofan.engine_length @@ -415,6 +416,7 @@ def vehicle_setup(): # setup combustor.efficiency = 0.99 + combustor.alphac = 1.0 combustor.turbine_inlet_temperature = 1450 # K combustor.pressure_ratio = 0.95 combustor.fuel_data = SUAVE.Attributes.Propellants.Jet_A() @@ -493,6 +495,7 @@ def vehicle_setup(): return vehicle + # ---------------------------------------------------------------------- # Define the Configurations # --------------------------------------------------------------------- @@ -717,167 +720,17 @@ def missions_setup(base_mission): def plot_mission(results,line_style='bo-'): - axis_font = {'fontname':'Arial', 'size':'14'} - - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - - - fig = plt.figure("Aerodynamic Forces",figsize=(8,6)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lbf - eta = segment.conditions.propulsion.throttle[:,0] - - axes = fig.add_subplot(2,1,1) - axes.plot( time , Thrust , line_style ) - axes.set_ylabel('Thrust (lbf)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(2,1,2) - axes.plot( time , eta , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Throttle',axis_font) - axes.grid(True) - - plt.savefig("B737_engine.pdf") - plt.savefig("B737_engine.png") - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , line_style ) - axes.set_ylabel('Lift Coefficient',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , l_d , line_style ) - axes.set_ylabel('L/D',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , aoa , 'ro-' ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('AOA (deg)',axis_font) - axes.grid(True) - - plt.savefig("B737_aero.pdf") - plt.savefig("B737_aero.png") - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components",figsize=(8,10)) - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - if line_style == 'bo-': - axes.plot( time , cdp , 'ko-', label='CD parasite' ) - axes.plot( time , cdi , 'bo-', label='CD induced' ) - axes.plot( time , cdc , 'go-', label='CD compressibility' ) - axes.plot( time , cdm , 'yo-', label='CD miscellaneous' ) - axes.plot( time , cd , 'ro-', label='CD total' ) - if i == 0: - axes.legend(loc='upper center') - else: - axes.plot( time , cdp , line_style ) - axes.plot( time , cdi , line_style ) - axes.plot( time , cdc , line_style ) - axes.plot( time , cdm , line_style ) - axes.plot( time , cd , line_style ) - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - plt.savefig("B737_drag.pdf") - plt.savefig("B737_drag.png") - - # ------------------------------------------------------------------ - # Altitude, sfc, vehicle weight - # ------------------------------------------------------------------ - - fig = plt.figure("Altitude_sfc_weight",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - mass = segment.conditions.weights.total_mass[:,0] / Units.lb - altitude = segment.conditions.freestream.altitude[:,0] / Units.ft - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = (mdot / Units.lb) / (thrust /Units.lbf) * Units.hr - - axes = fig.add_subplot(3,1,1) - axes.plot( time , altitude , line_style ) - axes.set_ylabel('Altitude (ft)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , sfc , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('sfc (lb/lbf-hr)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , mass , 'ro-' ) - axes.set_ylabel('Weight (lb)',axis_font) - axes.grid(True) - - plt.savefig("B737_mission.pdf") - plt.savefig("B737_mission.png") - - # ------------------------------------------------------------------ - # Velocities - # ------------------------------------------------------------------ - fig = plt.figure("Velocities",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Lift = -segment.conditions.frames.wind.lift_force_vector[:,2] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] / Units.lbf - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lb - velocity = segment.conditions.freestream.velocity[:,0] - pressure = segment.conditions.freestream.pressure[:,0] - density = segment.conditions.freestream.density[:,0] - EAS = velocity * np.sqrt(density/1.225) - mach = segment.conditions.freestream.mach_number[:,0] - - axes = fig.add_subplot(3,1,1) - axes.plot( time , velocity / Units.kts, line_style ) - axes.set_ylabel('velocity (kts)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , EAS / Units.kts, line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Equivalent Airspeed',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , mach , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Mach',axis_font) - axes.grid(True) + # Plot Aerodynamic Forces + plot_aerodynamic_forces(results, line_style) + + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results, line_style) + + # Drag Components + plot_drag_components(results, line_style) + + # Plot Velocities + plot_aircraft_velocities(results, line_style) return diff --git a/BWB_CFD/BWB.py b/BWB_CFD/BWB.py index deae1a6..12034bc 100644 --- a/BWB_CFD/BWB.py +++ b/BWB_CFD/BWB.py @@ -20,6 +20,8 @@ from SUAVE.Methods.Propulsion.turbofan_sizing import turbofan_sizing from SUAVE.Methods.Geometry.Two_Dimensional.Cross_Section.Propulsion import compute_turbofan_geometry +from SUAVE.Plots.Mission_Plots import * + # ---------------------------------------------------------------------- # Main # ---------------------------------------------------------------------- @@ -109,9 +111,12 @@ def base_analysis(vehicle): #aerodynamics.process.compute.lift.inviscid.settings.parallel = True #aerodynamics.process.compute.lift.inviscid.settings.processors = 12 - #aerodynamics.process.compute.lift.inviscid.training_file = 'base_data_1500.txt' + aerodynamics.process.compute.lift.inviscid.training_file = 'base_data_1500.txt' aerodynamics.process.compute.lift.inviscid.settings.maximum_iterations = 10 + aerodynamics.settings.drag_coefficient_increment = 0.0000 + aerodynamics.settings.half_mesh_flag = False + aerodynamics.settings.span_efficiency = 0.85 aerodynamics.process.compute.lift.inviscid.training.Mach = np.array([.3, .5, .7, .85]) aerodynamics.process.compute.lift.inviscid.training.angle_of_attack = np.array([0.,3.,6.]) * Units.deg @@ -168,31 +173,28 @@ def base_analysis(vehicle): # ---------------------------------------------------------------------- def vehicle_setup(): - + # ------------------------------------------------------------------ # Initialize the Vehicle # ------------------------------------------------------------------ - vehicle = SUAVE.Vehicle() vehicle.tag = 'Boeing_BWB_450' - # ------------------------------------------------------------------ # Vehicle-level Properties # ------------------------------------------------------------------ - # mass properties vehicle.mass_properties.max_takeoff = 823000. * Units.lb vehicle.mass_properties.takeoff = 823000. * Units.lb vehicle.mass_properties.max_zero_fuel = 0.9 * vehicle.mass_properties.max_takeoff - vehicle.mass_properties.cargo = 0. * Units.kilogram + vehicle.mass_properties.cargo = 00. * Units.kilogram # envelope properties vehicle.envelope.ultimate_load = 2.5 vehicle.envelope.limit_load = 1.5 # basic parameters - vehicle.reference_area = 15680. * Units.feet**2 + vehicle.reference_area = 7840. * 2 * Units.feet**2 vehicle.passengers = 450. vehicle.systems.control = "fully powered" vehicle.systems.accessories = "medium range" @@ -201,75 +203,87 @@ def vehicle_setup(): # ------------------------------------------------------------------ # Main Wing # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Main_Wing() wing.tag = 'main_wing' wing.aspect_ratio = 289.**2 / (7840. * 2) wing.thickness_to_chord = 0.15 wing.taper = 0.0138 - wing.span_efficiency = 0.95 - - wing.spans.projected = 289.0 * Units.feet - + wing.spans.projected = 289.0 * Units.feet wing.chords.root = 145.0 * Units.feet - wing.chords.tip = 3.5 * Units.feet - wing.chords.mean_aerodynamic = 86. * Units.feet - - wing.areas.reference = 15680. * Units.feet**2 + wing.chords.tip = 3.5 * Units.feet + wing.chords.mean_aerodynamic = 80. * Units.feet + wing.areas.reference = 7840. * 2 * Units.feet**2 wing.sweeps.quarter_chord = 33. * Units.degrees - wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees wing.dihedral = 2.5 * Units.degrees - - wing.origin = [0.,0.,0] + wing.origin = [[0.,0.,0]] wing.aerodynamic_center = [0,0,0] - wing.vertical = False wing.symmetric = True wing.high_lift = True - wing.dynamic_pressure_ratio = 1.0 segment = SUAVE.Components.Wings.Segment() + segment.tag = 'section_1' segment.percent_span_location = 0.0 segment.twist = 0. * Units.deg segment.root_chord_percent = 1. segment.dihedral_outboard = 0. * Units.degrees - segment.sweeps.quarter_chord = 30.0 * Units.degrees - segment.thickness_to_chord = 0.165 + segment.sweeps.quarter_chord = 40.0 * Units.degrees + segment.thickness_to_chord = 0.165 + segment.vsp_mesh = Data() + segment.vsp_mesh.inner_radius = 4. + segment.vsp_mesh.outer_radius = 4. + segment.vsp_mesh.inner_length = .14 + segment.vsp_mesh.outer_length = .14 wing.Segments.append(segment) segment = SUAVE.Components.Wings.Segment() - segment.tag = 'section_2' - segment.percent_span_location = 0.052 - segment.twist = 0. * Units.deg - segment.root_chord_percent = 0.921 - segment.dihedral_outboard = 0. * Units.degrees - segment.sweeps.quarter_chord = 52.5 * Units.degrees - segment.thickness_to_chord = 0.167 + segment.tag = 'section_2' + segment.percent_span_location = 0.052 + segment.twist = 0. * Units.deg + segment.root_chord_percent = 0.921 + segment.dihedral_outboard = 0. * Units.degrees + segment.sweeps.quarter_chord = 52.5 * Units.degrees + segment.thickness_to_chord = 0.167 + segment.vsp_mesh = Data() + segment.vsp_mesh.inner_radius = 4. + segment.vsp_mesh.outer_radius = 4. + segment.vsp_mesh.inner_length = .14 + segment.vsp_mesh.outer_length = .14 wing.Segments.append(segment) segment = SUAVE.Components.Wings.Segment() - segment.tag = 'section_3' - segment.percent_span_location = 0.138 - segment.twist = 0. * Units.deg - segment.root_chord_percent = 0.76 - segment.dihedral_outboard = 1.85 * Units.degrees - segment.sweeps.quarter_chord = 36.9 * Units.degrees - segment.thickness_to_chord = 0.171 + segment.tag = 'section_3' + segment.percent_span_location = 0.138 + segment.twist = 0. * Units.deg + segment.root_chord_percent = 0.76 + segment.dihedral_outboard = 1.85 * Units.degrees + segment.sweeps.quarter_chord = 36.9 * Units.degrees + segment.thickness_to_chord = 0.171 + segment.vsp_mesh = Data() + segment.vsp_mesh.inner_radius = 4. + segment.vsp_mesh.outer_radius = 4. + segment.vsp_mesh.inner_length = .14 + segment.vsp_mesh.outer_length = .14 wing.Segments.append(segment) segment = SUAVE.Components.Wings.Segment() - segment.tag = 'section_4' - segment.percent_span_location = 0.221 - segment.twist = 0. * Units.deg - segment.root_chord_percent = 0.624 - segment.dihedral_outboard = 1.85 * Units.degrees - segment.sweeps.quarter_chord = 30.4 * Units.degrees - segment.thickness_to_chord = 0.175 + segment.tag = 'section_4' + segment.percent_span_location = 0.221 + segment.twist = 0. * Units.deg + segment.root_chord_percent = 0.624 + segment.dihedral_outboard = 1.85 * Units.degrees + segment.sweeps.quarter_chord = 30.4 * Units.degrees + segment.thickness_to_chord = 0.175 + segment.vsp_mesh = Data() + segment.vsp_mesh.inner_radius = 4. + segment.vsp_mesh.outer_radius = 2.8 + segment.vsp_mesh.inner_length = .14 + segment.vsp_mesh.outer_length = .14 wing.Segments.append(segment) segment = SUAVE.Components.Wings.Segment() @@ -302,23 +316,32 @@ def vehicle_setup(): segment.thickness_to_chord = 0.10 wing.Segments.append(segment) + segment = SUAVE.Components.Wings.Segment() + segment.tag = 'tip' + segment.percent_span_location = 1 + segment.twist = 0. * Units.deg + segment.root_chord_percent = 0.0241 + segment.dihedral_outboard = 0. * Units.degrees + segment.sweeps.quarter_chord = 0. * Units.degrees + segment.thickness_to_chord = 0.10 + wing.Segments.append(segment) + # add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Turbofan Network # ------------------------------------------------------------------ - #instantiate the gas turbine network - turbofan = SUAVE.Components.Energy.Networks.Turbofan() turbofan.tag = 'turbofan1' - + # setup turbofan.number_of_engines = 3.0 turbofan.bypass_ratio = 8.1 turbofan.engine_length = 289. * Units.inches turbofan.nacelle_diameter = 3.96 * Units.meters + #turbofan.cooling_ratio = 1.0 turbofan.origin = [[133.0 *Units.feet, 25.0*Units.feet, 6.5*Units.feet],[145.0 *Units.feet, 0.0*Units.feet, 6.5*Units.feet],[133.0 *Units.feet, -25.0*Units.feet, 6.5*Units.feet]] # working fluid @@ -328,11 +351,9 @@ def vehicle_setup(): # Component 1 - Ram # to convert freestream static to stagnation quantities - # instantiate ram = SUAVE.Components.Energy.Converters.Ram() ram.tag = 'ram' - # add to the network turbofan.append(ram) @@ -342,11 +363,9 @@ def vehicle_setup(): # instantiate inlet_nozzle = SUAVE.Components.Energy.Converters.Compression_Nozzle() inlet_nozzle.tag = 'inlet_nozzle' - # setup inlet_nozzle.polytropic_efficiency = 1.0 inlet_nozzle.pressure_ratio = 1.0 - # add to network turbofan.append(inlet_nozzle) @@ -356,11 +375,9 @@ def vehicle_setup(): # instantiate compressor = SUAVE.Components.Energy.Converters.Compressor() compressor.tag = 'low_pressure_compressor' - # setup compressor.polytropic_efficiency = 0.91 compressor.pressure_ratio = 1.1 - # add to network turbofan.append(compressor) @@ -370,12 +387,10 @@ def vehicle_setup(): # instantiate compressor = SUAVE.Components.Energy.Converters.Compressor() compressor.tag = 'high_pressure_compressor' - # setup compressor.polytropic_efficiency = 0.91 compressor.pressure_ratio = 23.0 #compressor.hub_to_tip_ratio = 0.325 - # add to network turbofan.append(compressor) @@ -385,11 +400,9 @@ def vehicle_setup(): # instantiate turbine = SUAVE.Components.Energy.Converters.Turbine() turbine.tag='low_pressure_turbine' - # setup turbine.mechanical_efficiency = 0.99 turbine.polytropic_efficiency = 0.93 - # add to network turbofan.append(turbine) @@ -399,11 +412,9 @@ def vehicle_setup(): # instantiate turbine = SUAVE.Components.Energy.Converters.Turbine() turbine.tag='high_pressure_turbine' - # setup turbine.mechanical_efficiency = 0.99 turbine.polytropic_efficiency = 0.93 - # add to network turbofan.append(turbine) @@ -413,14 +424,12 @@ def vehicle_setup(): # instantiate combustor = SUAVE.Components.Energy.Converters.Combustor() combustor.tag = 'combustor' - # setup combustor.efficiency = 1.0 combustor.alphac = 1.0 combustor.turbine_inlet_temperature = 1592. * Units.kelvin combustor.pressure_ratio = 0.95 combustor.fuel_data = SUAVE.Attributes.Propellants.Jet_A() - # add to network turbofan.append(combustor) @@ -430,11 +439,9 @@ def vehicle_setup(): # instantiate nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle() nozzle.tag = 'core_nozzle' - # setup nozzle.polytropic_efficiency = 0.95 nozzle.pressure_ratio = 0.99 - # add to network turbofan.append(nozzle) @@ -444,11 +451,9 @@ def vehicle_setup(): # instantiate nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle() nozzle.tag = 'fan_nozzle' - # setup nozzle.polytropic_efficiency = 0.95 nozzle.pressure_ratio = 0.99 - # add to network turbofan.append(nozzle) @@ -458,12 +463,9 @@ def vehicle_setup(): # instantiate fan = SUAVE.Components.Energy.Converters.Fan() fan.tag = 'fan' - # setup fan.polytropic_efficiency = 0.93 fan.pressure_ratio = 1.58 - #fan.hub_to_tip_ratio = 0.325 - # add to network turbofan.append(fan) @@ -473,7 +475,7 @@ def vehicle_setup(): thrust.tag ='compute_thrust' #total design thrust (includes all the engines) - thrust.total_design = 3.0*512000 * Units.N + thrust.total_design = 2.0*512000 * Units.N thrust.bypass_ratio = 8.4 #design sizing conditions @@ -486,6 +488,7 @@ def vehicle_setup(): #size the turbofan turbofan_sizing(turbofan,mach_number,altitude) + #turbofan.size(mach_number,altitude) #computing the engine length and diameter compute_turbofan_geometry(turbofan,None) @@ -526,175 +529,20 @@ def configs_setup(vehicle): def plot_mission(results,line_style='bo-'): - axis_font = {'fontname':'Arial', 'size':'14'} - - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Forces",figsize=(8,6)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Lift = -segment.conditions.frames.wind.lift_force_vector[:,2] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] / Units.lbf - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lbf - eta = segment.conditions.propulsion.throttle[:,0] - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = 3600. * mdot / 0.1019715 / thrust + # Plot Aerodynamic Forces + plot_aerodynamic_forces(results, line_style) + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results, line_style) - axes = fig.add_subplot(2,1,1) - axes.plot( time , Thrust , line_style ) - axes.set_ylabel('Thrust (lbf)',axis_font) - axes.grid(True) + # Drag Components + plot_drag_components(results, line_style) - axes = fig.add_subplot(2,1,2) - axes.plot( time , eta , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Throttle',axis_font) - axes.grid(True) + # Plot Altitude, sfc, vehicle weight + plot_altitude_sfc_weight(results, line_style) - - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , line_style ) - axes.set_ylabel('Lift Coefficient',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , l_d , line_style ) - axes.set_ylabel('L/D',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , aoa , 'ro-' ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('AOA (deg)',axis_font) - axes.grid(True) - - # ------------------------------------------------------------------ - # Aerodynamics 3 - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components",figsize=(8,10)) - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - if line_style == 'bo-': - axes.plot( time , cdp , 'ko-', label='CD parasite' ) - axes.plot( time , cdi , 'bo-', label='CD induced' ) - axes.plot( time , cdc , 'go-', label='CD compressibility' ) - axes.plot( time , cdm , 'yo-', label='CD miscellaneous' ) - axes.plot( time , cd , 'ro-', label='CD total' ) - if i == 0: - axes.legend(loc='upper center') - else: - axes.plot( time , cdp , line_style ) - axes.plot( time , cdi , line_style ) - axes.plot( time , cdc , line_style ) - axes.plot( time , cdm , line_style ) - axes.plot( time , cd , line_style ) - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - - # ------------------------------------------------------------------ - # Altitude, sfc, vehicle weight - # ------------------------------------------------------------------ - - fig = plt.figure("Altitude_sfc_weight",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - mass = segment.conditions.weights.total_mass[:,0] / Units.lb - altitude = segment.conditions.freestream.altitude[:,0] / Units.ft - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = 3600. * mdot / 0.1019715 / thrust - - axes = fig.add_subplot(3,1,1) - axes.plot( time , altitude , line_style ) - axes.set_ylabel('Altitude (ft)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , sfc , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('sfc (lb/lbf-hr)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , mass , 'ro-' ) - axes.set_ylabel('Weight (lb)',axis_font) - axes.grid(True) - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Velocities",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Lift = -segment.conditions.frames.wind.lift_force_vector[:,2] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] / Units.lbf - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lbf - eta = segment.conditions.propulsion.throttle[:,0] - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = 3600. * mdot / 0.1019715 / thrust - velocity = segment.conditions.freestream.velocity[:,0] - pressure = segment.conditions.freestream.pressure[:,0] - density = segment.conditions.freestream.density[:,0] - EAS = velocity * np.sqrt(density/1.225) - mach = segment.conditions.freestream.mach_number[:,0] - - - axes = fig.add_subplot(3,1,1) - axes.plot( time , velocity / Units.kts, line_style ) - axes.set_ylabel('velocity (kts)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , EAS / Units.kts, line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Equivalent Airspeed',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , mach , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Mach',axis_font) - axes.grid(True) + # Plot Velocities + plot_aircraft_velocities(results, line_style) return diff --git a/Regional_Jet_Optimization/Analyses.py b/Regional_Jet_Optimization/Analyses.py index f18b449..2acc007 100644 --- a/Regional_Jet_Optimization/Analyses.py +++ b/Regional_Jet_Optimization/Analyses.py @@ -47,7 +47,7 @@ def base(vehicle): # ------------------------------------------------------------------ # Weights - weights = SUAVE.Analyses.Weights.Weights_Tube_Wing() + weights = SUAVE.Analyses.Weights.Weights_Transport() weights.vehicle = vehicle analyses.append(weights) diff --git a/Regional_Jet_Optimization/Optimize.py b/Regional_Jet_Optimization/Optimize.py index a425709..2631392 100644 --- a/Regional_Jet_Optimization/Optimize.py +++ b/Regional_Jet_Optimization/Optimize.py @@ -66,7 +66,7 @@ def setup(): # [ tag , initial, (lb,ub) , scaling , units ] problem.inputs = np.array([ - [ 'wing_area' , 95 , ( 90. , 130. ) , 100. , Units.meter**2], + [ 'wing_area' , 100 , ( 90. , 130. ) , 100. , Units.meter**2], [ 'cruise_altitude' , 11 , ( 9 , 14. ) , 10. , Units.km], ]) diff --git a/Regional_Jet_Optimization/Plot_Mission.py b/Regional_Jet_Optimization/Plot_Mission.py index 3f3e15e..e11ff20 100644 --- a/Regional_Jet_Optimization/Plot_Mission.py +++ b/Regional_Jet_Optimization/Plot_Mission.py @@ -9,7 +9,7 @@ import SUAVE from SUAVE.Core import Units - +from SUAVE.Plots.Mission_Plots import * import pylab as plt # ---------------------------------------------------------------------- @@ -17,103 +17,17 @@ # ---------------------------------------------------------------------- def plot_mission(nexus,line_style='bo-'): - results = nexus.results.base - axis_font = {'fontname':'Arial', 'size':'14'} - - - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients",figsize=(8,10)) - for segment in results.segments.values(): - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , line_style ) - axes.set_ylabel('Lift Coefficient',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , l_d , line_style ) - axes.set_ylabel('L/D',axis_font) - axes.grid(True) + results = nexus.results.base - axes = fig.add_subplot(3,1,3) - axes.plot( time , aoa , 'ro-' ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('AOA (deg)',axis_font) - axes.grid(True) + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results, line_style) - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components",figsize=(8,10)) - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - if line_style == 'bo-': - axes.plot( time , cdp , 'ko-', label='CD parasite' ) - axes.plot( time , cdi , 'bo-', label='CD induced' ) - axes.plot( time , cdc , 'go-', label='CD compressibility' ) - axes.plot( time , cdm , 'yo-', label='CD miscellaneous' ) - axes.plot( time , cd , 'ro-', label='CD total' ) - if i == 0: - axes.legend(loc='upper center') - else: - axes.plot( time , cdp , line_style ) - axes.plot( time , cdi , line_style ) - axes.plot( time , cdc , line_style ) - axes.plot( time , cdm , line_style ) - axes.plot( time , cd , line_style ) - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - - # ------------------------------------------------------------------ - # Altitude, sfc, vehicle weight - # ------------------------------------------------------------------ - - fig = plt.figure("Altitude_sfc_weight",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - mass = segment.conditions.weights.total_mass[:,0] / Units.lb - altitude = segment.conditions.freestream.altitude[:,0] / Units.ft - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = (mdot / Units.lb) / (thrust /Units.lbf) * Units.hr - - axes = fig.add_subplot(3,1,1) - axes.plot( time , altitude , line_style ) - axes.set_ylabel('Altitude (ft)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , sfc , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('sfc (lb/lbf-hr)',axis_font) - axes.grid(True) + # Drag Components + plot_drag_components(results, line_style) - axes = fig.add_subplot(3,1,2) - axes.plot( time , mass , 'ro-' ) - axes.set_ylabel('Weight (lb)',axis_font) - axes.grid(True) - plt.show(block=True) + # Plot Altitude, sfc, vehicle weight + plot_altitude_sfc_weight(results, line_style) return diff --git a/Regional_Jet_Optimization/Procedure.py b/Regional_Jet_Optimization/Procedure.py index f5315d7..fcd7967 100644 --- a/Regional_Jet_Optimization/Procedure.py +++ b/Regional_Jet_Optimization/Procedure.py @@ -144,41 +144,49 @@ def simple_sizing(nexus): # Landing Configuration # ------------------------------------------------------------------ landing = nexus.vehicle_configurations.landing - landing_conditions = Data() - landing_conditions.freestream = Data() + state = Data() + state.conditions = Data() + state.conditions.freestream = Data() # landing weight landing.mass_properties.landing = 0.85 * config.mass_properties.takeoff # Landing CL_max - altitude = nexus.missions.base.segments[-1].altitude_end - atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976() - freestream_landing = atmosphere.compute_values(0.) - landing_conditions.freestream.velocity = nexus.missions.base.segments['descent_3'].air_speed - landing_conditions.freestream.density = freestream_landing.density - landing_conditions.freestream.dynamic_viscosity = freestream_landing.dynamic_viscosity - CL_max_landing,CDi = compute_max_lift_coeff(landing,landing_conditions) - landing.maximum_lift_coefficient = CL_max_landing + altitude = nexus.missions.base.segments[-1].altitude_end + atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976() + p, T, rho, a, mu = atmosphere.compute_values(altitude) + state.conditions.freestream.velocity = nexus.missions.base.segments['descent_3'].air_speed + state.conditions.freestream.density = rho + state.conditions.freestream.dynamic_viscosity = mu/rho + settings = Data() + settings.maximum_lift_coefficient_factor = 1.0 + CL_max_landing, CDi = compute_max_lift_coeff(state,settings,landing) + landing.maximum_lift_coefficient = CL_max_landing - #Takeoff CL_max - takeoff = nexus.vehicle_configurations.takeoff - takeoff_conditions = Data() - takeoff_conditions.freestream = Data() - altitude = nexus.missions.base.airport.altitude - freestream_takeoff = atmosphere.compute_values(altitude) - - takeoff_conditions.freestream.velocity = nexus.missions.base.segments.climb_1.air_speed - takeoff_conditions.freestream.density = freestream_takeoff.density - takeoff_conditions.freestream.dynamic_viscosity = freestream_takeoff.dynamic_viscosity - max_CL_takeoff, CDi = compute_max_lift_coeff(takeoff,takeoff_conditions) - takeoff.maximum_lift_coefficient = max_CL_takeoff + #Takeoff CL_max + takeoff = nexus.vehicle_configurations.takeoff + altitude = nexus.missions.base.airport.altitude + atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976() + p, T, rho, a, mu = atmosphere.compute_values(altitude) + state.conditions.freestream.velocity = nexus.missions.base.segments.climb_1.air_speed + state.conditions.freestream.density = rho + state.conditions.freestream.dynamic_viscosity = mu/rho + settings.maximum_lift_coefficient_factor = 1.0 + max_CL_takeoff,CDi = compute_max_lift_coeff(state,settings,takeoff) + takeoff.maximum_lift_coefficient = max_CL_takeoff + #Base config CL_max - base = nexus.vehicle_configurations.base - base_conditions = Data() - base_conditions.freestream = takeoff_conditions.freestream - max_CL_base, CDi = compute_max_lift_coeff(base,base_conditions) - base.maximum_lift_coefficient = max_CL_base + base = nexus.vehicle_configurations.base + altitude = nexus.missions.base.airport.altitude + atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976() + p, T, rho, a, mu = atmosphere.compute_values(altitude) + state.conditions.freestream.velocity = nexus.missions.base.segments.climb_1.air_speed + state.conditions.freestream.density = rho + state.conditions.freestream.dynamic_viscosity = mu/rho + settings.maximum_lift_coefficient_factor = 1.0 + max_CL_base,CDi = compute_max_lift_coeff(state,settings,landing) + base.maximum_lift_coefficient = max_CL_base return nexus @@ -197,8 +205,6 @@ def weight(nexus): weights = nexus.analyses.takeoff.weights.evaluate() weights = nexus.analyses.short_field_takeoff.weights.evaluate() - empty_weight = vehicle.mass_properties.operating_empty - passenger_weight = vehicle.passenger_weights.mass_properties.mass for config in nexus.vehicle_configurations: config.mass_properties.zero_fuel_center_of_gravity = vehicle.mass_properties.zero_fuel_center_of_gravity config.fuel = vehicle.fuel @@ -247,7 +253,7 @@ def post_process(nexus): # Fuel margin and base fuel calculations operating_empty = vehicle.mass_properties.operating_empty - payload = vehicle.passenger_weights.mass_properties.mass + payload = vehicle.mass_properties.breakdown.payload design_landing_weight = results.base.segments[-1].conditions.weights.total_mass[-1] design_takeoff_weight = vehicle.mass_properties.takeoff max_takeoff_weight = nexus.vehicle_configurations.takeoff.mass_properties.max_takeoff diff --git a/Regional_Jet_Optimization/Vehicles.py b/Regional_Jet_Optimization/Vehicles.py index d2ddcf9..efc7bf6 100644 --- a/Regional_Jet_Optimization/Vehicles.py +++ b/Regional_Jet_Optimization/Vehicles.py @@ -47,18 +47,19 @@ def base_setup(): vehicle.mass_properties.max_fuel = 12971. # kg vehicle.mass_properties.cargo = 0.0 # kg - vehicle.mass_properties.center_of_gravity = [16.8, 0, 1.6]#[[60 * Units.feet, 0, 0]] # Not correct - vehicle.mass_properties.moments_of_inertia.tensor = [[10 ** 5, 0, 0],[0, 10 ** 6, 0,],[0,0, 10 ** 7]] # Not Correct + vehicle.mass_properties.center_of_gravity = [[16.8, 0, 1.6]] + vehicle.mass_properties.moments_of_inertia.tensor = [[10 ** 5, 0, 0],[0, 10 ** 6, 0,],[0,0, 10 ** 7]] # envelope properties - vehicle.envelope.ultimate_load = 3.5 - vehicle.envelope.limit_load = 1.5 - - # basic parameters - vehicle.reference_area = 92. - vehicle.passengers = 114 - vehicle.systems.control = "fully powered" - vehicle.systems.accessories = "medium range" + vehicle.envelope.ultimate_load = 3.5 + vehicle.envelope.limit_load = 1.5 + + # basic parameters + vehicle.reference_area = 92. + vehicle.passengers = 106 + vehicle.systems.control = "fully powered" + vehicle.systems.accessories = "medium range" + # ------------------------------------------------------------------ # Main Wing @@ -67,16 +68,21 @@ def base_setup(): wing.tag = 'main_wing' wing.areas.reference = 92.0 wing.aspect_ratio = 8.4 - wing.chords.root = 5.17 + wing.chords.root = 6.2 wing.chords.tip = 1.44 wing.sweeps.quarter_chord = 23.0 * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.28 - wing.dihedral = 5.00 - wing.origin = [13,0,0] + wing.dihedral = 5.00 * Units.deg + wing.spans.projected = 28.72 + wing.origin = [[13.0,0,-1.50]] wing.vertical = False wing.symmetric = True wing.high_lift = True + wing.areas.exposed = 0.80 * wing.areas.wetted + wing.twists.root = 2.0 * Units.degrees + wing.twists.tip = 0.0 * Units.degrees + wing.dynamic_pressure_ratio = 1.0 # control surfaces ------------------------------------------- flap = SUAVE.Components.Wings.Control_Surfaces.Flap() @@ -93,7 +99,7 @@ def base_setup(): slat.span_fraction_start = 0.324 slat.span_fraction_end = 0.963 slat.deflection = 1.0 * Units.deg - slat.chord_fraction = 0.1 + slat.chord_fraction = 0.1 wing.append_control_surface(slat) wing = wing_planform(wing) @@ -101,23 +107,24 @@ def base_setup(): wing.areas.exposed = 0.80 * wing.areas.wetted wing.twists.root = 2.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.span_efficiency = 1.0 wing.dynamic_pressure_ratio = 1.0 + # add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Horizontal Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + + wing = SUAVE.Components.Wings.Horizontal_Tail() wing.tag = 'horizontal_stabilizer' wing.areas.reference = 26.0 wing.aspect_ratio = 5.5 wing.sweeps.quarter_chord = 34.5 * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.11 - wing.dihedral = 8.00 - wing.origin = [32,0,0] + wing.dihedral = 8.4 * Units.degrees + wing.origin = [[31,0,0.44]] wing.vertical = False wing.symmetric = True wing.high_lift = False @@ -125,7 +132,6 @@ def base_setup(): wing.areas.exposed = 0.9 * wing.areas.wetted wing.twists.root = 2.0 * Units.degrees wing.twists.tip = 2.0 * Units.degrees - wing.span_efficiency = 0.90 wing.dynamic_pressure_ratio = 0.90 # add to vehicle @@ -134,15 +140,16 @@ def base_setup(): # ------------------------------------------------------------------ # Vertical Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() - wing.tag = 'vertical_stabilizer' + + wing = SUAVE.Components.Wings.Vertical_Tail() + wing.tag = 'vertical_stabilizer' wing.areas.reference = 16.0 wing.aspect_ratio = 1.7 wing.sweeps.quarter_chord = 35. * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.31 wing.dihedral = 0.00 - wing.origin = [32,0,0] + wing.origin = [[30.4,0,1.675]] wing.vertical = True wing.symmetric = False wing.high_lift = False @@ -150,7 +157,6 @@ def base_setup(): wing.areas.exposed = 0.9 * wing.areas.wetted wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.span_efficiency = 0.90 wing.dynamic_pressure_ratio = 1.00 # add to vehicle @@ -160,30 +166,37 @@ def base_setup(): # Fuselage # ------------------------------------------------------------------ - fuselage = SUAVE.Components.Fuselages.Fuselage() - fuselage.tag = 'fuselage' - fuselage.origin = [[0,0,0]] - fuselage.number_coach_seats = vehicle.passengers - fuselage.seats_abreast = 4 - fuselage.seat_pitch = 0.7455 - fuselage.fineness.nose = 2.0 - fuselage.fineness.tail = 3.0 - fuselage.lengths.nose = 6.0 - fuselage.lengths.tail = 9.0 - fuselage.lengths.cabin = 21.24 - fuselage.lengths.total = 36.24 - fuselage.lengths.fore_space = 0. - fuselage.lengths.aft_space = 0. - fuselage.width = 3.18 - fuselage.heights.maximum = 4.18 - fuselage.heights.at_quarter_length = 3.18 - fuselage.heights.at_three_quarters_length = 3.18 - fuselage.heights.at_wing_root_quarter_chord = 4.00 - fuselage.areas.side_projected = 239.20 - fuselage.areas.wetted = 327.01 - fuselage.areas.front_projected = 8.0110 - fuselage.effective_diameter = 3.18 - fuselage.differential_pressure = 10**5 * Units.pascal # Maximum differential pressure + fuselage = SUAVE.Components.Fuselages.Fuselage() + fuselage.tag = 'fuselage' + fuselage.origin = [[0,0,0]] + fuselage.number_coach_seats = vehicle.passengers + fuselage.seats_abreast = 4 + fuselage.seat_pitch = 30. * Units.inches + + fuselage.fineness.nose = 1.28 + fuselage.fineness.tail = 3.48 + + fuselage.lengths.nose = 6.0 + fuselage.lengths.tail = 9.0 + fuselage.lengths.cabin = 21.24 + fuselage.lengths.total = 36.24 + fuselage.lengths.fore_space = 0. + fuselage.lengths.aft_space = 0. + + fuselage.width = 3.01 * Units.meters + + fuselage.heights.maximum = 3.35 + fuselage.heights.at_quarter_length = 3.35 + fuselage.heights.at_three_quarters_length = 3.35 + fuselage.heights.at_wing_root_quarter_chord = 3.35 + + fuselage.areas.side_projected = 239.20 + fuselage.areas.wetted = 327.01 + fuselage.areas.front_projected = 8.0110 + + fuselage.effective_diameter = 3.18 + + fuselage.differential_pressure = 10**5 * Units.pascal # Maximum differential pressure # add to vehicle vehicle.append_component(fuselage) @@ -196,10 +209,13 @@ def base_setup(): #initialize the gas turbine network gt_engine = SUAVE.Components.Energy.Networks.Turbofan() gt_engine.tag = 'turbofan' + gt_engine.origin = [[12.0,4.38,-2.1],[12.0,-4.38,-2.1]] gt_engine.number_of_engines = 2.0 gt_engine.bypass_ratio = 5.4 gt_engine.engine_length = 2.71 gt_engine.nacelle_diameter = 2.05 + gt_engine.inlet_diameter = 2.0 + #compute engine areas) Amax = (np.pi/4.)*gt_engine.nacelle_diameter**2. Awet = 1.1*np.pi*gt_engine.nacelle_diameter*gt_engine.engine_length # 1.1 is simple coefficient @@ -207,6 +223,7 @@ def base_setup(): gt_engine.areas.wetted = Awet #set the working fluid for the network working_fluid = SUAVE.Attributes.Gases.Air() + #add working fluid to the network gt_engine.working_fluid = working_fluid @@ -323,7 +340,6 @@ def base_setup(): # ------------------------------------------------------------------ return vehicle - # ---------------------------------------------------------------------- # Define the Configurations diff --git a/Solar_UAV_Optimization/Analyses.py b/Solar_UAV_Optimization/Analyses.py index 3eda688..1888a95 100644 --- a/Solar_UAV_Optimization/Analyses.py +++ b/Solar_UAV_Optimization/Analyses.py @@ -45,7 +45,7 @@ def base(vehicle): # Weights # ------------------------------------------------------------------ weights = SUAVE.Analyses.Weights.Weights_UAV() - weights.settings.empty_weight_method = SUAVE.Methods.Weights.Correlations.UAV.empty + weights.settings.empty = SUAVE.Methods.Weights.Correlations.UAV.empty weights.vehicle = vehicle analyses.append(weights) diff --git a/Solar_UAV_Optimization/Optimize.py b/Solar_UAV_Optimization/Optimize.py index 7847a22..7d5ec5f 100644 --- a/Solar_UAV_Optimization/Optimize.py +++ b/Solar_UAV_Optimization/Optimize.py @@ -48,11 +48,11 @@ def setup(): # [ tag , initial, [lb,ub], scaling, units ] problem.inputs = np.array([ - [ 'wing_area' , 0.5, ( 0.1, 1.5 ), 0.5, Units.meter ], - [ 'aspect_ratio' , 10.0, ( 5.0, 20.0 ), 10.0, Units.less ], - [ 'dynamic_pressure', 125.0, ( 1.0, 2000.0 ), 125.0, Units.pascals ], - [ 'solar_ratio' , 0.0, ( 0.0, 0.97), 1.0, Units.less ], - [ 'kv' , 800.0, ( 10.0, 1500.0 ), 800.0, Units['rpm/volt']], + [ 'wing_area' , 0.62, ( 0.1, 1.5 ), 0.5, Units.meter ], + [ 'aspect_ratio' , 13.5, ( 5.0, 20.0 ), 10.0, Units.less ], + [ 'dynamic_pressure', 115.0, ( 1.0, 2000.0 ), 125.0, Units.pascals ], + [ 'solar_ratio' , 0.0, ( 0.0, 0.97), 1.0, Units.less ], + [ 'kv' , 900.0, ( 10.0, 1500.0 ), 800.0, Units['rpm/volt']], ]) # ------------------------------------------------------------------- @@ -86,9 +86,9 @@ def setup(): [ 'wing_area' ,['vehicle_configurations.*.wings.main_wing.areas.reference', 'vehicle_configurations.base.reference_area'] ], [ 'aspect_ratio' , 'vehicle_configurations.*.wings.main_wing.aspect_ratio' ], - [ 'kv' , 'vehicle_configurations.*.propulsors.network.motor.speed_constant' ], - [ 'battery_mass' , 'vehicle_configurations.base.propulsors.network.battery.mass_properties.mass'], - [ 'solar_ratio' , 'vehicle_configurations.*.propulsors.network.solar_panel.ratio' ], + [ 'kv' , 'vehicle_configurations.*.propulsors.solar_low_fidelity.motor.speed_constant' ], + [ 'battery_mass' , 'vehicle_configurations.base.propulsors.solar_low_fidelity.battery.mass_properties.mass'], + [ 'solar_ratio' , 'vehicle_configurations.*.propulsors.solar_low_fidelity.solar_panel.ratio' ], [ 'dynamic_pressure' , 'missions.mission.segments.cruise.dynamic_pressure' ], [ 'Nothing' , 'summary.nothing' ], [ 'energy_constraint', 'summary.energy_constraint' ], diff --git a/Solar_UAV_Optimization/Plot_Mission.py b/Solar_UAV_Optimization/Plot_Mission.py index 82a9906..9509f11 100644 --- a/Solar_UAV_Optimization/Plot_Mission.py +++ b/Solar_UAV_Optimization/Plot_Mission.py @@ -7,6 +7,7 @@ # Imports # ---------------------------------------------------------------------- +from SUAVE.Plots.Mission_Plots import * from SUAVE.Core import Units import pylab as plt @@ -15,57 +16,11 @@ # ---------------------------------------------------------------------- def plot_mission(results,line_style='bo-'): - axis_font = {'fontname':'Arial', 'size':'14'} + # Plot Solar Conditions + plot_solar_flux(results) - # ------------------------------------------------------------------ - # Battery Energy - # ------------------------------------------------------------------ - plt.figure("Battery Energy") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.battery_energy[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Battery Energy (J)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - plt.savefig("opt_battery_energy.png") - - # ------------------------------------------------------------------ - # Solar Flux - # ------------------------------------------------------------------ - plt.figure("Solar Flux") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.solar_flux[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Solar Flux ($W/m^{2}$)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - plt.savefig("opt_solar_flux.png") - - # ------------------------------------------------------------------ - # Battery Draw - # ------------------------------------------------------------------ - plt.figure("Battery Charging") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.battery_draw[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Battery Charging (Watts)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - plt.savefig("opt_battery_draw.png") - - plt.show() + # Plot Aircraft Electronics + plot_electronic_conditions(results) return diff --git a/Solar_UAV_Optimization/Procedure.py b/Solar_UAV_Optimization/Procedure.py index 9d78057..805546c 100644 --- a/Solar_UAV_Optimization/Procedure.py +++ b/Solar_UAV_Optimization/Procedure.py @@ -97,14 +97,14 @@ def simple_sizing(nexus): # Size solar panel area wing_area = vec.reference_area - spanel = vec.propulsors.network.solar_panel + spanel = vec.propulsors.solar_low_fidelity.solar_panel sratio = spanel.ratio solar_area = wing_area*sratio spanel.area = solar_area spanel.mass_properties.mass = solar_area*(0.60 * Units.kg) # Resize the motor - motor = vec.propulsors.network.motor + motor = vec.propulsors.solar_low_fidelity.motor motor = size_from_kv(motor) # diff the new data @@ -123,20 +123,20 @@ def weights_battery(nexus): config.weights.evaluate() vec = nexus.vehicle_configurations.base - payload = vec.propulsors.network.payload.mass_properties.mass - msolar = vec.propulsors.network.solar_panel.mass_properties.mass + payload = vec.propulsors.solar_low_fidelity.payload.mass_properties.mass + msolar = vec.propulsors.solar_low_fidelity.solar_panel.mass_properties.mass MTOW = vec.mass_properties.max_takeoff empty = vec.weight_breakdown.empty - mmotor = vec.propulsors.network.motor.mass_properties.mass + mmotor = vec.propulsors.solar_low_fidelity.motor.mass_properties.mass # Calculate battery mass batmass = MTOW - empty - payload - msolar -mmotor - bat = vec.propulsors.network.battery + bat = vec.propulsors.solar_low_fidelity.battery initialize_from_mass(bat,batmass) - vec.propulsors.network.battery.mass_properties.mass = batmass + vec.propulsors.solar_low_fidelity.battery.mass_properties.mass = batmass # Set Battery Charge - maxcharge = nexus.vehicle_configurations.base.propulsors.network.battery.max_energy + maxcharge = nexus.vehicle_configurations.base.propulsors.solar_low_fidelity.battery.max_energy charge = maxcharge nexus.missions.mission.segments.cruise.battery_energy = charge @@ -165,7 +165,7 @@ def post_process(nexus): res = nexus.results.mission.segments.cruise.conditions # Final Energy - maxcharge = vec.propulsors.network.battery.max_energy + maxcharge = vec.propulsors.solar_low_fidelity.battery.max_energy # Energy constraints, the battery doesn't go to zero anywhere, using a P norm p = 8. diff --git a/Solar_UAV_Optimization/Vehicles.py b/Solar_UAV_Optimization/Vehicles.py index 57bc234..6f5aa6e 100644 --- a/Solar_UAV_Optimization/Vehicles.py +++ b/Solar_UAV_Optimization/Vehicles.py @@ -66,7 +66,6 @@ def base_setup(): wing.high_lift = True wing.dynamic_pressure_ratio = 1.0 wing.chords.mean_aerodynamic = wing.areas.reference/wing.spans.projected - wing.span_efficiency = 0.98 wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees wing.highlift = False @@ -75,7 +74,7 @@ def base_setup(): wing.number_end_ribs = 2. wing.transition_x_upper = 0.6 wing.transition_x_lower = 1.0 - wing.origin = [3.0,0.0,0.0] + wing.origin = [[3.0,0.0,0.0]] # add to vehicle vehicle.append_component(wing) @@ -91,7 +90,6 @@ def base_setup(): wing.sweeps.quarter_chord = 0 * Units.deg wing.thickness_to_chord = 0.12 wing.taper = 1.0 - wing.span_efficiency = 0.95 wing.areas.reference = vehicle.reference_area * .15 wing.areas.wetted = 2.0 * wing.areas.reference wing.areas.exposed = 0.8 * wing.areas.wetted @@ -107,7 +105,7 @@ def base_setup(): wing.chords.root = wing.areas.reference/wing.spans.projected wing.chords.tip = wing.areas.reference/wing.spans.projected wing.chords.mean_aerodynamic = wing.areas.reference/wing.spans.projected - wing.origin = [10.,0.0,0.0] + wing.origin = [[10.,0.0,0.0]] # add to vehicle vehicle.append_component(wing) @@ -123,7 +121,6 @@ def base_setup(): wing.sweeps.quarter_chord = 0 * Units.deg wing.thickness_to_chord = 0.12 wing.taper = 1.0 - wing.span_efficiency = 0.97 wing.areas.reference = vehicle.reference_area * 0.1 wing.spans.projected = np.sqrt(wing.aspect_ratio*wing.areas.reference) @@ -135,7 +132,7 @@ def base_setup(): wing.areas.affected = 0.6 * wing.areas.wetted wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [10.,0.0,0.0] + wing.origin = [[10.,0.0,0.0]] wing.symmetric = True wing.vertical = True wing.t_tail = False @@ -204,7 +201,6 @@ def base_setup(): bat.mass_properties.mass = 5.0 * Units.kg bat.specific_energy = 250. *Units.Wh/Units.kg bat.resistance = 0.003 - bat.iters = 0 initialize_from_mass(bat,bat.mass_properties.mass) net.battery = bat diff --git a/tut_concorde.py b/tut_concorde.py index 7234d4c..39ae55b 100644 --- a/tut_concorde.py +++ b/tut_concorde.py @@ -13,6 +13,7 @@ import SUAVE from SUAVE.Core import Units, Data +from SUAVE.Plots.Mission_Plots import * from SUAVE.Methods.Propulsion.turbojet_sizing import turbojet_sizing import numpy as np @@ -98,7 +99,7 @@ def base_analysis(vehicle): # ------------------------------------------------------------------ # Weights - weights = SUAVE.Analyses.Weights.Weights_Tube_Wing() + weights = SUAVE.Analyses.Weights.Weights_Transport() weights.vehicle = vehicle analyses.append(weights) @@ -107,6 +108,8 @@ def base_analysis(vehicle): aerodynamics = SUAVE.Analyses.Aerodynamics.Supersonic_Zero() aerodynamics.geometry = vehicle aerodynamics.settings.drag_coefficient_increment = 0.0000 + aerodynamics.settings.span_efficiency = .8 + analyses.append(aerodynamics) # ------------------------------------------------------------------ @@ -177,7 +180,6 @@ def vehicle_setup(): wing.sweeps.quarter_chord = 59.5 * Units.deg wing.thickness_to_chord = 0.03 wing.taper = 0. - wing.span_efficiency = .8 wing.spans.projected = 25.6 * Units.meter wing.chords.root = 33.8 * Units.meter wing.total_length = 33.8 * Units.meter @@ -189,7 +191,7 @@ def vehicle_setup(): wing.areas.affected = .6 * wing.areas.reference wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [14,0,-.8] # meters + wing.origin = [[14,0,-.8]] # meters wing.aerodynamic_center = [35,0,0] # meters wing.vertical = False wing.symmetric = True @@ -212,7 +214,6 @@ def vehicle_setup(): wing.sweeps.quarter_chord = 60 * Units.deg wing.thickness_to_chord = 0.04 wing.taper = 0.14 - wing.span_efficiency = 0.9 wing.spans.projected = 6.0 * Units.meter wing.chords.root = 14.5 * Units.meter wing.total_length = 14.5 * Units.meter @@ -224,7 +225,7 @@ def vehicle_setup(): wing.areas.affected = 33.91 * Units['meter**2'] wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [42.,0,1.] # meters + wing.origin = [[42.,0,1.]] # meters wing.aerodynamic_center = [50,0,0] # meters wing.vertical = True wing.symmetric = False @@ -479,119 +480,23 @@ def configs_setup(vehicle): def plot_mission(results,line_style='bo-'): - axis_font = {'fontname':'Arial', 'size':'14'} - - # ------------------------------------------------------------------ - # Propulsion - # ------------------------------------------------------------------ - - fig = plt.figure("Propulsion",figsize=(8,6)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] /Units.lbf - eta = segment.conditions.propulsion.throttle[:,0] - - axes = fig.add_subplot(2,1,1) - axes.plot( time , Thrust , line_style ) - axes.set_ylabel('Thrust (lbf)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(2,1,2) - axes.plot( time , eta , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('eta (lb/lbf-hr)',axis_font) - axes.grid(True) - - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , line_style ) - axes.set_ylabel('Lift Coefficient',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , l_d , line_style ) - axes.set_ylabel('L/D',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , aoa , 'ro-' ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('AOA (deg)',axis_font) - axes.grid(True) - - # ------------------------------------------------------------------ - # Drag - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components",figsize=(8,10)) - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - if line_style == 'bo-': - axes.plot( time , cdp , 'ko-', label='CD parasite' ) - axes.plot( time , cdi , 'bo-', label='CD induced' ) - axes.plot( time , cdc , 'go-', label='CD compressibility' ) - axes.plot( time , cdm , 'yo-', label='CD miscellaneous' ) - axes.plot( time , cd , 'ro-', label='CD total' ) - if i == 0: - axes.legend(loc='upper center') - else: - axes.plot( time , cdp , line_style ) - axes.plot( time , cdi , line_style ) - axes.plot( time , cdc , line_style ) - axes.plot( time , cdm , line_style ) - axes.plot( time , cd , line_style ) - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - - # ------------------------------------------------------------------ - # Altitude, Vehicle Weight, Mach Number - # ------------------------------------------------------------------ - - fig = plt.figure("Altitude_sfc_weight",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - mass = segment.conditions.weights.total_mass[:,0] / Units.lb - altitude = segment.conditions.freestream.altitude[:,0] / Units.feet - mach = segment.conditions.freestream.mach_number[:,0] - - axes = fig.add_subplot(3,1,1) - axes.plot( time , altitude , line_style ) - axes.set_ylabel('Altitude (ft)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , mass , 'ro-' ) - axes.set_ylabel('Weight (lb)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , mach , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Mach Number',axis_font) - axes.grid(True) + # Plot Flight Conditions + plot_flight_conditions(results, line_style) + + # Plot Aerodynamic Forces + plot_aerodynamic_forces(results, line_style) + + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results, line_style) + + # Drag Components + plot_drag_components(results, line_style) + + # Plot Altitude, sfc, vehicle weight + plot_altitude_sfc_weight(results, line_style) + + # Plot Velocities + plot_aircraft_velocities(results, line_style) return diff --git a/tut_mission_B737.py b/tut_mission_B737.py index 49c7049..87a5e70 100644 --- a/tut_mission_B737.py +++ b/tut_mission_B737.py @@ -8,62 +8,65 @@ # Imports # ---------------------------------------------------------------------- -# Python Imports +# General Python Imports import numpy as np -import pylab as plt +# Numpy is a commonly used mathematically computing package. It contains many frequently used +# mathematical functions and is faster than native Python, especially when using vectorized +# quantities. +import matplotlib.pyplot as plt +# Matplotlib's pyplot can be used to generate a large variety of plots. Here it is used to create +# visualizations of the aircraft's performance throughout the mission. # SUAVE Imports import SUAVE from SUAVE.Core import Data, Units +# The Data import here is a native SUAVE data structure that functions similarly to a dictionary. +# However, iteration directly returns values, and values can be retrieved either with the +# typical dictionary syntax of "entry['key']" or the more class-like "entry.key". For this to work +# properly, all keys must be strings. +# The Units import is used to allow units to be specified in the vehicle setup (or elsewhere). +# This is because SUAVE functions generally operate using metric units, so inputs must be +# converted. To use a length of 20 feet, set l = 20 * Units.ft . Additionally, to convert to SUAVE +# output back to a desired units, use l_ft = l_m / Units.ft +from SUAVE.Plots.Mission_Plots import * +# These are a variety of plotting routines that simplify the plotting process for commonly +# requested metrics. Plots of specifically desired metrics can also be manually created. from SUAVE.Methods.Propulsion.turbofan_sizing import turbofan_sizing -from SUAVE.Methods.Geometry.Two_Dimensional.Cross_Section.Propulsion import compute_turbofan_geometry -from SUAVE.Input_Output.Results import print_parasite_drag, \ - print_compress_drag, \ - print_engine_data, \ - print_mission_breakdown, \ - print_weight_breakdown +# Rather than conventional sizing, this script builds the turbofan energy network. This process is +# covered in more detail in a separate tutorial. It does not size the turbofan geometry. + + +# Python Imports +import numpy as np +import matplotlib.pyplot as plt # ---------------------------------------------------------------------- # Main # ---------------------------------------------------------------------- def main(): - + """This function gets the vehicle configuration, analysis settings, and then runs the mission. + Once the mission is complete, the results are plotted.""" + + # Extract vehicle configurations and the analysis settings that go with them configs, analyses = full_setup() + # Size each of the configurations according to a given set of geometry relations simple_sizing(configs) + # Perform operations needed to make the configurations and analyses usable in the mission configs.finalize() analyses.finalize() - # weight analysis + # Determine the vehicle weight breakdown (independent of mission fuel usage) weights = analyses.configs.base.weights breakdown = weights.evaluate() - # mission analysis + # Performance a mission analysis mission = analyses.missions.base results = mission.evaluate() - ## print weight breakdown - #print_weight_breakdown(configs.base,filename = 'B737_weight_breakdown.dat') - - ## print engine data into file - #print_engine_data(configs.base,filename = 'B737_engine_data.dat') - - ## print parasite drag data into file - ## define reference condition for parasite drag - #ref_condition = Data() - #ref_condition.mach_number = 0.3 - #ref_condition.reynolds_number = 12e6 - #print_parasite_drag(ref_condition,configs.cruise,analyses,'B737_parasite_drag.dat') - - ## print compressibility drag data into file - #print_compress_drag(configs.cruise,analyses,filename = 'B737_compress_drag.dat') - - ## print mission breakdown - #print_mission_breakdown(results,filename='B737_mission_breakdown.dat') - - # plt the old results + # Plot all mission results, including items such as altitude profile and L/D plot_mission(results) return @@ -73,18 +76,21 @@ def main(): # ---------------------------------------------------------------------- def full_setup(): + """This function gets the baseline vehicle and creates modifications for different + configurations, as well as the mission and analyses to go with those configurations.""" - # vehicle data + # Collect baseline vehicle data and changes when using different configuration settings vehicle = vehicle_setup() configs = configs_setup(vehicle) - # vehicle analyses + # Get the analyses to be used when different configurations are evaluated configs_analyses = analyses_setup(configs) - # mission analyses + # Create the mission that will be flown mission = mission_setup(configs_analyses) missions_analyses = missions_setup(mission) + # Add the analyses to the proper containers analyses = SUAVE.Analyses.Analysis.Container() analyses.configs = configs_analyses analyses.missions = missions_analyses @@ -96,10 +102,12 @@ def full_setup(): # ---------------------------------------------------------------------- def analyses_setup(configs): + """Set up analyses for each of the different configurations.""" analyses = SUAVE.Analyses.Analysis.Container() - # build a base analysis for each config + # Build a base analysis for each configuration. Here the base analysis is always used, but + # this can be modified if desired for other cases. for tag,config in configs.items(): analysis = base_analysis(config) analyses[tag] = analysis @@ -107,21 +115,17 @@ def analyses_setup(configs): return analyses def base_analysis(vehicle): + """This is the baseline set of analyses to be used with this vehicle. Of these, the most + commonly changed are the weights and aerodynamics methods.""" # ------------------------------------------------------------------ # Initialize the Analyses # ------------------------------------------------------------------ analyses = SUAVE.Analyses.Vehicle() - # ------------------------------------------------------------------ - # Basic Geometry Relations - sizing = SUAVE.Analyses.Sizing.Sizing() - sizing.features.vehicle = vehicle - analyses.append(sizing) - # ------------------------------------------------------------------ # Weights - weights = SUAVE.Analyses.Weights.Weights_Tube_Wing() + weights = SUAVE.Analyses.Weights.Weights_Transport() weights.vehicle = vehicle analyses.append(weights) @@ -161,6 +165,8 @@ def base_analysis(vehicle): # ---------------------------------------------------------------------- def vehicle_setup(): + """This is the full physical definition of the vehicle, and is designed to be independent of the + analyses that are selected.""" # ------------------------------------------------------------------ # Initialize the Vehicle @@ -173,28 +179,40 @@ def vehicle_setup(): # Vehicle-level Properties # ------------------------------------------------------------------ - # mass properties + # Vehicle level mass properties + # The maximum takeoff gross weight is used by a number of methods, most notably the weight + # method. However, it does not directly inform mission analysis. vehicle.mass_properties.max_takeoff = 79015.8 * Units.kilogram + # The takeoff weight is used to determine the weight of the vehicle at the start of the mission vehicle.mass_properties.takeoff = 79015.8 * Units.kilogram + # Operating empty may be used by various weight methods or other methods. Importantly, it does + # not constrain the mission analysis directly, meaning that the vehicle weight in a mission + # can drop below this value if more fuel is needed than is available. vehicle.mass_properties.operating_empty = 62746.4 * Units.kilogram - vehicle.mass_properties.takeoff = 79015.8 * Units.kilogram - vehicle.mass_properties.max_zero_fuel = 62732.0 * Units.kilogram + # The maximum zero fuel weight is also used by methods such as weights + vehicle.mass_properties.max_zero_fuel = 62732.0 * Units.kilogram + # Cargo weight typically feeds directly into weights output and does not affect the mission vehicle.mass_properties.cargo = 10000. * Units.kilogram - # envelope properties - vehicle.envelope.ultimate_load = 2.5 - vehicle.envelope.limit_load = 1.5 + # Envelope properties + # These values are typical FAR values for a transport of this type + vehicle.envelope.ultimate_load = 3.75 + vehicle.envelope.limit_load = 2.5 - # basic parameters + # Vehicle level parameters + # The vehicle reference area typically matches the main wing reference area vehicle.reference_area = 124.862 * Units['meters**2'] + # Number of passengers, control settings, and accessories settings are used by the weights + # methods vehicle.passengers = 170 vehicle.systems.control = "fully powered" vehicle.systems.accessories = "medium range" # ------------------------------------------------------------------ # Landing Gear - # ------------------------------------------------------------------ - # used for noise calculations + # ------------------------------------------------------------------ + + # The settings here can be used for noise analysis, but are not used in this tutorial landing_gear = SUAVE.Components.Landing_Gear.Landing_Gear() landing_gear.tag = "main_landing_gear" @@ -202,24 +220,35 @@ def vehicle_setup(): landing_gear.nose_tire_diameter = 0.6858 * Units.m landing_gear.main_strut_length = 1.8 * Units.m landing_gear.nose_strut_length = 1.3 * Units.m - landing_gear.main_units = 2 #number of main landing gear units - landing_gear.nose_units = 1 #number of nose landing gear - landing_gear.main_wheels = 2 #number of wheels on the main landing gear - landing_gear.nose_wheels = 2 #number of wheels on the nose landing gear + landing_gear.main_units = 2 # Number of main landing gear + landing_gear.nose_units = 1 # Number of nose landing gear + landing_gear.main_wheels = 2 # Number of wheels on the main landing gear + landing_gear.nose_wheels = 2 # Number of wheels on the nose landing gear vehicle.landing_gear = landing_gear # ------------------------------------------------------------------ # Main Wing # ------------------------------------------------------------------ + # This main wing is approximated as a simple trapezoid. A segmented wing can also be created if + # desired. Segmented wings appear in later tutorials, and a version of the 737 with segmented + # wings can be found in the SUAVE testing scripts. + + # SUAVE allows conflicting geometric values to be set in terms of items such as aspect ratio + # when compared with span and reference area. Sizing scripts may be used to enforce + # consistency if desired. + wing = SUAVE.Components.Wings.Main_Wing() wing.tag = 'main_wing' wing.aspect_ratio = 10.18 + # Quarter chord sweep is used as the driving sweep in most of the low fidelity analysis methods. + # If a different known value (such as leading edge sweep) is given, it should be converted to + # quarter chord sweep and added here. In some cases leading edge sweep will be used directly as + # well, and can be entered here too. wing.sweeps.quarter_chord = 25 * Units.deg wing.thickness_to_chord = 0.1 wing.taper = 0.1 - wing.span_efficiency = 0.9 wing.spans.projected = 34.32 * Units.meter wing.chords.root = 7.760 * Units.meter wing.chords.tip = 0.782 * Units.meter @@ -227,21 +256,29 @@ def vehicle_setup(): wing.areas.reference = 124.862 * Units['meters**2'] wing.twists.root = 4.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [13.61,0,-1.27] # meters + wing.origin = [[13.61 * Units.meter, 0, -1.27 * Units.meter]] wing.vertical = False wing.symmetric = True + # The high lift flag controls aspects of maximum lift coefficient calculations wing.high_lift = True + # The dynamic pressure ratio is used in stability calculations wing.dynamic_pressure_ratio = 1.0 # ------------------------------------------------------------------ - # Flaps + # Main Wing Control Surfaces # ------------------------------------------------------------------ + # Information in this section is used for high lift calculations and when conversion to AVL + # is desired. + + # Deflections will typically be specified separately in individual vehicle configurations. + flap = SUAVE.Components.Wings.Control_Surfaces.Flap() flap.tag = 'flap' - flap.span_fraction_start = 0.10 - flap.span_fraction_end = 0.75 + flap.span_fraction_start = 0.20 + flap.span_fraction_end = 0.70 flap.deflection = 0.0 * Units.degrees + # Flap configuration types are used in computing maximum CL and noise flap.configuration_type = 'double_slotted' flap.chord_fraction = 0.30 wing.append_control_surface(flap) @@ -262,48 +299,46 @@ def vehicle_setup(): aileron.chord_fraction = 0.16 wing.append_control_surface(aileron) - # add to vehicle + # Add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Horizontal Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Horizontal_Tail() wing.tag = 'horizontal_stabilizer' wing.aspect_ratio = 6.16 wing.sweeps.quarter_chord = 40 * Units.deg wing.thickness_to_chord = 0.08 wing.taper = 0.2 - wing.span_efficiency = 0.9 wing.spans.projected = 14.2 * Units.meter wing.chords.root = 4.7 * Units.meter wing.chords.tip = .955 * Units.meter - wing.chords.mean_aerodynamic = 8.0 * Units.meter + wing.chords.mean_aerodynamic = 3.0 * Units.meter wing.areas.reference = 32.488 * Units['meters**2'] wing.twists.root = 3.0 * Units.degrees wing.twists.tip = 3.0 * Units.degrees - wing.origin = [32.83,0,1.14] # meters + wing.origin = [[32.83 * Units.meter, 0 , 1.14 * Units.meter]] wing.vertical = False wing.symmetric = True wing.dynamic_pressure_ratio = 0.9 - # add to vehicle + # Add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Vertical Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Vertical_Tail() wing.tag = 'vertical_stabilizer' wing.aspect_ratio = 1.91 wing.sweeps.quarter_chord = 25. * Units.deg wing.thickness_to_chord = 0.08 wing.taper = 0.25 - wing.span_efficiency = 0.9 wing.spans.projected = 7.777 * Units.meter wing.chords.root = 8.19 * Units.meter wing.chords.tip = 0.95 * Units.meter @@ -311,13 +346,14 @@ def vehicle_setup(): wing.areas.reference = 27.316 * Units['meters**2'] wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [28.79,0,1.54] # meters + wing.origin = [[28.79 * Units.meter, 0, 1.54 * Units.meter]] # meters wing.vertical = True wing.symmetric = False + # The t tail flag is used in weights calculations wing.t_tail = False wing.dynamic_pressure_ratio = 1.0 - # add to vehicle + # Add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ @@ -327,15 +363,22 @@ def vehicle_setup(): fuselage = SUAVE.Components.Fuselages.Fuselage() fuselage.tag = 'fuselage' + # Number of coach seats is used in some weights methods fuselage.number_coach_seats = vehicle.passengers + # The seats abreast can be used along with seat pitch and the number of coach seats to + # determine the length of the cabin if desired. fuselage.seats_abreast = 6 fuselage.seat_pitch = 1 * Units.meter + # Fineness ratios are used to determine VLM fuselage shape and sections to use in OpenVSP + # output fuselage.fineness.nose = 1.6 fuselage.fineness.tail = 2. + # Nose and tail lengths are used in the VLM setup fuselage.lengths.nose = 6.4 * Units.meter fuselage.lengths.tail = 8.0 * Units.meter - fuselage.lengths.cabin = 28.85 * Units.meter fuselage.lengths.total = 38.02 * Units.meter + # Fore and aft space are added to the cabin length if the fuselage is sized based on + # number of seats fuselage.lengths.fore_space = 6. * Units.meter fuselage.lengths.aft_space = 5. * Units.meter fuselage.width = 3.74 * Units.meter @@ -344,8 +387,11 @@ def vehicle_setup(): fuselage.areas.side_projected = 142.1948 * Units['meters**2'] fuselage.areas.wetted = 446.718 * Units['meters**2'] fuselage.areas.front_projected = 12.57 * Units['meters**2'] - fuselage.differential_pressure = 5.0e4 * Units.pascal # Maximum differential pressure + # Maximum differential pressure between the cabin and the atmosphere + fuselage.differential_pressure = 5.0e4 * Units.pascal + # Heights at different longitudinal locations are used in stability calculations and + # in output to OpenVSP fuselage.heights.at_quarter_length = 3.74 * Units.meter fuselage.heights.at_three_quarters_length = 3.65 * Units.meter fuselage.heights.at_wing_root_quarter_chord = 3.74 * Units.meter @@ -357,28 +403,32 @@ def vehicle_setup(): # Turbofan Network # ------------------------------------------------------------------ - #instantiate the gas turbine network turbofan = SUAVE.Components.Energy.Networks.Turbofan() + # For some methods, the 'turbofan' tag is still necessary. This will be changed in the + # future to allow arbitrary tags. turbofan.tag = 'turbofan' - # setup + # High-level setup turbofan.number_of_engines = 2 turbofan.bypass_ratio = 5.4 turbofan.engine_length = 2.71 * Units.meter turbofan.nacelle_diameter = 2.05 * Units.meter - turbofan.origin = [[13.72, 4.86,-1.9],[13.72, -4.86,-1.9]] # meters + turbofan.origin = [[13.72, 4.86,-1.9],[13.72, -4.86,-1.9]] - #compute engine areas + # Approximate the wetted area turbofan.areas.wetted = 1.1*np.pi*turbofan.nacelle_diameter*turbofan.engine_length - # working fluid + # Establish the correct working fluid turbofan.working_fluid = SUAVE.Attributes.Gases.Air() + + # Components use estimated efficiencies. Estimates by technology level can be + # found in textbooks such as those by J.D. Mattingly + # ------------------------------------------------------------------ # Component 1 - Ram - # to convert freestream static to stagnation quantities - # instantiate + # Converts freestream static to stagnation quantities ram = SUAVE.Components.Energy.Converters.Ram() ram.tag = 'ram' @@ -388,129 +438,130 @@ def vehicle_setup(): # ------------------------------------------------------------------ # Component 2 - Inlet Nozzle - # instantiate + # Create component inlet_nozzle = SUAVE.Components.Energy.Converters.Compression_Nozzle() inlet_nozzle.tag = 'inlet_nozzle' - # setup + # Specify performance inlet_nozzle.polytropic_efficiency = 0.98 inlet_nozzle.pressure_ratio = 0.98 - # add to network + # Add to network turbofan.append(inlet_nozzle) # ------------------------------------------------------------------ # Component 3 - Low Pressure Compressor - # instantiate + # Create component compressor = SUAVE.Components.Energy.Converters.Compressor() compressor.tag = 'low_pressure_compressor' - # setup + # Specify performance compressor.polytropic_efficiency = 0.91 compressor.pressure_ratio = 1.14 - # add to network + # Add to network turbofan.append(compressor) # ------------------------------------------------------------------ # Component 4 - High Pressure Compressor - # instantiate + # Create component compressor = SUAVE.Components.Energy.Converters.Compressor() compressor.tag = 'high_pressure_compressor' - # setup + # Specify performance compressor.polytropic_efficiency = 0.91 compressor.pressure_ratio = 13.415 - # add to network + # Add to network turbofan.append(compressor) # ------------------------------------------------------------------ # Component 5 - Low Pressure Turbine - # instantiate + # Create component turbine = SUAVE.Components.Energy.Converters.Turbine() turbine.tag='low_pressure_turbine' - # setup + # Specify performance turbine.mechanical_efficiency = 0.99 turbine.polytropic_efficiency = 0.93 - # add to network + # Add to network turbofan.append(turbine) # ------------------------------------------------------------------ # Component 6 - High Pressure Turbine - # instantiate + # Create component turbine = SUAVE.Components.Energy.Converters.Turbine() turbine.tag='high_pressure_turbine' - # setup + # Specify performance turbine.mechanical_efficiency = 0.99 turbine.polytropic_efficiency = 0.93 - # add to network + # Add to network turbofan.append(turbine) # ------------------------------------------------------------------ # Component 7 - Combustor - # instantiate + # Create component combustor = SUAVE.Components.Energy.Converters.Combustor() combustor.tag = 'combustor' - # setup + # Specify performance combustor.efficiency = 0.99 + combustor.alphac = 1.0 combustor.turbine_inlet_temperature = 1450 # K combustor.pressure_ratio = 0.95 combustor.fuel_data = SUAVE.Attributes.Propellants.Jet_A() - # add to network + # Add to network turbofan.append(combustor) # ------------------------------------------------------------------ # Component 8 - Core Nozzle - # instantiate + # Create component nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle() nozzle.tag = 'core_nozzle' - # setup + # Specify performance nozzle.polytropic_efficiency = 0.95 nozzle.pressure_ratio = 0.99 - # add to network + # Add to network turbofan.append(nozzle) # ------------------------------------------------------------------ # Component 9 - Fan Nozzle - # instantiate + # Create component nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle() nozzle.tag = 'fan_nozzle' - # setup + # Specify performance nozzle.polytropic_efficiency = 0.95 nozzle.pressure_ratio = 0.99 - # add to network + # Add to network turbofan.append(nozzle) # ------------------------------------------------------------------ # Component 10 - Fan - # instantiate + # Create component fan = SUAVE.Components.Energy.Converters.Fan() fan.tag = 'fan' - # setup + # Specify performance fan.polytropic_efficiency = 0.93 fan.pressure_ratio = 1.7 - # add to network + # Add to network turbofan.append(fan) # ------------------------------------------------------------------ @@ -518,22 +569,20 @@ def vehicle_setup(): thrust = SUAVE.Components.Energy.Processes.Thrust() thrust.tag ='compute_thrust' - #total design thrust (includes all the engines) + # Design thrust is used to determine mass flow at full throttle thrust.total_design = 2*24000. * Units.N #Newtons - #design sizing conditions + # Design sizing conditions are also used to determine mass flow altitude = 35000.0*Units.ft mach_number = 0.78 - isa_deviation = 0. - #Engine setup for noise module - # add to network + # Add to network turbofan.thrust = thrust - #size the turbofan + # Determine turbofan behavior at the design condition turbofan_sizing(turbofan,mach_number,altitude) - # add gas turbine network turbofan to the vehicle + # Add turbofan network to the vehicle vehicle.append_component(turbofan) # ------------------------------------------------------------------ @@ -547,6 +596,8 @@ def vehicle_setup(): # --------------------------------------------------------------------- def configs_setup(vehicle): + """This function sets up vehicle configurations for use in different parts of the mission. + Here, this is mostly in terms of high lift settings.""" # ------------------------------------------------------------------ # Initialize Configurations @@ -571,6 +622,7 @@ def configs_setup(vehicle): config.tag = 'takeoff' config.wings['main_wing'].control_surfaces.flap.deflection = 20. * Units.deg config.wings['main_wing'].control_surfaces.slat.deflection = 25. * Units.deg + # A max lift coefficient factor of 1 is the default, but it is highlighted here as an option config.max_lift_coefficient_factor = 1. configs.append(config) @@ -615,20 +667,24 @@ def configs_setup(vehicle): return configs def simple_sizing(configs): + """This function applies a few basic geometric sizing relations and modifies the landing + configuration.""" base = configs.base + # Update the baseline data structure to prepare for changes base.pull_base() - # zero fuel weight + # Revise the zero fuel weight. This will only affect the base configuration. To do all + # configurations, this should be specified in the top level vehicle definition. base.mass_properties.max_zero_fuel = 0.9 * base.mass_properties.max_takeoff - # wing areas + # Estimate wing areas for wing in base.wings: wing.areas.wetted = 2.0 * wing.areas.reference wing.areas.exposed = 0.8 * wing.areas.wetted wing.areas.affected = 0.6 * wing.areas.wetted - # diff the new data + # Store how the changes compare to the baseline configuration base.store_diff() # ------------------------------------------------------------------ @@ -636,13 +692,14 @@ def simple_sizing(configs): # ------------------------------------------------------------------ landing = configs.landing - # make sure base data is current + # Make sure base data is current landing.pull_base() - # landing weight + # Add a landing weight parameter. This is used in field length estimation and in + # initially the landing mission segment type. landing.mass_properties.landing = 0.85 * base.mass_properties.takeoff - # diff the new data + # Store how the changes compare to the baseline configuration landing.store_diff() return @@ -652,6 +709,8 @@ def simple_sizing(configs): # ---------------------------------------------------------------------- def mission_setup(analyses): + """This function defines the baseline mission that will be flown by the aircraft in order + to compute performance.""" # ------------------------------------------------------------------ # Initialize the Mission @@ -660,7 +719,9 @@ def mission_setup(analyses): mission = SUAVE.Analyses.Mission.Sequential_Segments() mission.tag = 'the_mission' - #airport + # Airport + # The airport parameters are used in calculating field length and noise. They are not + # directly used in mission performance estimation airport = SUAVE.Attributes.Airports.Airport() airport.altitude = 0.0 * Units.ft airport.delta_isa = 0.0 @@ -668,19 +729,27 @@ def mission_setup(analyses): mission.airport = airport - # unpack Segments module + # Unpack Segments module Segments = SUAVE.Analyses.Mission.Segments - # base segment + # Base segment base_segment = Segments.Segment() # ------------------------------------------------------------------ # First Climb Segment: Constant Speed, Constant Rate # ------------------------------------------------------------------ + # A constant speed, constant rate climb segment is used first. This means that the aircraft + # will maintain a constant airspeed and constant climb rate until it hits the end altitude. + # For this type of segment, the throttle is allowed to vary as needed to match required + # performance. segment = Segments.Climb.Constant_Speed_Constant_Rate(base_segment) + # It is important that all segment tags must be unique for proper evaluation. At the moment + # this is not automatically enforced. segment.tag = "climb_1" + # The analysis settings for mission segment are chosen here. These analyses include information + # on the vehicle configuration. segment.analyses.extend( analyses.takeoff ) segment.altitude_start = 0.0 * Units.km @@ -688,7 +757,7 @@ def mission_setup(analyses): segment.air_speed = 125.0 * Units['m/s'] segment.climb_rate = 6.0 * Units['m/s'] - # add to misison + # Add to misison mission.append_segment(segment) # ------------------------------------------------------------------ @@ -700,11 +769,14 @@ def mission_setup(analyses): segment.analyses.extend( analyses.cruise ) + # A starting altitude is no longer needed as it will automatically carry over from the + # previous segment. However, it could be specified if desired. This would potentially cause + # a jump in altitude but would otherwise not cause any problems. segment.altitude_end = 8.0 * Units.km segment.air_speed = 190.0 * Units['m/s'] segment.climb_rate = 6.0 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -720,7 +792,7 @@ def mission_setup(analyses): segment.air_speed = 226.0 * Units['m/s'] segment.climb_rate = 3.0 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -735,7 +807,7 @@ def mission_setup(analyses): segment.air_speed = 230.412 * Units['m/s'] segment.distance = 2490. * Units.nautical_miles - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -751,7 +823,7 @@ def mission_setup(analyses): segment.air_speed = 220.0 * Units['m/s'] segment.descent_rate = 4.5 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -767,7 +839,7 @@ def mission_setup(analyses): segment.air_speed = 195.0 * Units['m/s'] segment.descent_rate = 5.0 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -778,13 +850,16 @@ def mission_setup(analyses): segment.tag = "descent_3" segment.analyses.extend( analyses.landing ) + # While it is set to zero here and therefore unchanged, a drag increment can be used if + # desired. This can avoid negative throttle values if drag generated by the base airframe + # is insufficient for the desired descent speed and rate. analyses.landing.aerodynamics.settings.spoiler_drag_increment = 0.00 segment.altitude_end = 4.0 * Units.km segment.air_speed = 170.0 * Units['m/s'] segment.descent_rate = 5.0 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -801,7 +876,7 @@ def mission_setup(analyses): segment.air_speed = 150.0 * Units['m/s'] segment.descent_rate = 5.0 * Units['m/s'] - # add to mission + # Add to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -818,7 +893,7 @@ def mission_setup(analyses): segment.air_speed = 145.0 * Units['m/s'] segment.descent_rate = 3.0 * Units['m/s'] - # append to mission + # Append to mission mission.append_segment(segment) # ------------------------------------------------------------------ @@ -828,14 +903,16 @@ def mission_setup(analyses): return mission def missions_setup(base_mission): + """This allows multiple missions to be incorporated if desired, but only one is used here.""" - # the mission container + # Setup the mission container missions = SUAVE.Analyses.Mission.Mission.Container() # ------------------------------------------------------------------ # Base Mission # ------------------------------------------------------------------ + # Only one mission (the base mission) is defined in this case missions.base = base_mission return missions @@ -845,171 +922,31 @@ def missions_setup(base_mission): # ---------------------------------------------------------------------- def plot_mission(results,line_style='bo-'): + """This function plots the results of the mission analysis and saves those results to + png files.""" - axis_font = {'fontname':'Arial', 'size':'14'} - - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - - - fig = plt.figure("Aerodynamic Forces",figsize=(8,6)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lbf - eta = segment.conditions.propulsion.throttle[:,0] - - axes = fig.add_subplot(2,1,1) - axes.plot( time , Thrust , line_style ) - axes.set_ylabel('Thrust (lbf)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(2,1,2) - axes.plot( time , eta , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Throttle',axis_font) - axes.grid(True) - - plt.savefig("B737_engine.pdf") - plt.savefig("B737_engine.png") - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - l_d = CLift/CDrag - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , line_style ) - axes.set_ylabel('Lift Coefficient',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , l_d , line_style ) - axes.set_ylabel('L/D',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , aoa , 'ro-' ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('AOA (deg)',axis_font) - axes.grid(True) - - plt.savefig("B737_aero.pdf") - plt.savefig("B737_aero.png") - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components",figsize=(8,10)) - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - if line_style == 'bo-': - axes.plot( time , cdp , 'ko-', label='CD parasite' ) - axes.plot( time , cdi , 'bo-', label='CD induced' ) - axes.plot( time , cdc , 'go-', label='CD compressibility' ) - axes.plot( time , cdm , 'yo-', label='CD miscellaneous' ) - axes.plot( time , cd , 'ro-', label='CD total' ) - if i == 0: - axes.legend(loc='upper center') - else: - axes.plot( time , cdp , line_style ) - axes.plot( time , cdi , line_style ) - axes.plot( time , cdc , line_style ) - axes.plot( time , cdm , line_style ) - axes.plot( time , cd , line_style ) - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - plt.savefig("B737_drag.pdf") - plt.savefig("B737_drag.png") - - # ------------------------------------------------------------------ - # Altitude, sfc, vehicle weight - # ------------------------------------------------------------------ - - fig = plt.figure("Altitude_sfc_weight",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - mass = segment.conditions.weights.total_mass[:,0] / Units.lb - altitude = segment.conditions.freestream.altitude[:,0] / Units.ft - mdot = segment.conditions.weights.vehicle_mass_rate[:,0] - thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - sfc = (mdot / Units.lb) / (thrust /Units.lbf) * Units.hr - - axes = fig.add_subplot(3,1,1) - axes.plot( time , altitude , line_style ) - axes.set_ylabel('Altitude (ft)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , sfc , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('sfc (lb/lbf-hr)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , mass , 'ro-' ) - axes.set_ylabel('Weight (lb)',axis_font) - axes.grid(True) - - plt.savefig("B737_mission.pdf") - plt.savefig("B737_mission.png") - - # ------------------------------------------------------------------ - # Velocities - # ------------------------------------------------------------------ - fig = plt.figure("Velocities",figsize=(8,10)) - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Lift = -segment.conditions.frames.wind.lift_force_vector[:,2] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] / Units.lbf - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] / Units.lb - velocity = segment.conditions.freestream.velocity[:,0] - pressure = segment.conditions.freestream.pressure[:,0] - density = segment.conditions.freestream.density[:,0] - EAS = velocity * np.sqrt(density/1.225) - mach = segment.conditions.freestream.mach_number[:,0] - - axes = fig.add_subplot(3,1,1) - axes.plot( time , velocity / Units.kts, line_style ) - axes.set_ylabel('velocity (kts)',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , EAS / Units.kts, line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Equivalent Airspeed',axis_font) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , mach , line_style ) - axes.set_xlabel('Time (min)',axis_font) - axes.set_ylabel('Mach',axis_font) - axes.grid(True) + # Plot Flight Conditions + plot_flight_conditions(results, line_style) + + # Plot Aerodynamic Forces + plot_aerodynamic_forces(results, line_style) + + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results, line_style) + + # Drag Components + plot_drag_components(results, line_style) + + # Plot Altitude, sfc, vehicle weight + plot_altitude_sfc_weight(results, line_style) + + # Plot Velocities + plot_aircraft_velocities(results, line_style) return +# This section is needed to actually run the various functions in the file if __name__ == '__main__': main() + # The show commands makes the plots actually appear plt.show() \ No newline at end of file diff --git a/tut_payload_range.py b/tut_payload_range.py index 2d00f18..08eebb0 100644 --- a/tut_payload_range.py +++ b/tut_payload_range.py @@ -105,7 +105,7 @@ def base_analysis(vehicle): # ------------------------------------------------------------------ # Weights - weights = SUAVE.Analyses.Weights.Weights_Tube_Wing() + weights = SUAVE.Analyses.Weights.Weights_Transport() weights.vehicle = vehicle analyses.append(weights) @@ -166,18 +166,19 @@ def vehicle_setup(): vehicle.mass_properties.max_fuel = 12971. # kg vehicle.mass_properties.cargo = 0.0 # kg - vehicle.mass_properties.center_of_gravity = [16.8, 0, 1.6]#[[60 * Units.feet, 0, 0]] # Not correct - vehicle.mass_properties.moments_of_inertia.tensor = [[10 ** 5, 0, 0],[0, 10 ** 6, 0,],[0,0, 10 ** 7]] # Not Correct + vehicle.mass_properties.center_of_gravity = [[16.8, 0, 1.6]] + vehicle.mass_properties.moments_of_inertia.tensor = [[10 ** 5, 0, 0],[0, 10 ** 6, 0,],[0,0, 10 ** 7]] # envelope properties - vehicle.envelope.ultimate_load = 3.5 - vehicle.envelope.limit_load = 1.5 - - # basic parameters - vehicle.reference_area = 92. - vehicle.passengers = 114 - vehicle.systems.control = "fully powered" - vehicle.systems.accessories = "medium range" + vehicle.envelope.ultimate_load = 3.5 + vehicle.envelope.limit_load = 1.5 + + # basic parameters + vehicle.reference_area = 92. + vehicle.passengers = 106 + vehicle.systems.control = "fully powered" + vehicle.systems.accessories = "medium range" + # ------------------------------------------------------------------ # Main Wing @@ -186,16 +187,21 @@ def vehicle_setup(): wing.tag = 'main_wing' wing.areas.reference = 92.0 wing.aspect_ratio = 8.4 - wing.chords.root = 5.17 + wing.chords.root = 6.2 wing.chords.tip = 1.44 wing.sweeps.quarter_chord = 23.0 * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.28 - wing.dihedral = 5.00 - wing.origin = [13,0,0] + wing.dihedral = 5.00 * Units.deg + wing.spans.projected = 28.72 + wing.origin = [[13.0,0,-1.50]] wing.vertical = False wing.symmetric = True wing.high_lift = True + wing.areas.exposed = 0.80 * wing.areas.wetted + wing.twists.root = 2.0 * Units.degrees + wing.twists.tip = 0.0 * Units.degrees + wing.dynamic_pressure_ratio = 1.0 # control surfaces ------------------------------------------- flap = SUAVE.Components.Wings.Control_Surfaces.Flap() @@ -212,7 +218,7 @@ def vehicle_setup(): slat.span_fraction_start = 0.324 slat.span_fraction_end = 0.963 slat.deflection = 1.0 * Units.deg - slat.chord_fraction = 0.1 + slat.chord_fraction = 0.1 wing.append_control_surface(slat) wing = wing_planform(wing) @@ -220,23 +226,24 @@ def vehicle_setup(): wing.areas.exposed = 0.80 * wing.areas.wetted wing.twists.root = 2.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.span_efficiency = 1.0 wing.dynamic_pressure_ratio = 1.0 + # add to vehicle vehicle.append_component(wing) # ------------------------------------------------------------------ # Horizontal Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + + wing = SUAVE.Components.Wings.Horizontal_Tail() wing.tag = 'horizontal_stabilizer' wing.areas.reference = 26.0 wing.aspect_ratio = 5.5 wing.sweeps.quarter_chord = 34.5 * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.11 - wing.dihedral = 8.00 - wing.origin = [32,0,0] + wing.dihedral = 8.4 * Units.degrees + wing.origin = [[31,0,0.44]] wing.vertical = False wing.symmetric = True wing.high_lift = False @@ -244,7 +251,6 @@ def vehicle_setup(): wing.areas.exposed = 0.9 * wing.areas.wetted wing.twists.root = 2.0 * Units.degrees wing.twists.tip = 2.0 * Units.degrees - wing.span_efficiency = 0.90 wing.dynamic_pressure_ratio = 0.90 # add to vehicle @@ -253,15 +259,16 @@ def vehicle_setup(): # ------------------------------------------------------------------ # Vertical Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() - wing.tag = 'vertical_stabilizer' + + wing = SUAVE.Components.Wings.Vertical_Tail() + wing.tag = 'vertical_stabilizer' wing.areas.reference = 16.0 wing.aspect_ratio = 1.7 wing.sweeps.quarter_chord = 35. * Units.deg wing.thickness_to_chord = 0.11 wing.taper = 0.31 wing.dihedral = 0.00 - wing.origin = [32,0,0] + wing.origin = [[30.4,0,1.675]] wing.vertical = True wing.symmetric = False wing.high_lift = False @@ -269,7 +276,6 @@ def vehicle_setup(): wing.areas.exposed = 0.9 * wing.areas.wetted wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.span_efficiency = 0.90 wing.dynamic_pressure_ratio = 1.00 # add to vehicle @@ -279,30 +285,37 @@ def vehicle_setup(): # Fuselage # ------------------------------------------------------------------ - fuselage = SUAVE.Components.Fuselages.Fuselage() - fuselage.tag = 'fuselage' - fuselage.origin = [[0,0,0]] - fuselage.number_coach_seats = vehicle.passengers - fuselage.seats_abreast = 4 - fuselage.seat_pitch = 0.7455 - fuselage.fineness.nose = 2.0 - fuselage.fineness.tail = 3.0 - fuselage.lengths.nose = 6.0 - fuselage.lengths.tail = 9.0 - fuselage.lengths.cabin = 21.24 - fuselage.lengths.total = 36.24 - fuselage.lengths.fore_space = 0. - fuselage.lengths.aft_space = 0. - fuselage.width = 3.18 - fuselage.heights.maximum = 4.18 - fuselage.heights.at_quarter_length = 3.18 - fuselage.heights.at_three_quarters_length = 3.18 - fuselage.heights.at_wing_root_quarter_chord = 4.00 - fuselage.areas.side_projected = 239.20 - fuselage.areas.wetted = 327.01 - fuselage.areas.front_projected = 8.0110 - fuselage.effective_diameter = 3.18 - fuselage.differential_pressure = 10**5 * Units.pascal # Maximum differential pressure + fuselage = SUAVE.Components.Fuselages.Fuselage() + fuselage.tag = 'fuselage' + fuselage.origin = [[0,0,0]] + fuselage.number_coach_seats = vehicle.passengers + fuselage.seats_abreast = 4 + fuselage.seat_pitch = 30. * Units.inches + + fuselage.fineness.nose = 1.28 + fuselage.fineness.tail = 3.48 + + fuselage.lengths.nose = 6.0 + fuselage.lengths.tail = 9.0 + fuselage.lengths.cabin = 21.24 + fuselage.lengths.total = 36.24 + fuselage.lengths.fore_space = 0. + fuselage.lengths.aft_space = 0. + + fuselage.width = 3.01 * Units.meters + + fuselage.heights.maximum = 3.35 + fuselage.heights.at_quarter_length = 3.35 + fuselage.heights.at_three_quarters_length = 3.35 + fuselage.heights.at_wing_root_quarter_chord = 3.35 + + fuselage.areas.side_projected = 239.20 + fuselage.areas.wetted = 327.01 + fuselage.areas.front_projected = 8.0110 + + fuselage.effective_diameter = 3.18 + + fuselage.differential_pressure = 10**5 * Units.pascal # Maximum differential pressure # add to vehicle vehicle.append_component(fuselage) @@ -315,10 +328,13 @@ def vehicle_setup(): #initialize the gas turbine network gt_engine = SUAVE.Components.Energy.Networks.Turbofan() gt_engine.tag = 'turbofan' + gt_engine.origin = [[12.0,4.38,-2.1],[12.0,-4.38,-2.1]] gt_engine.number_of_engines = 2.0 gt_engine.bypass_ratio = 5.4 gt_engine.engine_length = 2.71 gt_engine.nacelle_diameter = 2.05 + gt_engine.inlet_diameter = 2.0 + #compute engine areas) Amax = (np.pi/4.)*gt_engine.nacelle_diameter**2. Awet = 1.1*np.pi*gt_engine.nacelle_diameter*gt_engine.engine_length # 1.1 is simple coefficient @@ -326,6 +342,7 @@ def vehicle_setup(): gt_engine.areas.wetted = Awet #set the working fluid for the network working_fluid = SUAVE.Attributes.Gases.Air() + #add working fluid to the network gt_engine.working_fluid = working_fluid diff --git a/tut_solar_uav.py b/tut_solar_uav.py index 25b4e58..e788214 100644 --- a/tut_solar_uav.py +++ b/tut_solar_uav.py @@ -13,6 +13,7 @@ import pylab as plt import time +from SUAVE.Plots.Mission_Plots import * from SUAVE.Components.Energy.Networks.Solar import Solar from SUAVE.Methods.Propulsion import propeller_design from SUAVE.Methods.Power.Battery.Sizing import initialize_from_energy_and_power, initialize_from_mass @@ -81,9 +82,9 @@ def vehicle_setup(): # Vehicle-level Properties # ------------------------------------------------------------------ # mass properties - vehicle.mass_properties.takeoff = 200. * Units.kg - vehicle.mass_properties.operating_empty = 200. * Units.kg - vehicle.mass_properties.max_takeoff = 200. * Units.kg + vehicle.mass_properties.takeoff = 250. * Units.kg + vehicle.mass_properties.operating_empty = 250. * Units.kg + vehicle.mass_properties.max_takeoff = 250. * Units.kg # basic parameters vehicle.reference_area = 80. @@ -95,7 +96,7 @@ def vehicle_setup(): # Main Wing # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Main_Wing() wing.tag = 'main_wing' wing.areas.reference = vehicle.reference_area @@ -111,7 +112,6 @@ def vehicle_setup(): wing.chords.mean_aerodynamic = wing.areas.reference/wing.spans.projected wing.chords.root = wing.areas.reference/wing.spans.projected wing.chords.tip = wing.areas.reference/wing.spans.projected - wing.span_efficiency = 0.98 wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees wing.highlift = False @@ -120,8 +120,8 @@ def vehicle_setup(): wing.number_end_ribs = 2. wing.transition_x_upper = 0.6 wing.transition_x_lower = 1.0 - wing.origin = [3.0,0.0,0.0] # meters - wing.aerodynamic_center = [3.0,0.0,0.0] # meters + wing.origin = [[3.0,0.0,0.0]] # meters + wing.aerodynamic_center = [1.0,0.0,0.0] # meters # add to vehicle vehicle.append_component(wing) @@ -130,14 +130,13 @@ def vehicle_setup(): # Horizontal Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Horizontal_Tail() wing.tag = 'horizontal_stabilizer' wing.aspect_ratio = 20. wing.sweeps.quarter_chord = 0 * Units.deg wing.thickness_to_chord = 0.12 wing.taper = 1.0 - wing.span_efficiency = 0.95 wing.areas.reference = vehicle.reference_area * .15 wing.areas.wetted = 2.0 * wing.areas.reference wing.areas.exposed = 0.8 * wing.areas.wetted @@ -153,7 +152,7 @@ def vehicle_setup(): wing.chords.root = wing.areas.reference/wing.spans.projected wing.chords.tip = wing.areas.reference/wing.spans.projected wing.chords.mean_aerodynamic = wing.areas.reference/wing.spans.projected - wing.origin = [10.,0.0,0.0] # meters + wing.origin = [[10.,0.0,0.0]] # meters wing.aerodynamic_center = [0.5,0.0,0.0] # meters # add to vehicle @@ -163,7 +162,7 @@ def vehicle_setup(): # Vertical Stabilizer # ------------------------------------------------------------------ - wing = SUAVE.Components.Wings.Wing() + wing = SUAVE.Components.Wings.Vertical_Tail() wing.tag = 'vertical_stabilizer' @@ -171,7 +170,6 @@ def vehicle_setup(): wing.sweeps.quarter_chord = 0 * Units.deg wing.thickness_to_chord = 0.12 wing.taper = 1.0 - wing.span_efficiency = 0.97 wing.areas.reference = vehicle.reference_area * 0.1 wing.spans.projected = np.sqrt(wing.aspect_ratio*wing.areas.reference) @@ -183,7 +181,7 @@ def vehicle_setup(): wing.areas.affected = 0.6 * wing.areas.wetted wing.twists.root = 0.0 * Units.degrees wing.twists.tip = 0.0 * Units.degrees - wing.origin = [10.,0.0,0.0] # meters + wing.origin = [[10.,0.0,0.0]] # meters wing.aerodynamic_center = [0.5,0.0,0.0] # meters wing.symmetric = True wing.vertical = True @@ -264,9 +262,10 @@ def vehicle_setup(): # Component 8 the Battery bat = SUAVE.Components.Energy.Storages.Batteries.Constant_Mass.Lithium_Ion() - bat.mass_properties.mass = 55.0 * Units.kg - bat.specific_energy = 450. * Units.Wh/Units.kg + bat.mass_properties.mass = 90.0 * Units.kg + bat.specific_energy = 600. * Units.Wh/Units.kg bat.resistance = 0.05 + bat.max_voltage = 45.0 initialize_from_mass(bat,bat.mass_properties.mass) net.battery = bat @@ -340,7 +339,7 @@ def base_analysis(vehicle): # ------------------------------------------------------------------ # Weights weights = SUAVE.Analyses.Weights.Weights_UAV() - weights.settings.empty_weight_method = \ + weights.settings.empty = \ SUAVE.Methods.Weights.Correlations.Human_Powered.empty weights.vehicle = vehicle analyses.append(weights) @@ -394,10 +393,10 @@ def mission_setup(analyses,vehicle): # base segment base_segment = Segments.Segment() ones_row = base_segment.state.ones_row - base_segment.process.iterate.unknowns.network = vehicle.propulsors.propulsor.unpack_unknowns - base_segment.process.iterate.residuals.network = vehicle.propulsors.propulsor.residuals + base_segment.process.iterate.unknowns.network = vehicle.propulsors.solar.unpack_unknowns + base_segment.process.iterate.residuals.network = vehicle.propulsors.solar.residuals base_segment.process.iterate.initials.initialize_battery = SUAVE.Methods.Missions.Segments.Common.Energy.initialize_battery - base_segment.state.unknowns.propeller_power_coefficient = vehicle.propulsors.propulsor.propeller.power_coefficient * ones_row(1)/15. + base_segment.state.unknowns.propeller_power_coefficient = vehicle.propulsors.solar.propeller.power_coefficient * ones_row(1)/15. base_segment.state.residuals.network = 0. * ones_row(1) # ------------------------------------------------------------------ @@ -408,7 +407,7 @@ def mission_setup(analyses,vehicle): segment.tag = "cruise1" # connect vehicle configuration - segment.analyses.extend( analyses.cruise) + segment.analyses.extend(analyses.cruise) # segment attributes segment.state.numerics.number_control_points = 64 @@ -416,7 +415,7 @@ def mission_setup(analyses,vehicle): segment.altitude = 15.0 * Units.km segment.mach = 0.12 segment.distance = 3050.0 * Units.km - segment.battery_energy = vehicle.propulsors.propulsor.battery.max_energy*0.2 #Charge the battery to start + segment.battery_energy = vehicle.propulsors.solar.battery.max_energy*0.2 #Charge the battery to start segment.latitude = 37.4300 # this defaults to degrees (do not use Units.degrees) segment.longitude = -122.1700 # this defaults to degrees @@ -447,287 +446,27 @@ def missions_setup(base_mission): # ---------------------------------------------------------------------- def plot_mission(results): - # ------------------------------------------------------------------ - # Throttle - # ------------------------------------------------------------------ - plt.figure("Throttle History") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - eta = results.segments[i].conditions.propulsion.throttle[:,0] - - axes.plot(time, eta, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Throttle') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - plt.ylim((0,1)) - axes.grid(True) - - # ------------------------------------------------------------------ - # Altitude - # ------------------------------------------------------------------ - plt.figure("Altitude") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - altitude = results.segments[i].conditions.freestream.altitude[:,0] / Units.km - axes.plot(time, altitude, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Altitude (km)') - axes.grid(True) + # Plot Flight Conditions + plot_flight_conditions(results) - # ------------------------------------------------------------------ - # Aerodynamics - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Forces") - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - Lift = -segment.conditions.frames.wind.lift_force_vector[:,2] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - - axes = fig.add_subplot(3,1,1) - axes.plot( time , Lift , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Lift (N)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , Drag , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Drag (N)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , Thrust , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Thrust (N)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - plt.ylim((0,50)) - axes.grid(True) - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Aerodynamic Coefficients") - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - CLift = segment.conditions.aerodynamics.lift_coefficient[:,0] - CDrag = segment.conditions.aerodynamics.drag_coefficient[:,0] - Drag = -segment.conditions.frames.wind.drag_force_vector[:,0] - Thrust = segment.conditions.frames.body.thrust_force_vector[:,0] - - axes = fig.add_subplot(3,1,1) - axes.plot( time , CLift , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('CL') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , CDrag , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , Drag , 'bo-' ) - axes.plot( time , Thrust , 'ro-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Drag and Thrust (N)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - - # ------------------------------------------------------------------ - # Aerodynamics 2 - # ------------------------------------------------------------------ - fig = plt.figure("Drag Components") - axes = plt.gca() - for i, segment in enumerate(results.segments.values()): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - drag_breakdown = segment.conditions.aerodynamics.drag_breakdown - cdp = drag_breakdown.parasite.total[:,0] - cdi = drag_breakdown.induced.total[:,0] - cdc = drag_breakdown.compressible.total[:,0] - cdm = drag_breakdown.miscellaneous.total[:,0] - cd = drag_breakdown.total[:,0] - - axes.plot( time , cdp , 'ko-', label='CD_P' ) - axes.plot( time , cdi , 'bo-', label='CD_I' ) - axes.plot( time , cdc , 'go-', label='CD_C' ) - axes.plot( time , cdm , 'yo-', label='CD_M' ) - axes.plot( time , cd , 'ro-', label='CD' ) - - if i == 0: - axes.legend(loc='upper center') - - axes.set_xlabel('Time (min)') - axes.set_ylabel('CD') - axes.grid(True) - - # ------------------------------------------------------------------ - # Battery Energy - # ------------------------------------------------------------------ - plt.figure("Battery Energy") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.battery_energy[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Battery Energy (J)') - axes.grid(True) - - # ------------------------------------------------------------------ - # Solar Flux - # ------------------------------------------------------------------ - plt.figure("Solar Flux") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.solar_flux[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Solar Flux ($W/m^{2}$)') - axes.grid(True) - - # ------------------------------------------------------------------ - # Current Draw - # ------------------------------------------------------------------ - plt.figure("Current Draw") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.current[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Current Draw (Amps)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - plt.ylim((0,200)) - axes.grid(True) - - # ------------------------------------------------------------------ - # Motor RPM - # ------------------------------------------------------------------ - plt.figure("Motor RPM") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.rpm[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Motor RPM') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - plt.ylim((0,200)) - axes.grid(True) - - # ------------------------------------------------------------------ - # Battery Draw - # ------------------------------------------------------------------ - plt.figure("Battery Charging") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - energy = results.segments[i].conditions.propulsion.battery_draw[:,0] - axes.plot(time, energy, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Battery Charging (Watts)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - # ------------------------------------------------------------------ - # Propulsive efficiency - # ------------------------------------------------------------------ - plt.figure("Propeller Efficiency") - axes = plt.gca() - for i in range(len(results.segments)): - time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min - etap = results.segments[i].conditions.propulsion.etap[:,0] - axes.plot(time, etap, 'bo-') - axes.set_xlabel('Time (mins)') - axes.set_ylabel('Etap') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - plt.ylim((0,1)) + # Plot Solar Conditions + plot_solar_flux(results) + + # Plot Aerodynamic Coefficients + plot_aerodynamic_coefficients(results) + + # Plot Aircraft Flight Speed + plot_aircraft_velocities(results) + + # Plot Aircraft Electronics + plot_electronic_conditions(results) + + # Plot Propeller Conditions + plot_propeller_conditions(results) + + # Plot Electric Motor and Propeller Efficiencies + plot_eMotor_Prop_efficiencies(results) - # ------------------------------------------------------------------ - # Flight Conditions - # ------------------------------------------------------------------ - fig = plt.figure("Flight Conditions") - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - altitude = segment.conditions.freestream.altitude[:,0] / Units.km - mach = segment.conditions.freestream.mach_number[:,0] - aoa = segment.conditions.aerodynamics.angle_of_attack[:,0] / Units.deg - - axes = fig.add_subplot(3,1,1) - axes.plot( time , aoa , 'bo-' ) - axes.set_ylabel('Angle of Attack (deg)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , altitude , 'bo-' ) - axes.set_ylabel('Altitude (km)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , mach, 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Mach Number (-)') - axes.get_yaxis().get_major_formatter().set_scientific(False) - axes.get_yaxis().get_major_formatter().set_useOffset(False) - axes.grid(True) - - # ------------------------------------------------------------------ - # Solar Flux, Charging Power, Battery Energy - # ------------------------------------------------------------------ - - fig = plt.figure("Electric Outputs") - for segment in results.segments.values(): - - time = segment.conditions.frames.inertial.time[:,0] / Units.min - flux = results.segments[i].conditions.propulsion.solar_flux[:,0] - charge = results.segments[i].conditions.propulsion.battery_draw[:,0] - energy = results.segments[i].conditions.propulsion.battery_energy[:,0] / Units.MJ - - axes = fig.add_subplot(3,1,1) - axes.plot( time , flux , 'bo-' ) - axes.set_ylabel('Solar Flux (W/m$^2$)') - axes.grid(True) - - axes = fig.add_subplot(3,1,2) - axes.plot( time , charge , 'bo-' ) - axes.set_ylabel('Charging Power (W)') - axes.grid(True) - - axes = fig.add_subplot(3,1,3) - axes.plot( time , energy , 'bo-' ) - axes.set_xlabel('Time (min)') - axes.set_ylabel('Battery Energy (MJ)') - axes.grid(True) return