def fuselage(config, maximum_g_load=3.8, landing_impact_factor=3.5, safety_factor=1.5): """ weight = SUAVE.Methods.Weights.Buildups.Common.fuselage( config, max_g_load = 3.8, landing_impact_factor = 3.5, safety_factor = 1.5) Calculates the structural mass of a fuselage for an eVTOL vehicle, assuming a structural keel taking bending an torsional loads. Assumptions: Assumes an elliptical fuselage. Intended for use with the following SUAVE vehicle types, but may be used elsewhere: Electric Multicopter Electric Vectored_Thrust Electric Stopped Rotor Originally written as part of an AA 290 project intended for trade study of the above vehicle types. Sources: Project Vahana Conceptual Trade Study Inputs: config SUAVE Vehicle Configuration max_g_load Max Accelerative Load During Flight [Unitless] landing_impact_factor Maximum Load Multiplier on Landing [Unitless] Outputs: weight: Estimated Fuselage Mass [kg] Properties Used: Material Properties of Imported SUAVE Solids """ #------------------------------------------------------------------------------- # Unpack Inputs #------------------------------------------------------------------------------- fLength = config.fuselages.fuselage.lengths.total fWidth = config.fuselages.fuselage.width fHeight = config.fuselages.fuselage.heights.maximum maxSpan = config.wings['main_wing'].spans.projected MTOW = config.mass_properties.max_takeoff G_max = maximum_g_load LIF = landing_impact_factor SF = safety_factor #------------------------------------------------------------------------------- # Unpack Material Properties #------------------------------------------------------------------------------- BiCF = Bidirectional_Carbon_Fiber() BiCF_MGT = BiCF.minimum_gage_thickness BiCF_DEN = BiCF.density BiCF_UTS = BiCF.ultimate_tensile_strength BiCF_USS = BiCF.ultimate_shear_strength BiCF_UBS = BiCF.ultimate_bearing_strength UniCF = Unidirectional_Carbon_Fiber() UniCF_MGT = UniCF.minimum_gage_thickness UniCF_DEN = UniCF.density UniCF_UTS = UniCF.ultimate_tensile_strength UniCF_USS = UniCF.ultimate_shear_strength HCMB = Carbon_Fiber_Honeycomb() HCMB_MGT = HCMB.minimum_gage_thickness HCMB_DEN = HCMB.density PAINT = Paint() PAINT_MGT = PAINT.minimum_gage_thickness PAINT_DEN = PAINT.density ACRYL = Acrylic() ACRYL_MGT = ACRYL.minimum_gage_thickness ACRYL_DEN = ACRYL.density STEEL = Steel() STEEL_USS = STEEL.ultimate_shear_strength # Calculate Skin Weight Per Unit Area (arealWeight) based on material # properties. In this instance we assume the use of # Bi-directional Carbon Fiber, a Honeycomb Core, and Paint: arealWeight = (BiCF_MGT * BiCF_DEN + HCMB_MGT * HCMB_DEN + PAINT_MGT * PAINT_DEN) # Calculate fuselage area (using assumption of ellipsoid), and weight: S_wet = 4 * np.pi * (((fLength * fWidth / 4)**1.6 + (fLength * fHeight / 4)**1.6 + (fWidth * fHeight / 4)**1.6) / 3)**(1 / 1.6) skinMass = S_wet * arealWeight # Calculate the mass of a structural bulkhead bulkheadMass = 3 * np.pi * fHeight * fWidth / 4 * arealWeight # Calculate the mass of a canopy, assuming Acrylic: canopyMass = S_wet / 8 * ACRYL_MGT * ACRYL_DEN # Calculate keel mass needed to carry lifting moment, assuming # Uni-directional Carbon Fiber used to carry load L_max = G_max * MTOW * 9.8 * SF # Max Lifting Load M_lift = L_max * fLength / 2. # Max Moment Due to Lift beamWidth = fWidth / 3. # Allowable Keel Width beamHeight = fHeight / 10. # Allowable Keel Height beamArea = M_lift * beamHeight / (4 * UniCF_UTS * (beamHeight / 2)**2) massKeel = beamArea * fLength * UniCF_DEN # Calculate keel mass needed to carry wing bending moment, assuming # thin walled Bi-directional Carbon Fiber used to carry load M_bend = L_max / 2 * maxSpan / 2 # Max Bending Moment beamArea = beamHeight * beamWidth # Enclosed Beam Area beamThk = 0.5 * M_bend / (BiCF_USS * beamArea) # Beam Thickness massKeel += 2 * (beamHeight + beamWidth) * beamThk * BiCF_DEN # Calculate keel mass needed to carry landing impact load assuming # Steel bolts, and Bi-directional Carbon Fiber laminate pads used to carry # loads in a side landing F_landing = SF * MTOW * 9.8 * LIF * 0.6403 # Side Landing Force boltArea = F_landing / STEEL_USS # Required Bolt Area boltDiam = 2 * np.sqrt(boltArea / np.pi) # Bolt Diameter lamThk = F_landing / (boltDiam * BiCF_UBS) # Laminate Thickness lamVol = (np.pi * (20 * lamThk)**2) * (lamThk / 3) # Laminate Pad volume massKeel += 4 * lamVol * BiCF_DEN # Mass of 4 Pads # Calculate total mass as the sum of skin mass, bulkhead mass, canopy pass, # and keel mass. Called weight by SUAVE convention weight = skinMass + bulkheadMass + canopyMass + massKeel return weight
def wing(wing, config, max_thrust, num_analysis_points=10, safety_factor=1.5, max_g_load=3.8, moment_to_lift_ratio=0.02, lift_to_drag_ratio=7, forward_web_locations=[0.25, 0.35], rear_web_locations=[0.65, 0.75], shear_center_location=0.25, margin_factor=1.2): """weight = SUAVE.Methods.Weights.Buildups.Common.wing( wing, config, maxThrust, numAnalysisPoints, safety_factor, max_g_load, moment_to_lift_ratio, lift_to_drag_ratio, forward_web_locations = [0.25, 0.35], rear_web_locations = [0.65, 0.75], shear_center = 0.25, margin_factor = 1.2) Calculates the structural mass of a wing for an eVTOL vehicle based on assumption of NACA airfoil wing, an assumed L/D, cm/cl, and structural geometry. Intended for use with the following SUAVE vehicle types, but may be used elsewhere: Electric Multicopter Electric Vectored_Thrust Electric Stopped Rotor Originally written as part of an AA 290 project intended for trade study of the above vehicle types plus an electric Multicopter. Sources: Project Vahana Conceptual Trade Study Inputs: wing SUAVE Wing Data Structure config SUAVE Confiug Data Structure maxThrust Maximum Thrust [N] numAnalysisPoints Analysis Points for Sizing [Unitless] safety_factor Design Saftey Factor [Unitless] max_g_load Maximum Accelerative Load [Unitless] moment_to_lift_ratio Coeff. of Moment to Coeff. of Lift [Unitless] lift_to_drag_ratio Coeff. of Lift to Coeff. of Drag [Unitess] forward_web_locations Location of Forward Spar Webbing [m] rear_web_locations Location of Rear Spar Webbing [m] shear_center Location of Shear Center [m] margin_factor Allowable Extra Mass Fraction [Unitless] Outputs: weight: Wing Mass [kg] """ #------------------------------------------------------------------------------- # Unpack Inputs #------------------------------------------------------------------------------- MTOW = config.mass_properties.max_takeoff wingspan = wing.spans.projected chord = wing.chords.mean_aerodynamic, thicknessToChord = wing.thickness_to_chord, wingletFraction = wing.winglet_fraction, wingArea = wing.areas.reference totalWingArea = 0 for w in config.wings: totalWingArea += w.areas.reference liftFraction = wingArea / totalWingArea motor_spanwise_locations = wing.motor_spanwise_locations N = num_analysis_points # Number of spanwise points SF = safety_factor # Safety Factor G_max = max_g_load # Maximum G's experienced during climb cmocl = moment_to_lift_ratio # Ratio of cm to cl LoD = lift_to_drag_ratio # L/D fwdWeb = cp.deepcopy(forward_web_locations) # Locations of forward spars aftWeb = cp.deepcopy(rear_web_locations) # Locations of aft spars xShear = shear_center_location # Approximate shear center grace = margin_factor # Grace factor for estimation nRibs = len(motor_spanwise_locations) + 2 motor_spanwise_locations = np.multiply(motor_spanwise_locations, wingspan / 2) #------------------------------------------------------------------------------- # Unpack Material Properties #------------------------------------------------------------------------------- BiCF = Bidirectional_Carbon_Fiber() BiCF_MGT = BiCF.minimum_gage_thickness BiCF_DEN = BiCF.density BiCF_UTS = BiCF.ultimate_tensile_strength BiCF_USS = BiCF.ultimate_shear_strength BiCF_UBS = BiCF.ultimate_bearing_strength UniCF = Unidirectional_Carbon_Fiber() UniCF_MGT = UniCF.minimum_gage_thickness UniCF_DEN = UniCF.density UniCF_UTS = UniCF.ultimate_tensile_strength UniCF_USS = UniCF.ultimate_shear_strength HCMB = Carbon_Fiber_Honeycomb() HCMB_MGT = HCMB.minimum_gage_thickness HCMB_DEN = HCMB.density RIB = Aluminum_Rib() RIB_WID = RIB.minimum_width RIB_MGT = RIB.minimum_gage_thickness RIB_DEN = RIB.density ALUM = Aluminum() ALUM_DEN = ALUM.density ALUM_MGT = ALUM.minimum_gage_thickness ALUM_UTS = ALUM.ultimate_tensile_strength EPOXY = Epoxy() EPOXY_MGT = EPOXY.minimum_gage_thickness EPOXY_DEN = EPOXY.density PAINT = Paint() PAINT_MGT = PAINT.minimum_gage_thickness PAINT_DEN = PAINT.density #------------------------------------------------------------------------------- # Airfoil #------------------------------------------------------------------------------- NACA = np.multiply(5 * thicknessToChord, [0.2969, -0.1260, -0.3516, 0.2843, -0.1015]) coord = np.unique(fwdWeb + aftWeb + np.linspace(0, 1, N).tolist())[:, np.newaxis] coordMAT = np.concatenate( (coord**0.5, coord, coord**2, coord**3, coord**4), axis=1) nacaMAT = coordMAT.dot(NACA)[:, np.newaxis] coord = np.concatenate((coord, nacaMAT), axis=1) coord = np.concatenate( (coord[-1:0:-1], coord.dot(np.array([[1., 0.], [0., -1.]]))), axis=0) coord[:, 0] = coord[:, 0] - xShear #------------------------------------------------------------------------------- # Beam Geometry #------------------------------------------------------------------------------- x = np.concatenate( (np.linspace(0, 1, N), np.linspace(1, 1 + wingletFraction[0], N)), axis=0) x = x * wingspan / 2 x = np.sort(np.concatenate((x, motor_spanwise_locations), axis=0)) dx = x[1] - x[0] N = np.size(x) fwdWeb[:] = [round(locFwd - xShear, 2) for locFwd in fwdWeb] aftWeb[:] = [round(locAft - xShear, 2) for locAft in aftWeb] #------------------------------------------------------------------------------- # Loads #------------------------------------------------------------------------------- L = (1 - (x / np.max(x))**2)**0.5 # Assumes Elliptic Lift Distribution L0 = 0.5 * G_max * MTOW * 9.8 * liftFraction * SF # Total Design Lift Force L = L0 / np.sum(L[0:-1] * np.diff(x)) * L # Net Lift Distribution T = L * chord[0] * cmocl # Torsion Distribution D = L / LoD # Drag Distribution #------------------------------------------------------------------------------- # Shear/Moments #------------------------------------------------------------------------------- Vx = np.append(np.cumsum((D[0:-1] * np.diff(x))[::-1])[::-1], 0) # Drag Shear Vz = np.append(np.cumsum((L[0:-1] * np.diff(x))[::-1])[::-1], 0) # Lift Shear Vt = 0 * Vz # Initialize Thrust Shear # Calculate shear due to thrust by adding thrust from each motor to each # analysis point that's closer to the wing root than the motor. Accomplished # by indexing Vt according to a boolean mask of the design points that area # less than or aligned with the motor location under consideration in an # iterative loop for i in range(np.size(motor_spanwise_locations)): Vt[x <= motor_spanwise_locations[i]] = Vt[ x <= motor_spanwise_locations[i]] + max_thrust Mx = np.append(np.cumsum((Vz[0:-1] * np.diff(x))[::-1])[::-1], 0) # Bending Moment My = np.append(np.cumsum((T[0:-1] * np.diff(x))[::-1])[::-1], 0) # Torsion Moment Mz = np.append(np.cumsum((Vx[0:-1] * np.diff(x))[::-1])[::-1], 0) # Drag Moment Mt = np.append(np.cumsum((Vt[0:-1] * np.diff(x))[::-1])[::-1], 0) # Thrust Moment Mz = np.max((Mz, Mt)) # Worst Case of Drag vs. Thrust Moment #------------------------------------------------------------------------------- # General Structural Properties #------------------------------------------------------------------------------- seg = [] # LIST of Structural Segments # Torsion box = coord # Box Initally Matches Airfoil box = box[box[:, 0] <= aftWeb[1]] # Inlcude Only Parts Fwd of Aftmost Spar box = box[box[:, 0] >= fwdWeb[0]] # Include Only Parts Aft of Fwdmost Spar box = box * chord[0] # Scale by Chord Length # Use Shoelace Formula to calculate box area torsionArea = 0.5 * np.abs( np.dot(box[:, 0], np.roll(box[:, 1], 1)) - np.dot(box[:, 1], np.roll(box[:, 0], 1))) torsionLength = np.sum(np.sqrt(np.sum(np.diff(box, axis=0)**2, axis=1))) # Bending box = coord # Box Initally Matches Airfoil box = box[box[:, 0] <= fwdWeb[1]] # Inlcude Only Parts Fwd of Aft Fwd Spar box = box[box[:, 0] >= fwdWeb[0]] # Include Only Parts Aft of Fwdmost Spar seg.append(box[box[:, 1] > np.mean(box[:, 1])] * chord[0]) # Upper Fwd Segment seg.append(box[box[:, 1] < np.mean(box[:, 1])] * chord[0]) # Lower Fwd Segment # Drag box = coord # Box Initally Matches Airfoil box = box[box[:, 0] <= aftWeb[1]] # Inlcude Only Parts Fwd of Aftmost Spar box = box[box[:, 0] >= aftWeb[0]] # Include Only Parts Aft of Fwd Aft Spar seg.append(box[box[:, 1] > np.mean(box[:, 1])] * chord[0]) # Upper Aft Segment seg.append(box[box[:, 1] < np.mean(box[:, 1])] * chord[0]) # Lower Aft Segment # Bending/Drag Inertia flapInertia = 0 flapLength = 0 dragInertia = 0 dragLength = 0 for i in range(0, 4): l = np.sqrt(np.sum(np.diff(seg[i], axis=0)**2, axis=1)) # Segment lengths c = (seg[i][1::] + seg[i][0:-1]) / 2 # Segment centroids if i < 2: flapInertia += np.abs(np.sum( l * c[:, 1]**2)) # Bending Inertia per Unit Thickness flapLength += np.sum(l) else: dragInertia += np.abs(np.sum( l * c[:, 0]**2)) # Drag Inertia per Unit Thickness dragLength += np.sum(l) # Shear box = coord # Box Initially Matches Airfoil box = box[box[:, 0] <= fwdWeb[1]] # Include Only Parts Fwd of Aft Fwd Spar z = np.zeros(2) z[0] = np.interp(fwdWeb[0], box[box[:, 1] > 0, 0], box[box[:, 1] > 0, 1]) * chord[0] # Upper Surface of Box at Fwdmost Spar z[1] = np.interp(fwdWeb[0], box[box[:, 1] < 0, 0], box[box[:, 1] < 0, 1]) * chord[0] # Lower Surface of Box at Fwdmost Spar h = np.abs(z[0] - z[1]) # Height of Box at Fwdmost Spar # Skin box = coord * chord # Box Initially is Airfoil Scaled by Chord skinLength = np.sum(np.sqrt(np.sum(np.diff(box, axis=0)**2, axis=1))) A = 0.5 * np.abs( np.dot(box[:, 0], np.roll(box[:, 1], 1)) - np.dot( box[:, 1], np.roll(box[:, 0], 1))) # Box Area via Shoelace Formula #--------------------------------------------------------------------------- # Structural Calculations #--------------------------------------------------------------------------- # Calculate Skin Weight Based on Torsion tTorsion = My * dx / (2 * BiCF_USS * torsionArea) # Torsion Skin Thickness tTorsion = np.maximum(tTorsion, BiCF_MGT * np.ones(N)) # Gage Constraint mTorsion = tTorsion * torsionLength * BiCF_DEN # Torsion Mass mCore = HCMB_MGT * torsionLength * HCMB_DEN * np.ones(N) # Core Mass mGlue = EPOXY_MGT * EPOXY_DEN * torsionLength * np.ones(N) # Epoxy Mass # Calculate Flap Mass Based on Bending tFlap = Mx * np.max(seg[0][:, 1]) / (flapInertia * UniCF_UTS ) # Bending Flap Thickness mFlap = tFlap * flapLength * UniCF_DEN # Bending Flap Mass mGlue += EPOXY_MGT * EPOXY_DEN * flapLength * np.ones( N) # Updated Epoxy Mass # Calculate Drag Flap Mass tDrag = Mz * np.max(seg[2][:, 0]) / (dragInertia * UniCF_UTS ) # Drag Flap Thickness mDrag = tDrag * dragLength * UniCF_DEN # Drag Flap Mass mGlue += EPOXY_MGT * EPOXY_DEN * dragLength * np.ones( N) # Updated Epoxy Mass # Calculate Shear Spar Mass tShear = 1.5 * Vz / (BiCF_USS * h) # Shear Spar Thickness tShear = np.maximum(tShear, BiCF_MGT * np.ones(N)) # Gage constraint mShear = tShear * h * BiCF_DEN # Shear Spar Mass # Paint mPaint = skinLength * PAINT_MGT * PAINT_DEN * np.ones(N) # Paint Mass # Section Mass Total m = mTorsion + mCore + mFlap + mDrag + mShear + mGlue + mPaint # Rib Mass mRib = (A + skinLength * RIB_WID) * RIB_MGT * RIB_DEN # Total Mass mass = 2 * (sum(m[0:-1] * np.diff(x)) + nRibs * mRib) * grace return mass
def prop(prop, maximum_thrust, chord_to_radius_ratio=0.1, thickness_to_chord=0.12, root_to_radius_ratio=0.1, moment_to_lift_ratio=0.02, spanwise_analysis_points=5, safety_factor=1.5, margin_factor=1.2, forward_web_locations=[0.25, 0.35], shear_center=0.25, speed_of_sound=340.294, tip_max_mach_number=0.65): """weight = SUAVE.Methods.Weights.Buildups.Common.prop( prop, maximum_thrust, chord_to_radius_ratio = 0.1, thickness_to_chord = 0.12, root_to_radius_ratio = 0.1, moment_to_lift_ratio = 0.02, spanwise_analysis_points = 5, safety_factor = 1.5, margin_factor = 1.2, forward_web_locationss = [0.25, 0.35], shear_center = 0.25, speed_of_sound = 340.294, tip_max_mach_number = 0.65) Assumptions: Calculates propeller blade pass for an eVTOL vehicle based on assumption of a NACA airfoil prop, an assumed cm/cl, tip Mach limit, and structural geometry. Intended for use with the following SUAVE vehicle types, but may be used elsewhere: Electric Multicopter Electric Vectored_Thrust Electric Stopped Rotor Originally written as part of an AA 290 project inteded for trade study of the above vehicle types. Sources: Project Vahana Conceptual Trade Study Inputs: prop SUAVE Propeller Data Structure maximum_thrust Maximum Design Thrust [N] chord_to_radius_ratio Chord to Blade Radius [Unitless] thickness_to_chord Blade Thickness to Chord [Unitless] root_to_radius_ratio Root Structure to Blade Radius [Unitless] moment_to_lift_ratio Coeff. of Moment to Coeff. of Lift [Unitless] spanwise_analysis_points Analysis Points for Sizing [Unitless] safety_factor Design Safety Factor [Unitless] margin_factor Allowable Extra Mass Fraction [Unitless] forward_web_locationss Location of Forward Spar Webbing [m] shear_center Location of Shear Center [m] speed_of_sound Local Speed of Sound [m/s] tip_max_mach_number Allowable Tip Mach Number [Unitless] Outputs: weight: Propeller Mass [kg] Properties Used: Material properties of imported SUAVE Solids """ #------------------------------------------------------------------------------- # Unpack Inputs #------------------------------------------------------------------------------- rProp = prop.tip_radius maxThrust = maximum_thrust nBlades = prop.number_blades chord = rProp * chord_to_radius_ratio N = spanwise_analysis_points SF = safety_factor toc = thickness_to_chord fwdWeb = cp.deepcopy(forward_web_locations) xShear = shear_center rootLength = rProp * root_to_radius_ratio grace = margin_factor sound = speed_of_sound tipMach = tip_max_mach_number cmocl = moment_to_lift_ratio #------------------------------------------------------------------------------- # Unpack Material Properties #------------------------------------------------------------------------------- BiCF = Bidirectional_Carbon_Fiber() BiCF_MGT = BiCF.minimum_gage_thickness BiCF_DEN = BiCF.density BiCF_UTS = BiCF.ultimate_tensile_strength BiCF_USS = BiCF.ultimate_shear_strength BiCF_UBS = BiCF.ultimate_bearing_strength UniCF = Unidirectional_Carbon_Fiber() UniCF_MGT = UniCF.minimum_gage_thickness UniCF_DEN = UniCF.density UniCF_UTS = UniCF.ultimate_tensile_strength UniCF_USS = UniCF.ultimate_shear_strength HCMB = Carbon_Fiber_Honeycomb() HCMB_MGT = HCMB.minimum_gage_thickness HCMB_DEN = HCMB.density RIB = Aluminum_Rib() RIB_WID = RIB.minimum_width RIB_MGT = RIB.minimum_gage_thickness RIB_DEN = RIB.density ALUM = Aluminum() ALUM_DEN = ALUM.density ALUM_MGT = ALUM.minimum_gage_thickness ALUM_UTS = ALUM.ultimate_tensile_strength NICK = Nickel() NICK_DEN = NICK.density EPOXY = Epoxy() EPOXY_MGT = EPOXY.minimum_gage_thickness EPOXY_DEN = EPOXY.density PAINT = Paint() PAINT_MGT = PAINT.minimum_gage_thickness PAINT_DEN = PAINT.density #------------------------------------------------------------------------------- # Airfoil #------------------------------------------------------------------------------- NACA = np.multiply(5 * toc, [0.2969, -0.1260, -0.3516, 0.2843, -0.1015]) coord = np.unique(fwdWeb + np.linspace(0, 1, N).tolist())[:, np.newaxis] coordMAT = np.concatenate( (coord**0.5, coord, coord**2, coord**3, coord**4), axis=1) nacaMAT = coordMAT.dot(NACA)[:, np.newaxis] coord = np.concatenate((coord, nacaMAT), axis=1) coord = np.concatenate( (coord[-1:0:-1], coord.dot(np.array([[1., 0.], [0., -1.]]))), axis=0) coord[:, 0] = coord[:, 0] - xShear #------------------------------------------------------------------------------- # Beam Geometry #------------------------------------------------------------------------------- x = np.linspace(0, rProp, N) dx = x[1] - x[0] fwdWeb[:] = [round(loc - xShear, 2) for loc in fwdWeb] #------------------------------------------------------------------------------- # Loads #------------------------------------------------------------------------------- omega = sound * tipMach / rProp # Propeller Angular Velocity F = SF * 3 * (maxThrust / rProp**3) * (x** 2) / nBlades # Force Distribution Q = F * chord * cmocl # Torsion Distribution #------------------------------------------------------------------------------- # Initial Mass Estimates #------------------------------------------------------------------------------- box = coord * chord skinLength = np.sum(np.sqrt(np.sum(np.diff(box, axis=0)**2, axis=1))) maxThickness = (np.amax(box[:, 1]) - np.amin(box[:, 1])) / 2 rootBendingMoment = SF * maxThrust / nBlades * 0.75 * rProp m = (UniCF_DEN*dx*rootBendingMoment/ (2*UniCF_USS*maxThickness))+ \ skinLength*BiCF_MGT*dx*BiCF_DEN m = m * np.ones(N) error = 1 # Initialize Error tolerance = 1e-8 # Mass Tolerance massOld = np.sum(m) #------------------------------------------------------------------------------- # General Structural Properties #------------------------------------------------------------------------------- seg = [] # List of Structural Segments # Torsion enclosedArea = 0.5 * np.abs( np.dot(box[:, 0], np.roll(box[:, 1], 1)) - np.dot(box[:, 1], np.roll(box[:, 0], 1))) # Shoelace Formula # Flap Properties box = coord # Box Initially Matches Airfoil box = box[box[:, 0] <= fwdWeb[1]] # Trim Coordinates Aft of Aft Web box = box[box[:, 0] >= fwdWeb[0]] # Trim Coordinates Fwd of Fwd Web seg.append(box[box[:, 1] > np.mean(box[:, 1])] * chord) # Upper Fwd Segment seg.append(box[box[:, 1] < np.mean(box[:, 1])] * chord) # Lower Fwd Segment # Flap & Drag Inertia capInertia = 0 capLength = 0 for i in range(0, 2): l = np.sqrt(np.sum(np.diff(seg[i], axis=0)**2, axis=1)) # Segment Lengths c = (seg[i][1::] + seg[i][0::-1]) / 2 # Segment Centroids capInertia += np.abs(np.sum(l * c[:, 1]**2)) capLength += np.sum(l) # Shear Properties box = coord box = box[box[:, 0] <= fwdWeb[1]] z = box[box[:, 0] == fwdWeb[0], 1] * chord shearHeight = np.abs(z[0] - z[1]) # Core Properties box = coord box = box[box[:, 0] >= fwdWeb[0]] box = box * chord coreArea = 0.5 * np.abs( np.dot(box[:, 0], np.roll(box[:, 1], 1)) - np.dot(box[:, 1], np.roll(box[:, 0], 1))) # Shoelace Formula # Shear/Moment Calculations Vz = np.append(np.cumsum((F[0:-1] * np.diff(x))[::-1])[::-1], 0) # Bending Moment Mx = np.append(np.cumsum((Vz[0:-1] * np.diff(x))[::-1])[::-1], 0) # Torsion Moment My = np.append(np.cumsum((Q[0:-1] * np.diff(x))[::-1])[::-1], 0) # Drag Moment #------------------------------------------------------------------------------- # Mass Calculation #------------------------------------------------------------------------------- while error > tolerance: CF = (SF * omega**2 * np.append( np.cumsum((m[0:-1] * np.diff(x) * x[0:-1])[::-1])[::-1], 0) ) # Centripetal Force # Calculate Skin Weight Based on Torsion tTorsion = My / (2 * BiCF_USS * enclosedArea) # Torsion Skin Thickness tTorsion = np.maximum(tTorsion, BiCF_MGT * np.ones(N)) # Gage Constraint mTorsion = tTorsion * skinLength * BiCF_DEN # Torsion Mass # Calculate Flap Mass Based on Bending tFlap = CF/(capLength*UniCF_UTS) + \ Mx*np.amax(np.abs(box[:,1]))/(capInertia*UniCF_UTS) mFlap = tFlap * capLength * UniCF_DEN mGlue = EPOXY_MGT * EPOXY_DEN * capLength * np.ones(N) # Calculate Web Mass Based on Shear tShear = 1.5 * Vz / (BiCF_USS * shearHeight) tShear = np.maximum(tShear, BiCF_MGT * np.ones(N)) mShear = tShear * shearHeight * BiCF_DEN # Paint Weight mPaint = skinLength * PAINT_MGT * PAINT_DEN * np.ones(N) # Core Mass mCore = coreArea * HCMB_DEN * np.ones(N) mGlue += EPOXY_MGT * EPOXY_DEN * skinLength * np.ones(N) # Leading Edge Protection box = coord * chord box = box[box[:, 0] < (0.1 * chord)] leLength = np.sum(np.sqrt(np.sum(np.diff(box, axis=0)**2, axis=1))) mLE = leLength * 420e-6 * NICK_DEN * np.ones(N) # Section Mass m = mTorsion + mCore + mFlap + mShear + mGlue + mPaint + mLE # Rib Weight mRib = (enclosedArea + skinLength * RIB_WID) * RIB_MGT * RIB_DEN # Root Fitting box = coord * chord rRoot = (np.amax(box[:, 1]) - np.amin(box[:, 1])) / 2 t = np.amax(CF)/(2*np.pi*rRoot*ALUM_UTS) + \ np.amax(Mx)/(3*np.pi*rRoot**2*ALUM_UTS) mRoot = 2 * np.pi * rRoot * t * rootLength * ALUM_DEN # Total Weight mass = nBlades * (np.sum(m[0:-1] * np.diff(x)) + 2 * mRib + mRoot) error = np.abs(mass - massOld) massOld = mass mass = mass * grace return mass
def fuselage(config, maximum_g_load=3.8, landing_impact_factor=3.5, safety_factor=1.5): """ Calculates the structural mass of a fuselage for an eVTOL vehicle, assuming a structural keel taking bending an torsional loads. Assumptions: Assumes an elliptical fuselage. Intended for use with the following SUAVE vehicle types, but may be used elsewhere: Electric Multicopter Electric Vectored_Thrust Electric Stopped Rotor Originally written as part of an AA 290 project intended for trade study of the above vehicle types. If vehicle model does not have material properties assigned, appropriate assumptions are made based on SUAVE's Solids Attributes library. Sources: Project Vahana Conceptual Trade Study Inputs: config SUAVE Vehicle Configuration max_g_load Max Accelerative Load During Flight [Unitless] landing_impact_factor Maximum Load Multiplier on Landing [Unitless] Outputs: weight: Estimated Fuselage Mass [kg] Properties Used: Material Properties of Imported SUAVE Solids """ #------------------------------------------------------------------------------- # Unpack Inputs #------------------------------------------------------------------------------- fuse = config.fuselages.fuselage fLength = fuse.lengths.total fWidth = fuse.width fHeight = fuse.heights.maximum maxSpan = config.wings["main_wing"].spans.projected MTOW = config.mass_properties.max_takeoff G_max = maximum_g_load LIF = landing_impact_factor SF = safety_factor #------------------------------------------------------------------------------- # Unpack Material Properties #------------------------------------------------------------------------------- try: rbmMat = fuse.keel_materials.root_bending_moment_carrier except AttributeError: rbmMat = Unidirectional_Carbon_Fiber() rbmDen = rbmMat.density rbmUTS = rbmMat.ultimate_tensile_strength try: shearMat = fuse.keel_materials.shear_carrier except AttributeError: shearMat = Bidirectional_Carbon_Fiber() shearDen = shearMat.density shearUSS = shearMat.ultimate_shear_strength try: bearingMat = fuse.keel_materials.bearing_carrier except AttributeError: bearingMat = Bidirectional_Carbon_Fiber() bearingDen = bearingMat.density bearingUBS = bearingMat.ultimate_bearing_strength try: boltMat = fuse.materials.bolt_materials.landing_pad_bolt except AttributeError: boltMat = Steel() boltUSS = boltMat.ultimate_shear_strength # Calculate Skin & Canopy Weight Per Unit Area (arealWeight) based on material try: skinArealWeight = np.sum([(mat.minimum_gage_thickness * mat.density) for mat in fuse.skin_materials]) except AttributeError: skinArealWeight = 1.2995 # Stack of bidirectional CFRP, Honeycomb Core, Paint try: canopyArealWeight = np.sum([(mat.minimum_gage_thickness * mat.density) for mat in fuse.canopy_materials]) except AttributeError: canopyArealWeight = 3.7465 # Acrylic # Calculate fuselage area (using assumption of ellipsoid), and weight: S_wet = 4 * np.pi * (((fLength * fWidth / 4)**1.6 + (fLength * fHeight / 4)**1.6 + (fWidth * fHeight / 4)**1.6) / 3)**(1 / 1.6) skinMass = S_wet * skinArealWeight # Calculate the mass of a structural bulkhead bulkheadMass = 3 * np.pi * fHeight * fWidth / 4 * skinArealWeight # Calculate the mass of a canopy canopyMass = S_wet / 8 * canopyArealWeight # Calculate keel mass needed to carry lifting moment L_max = G_max * MTOW * 9.8 * SF # Max Lifting Load M_lift = L_max * fLength / 2. # Max Moment Due to Lift beamWidth = fWidth / 3. # Allowable Keel Width beamHeight = fHeight / 10. # Allowable Keel Height beamArea = M_lift * beamHeight / (4 * rbmUTS * (beamHeight / 2)**2) massKeel = beamArea * fLength * rbmDen # Calculate keel mass needed to carry wing bending moment shear M_bend = L_max / 2 * maxSpan / 2 # Max Bending Moment beamArea = beamHeight * beamWidth # Enclosed Beam Area beamThk = 0.5 * M_bend / (shearUSS * beamArea) # Beam Thickness massKeel += 2 * (beamHeight + beamWidth) * beamThk * shearDen # Calculate keel mass needed to carry landing impact load assuming F_landing = SF * MTOW * 9.8 * LIF * 0.6403 # Side Landing Force boltArea = F_landing / boltUSS # Required Bolt Area boltDiam = 2 * np.sqrt(boltArea / np.pi) # Bolt Diameter lamThk = F_landing / (boltDiam * bearingUBS) # Laminate Thickness lamVol = (np.pi * (20 * lamThk)**2) * (lamThk / 3) # Laminate Pad volume massKeel += 4 * lamVol * bearingDen # Mass of 4 Pads # Calculate total mass as the sum of skin mass, bulkhead mass, canopy pass, # and keel mass. Called weight by SUAVE convention weight = skinMass + bulkheadMass + canopyMass + massKeel return weight