| name | fatigue-analysis-4-spectral-fatigue-analysis |
| description | Sub-skill of fatigue-analysis: 4. Spectral Fatigue Analysis (+1). |
| version | 1.0.0 |
| category | engineering |
| type | reference |
| scripts_exempt | true |
4. Spectral Fatigue Analysis (+1)
4. Spectral Fatigue Analysis
Narrow-Band Spectral Method:
def spectral_fatigue_narrow_band(
spectrum: np.ndarray,
frequencies: np.ndarray,
sn_curve: dict,
duration: float,
design_factor: float = 10.0
) -> dict:
"""
Calculate fatigue damage using narrow-band spectral method.
Assumes Rayleigh distribution of stress ranges.
Args:
spectrum: Stress response spectrum S(f)
frequencies: Frequency array (Hz)
sn_curve: S-N curve parameters
duration: Duration of analysis (seconds)
design_factor: Safety factor
Returns:
Fatigue damage
"""
m0 = np.trapz(spectrum, frequencies)
m2 = np.trapz(spectrum * frequencies**2, frequencies)
m4 = np.trapz(spectrum * frequencies**4, frequencies)
f0 = np.sqrt(m2 / m0)
N0 = f0 * duration
sigma = np.sqrt(m0)
m = sn_curve['m1']
a = sn_curve['a1']
from scipy.special import gamma
damage = N0 * (2 * sigma)**m * gamma(1 + m/2) / a
damage_with_df = damage * design_factor
if damage > 0:
fatigue_life = duration / damage
else:
fatigue_life = np.inf
return {
'total_damage': damage,
'damage_with_design_factor': damage_with_df,
'fatigue_life_seconds': fatigue_life,
'fatigue_life_years': fatigue_life / (365.25 * 24 * 3600),
'sigma_stress': sigma,
'zero_crossing_freq': f0
}
freq_hz = np.linspace(0.01, 0.5, 500)
S_stress = 100 * freq_hz**(-2)
fatigue_spectral = spectral_fatigue_narrow_band(
S_stress,
freq_hz,
sn_f3,
duration=3600,
design_factor=10.0
)
fatigue_spectral['damage_25yr'] = fatigue_spectral['total_damage'] * 8760 * 25
print(f"Spectral Fatigue (25 years):")
print(f" Damage: {fatigue_spectral['damage_25yr']:.4f}")
print(f" Utilization: {fatigue_spectral['damage_25yr'] * 10:.1f}%")
5. Mooring Line Fatigue
Chain Fatigue at Fairlead:
def mooring_chain_fatigue_analysis(
tension_time_series: np.ndarray,
chain_diameter: float,
chain_grade: str = 'R4',
design_life_years: float = 25,
time_step: float = 0.1
) -> dict:
"""
Complete mooring chain fatigue analysis.
Args:
tension_time_series: Tension time series (kN)
chain_diameter: Chain diameter (mm)
chain_grade: Chain grade (R3, R4, R5)
design_life_years: Design life (years)
time_step: Time step (seconds)
Returns:
Fatigue results
"""
grade_factors = {'R3': 0.0219, 'R4': 0.0246, 'R5': 0.0273}
MBL = grade_factors[chain_grade] * chain_diameter**2
d_mm = chain_diameter
A = np.pi * (d_mm/2)**2
stress_time_series = tension_time_series * 1000 / A
stress_ranges, cycle_counts = rainflow_counting(stress_time_series)
duration_hours = len(tension_time_series) * time_step / 3600
hours_total = 8760 * design_life_years
scale_factor = hours_total / duration_hours
cycle_counts_scaled = cycle_counts * scale_factor
sn_curve = get_dnv_sn_curve('F3', thickness=chain_diameter)
fatigue_result = calculate_fatigue_damage_miners_rule(
stress_ranges,
cycle_counts_scaled,
sn_curve,
design_factor=
)
{
: chain_diameter,
: chain_grade,
: MBL,
: design_life_years,
: fatigue_result[],
: fatigue_result[],
: fatigue_result[],
: fatigue_result[],
: stress_ranges,
: cycle_counts_scaled
}
tension = + * np.sin(*np.pi*np.arange()/)
chain_fatigue = mooring_chain_fatigue_analysis(
tension,
chain_diameter=,
chain_grade=,
design_life_years=,
time_step=
)
()
()
()
()
()
()