Tutorial 25 - V-n Diagram#
Welcome to this tutorial on performing V-n diagram analysis of a turbofan aircraft using RCAIDE. This guide will walk you through the code, explain its components, and highlight where modifications can be made to customize the simulation for different vehicle designs.
1. Header and Imports#
The Imports section is divided into two parts: general-purpose Python libraries and simulation-specific libraries.
[1]:
import sys
import os
import numpy as np
2. RCAIDE Imports#
The RCAIDE Imports section includes the core modules needed for the simulation. These libraries provide specialized classes and tools for building, analyzing, and running aircraft models.
Key Imports:#
RCAIDE: The core package is imported directly. This approach allows us to access specific classes and methods from RCAIDE without repeatedly importing individual components at the top of the script.
``Units`` Module: The Units module is a standardized way to handle unit conversions within RCAIDE. It ensures consistent units across all inputs and outputs, reducing the likelihood of conversion errors.
[2]:
import RCAIDE
from RCAIDE.Framework.Core import Data,Units
from RCAIDE.Library.Methods.Performance.generate_V_n_diagram import generate_V_n_diagram
from RCAIDE.Library.Methods.Powertrain.Converters.Rotor import design_propeller
from RCAIDE.Library.Methods.Powertrain.Propulsors.Internal_Combustion_Engine import design_internal_combustion_engine
from RCAIDE.Library.Plots import *
Vehicle Setup#
The ``vehicle_setup`` function defines the baseline configuration of the aircraft. This section builds the vehicle step-by-step by specifying its components, geometric properties, and high-level parameters.
A detailed description of the vehicle setup is provided in the a tutorial coming soon.
[3]:
def vehicle_setup():
#------------------------------------------------------------------------------------------------------------------------------------
# ################################################# Vehicle-level Properties ########################################################
#------------------------------------------------------------------------------------------------------------------------------------
vehicle = RCAIDE.Vehicle()
vehicle.tag = 'Cessna_172'
vehicle.mass_properties.max_takeoff = 2550. * Units.pounds
vehicle.mass_properties.takeoff = 2550. * Units.pounds
vehicle.mass_properties.operating_empty = 1600 * Units.pounds
vehicle.mass_properties.max_zero_fuel = 1680 * Units.pounds
vehicle.mass_properties.max_fuel = 152.407
vehicle.mass_properties.max_payload = 910 * Units.pounds
vehicle.mass_properties.payload = 200
# envelope properties
vehicle.flight_envelope.ultimate_load = 5.7
vehicle.flight_envelope.positive_limit_load = 3.8
vehicle.flight_envelope.design_range = 750 * Units.nmi
vehicle.flight_envelope.design_dynamic_pressure = 2755 # max speed at 10 k feet
vehicle.flight_envelope.design_mach_number = 0.18745866156304694
vehicle.flight_envelope.category = 'normal'
vehicle.flight_envelope.FAR_part_number = '23'
vehicle.flight_envelope.maximum_lift_coefficient = 3
vehicle.flight_envelope.minimum_lift_coefficient = -1.5
# basic parameters
vehicle.reference_area = 174. * Units.feet**2
vehicle.number_of_passengers = 4
#------------------------------------------------------------------------------------------------------------------------------------
# ##################################################### Landing Gear ################################################################
#------------------------------------------------------------------------------------------------------------------------------------
main_gear = RCAIDE.Library.Components.Landing_Gear.Main_Landing_Gear()
main_gear.strut_length = 12. * Units.inches
vehicle.append_component(main_gear)
nose_gear = RCAIDE.Library.Components.Landing_Gear.Nose_Landing_Gear()
nose_gear.strut_length = 6. * Units.inches
vehicle.append_component(nose_gear)
#------------------------------------------------------------------------------------------------------------------------------------
# ######################################################## Wings ####################################################################
#------------------------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------
# Main Wing
# ------------------------------------------------------------------
wing = RCAIDE.Library.Components.Wings.Main_Wing()
wing.tag = 'main_wing'
wing.sweeps.quarter_chord = 0.0 * Units.deg
wing.thickness_to_chord = 0.12
wing.areas.reference = 174. * Units.feet**2
wing.spans.projected = 36. * Units.feet + 1. * Units.inches
wing.chords.root = 66. * Units.inches
wing.chords.tip = 45. * Units.inches
wing.chords.mean_aerodynamic = 58. * Units.inches
wing.taper = wing.chords.tip/wing.chords.root
wing.aspect_ratio = wing.spans.projected**2. / wing.areas.reference
wing.twists.root = 3.0 * Units.degrees
wing.twists.tip = 1.5 * Units.degrees
wing.origin = [[80.* Units.inches,0, 0.820]]
wing.aerodynamic_center = [22.* Units.inches,0,0]
wing.vertical = False
wing.symmetric = True
wing.high_lift = True
wing.dynamic_pressure_ratio = 1.0
# control surfaces -------------------------------------------
flap = RCAIDE.Library.Components.Wings.Control_Surfaces.Flap()
flap.tag = 'flap'
flap.span_fraction_start = 0.15
flap.span_fraction_end = 0.324
flap.deflection = 1.0 * Units.deg
flap.chord_fraction = 0.19
wing.append_control_surface(flap)
slat = RCAIDE.Library.Components.Wings.Control_Surfaces.Slat()
slat.tag = 'slat'
slat.span_fraction_start = 0.324
slat.span_fraction_end = 0.963
slat.deflection = 1.0 * Units.deg
slat.chord_fraction = 0.1
wing.append_control_surface(slat)
RCAIDE.Library.Methods.Geometry.Planform.wing_planform(wing)
# add to vehicle
vehicle.append_component(wing)
# ------------------------------------------------------------------
# Horizontal Stabilizer
# ------------------------------------------------------------------
wing = RCAIDE.Library.Components.Wings.Horizontal_Tail()
wing.tag = 'horizontal_stabilizer'
wing.sweeps.quarter_chord = 0.0 * Units.deg
wing.thickness_to_chord = 0.12
wing.areas.reference = 5800. * Units.inches**2
wing.spans.projected = 136. * Units.inches
wing.chords.root = 55. * Units.inches
wing.chords.tip = 30. * Units.inches
wing.chords.mean_aerodynamic = 43. * Units.inches
wing.taper = wing.chords.tip/wing.chords.root
wing.aspect_ratio = wing.spans.projected**2. / wing.areas.reference
wing.twists.root = 0.0 * Units.degrees
wing.twists.tip = 0.0 * Units.degrees
wing.origin = [[246.* Units.inches,0,0]]
wing.aerodynamic_center = [20.* Units.inches,0,0]
wing.vertical = False
wing.symmetric = True
wing.high_lift = False
wing.dynamic_pressure_ratio = 0.9
elevator = RCAIDE.Library.Components.Wings.Control_Surfaces.Elevator()
elevator.tag = 'elevator'
elevator.span_fraction_start = 0.1
elevator.span_fraction_end = 0.9
elevator.deflection = 0.0 * Units.deg
elevator.chord_fraction = 0.35
wing.append_control_surface(elevator)
vehicle.append_component(wing)
# ------------------------------------------------------------------
# Vertical Stabilizer
# ------------------------------------------------------------------
wing = RCAIDE.Library.Components.Wings.Vertical_Tail()
wing.tag = 'vertical_stabilizer'
wing.sweeps.quarter_chord = 25. * Units.deg
wing.thickness_to_chord = 0.12
wing.areas.reference = 3500. * Units.inches**2
wing.spans.projected = 73. * Units.inches
wing.chords.root = 66. * Units.inches
wing.chords.tip = 27. * Units.inches
wing.chords.mean_aerodynamic = 48. * Units.inches
wing.taper = wing.chords.tip/wing.chords.root
wing.aspect_ratio = wing.spans.projected**2. / wing.areas.reference
wing.twists.root = 0.0 * Units.degrees
wing.twists.tip = 0.0 * Units.degrees
wing.origin = [[237.* Units.inches,0,0]]
wing.aerodynamic_center = [20.* Units.inches,0,0]
wing.vertical = True
wing.symmetric = False
wing.t_tail = False
wing.dynamic_pressure_ratio = 1.0
rudder = RCAIDE.Library.Components.Wings.Control_Surfaces.Rudder()
rudder.tag = 'rudder'
rudder.span_fraction_start = 0.1
rudder.span_fraction_end = 0.9
rudder.deflection = 0.0 * Units.deg
rudder.chord_fraction = 0.4
wing.append_control_surface(rudder)
# add to vehicle
vehicle.append_component(wing)
#------------------------------------------------------------------------------------------------------------------------------------
# ########################################################## Fuselage ###############################################################
#------------------------------------------------------------------------------------------------------------------------------------
fuselage = RCAIDE.Library.Components.Fuselages.Fuselage()
# define cabin
cabin = RCAIDE.Library.Components.Fuselages.Cabins.Cabin()
economy_class = RCAIDE.Library.Components.Fuselages.Cabins.Classes.Economy()
economy_class.number_of_seats_abrest = 2
economy_class.number_of_rows = 2
economy_class.galley_lavatory_percent_x_locations = []
economy_class.emergency_exit_percent_x_locations = []
economy_class.type_A_exit_percent_x_locations = []
cabin.append_cabin_class(economy_class)
fuselage.append_cabin(cabin)
fuselage.differential_pressure = 8*Units.psi # Maximum differential pressure
fuselage.width = 42. * Units.inches # Width of the fuselage
fuselage.heights.maximum = 62. * Units.inches # Height of the fuselage
fuselage.lengths.total = 326. * Units.inches # Length of the fuselage
fuselage.lengths.tail = 161. * Units.inches
fuselage.lengths.cabin = 105. * Units.inches
fuselage.mass_properties.gross_volume = .4*fuselage.lengths.total*(np.pi/4.)*(fuselage.heights.maximum**2.)
fuselage.areas.wetted = 30000. * Units.inches**2.
fuselage.fineness.nose = 1.6
fuselage.fineness.tail = 2.
fuselage.lengths.nose = 60. * Units.inches
fuselage.heights.at_quarter_length = 62. * Units.inches
fuselage.heights.at_three_quarters_length = 62. * Units.inches
fuselage.heights.at_wing_root_quarter_chord = 23. * Units.inches
fuselage.areas.front_projected = fuselage.width* fuselage.heights.maximum
fuselage.effective_diameter = 50. * Units.inches
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Segment()
segment.tag = 'segment_0'
segment.percent_x_location = 0.0000
segment.percent_z_location = 0.0000
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Super_Ellipse_Segment()
segment.tag = 'segment_1'
segment.percent_x_location = 0.02077
segment.percent_z_location = 0.0
segment.height = 0.31619
segment.width = 0.33071
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Rounded_Rectangle_Segment()
segment.tag = 'segment_2'
segment.percent_x_location = 0.03852
segment.percent_z_location = -0.02000
segment.height = 0.73441
segment.width = 0.40654
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Rounded_Rectangle_Segment()
segment.tag = 'segment_3'
segment.percent_x_location = 0.16595
segment.percent_z_location = -0.01226
segment.height = 1.00366
segment.width = 0.90341
segment.radius = 0.29143
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Rounded_Rectangle_Segment()
segment.tag = 'segment_4'
segment.percent_x_location = 0.24391
segment.percent_z_location = 0.01016
segment.height = 1.52704
segment.width = 1.06680
segment.radius = 0.43714
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Rounded_Rectangle_Segment()
segment.tag = 'segment_5'
segment.percent_x_location = 0.43388
segment.percent_z_location = 0.0132
segment.height = 1.50557
segment.width = 1.06680
segment.radius = 0.4007
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Rounded_Rectangle_Segment()
segment.tag = 'segment_6'
segment.percent_x_location = 0.53122
segment.percent_z_location = -0.00895
segment.height = 0.97386
segment.width = 0.73776
segment.radius = 0.29143
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Ellipse_Segment()
segment.tag = 'segment_7'
segment.percent_x_location = 0.74233
segment.percent_z_location = 0
segment.height = 0.55067
segment.width = 0.4517
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Segment()
segment.tag = 'segment_9'
segment.percent_x_location = 0.98310
segment.percent_z_location = 0
segment.height = 0.17226
segment.width = 0.18068
fuselage.segments.append(segment)
# Segment
segment = RCAIDE.Library.Components.Fuselages.Segments.Segment()
segment.tag = 'segment_9'
segment.percent_x_location = 1.0
segment.percent_z_location = 0.00189
fuselage.segments.append(segment)
# add to vehicle
vehicle.append_component(fuselage)
#------------------------------------------------------------------------------------------------------------------------------------
# ########################################################## Energy Network #########################################################
#------------------------------------------------------------------------------------------------------------------------------------
#initialize the fuel network
net = RCAIDE.Framework.Networks.Fuel()
# add the network to the vehicle
vehicle.append_energy_network(net)
#------------------------------------------------------------------------------------------------------------------------------------
# Bus
#------------------------------------------------------------------------------------------------------------------------------------
fuel_line = RCAIDE.Library.Components.Powertrain.Distributors.Fuel_Line()
#------------------------------------------------------------------------------------------------------------------------------------
# Fuel Tank & Fuel
#------------------------------------------------------------------------------------------------------------------------------------
fuel_tank = RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Fuel_Tank()
fuel_tank.origin = vehicle.wings.main_wing.origin
fuel_tank.fuel = RCAIDE.Library.Attributes.Propellants.Aviation_Gasoline()
fuel_tank.fuel.mass_properties.mass = 319 *Units.lbs
fuel_tank.mass_properties.center_of_gravity = wing.mass_properties.center_of_gravity
fuel_tank.volume = fuel_tank.fuel.mass_properties.mass/fuel_tank.fuel.density
fuel_line.fuel_tanks.append(fuel_tank)
#------------------------------------------------------------------------------------------------------------------------------------
# Propulsor
#------------------------------------------------------------------------------------------------------------------------------------
ice_prop = RCAIDE.Library.Components.Powertrain.Propulsors.Internal_Combustion_Engine()
# Engine
engine = RCAIDE.Library.Components.Powertrain.Converters.Engine()
engine.sea_level_power = 180. * Units.horsepower
engine.flat_rate_altitude = 0.0
engine.rated_speed = 2700. * Units.rpm
engine.power_specific_fuel_consumption = 0.52 * Units['lb/hp/hr']
ice_prop.engine = engine
# Propeller
prop = RCAIDE.Library.Components.Powertrain.Converters.Propeller()
prop.tag = 'propeller'
prop.number_of_blades = 2.0
prop.tip_radius = 76./2. * Units.inches
prop.hub_radius = 8. * Units.inches
prop.cruise.design_freestream_velocity = 119. * Units.knots
prop.cruise.design_angular_velocity = 2650. * Units.rpm
prop.cruise.design_lift_coefficient = 0.8
prop.cruise.design_altitude = 12000. * Units.feet
prop.cruise.design_power = .64 * 180. * Units.horsepower
prop.variable_pitch = True
ospath = os.path.abspath(os.path.join('Notebook'))
separator = os.path.sep
rel_path = os.path.dirname(ospath) + separator + '..' + separator + '..' + separator + 'VnV' + separator + 'Vehicles' + separator
airfoil_path = rel_path
airfoil = RCAIDE.Library.Components.Airfoils.Airfoil()
airfoil.tag = 'NACA_4412'
airfoil.coordinate_file = airfoil_path + 'Airfoils' + separator + 'NACA_4412.txt' # absolute path
airfoil.polar_files =[ airfoil_path + 'Airfoils' + separator + 'Polars' + separator + 'NACA_4412_polar_Re_50000.txt',
airfoil_path + 'Airfoils' + separator + 'Polars' + separator + 'NACA_4412_polar_Re_100000.txt',
airfoil_path + 'Airfoils' + separator + 'Polars' + separator + 'NACA_4412_polar_Re_200000.txt',
airfoil_path + 'Airfoils' + separator + 'Polars' + separator + 'NACA_4412_polar_Re_500000.txt',
airfoil_path + 'Airfoils' + separator + 'Polars' + separator + 'NACA_4412_polar_Re_1000000.txt']
prop.append_airfoil(airfoil)
prop.airfoil_polar_stations = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
ice_prop.propeller = prop
# design propeller ICE
design_internal_combustion_engine(ice_prop)
net.propulsors.append(ice_prop)
#------------------------------------------------------------------------------------------------------------------------------------
# Assign propulsors to fuel line to network
fuel_line.assigned_propulsors = [[ice_prop.tag]]
#------------------------------------------------------------------------------------------------------------------------------------
# Append fuel line to fuel line to network
net.fuel_lines.append(fuel_line)
#------------------------------------------------------------------------------------------------------------------------------------
# Avionics
#------------------------------------------------------------------------------------------------------------------------------------
Wuav = 2. * Units.lbs
avionics = RCAIDE.Library.Components.Powertrain.Systems.Avionics()
avionics.mass_properties.uninstalled = Wuav
vehicle.avionics = avionics
#------------------------------------------------------------------------------------------------------------------------------------
# Vehicle Definition Complete
#------------------------------------------------------------------------------------------------------------------------------------
return vehicle
[4]:
def configs_setup(vehicle):
# ------------------------------------------------------------------
# Initialize Configurations
# ------------------------------------------------------------------
configs = RCAIDE.Library.Components.Configs.Config.Container()
base_config = RCAIDE.Library.Components.Configs.Config(vehicle)
base_config.tag = 'base'
configs.append(base_config)
# ------------------------------------------------------------------
# Cruise Configuration
# ------------------------------------------------------------------
config = RCAIDE.Library.Components.Configs.Config(base_config)
config.tag = 'cruise'
configs.append(config)
# ------------------------------------------------------------------
# Takeoff Configuration
# ------------------------------------------------------------------
config = RCAIDE.Library.Components.Configs.Config(base_config)
config.tag = 'takeoff'
config.wings['main_wing'].control_surfaces.flap.deflection = 20. * Units.deg
config.maximum_lift_coefficient = 2.
configs.append(config)
# ------------------------------------------------------------------
# Landing Configuration
# ------------------------------------------------------------------
config = RCAIDE.Library.Components.Configs.Config(base_config)
config.tag = 'landing'
config.wings['main_wing'].control_surfaces.flap.deflection = 20. * Units.deg
config.Vref_VS_ratio = 1.23
config.maximum_lift_coefficient = 2.
configs.append(config)
# done!
return configs
[5]:
def base_analysis(vehicle):
# ------------------------------------------------------------------
# Initialize the Analyses
# ------------------------------------------------------------------
analyses = RCAIDE.Framework.Analyses.Vehicle()
analyses.vehicle = vehicle
# ------------------------------------------------------------------
# Geometry
geometry = RCAIDE.Framework.Analyses.Geometry.Geometry()
analyses.append(geometry)
# ------------------------------------------------------------------
# Weights
weights = RCAIDE.Framework.Analyses.Weights.Conventional_General_Aviation()
weights.method = 'Raymer'
analyses.append(weights)
# ------------------------------------------------------------------
# Aerodynamics
aerodynamics = RCAIDE.Framework.Analyses.Aerodynamics.Vortex_Lattice_Method()
analyses.append(aerodynamics)
# ------------------------------------------------------------------
# Energy
energy= RCAIDE.Framework.Analyses.Energy.Energy()
analyses.append(energy)
# ------------------------------------------------------------------
# Planet Analysis
planet = RCAIDE.Framework.Analyses.Planets.Earth()
analyses.append(planet)
# ------------------------------------------------------------------
# Atmosphere Analysis
atmosphere = RCAIDE.Framework.Analyses.Atmospheric.US_Standard_1976()
analyses.append(atmosphere)
# done!
return analyses
[6]:
def analyses_setup(configs):
analyses = RCAIDE.Framework.Analyses.Analysis.Container()
# build a base analysis for each config
for tag,config in configs.items():
analysis = base_analysis(config)
analyses[tag] = analysis
return analyses
Vehicle Aerodynamic Analysis Setup#
The setup for aerodynamic analysis involves:
Initialize Analyses: Create a vehicle analysis object and append Earth as the planetary environment and the US Standard Atmosphere 1976 model.
Define Conditions: Set altitude (
0 m) and ISA deviation (0).Vehicle Setup: Configure the vehicle with
normalcategory, FAR part23, and lift coefficient limits (3and-1.5).Generate V-n Diagram: Calculate and plot the flight envelope using
generate_V_n_diagram.
[7]:
vehicle = vehicle_setup()
configs = configs_setup(vehicle)
analyses = analyses_setup(configs)
V_n_data = generate_V_n_diagram(analyses.cruise)
plot_V_n_diagram(V_n_data, save_filename='GA_Vn')
Performing Weights Analysis
--------------------------------------------------------
Propulsion Architecture: Conventional
Aircraft Type : General_Aviation
Method : Raymer
=== WEIGHT BREAKDOWN REPORT ===
Structural Components:
Component Weight (kg)
----------------------------------------
Wings 139.40+1.53j
Fuselage 75.09
Empennage 23.63
Landing Gear 74.95
Nacelle 0.00
Booms 0.00
Paint 0.00
----------------------------------------
Total 313.07+1.53j
Propulsion Components:
Component Weight (kg)
----------------------------------------
Engines 0.00
Thrust Reversers 0.00
Miscellaneous 0.00
Fuel System -0.00+0.00j
Fuel Tanks 0.00
Electrical Cabling 0.00
Thermal Management 0.00
Battery 0.00
Motors 0.00
----------------------------------------
Total 224.41
Systems:
Component Weight (kg)
----------------------------------------
Control Systems 58.39
Hydraulics 1.16
Avionics 0.00
Electrical 0.03+0.06j
Air Conditioner 0.00
Furnishings 37.83
Apu 0.00
Instruments 0.00
Anti Ice 0.00
----------------------------------------
Total 97.41+0.06j
Payload Breakdown:
Component Weight (kg)
----------------------------------------
Passengers 353.80
Baggage 54.43
Cargo 54.43
----------------------------------------
Total 200.00
Operational Items Breakdown:
Component Weight (kg)
----------------------------------------
Misc 0.00
Flight Crew 0.00
Flight Attendants 0.00
Passenger Service 0.00
----------------------------------------
Total 0.00
Overall Summary:
Metric Weight (kg)
----------------------------------------
Operating Empty Weight 634.88+1.59j
Payload Weight 200.00
Fuel Weight -0.00
Takeoff Weight 1156.66
Zero Fuel Weight 834.88+1.59j
Max Takeoff Weight 1156.66
===============================
Creating aerodynamic surrogate ...
+----------------------------------------------------+
| MISSION SOLVER INITIATED |
+----------------------------------------------------+
Solving cruise: |██████████| 1/1 segs [00:00<00:00, 50.24seg/s]
[7]: