FDS Workflows

This page summarizes the main ways fdscore computes and combines Fatigue Damage Spectra.

Time-Domain FDS

compute_fds_time(...) is the main time-domain route. It reconstructs SDOF responses in the FFT domain, performs rainflow counting on each response, and accumulates damage with Miner rule.

from fdscore import SNParams, SDOFParams, compute_fds_time

sn = SNParams.normalized(slope_k=4.0)
sdof = SDOFParams(q=10.0, metric="pv", fmin=10.0, fmax=200.0, df=10.0)

fds = compute_fds_time(x, fs, sn=sn, sdof=sdof, detrend="linear", batch_size=64)

Use this route when you have a measured or synthesized acceleration time history and want fatigue damage based on actual time-domain cycle counting.

Reusing FDSTimePlan

When multiple signals share the same sampling setup, precomputing the transfer plan avoids rebuilding the FFT-domain transfer matrix for every call.

from fdscore import prepare_fds_time_plan

plan = prepare_fds_time_plan(fs=fs, n_samples=len(x), sdof=sdof)
fds_x = compute_fds_time(x, fs, sn=sn, sdof=sdof, plan=plan)
fds_y = compute_fds_time(y, fs, sn=sn, sdof=sdof, plan=plan)

Spectral FDS

The spectral route uses an internal Dirlik-based fatigue estimator.

From an explicit PSD

from fdscore import compute_fds_spectral_psd

fds = compute_fds_spectral_psd(
    f_psd_hz,
    psd_values,
    duration_s=3600.0,
    sn=sn,
    sdof=sdof,
)

From a time history through Welch

from fdscore import compute_fds_spectral_time

fds = compute_fds_spectral_time(
    x,
    fs,
    sn=sn,
    sdof=sdof,
    duration_s=3600.0,
)

This second route first estimates the PSD with Welch and then applies the same spectral fatigue model.

Deterministic Harmonic FDS

fdscore also supports deterministic harmonic workflows without requiring time-domain simulation of the whole signal.

Single sine

from fdscore import compute_fds_sine

fds = compute_fds_sine(
    freq_hz=80.0,
    amp=2.0,
    duration_s=300.0,
    sn=sn,
    sdof=sdof,
)

Dwell profiles

from fdscore import SineDwellSegment, compute_fds_dwell_profile

segments = [
    SineDwellSegment(freq_hz=40.0, amp=1.5, duration_s=600.0),
    SineDwellSegment(freq_hz=80.0, amp=2.0, duration_s=300.0),
]

fds_mission = compute_fds_dwell_profile(segments, sn=sn, sdof=sdof)

Dwell-discretized sine sweeps

from fdscore import compute_fds_sine_sweep

fds_sweep = compute_fds_sine_sweep(
    f_start_hz=20.0,
    f_stop_hz=200.0,
    amp=2.0,
    duration_s=180.0,
    sn=sn,
    sdof=sdof,
    spacing="log",
    n_steps=200,
)

This sweep route is intentionally modeled as a dwell-discretized approximation, not as a closed-form sweep fatigue equation.

FDS Algebra

fdscore provides explicit helpers for scaling and summing compatible FDS results.

from fdscore import scale_fds, sum_fds

fds_scaled = scale_fds(fds, factor=1.5)
fds_total = sum_fds([fds_x, fds_y, fds_z], weights=[0.5, 0.3, 0.2])

These operations require compatible fatigue semantics and the same oscillator grid. No implicit regridding is performed.

Choosing a Route

Use these rules of thumb:

  • compute_fds_time(...): best when you trust the time history and want time-domain cycle counting.

  • compute_fds_spectral_psd(...): best when the PSD is already the natural input and the Dirlik approximation is acceptable.

  • compute_fds_spectral_time(...): useful when your input is a time history but you want a PSD-based fatigue workflow.

  • deterministic helpers: use for sine, dwell, and sweep specifications rather than random vibration.