Skip to content

Commit 85b66fe

Browse files
authored
Merge pull request #52 from Czarified/fuselage
Fuselage work on MinorFrames
2 parents 794a299 + 792d150 commit 85b66fe

File tree

3 files changed

+162
-10
lines changed

3 files changed

+162
-10
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "hyperstruct"
3-
version = "0.0.3"
3+
version = "0.0.4"
44
description = "Hyperstruct"
55
authors = ["Benjamin Crews <[email protected]>"]
66
license = "MIT"

src/hyperstruct/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"""Hyperstruct."""
22

33
from dataclasses import dataclass
4+
from importlib.metadata import version
5+
6+
7+
__version__ = version("hyperstruct")
48

59

610
@dataclass
@@ -54,6 +58,9 @@ class Component:
5458
weights estimation.
5559
"""
5660

61+
material: Material
62+
"""material the cover is made of."""
63+
5764
def synthesis(self) -> None:
5865
"""The sizing method.
5966

src/hyperstruct/fuselage.py

Lines changed: 154 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import numpy as np
1313

1414
from hyperstruct import Component
15-
from hyperstruct import Material
1615

1716

1817
@dataclass
@@ -27,9 +26,6 @@ class Cover(Component):
2726
through a systematic check for the different criteria.
2827
"""
2928

30-
material: Material
31-
"""material the cover is made of."""
32-
3329
milled: bool
3430
"""if panel is to be milled for different field vs land thicknesses."""
3531

@@ -130,6 +126,12 @@ def field_thickness_postbuckled(self, alpha: float = 45) -> float:
130126
Postbuckled strength assumes sizing covers with diagonal tension. The
131127
diagonal tension angle is unknown because intermediate frame and
132128
stringer sizing is not known. An initial estimate of 45 degrees is used.
129+
130+
Args:
131+
alpha: Diagonal tension angle (assumed 45 degrees)
132+
133+
Returns:
134+
A float of field thickness.
133135
"""
134136
F_scr = (
135137
self.k_s
@@ -195,7 +197,11 @@ def thickness_pressure(self, F_allow: Any = None) -> Tuple[float, float]:
195197
from zero to peak pressure 20,000 times during the vehicle's useful
196198
life, with a stress concentration factor of 4.0.
197199
198-
Returns: (t_l, t_c)
200+
Args:
201+
F_allow: Allowable stress (25% yield, if not provided)
202+
203+
Returns:
204+
A tuple of (Land thickness, Field thickness).
199205
"""
200206
b = min(self.D, self.L)
201207
if not F_allow:
@@ -255,22 +261,32 @@ def panel_flutter(self, mach: float, altitude: float) -> float:
255261
To find the final required thickness, this method must be looped
256262
over for all Mach and altitudes corresponding to the flight
257263
envelope conditions of the aircraft.
264+
265+
Args:
266+
mach: Mach Number
267+
altitude: Altitude (in thousands of feet)
268+
269+
Returns:
270+
A float of Field Thickness.
258271
"""
259272
# Dynamic pressures based on standard day atmosphere.
260273
# Dynamic Pressure, q, in [psf]
261274
# Altitudes must be measured in [ft]
262-
if altitude <= 20000:
275+
if altitude <= 20:
263276
q = mach**2 * (1479.757 - 52.187 * altitude + 0.619868 * altitude**2)
264-
elif 20000 < altitude <= 70000:
277+
elif 20 < altitude <= 70:
265278
q = mach**2 * (
266279
1465.175
267280
- 50.76695 * altitude
268281
+ 0.6434412 * altitude**2
269282
- 0.002907194 * altitude**3
270283
)
271-
elif altitude > 70000:
284+
elif altitude > 70:
272285
q = mach**2 * (199.659 / altitude) ** 4
273286

287+
# Dynamic pressure is in [psf] convert to [psi]
288+
q = q / 144
289+
274290
# Calculate the Mach Number Effect
275291
# The Mach Number Effect, FM, is a 3 piece function from SWEEP.
276292
# This function is more conservative than the AFRL baseline curve,
@@ -320,7 +336,8 @@ def acoustic_fatigue(self) -> Tuple[float, float]:
320336
decibel level is then increased by 30, which represents jet noise instead
321337
of a purely random spectrum.
322338
323-
Returns: (t_l, t_c)
339+
Returns:
340+
A tuple of Land thickness, Field thickness (t_l, t_c).
324341
"""
325342
# Random distribution acoustic level, that provides a material fatigue
326343
# life of 10^9 cycles.
@@ -343,3 +360,131 @@ def acoustic_fatigue(self) -> Tuple[float, float]:
343360
f_c = 1.0794 + 0.000143 * x_c - 0.076475 * (1 / x_c) - 0.29969 * np.log(x_c)
344361

345362
return (float(f_l * t_l), float(f_c * t_c))
363+
364+
365+
@dataclass
366+
class MinorFrame(Component):
367+
"""Fuselage Minor Frame Component.
368+
369+
Minor Frames form part of the basic structural grid work that resists
370+
vehicle shear and bending loads. As opposed to Major Frames, Minor
371+
Frames do not redistribute concentrated loads. Minor Frames are sized
372+
for general shell stability, acoustic fatigue, and forced crippling
373+
due to postbuckled cover (skin) design.
374+
375+
Minor Frames have an assumed construction, shown here? The geometry
376+
variables, frame depth (c), and cap flange width (b), are user input
377+
parameters. Thickness is the only parameter determined by sizing.
378+
379+
For simplicity, the flanges are assumed to have a thickness twice
380+
that of the web.
381+
"""
382+
383+
c: float
384+
"""frame depth."""
385+
386+
b: float
387+
"""cap flange width."""
388+
389+
t_r: float = 0.0
390+
"""cap flange thickness."""
391+
392+
@property
393+
def t_w(self) -> float:
394+
"""Web thickness."""
395+
return self.t_r / 2
396+
397+
@property
398+
def area(self) -> float:
399+
"""Cross-sectional area."""
400+
return 4 * self.b * self.t_r + self.c * self.t_w
401+
402+
@property
403+
def i_xx(self) -> float:
404+
"""Second moment of area (bending moment of inertia).
405+
406+
Assumes the simplified case that t_r = 2*t_w.
407+
"""
408+
return self.t_r * (
409+
self.b * self.c**2 + 2 * self.b**3 / 3 - self.b**2 * self.c + self.c**3 / 24
410+
)
411+
412+
@property
413+
def rho(self) -> float:
414+
"""Radius of gyration."""
415+
return float(
416+
(
417+
(
418+
self.b * self.c**2
419+
+ 2 * self.b**3 / 3
420+
- self.b**2 * self.c
421+
+ self.c**3 / 24
422+
)
423+
/ (4 * self.b + self.c / 2)
424+
)
425+
** 0.5
426+
)
427+
428+
def general_stability(self, L: float, D: float, M: float) -> float:
429+
"""Thickness to avoid general instability.
430+
431+
The thickness that provides frame stiffness sufficient to prevent
432+
general instability failure is solved via the Shanley equation.
433+
434+
Args:
435+
L: Frame Spacing
436+
D: Fuselage Diameter
437+
M: Bending moment at the cut
438+
439+
Returns:
440+
A float of Flange thickness.
441+
"""
442+
c_f = 1 / 16000
443+
numerator = c_f * M * D**2
444+
denominator = (
445+
self.material.E_c
446+
* L
447+
* (self.b * self.c**2 + 2 * self.b**3 * self.c / 3 + self.c**3 / 24)
448+
)
449+
450+
return float(numerator / denominator)
451+
452+
def acoustic_fatigue(self, b: float) -> float:
453+
"""Thickness requirements based on acoustic fatigue.
454+
455+
Assumptions are:
456+
1.) The overall pressure level from jet engine noise is approximately
457+
30db higher than the random spectrum pressure level.
458+
2.) The accuracy of noise intensity prediction is on the order of +/-3db.
459+
3.) Beam theory is sufficient for modelign the shell elements.
460+
4.) The design to repetitive pressure intensity from jet engine noise
461+
can be correlated tot he material endurance limit. Polished specimen
462+
s-n data, K_t=1, is a sufficiently representative strength index.
463+
5.) The method is based on a limited amount of testing.
464+
6.) The method does not consider panel aspect ratio, and is, therefore,
465+
conservative when aspect ratios approach 1.
466+
467+
The sound pressure level used is based on a material property. This value
468+
provides the fatigue life of 10^9 cycles for the material. The overall
469+
decibel level is then increased by 30, which represents jet noise instead
470+
of a purely random spectrum.
471+
472+
Args:
473+
b: Support spacing (frame spacing)
474+
475+
Returns:
476+
A float of Flange thickness.
477+
"""
478+
# Random distribution acoustic level, that provides a material fatigue
479+
# life of 10^9 cycles.
480+
db_r = self.material.db_r
481+
db_oa = db_r + 30
482+
P = 2.9e-9 * 10 ** (db_oa / 20)
483+
# Note: K_c is directly hardcoded to 7.025, per Fig. 20 of ADA002867
484+
t_r = 7.025 * b**0.5 * P**2 / self.material.F_en
485+
486+
return float(t_r)
487+
488+
def forced_crippling(self) -> float:
489+
"""Thickness from force crippling."""
490+
return 0.0

0 commit comments

Comments
 (0)