Code documentation

Contents

Code documentation#

Spectral data#

Frequency-domain fatigue life#

Narrowband#

class FLife.freq_domain.Narrowband(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Miles [1] / Bendat and Piersol [2].

References

[1] John W. Miles. On structural fatigue under random loading. Journal

of the Aeronautical Sciences, 21(11):753{762, 1954.

[2] Julius S. Bendat and Allen G. Piersol. Measurement and Analysis of Random Data.

Wiley, 1966.

[3] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD = es.get_psd(freq, 20, 60, variance = 5)  # one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> nb = FLife.Narrowband(sd)
>>> print(f'Fatigue life: {nb.get_life(C,k):.3e} s.')

Define stress vector and depict stress peak PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,nb.get_PDF(s))
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s)[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:

s – numpy.ndarray Stress vector.

Returns:

function pdf(s)

damage_intesity_NB(m0, nu, C, k)[source]#

Calculates narrowband damage intensity with parameters m0, nu, C, k, as defined in [2].

Parameters:
  • m0 – [int,float] Zeroth spectral moment [MPa**2].

  • nu – [int,float] Frequency of positive slope zero crossing [Hz].

  • C – [int,float] Fatigue strength coefficient [MPa**k].

  • k – [int,float] Fatigue strength exponent [/].

Returns:

Estimated damage intensity.

Return type:

float

get_life(C, k, integrate_pdf=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • integrate_pdf – boolean If true the the fatigue life is estimated by integrating the PDF, Default is false which means that the theoretical equation is used

Returns:

Estimated fatigue life in seconds.

Return type:

float

Wirsching-Light#

class FLife.freq_domain.WirschingLight(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Wirsching and Light [1].

References

[1] Paul H. Wirsching and Mark C. Light. Fatigue under wide band random

stresses. Journal of the Structural Division, 106(7):1593-1607, 1980

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> wl = FLife.WirschingLight(sd)
>>> print(f'Fatigue life: {wl.get_life(C,k):.3e} s.')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Ortiz-Chen#

class FLife.freq_domain.OrtizChen(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Ortiz and Chen [1].

References

[1] K. Ortiz and N.K. Chen. Fatigue damage prediction for stationary wideband processes.

Fifth international conference on applications of statistics and probability in soil and structural engineering, 1987

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> oc = FLife.OrtizChen(sd)
>>> print(f'Fatigue life: {oc.get_life(C,k):.3e} s.')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Alpha075#

class FLife.freq_domain.Alpha075(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Benasciutti and Tovo [1].

References

[1] Denis Benasciutti and Robert Tovo. Rainflow cycle distribution and

fatigue damage in Gaussian random loadings. Technical report, Department of Engineering, University of Ferrara, 2004

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> alpha075 = FLife.Alpha075(sd)
>>> print(f'Fatigue life: {alpha075.get_life(C,k):.3e} s.')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Tovo-Benasciutti#

class FLife.freq_domain.TovoBenasciutti(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Tovo and Benasciutti[1, 2, 3].

References

[1] Roberto Tovo. Cycle distribution and fatigue damage under broadband

random loading. International Journal of Fatigue, 24(11):1137{ 1147, 2002

[2] Denis Benasciutti and Roberto Tovo. Spectral methods for lifetime

prediction under wide-band stationary random processes. International Journal of Fatigue, 27(8):867{877, 2005

[3] Denis Benasciutti and Roberto Tovo. Comparison of spectral methods for fatigue

analysis of broad-band Gaussian random processes. Probabilistic Engineering Mechanics, 21(4), 287-299, 2006

[4] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> tb = FLife.TovoBenasciutti(sd)
>>> print(f'Fatigue life, method 1: {tb.get_life(C,k, method="method 1"):.3e} s.')
>>> print(f'Fatigue life, method 2: {tb.get_life(C,k, method="method 2"):.3e} s.')

Define stress vector and depict stress peak PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,tb.get_PDF(s, method='method 1'), lw=5, alpha=.5, label = 'method 1')
>>> plt.plot(s,tb.get_PDF(s, method='method 2'), '--', label = 'method 2')
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
>>> plt.legend()
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s, method='method 2')[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:
  • s – numpy.ndarray Stress vector.

  • method

    string

    • ’method 1’: weighting parameter b is defined by Tovo[1].

    • ’method 2’: weighting parameter b is defined by Tovo and Benasciutti [2].

    • ’method 3’: weighting parameter b is defined by Tovo and Benasciutti [3].

Returns:

function pdf(s)

get_life(C, k, method='method 2', integrate_pdf=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [4].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • method

    string

    • ’method 1’: weighting parameter b is defined by Tovo[1].

    • ’method 2’: weighting parameter b is defined by Tovo and Benasciutti [2].

    • ’method 3’: weighting parameter b is defined by Tovo and Benasciutti [3].

  • integrate_pdf – boolean If true the the fatigue life is estimated by integrating the PDF, Default is false which means that the theoretical equation is used

Returns:

Estimated fatigue life in seconds.

Return type:

float

Dirlik#

class FLife.freq_domain.Dirlik(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Dirlik [1].

References

[1] Turan Dirlik. Application of computers in fatigue analysis. PhD thesis,

University of Warwick, 1985

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> dirlik = FLife.Dirlik(sd) # Dirlik's fatigue-life estimator
>>> print(f'Dirlik: {dirlik.get_life(C,k):.3e} s.')

Define stress vector and depict peak stress PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,dirlik.get_PDF(s))
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s)[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:

s – numpy.ndarray Stress vector

Returns:

function pdf(s)

get_life(C, k, integrate_pdf=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • integrate_pdf – boolean If true the the fatigue life is estimated by integrating the PDF. Default is false which means that the theoretical equation is used.

Returns:

Estimated fatigue life in seconds.

Return type:

float

Zhao-Baker#

class FLife.freq_domain.ZhaoBaker(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Zhao and Baker[1].

References

[1] Wangwen Zhao and Michael J. Baker. On the probability density function

of rainflow stress range for stationary Gaussian processes. International Journal of Fatigue, 14(2):121-135, 1992

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> tb = FLife.TovoBenasciutti(sd)
>>> zb = FLife.ZhaoBaker(sd)
>>> print(f'Fatigue life, method 1: {zb.get_life(C,k, method="method 1"):.3e} s.')
>>> print(f'Fatigue life, method 2: {zb.get_life(C,k, method="method 2"):.3e} s.')

Define stress vector and depict stress peak PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,zb.get_PDF(s, method='method 1'), lw=5, alpha=.5, label = 'method 1')
>>> plt.plot(s,zb.get_PDF(s, method='method 1'), '--', label = 'method 2')
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
>>> plt.legend()
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s, method='method 1')[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:
  • s – numpy.ndarray Stress vector.

  • method

    string

    • ’method 1’ is tuned in simulations with material parameters in the range of 2 <= k <= 6, where k is S-N curve coefficient.

    • ’method 2’ is derived for S-N curve coefficient k = 3.

Returns:

function pdf(s)

get_life(C, k, method='method 1', integrate_pdf=False)[source]#

Calculate fatigue life with parameters C and k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • method

    string

    • ’method 1’ is tuned in simulations with material parameters in the range of 2 <= k <= 6, where k is S-N curve coefficient.

    • ’method 2’ is derived for S-N curve coefficient k = 3.

  • integrate_pdf – boolean If true the the fatigue life is estimated by integrating the PDF, Default is false which means that the theoretical equation is used

Returns:

Estimated fatigue life in seconds.

Return type:

float

Park#

class FLife.freq_domain.Park(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Park et al.[1].

References

[1] Jun-Bum Park, Joonmo Choung and Kyung-Su Kim. A new fatigue prediction model for marine

structures subject to wide band stress process. Ocean Engineering, 76: 144-151, 2014

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> park = FLife.Park(sd)
>>> print(f'Fatigue life: {park.get_life(C,k):.3e} s.')

Define stress vector and depict stress peak PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,park.get_PDF(s))
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s)[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:

s – numpy.ndarray Stress vector.

Returns:

function pdf(s)

get_life(C, k, integrate_pdf=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Jun-Park#

class FLife.freq_domain.JunPark(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Jun and Park[1].

References

[1] Seock-Hee Jun and Jun-Bum Park. Development of a novel fatigue damage model for

Gaussian wide band stress responses using numerical approximation methods. International Journal of Naval Architecture and Ocean Engineering, 12: 755-767, 2020

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> jp = FLife.Jun(sd)
>>> print(f'Fatigue life: {jp.get_life(C,k):.3e} s.')

Define stress vector and depict stress peak PDF

>>> s = np.arange(0,np.max(x),.01)
>>> plt.plot(s,jp.get_PDF(s))
>>> plt.xlabel('Stress [MPa]')
>>> plt.ylabel('PDF')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

get_PDF(s)[source]#

Returns cycle PDF(Probability Density Function) as a function of stress s.

Parameters:

s – numpy.ndarray Stress vector.

Returns:

function pdf(s)

get_life(C, k, integrate_pdf=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Jiao-Moan#

class FLife.freq_domain.JiaoMoan(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Jiao and Moan [1].

References

[1] Guoyang Jiao and Torgeir Moan. Probabilistic analysis of fatigue due to Gaussian load processes.

Probabilistic Engineering Mechanics, 5(2):76-83, 1990

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> jm = FLife.JiaoMoan(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {jm.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Jiao-Moan method

>>> lower_band_index, upper_band_index= jm.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k, approximation=False)[source]#

Calculate fatigue life with parameters C, k, as defined in [1, 2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • approximation – Boolean IF true, approximated PDF of large peaks is used for bimodal random process.

Returns:

Estimated fatigue life in seconds.

Return type:

float

Sakai-Okamura#

class FLife.freq_domain.SakaiOkamura(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Sakai and Okamura[1].

References

[1] Shinsuke Sakai, Hiroyuki Okamura. On the distribution of rainflow range for Gaussian

random processes with bimodal PSD. JSME International Journal, Series A: Mechanics and Material Engineering, 38(4):440-445, 1995

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> so = FLife.SakaiOkamura(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {so.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Sakai-Okamura method

>>> lower_band_index, upper_band_index= so.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Fu-Cebon#

class FLife.freq_domain.FuCebon(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Fu and Cebon [1].

References

[1] Tsengti Fu, David Cebon. Predicting fatigue lives for bi-modal stress spectral densities.

International Journal of Fatigue, 22(1):11-21, 2000

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> fc = FLife.FuCebon(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {fc.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Fu-Cebon method

>>> lower_band_index, upper_band_index= fc.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [1, 2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Modified Fu-Cebon#

class FLife.freq_domain.ModifiedFuCebon(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Benasciutti and Tovo[1].

References

[1] Denis Benasciutti and Roberto Tovo. Comparison of spectral methods for fatigue damage

assessment in bimodal random processes. 9th International Conference on Structural Safety & Reliability (ICOSSAR), 230:3207-3214, 2005

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> mfc = FLife.ModifiedFuCebon(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {mfc.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in modified Fu-Cebon method

>>> lower_band_index, upper_band_index= mfc.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Low’s bimodal#

class FLife.freq_domain.Low(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Low[1].

Notes

Numerical implementation supports only integer values of S-N curve parameter k (inverse slope). Due to approximation of large stress cycles through McLaurin series, sufficient engineering precision is up to k=6 [1].

References

[1] Y.M.Low. A method for accurate estimation of the fatigue damage

induced by bimodal processes. Probabilistic Engineering Mechanics, 25(1):75-85, 2010

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> low = FLife.Low(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {low.get_life(C,int(k)):.3e} s.')

Plot segmentated PSD, used in Low’s method

>>> lower_band_index, upper_band_index= low.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Low 2014#

class FLife.freq_domain.Low2014(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Low[1].

References

[1] Ying Min Low. A simple surrogate model for the rainflow fatigue damage arising

from processes with bimodal spectra. Marine Structures, 38:72-88, 2014

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> low2014 = FLife.LowBimodal2014(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {low2014.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in LowBimodal2014 method

>>> lower_band_index, upper_band_index= low2014.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [1, 2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • approximation – Boolean IF true, approximated PDF of large peaks is used for bimodal random process.

Returns:

Estimated fatigue life in seconds.

Return type:

float

Lotsberg#

class FLife.freq_domain.Lotsberg(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Lotsberg[1].

References

[1] Inge Lotsberg. Background for Revision of DNV-RP-C203 Fatigue Analysis of

Offshore Steel Structure. 24th International Conference on Offshore Mechanics and Arctic Engineering, Halkidiki, Greece, 2005. ASME, Paper No. OMAE2005–67549.

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> lb = FLife.Lotsberg(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {lb.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Lotsberg method

>>> lower_band_index, upper_band_index= lb.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Huang-Moan#

class FLife.freq_domain.HuangMoan(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Class for fatigue life estimation using frequency domain method by Huang and Moan[1].

References

[1] Wenbo Huang and Torgeir Moan. Fatigue Under Combined High and Low Frequency Loads.

25th International Conference on Offshore Mechanics and Arctic Engineering, Hamburg, Germany, 2006. ASME, Paper No. OMAE2006–92247.

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> hm = FLife.HuangMoan(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {hm.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in HuangMoan method

>>> lower_band_index, upper_band_index= hm.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,300)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 2))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 2).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Gao-Moan#

class FLife.freq_domain.GaoMoan(spectral_data, PSD_splitting=('equalAreaBands', 3))[source]#

Class for fatigue life estimation using frequency domain method by Gao and Moan [1].

References

[1] Zhen Gao and Torgeir Moan. Frequency-domain fatigue analysis of

wide-band stationary Gaussian processes using a trimodal spectral formulation. International Journal of Fatigue, 30(10-11): 1944-1955, 2008

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_middle = es.get_psd(freq, 100, 120, variance = 1)  # middle mode of random process
>>> PSD_higher = es.get_psd(freq, 300, 350, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_middle + PSDb_higher # trimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> gm = FLife.GaoMoan(sd, PSD_splitting=('userDefinedBands', [80,150,400]))  # fatigue-life estimator
>>> print(f'Fatigue life: {gm.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Gao-Moan method

>>> lower_band_index, middle_band_index, upper_band_index= gm.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> # lower band
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][middle_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> # middle band
>>> plt.fill_between(sd.psd[lower_band_index:middle_band_index,0], sd.psd[lower_band_index:middle_band_index,1], 'o', label='middle band', alpha=.5, color ='orange')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> # upper band
>>> plt.fill_between(sd.psd[middle_band_index:upper_band_index,0], sd.psd[middle_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='green')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,450)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 3))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 3).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [1, 2].

Parameters:
  • C – [int,float]; S-N curve intercept [MPa**k].

  • k – [int,float]; S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Single moment#

class FLife.freq_domain.SingleMoment(spectral_data)[source]#

Class for fatigue life estimation using frequency domain method by Lutes and Larsen[1, 2].

References

[1] L.D. Lutes, C.E. Larsen. Improved spectral method for variable amplitude fatigue prediction,

Journal of Structural Engineering ASCE, 116(4):1149-1164, 1990

[2] C.E. Larsen, L.D. Lutes. Predicting the Fatigue Life of Offshore Structures by the Single-Moment Spectral Method,

Probabilistic Engineering Mechanics, 6(2):96-108, 1991

[3] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> sm = FLife.SingleMoment(sd)
>>> print(f'Fatigue life: {sm.get_life(C,k):.3e} s.')
__init__(spectral_data)[source]#

Get needed values from reference object.

Parameters:

spectral_data – Instance of class SpectralData

damage_intesity_SM(m_2k, C, k)[source]#

Calculates damage intensity with parameters m_2k, nu, C, k, as defined in [1,2].

Parameters:
  • m_2k – [int,float] 2/k-th spectral moment [MPa**2].

  • C – [int,float] Fatigue strength coefficient [MPa**k].

  • k – [int,float] Fatigue strength exponent [/].

Returns:

Estimated damage intensity.

Return type:

float

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [1,2,3].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Bands method#

class FLife.freq_domain.BandsMethod(spectral_data, PSD_splitting=('equalAreaBands', 1))[source]#

Class for fatigue life estimation using frequency domain method by Braccesi et al. [1].

References

[1] Claudio Braccesi, Filippo Cianetti and Lorenzo Tomassini. Random fatigue. A new

frequency domain criterion for the damage evaluation of mechanical components. International Journal of Fatigue, 70:417-427, 2015

[2] Aleš Zorman and Janko Slavič and Miha Boltežar.

Vibration fatigue by spectral methods—A review with open-source support, Mechanical Systems and Signal Processing, 2023, https://doi.org/10.1016/j.ymssp.2023.110149

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> bm = FLife.BandsMethod(sd, PSD_splitting=('userDefinedBands', [80,150]))
>>> print(f'Fatigue life: {bm.get_life(C,k):.3e} s.')

Plot segmentated PSD, used in Bands method

>>> lower_band_index, upper_band_index= bm.band_stop_indexes
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.vlines(sd.psd[:,0][lower_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[:lower_band_index,0], sd.psd[:lower_band_index,1], 'o', label='lower band', alpha=.2, color='blue')
>>> plt.vlines(sd.psd[:,0][upper_band_index], 0, np.max(sd.psd[:,1]), 'k', linestyles='dashed', alpha=.5)
>>> plt.fill_between(sd.psd[lower_band_index:upper_band_index,0], sd.psd[lower_band_index:upper_band_index,1], 'o', label='upper band', alpha=.5, color ='orange')
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')
>>> plt.xlim(0,200)
>>> plt.legend()
__init__(spectral_data, PSD_splitting=('equalAreaBands', 1))[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of class SpectralData

  • PSD_splitting

    tuple PSD_splitting[0] is PSD spliting method, PSD_splitting[1] is method argument. Splitting methods:

    • ’userDefinedBands’, PSD_splitting[1] must be of type list or tupple, with N elements specifying upper band frequencies of N random processes.

    • ’equalAreaBands’, PSD_splitting[1] must be of type int, specifying N random processes.

    Defaults to (‘equalAreaBands’, 1).

get_life(C, k)[source]#

Calculate fatigue life with parameters C, k, as defined in [1, 2].

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

Returns:

Estimated fatigue life in seconds.

Return type:

float

Time-domain fatigue life#

class FLife.time_domain.Rainflow(spectral_data, **kwargs)[source]#

Class for fatigue life estimation using rainflow counting method [1, 2].

References

[1] C. Amzallag et. al. Standardization of the rainflow counting method for

fatigue analysis. International Journal of Fatigue, 16 (1994) 287-293

[2] ASTM E1049-85

[3] Janko Slavič, Matjaž Mršnik, Martin Česnik, Jaka Javh, Miha Boltežar.

Vibration Fatigue by Spectral Methods, From Structural Dynamics to Fatigue Damage – Theory and Experiments, ISBN: 9780128221907, Elsevier, 1st September 2020

Example

Import modules, define time- and frequency-domain data

>>> import FLife
>>> import pyExSi as es
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> # time-domain data
>>> N = 2 ** 16  # number of data points of time signal
>>> fs = 2048  # sampling frequency [Hz]
>>> t = np.arange(0, N) / fs  # time vector
>>> # frequency-domain data
>>> M = N // 2 + 1  # number of data points of frequency vector
>>> freq = np.arange(0, M, 1) * fs / N  # frequency vector
>>> PSD_lower = es.get_psd(freq, 20, 60, variance = 5)  # lower mode of random process
>>> PSD_higher = es.get_psd(freq, 100, 120, variance = 2)  # higher mode of random process
>>> PSD = PSD_lower + PSD_higher # bimodal one-sided flat-shaped PSD

Get Gaussian stationary signal, instantiate SpectralData object and plot PSD

>>> rg = np.random.default_rng(123) # random generator seed
>>> x = es.random_gaussian(N, PSD, fs, rg) # Gaussian stationary signal
>>> sd = FLife.SpectralData(input=x, dt=1/fs) # SpectralData instance
>>> plt.plot(sd.psd[:,0], sd.psd[:,1])
>>> plt.xlabel('Frequency [Hz]')
>>> plt.ylabel('PSD')

Define S-N curve parameters and get fatigue-life estimatate

>>> C = 1.8e+22  # S-N curve intercept [MPa**k]
>>> k = 7.3 # S-N curve inverse slope [/]
>>> rf = FLife.Rainflow(sd)
>>> print(f'Fatigue life: {rf.get_life(C,k):.3e} s.')
__init__(spectral_data, **kwargs)[source]#

Get needed values from reference object.

Parameters:
  • spectral_data – Instance of object SpectralData

  • rg – Instance of numpy.random._generator.Generator Parameter rg cotrols phase of generated time history, if not already exist in spectral_data.

get_life(C, k, algorithm='four-point', Su=False, range=False, nr_load_classes=512, **kwargs)[source]#

Calculate fatigue life with parameters C, k, as defined in [3]

Parameters:
  • C – [int,float] S-N curve intercept [MPa**k].

  • k – [int,float] S-N curve inverse slope [/].

  • algorithm – str Cycle counting method. Options are ‘three-point’ and ‘four-point’. Defaults to ‘four-point’.

  • Su – [int,float] Ultimate tensile strength [MPa]. If specified, Goodman equivalent stress is used for fatigue life estimation. Defaults to False.

  • range – bool If True, ranges instead of amplitudes are used for fatigue life estimation. Defaults to False.

  • nr_load_classes – int The number of intervals to divide the min-max range of the dataseries into. Used with algorithm =’four-point’. Defaults to 512.

Returns:

Estimated fatigue life in seconds.

Return type:

float

Multiaxial fatigue life#

class FLife.multiaxial.EquivalentStress(input=None, window='hann', nperseg=1280, noverlap=None, psd_trim_length=None, T=None, fs=None, rg=None, **kwargs)[source]#

EquivalentStress object contains multiaxial data, based on input power spectral density (PSD). It is used to convert multiaxial stress states into equivalent uniaxiail stress states, that can be used in fatigue life estimation.

EquivalentStress inherits from SpectralData class, so all methods from SpectralData are available for fatigue analysis. If instance of SpectralData is passed as input, the multiaxial PSD is inherited, otherwise it is created from input PSD.


The following multiaxial criteria are available for equivalent stress calculation: - max_normal: Maximum normal stress on critical plane - max_shear: Maximum shear stress on critical plane - max_normal_and_shear: Maximum normal and shear stress on critical plane - EVMS: Equivalent von Misses stress - cs: Carpinteri-Spagnoli criterion - multiaxial_rainflow: Frequency-based multiaxial rainflow criterion - thermoelastic: Thermoelasticity-based criterion - EVMS_out_of_phase: EVMS adaptation for out-of-phase components - Nieslony: Nieslony criterion, combining von Mises and hydrostatic stresses - Lemaitre: Equivalent Lemaitre stress - liwi: LiWI approach - coin_liwi: COIN-LiWI method

__init__(input=None, window='hann', nperseg=1280, noverlap=None, psd_trim_length=None, T=None, fs=None, rg=None, **kwargs)[source]#

Class constructor for EquivalentStress object.

Parameters:
  • input – dictionary or instance of SpectralData class. Input data for EquivalentStress object. If dictionary, it should contain keys: PSD and f or keys ‘amplitude_spectrum’ and ‘f’. PSD should be an array with shape (f,6,6) for 3D stress state or (f,3,3) for 2D stress state. If multi-point PSD is provided, the shape should be (N,f,6,6) or (N,f,3,3) respectively. Amplitude spectrum should be an array with shape (f,3) for 2D stress state or (f,6) for 3D stress state. If multi-point amplitude spectrum is provided, the shape should be (N,f,3) or (N,f,6) respectively. If instance of SpectralData class is passed, the multiaxial PSD is inherited.

  • window – str or tuple or array_like, optional Desired window to use. Defaults to ‘hann’.

  • nperseg – int, optional Length of each segment. Defaults to 1280.

  • noverlap – int, optional Number of points to overlap between segments. If None, noverlap = nperseg / 2. Defaults to None.

  • psd_trim_length – int, optional Number of frequency points to be used for PSD. Defaults to None.

  • T – int, float, optional Length of time history when random process is defined by input parameter ‘GUI’ or by PSD and frequency vector. If T and fs are provided, time histoy is generated. Defaults to None.

  • fs – int, float, optional Sampling frequency of time history when random process is defined by input parameter ‘GUI’ or by PSD and frequency vector. If T and fs are provided, time histoy is generated. Defaults to None.

  • rg – numpy.random._generator.Generator, optional Random generator controls phase of generated time history, when input is ‘GUI’ or (PSD, frequency vector). Defaults to None.

loop_over_points(criterion, *args, **kwargs)[source]#

Loop the selected criterion over multiple points on the model

set_eq_stress(eq_psd, f)[source]#

Set equivalent stress to the object. Also generate im ehistory if T and fs are provided

select_critical_point(point_index)[source]#

Manually select a critical point from multipoint equivalent stress

Parameters:

point_index – int Index of the critical point

max_normal(search_method='local')[source]#

Converts the stress tensor at one node or multiple nodes to equivalent, scalar psd stress, using method of maximum normal stress.

Parameters:

search_method – str, optional, default ‘local’ Search method for optimization. Options are ‘local’ or ‘global’. Local is prefered, unless the optimization fails.


  • Nieslony, Adam and Macha, Ewald (2007);

    Spectral method in multiaxial random fatigue

max_shear(search_method='local')[source]#

Converts the stress tensor at one node or multiple nodes to equivalent, scalar psd stress, using method of maximum shear stress.

Parameters:

search_method – str, optional, default ‘local’ Search method for optimization. Options are ‘local’ or ‘global’. Local is prefered, unless the optimization fails.


  • Nieslony, Adam and Macha, Ewald (2007);

    Spectral method in multiaxial random fatigue

max_normal_and_shear(s_af, tau_af, search_method='local')[source]#

Converts the stress tensor at one node or multiple nodes to equivalent, scalar psd stress, using method of maximum normal and shear stress.

Critical plane is based on max variance of shear stress

Parameters:
  • s_af – float Fully reversed bending-fatigue limit. Used for calculating material fatigue coefficient K [1].

  • tau_af – float Fully reversed torsion-fatigue limit. Used Used for calculating material fatigue coefficient K [1].


  • Nieslony, Adam and Macha, Ewald (2007);

    Spectral method in multiaxial random fatigue

  • Matjaz Mrsnik, Janko Slavic and Miha Boltezar

    Multiaxial Vibration Fatigue A Theoretical and Experimental Comparison. Mechanical Systems and Signal Processing, 2016

EVMS()[source]#

Converts the stress tensor at one node or multiple nodes to equivalent, scalar psd stress, using ther equivalent von Misses stress in frequency domain (EVMS)


  • Preumont, A., & Piéfort, V. (1994);

    Predicting Random High-Cycle Fatigue Life With Finite Elements.

cs(s_af, tau_af)[source]#

Converts the stress tensor at one node to equivalent, scalar psd stress, using the C-S criterion.

Parameters:
  • s_af – float Fully reversed torsion-fatigue limit.

  • tau_af – float Fully reversed torsion-fatigue limit.


  • Carpinteri A, Spagnoli A and Vantadori S;

    Reformulation in the frequency domain of a critical plane-based multiaxial fatigue criterion, Int J Fat, 2014

multiaxial_rainflow()[source]#

Converts the stress tensor at one node to equivalent, scalar psd stress, for use in frequency domain multiaxial rainflow.

ONLY WORKS FOR BIAXIAL STRESSES: PSD MATRIX (f,3,3) - single point or (N,f,3,3) - multiple points


  • Pitoiset, Xavier, and André Preumont;

    Spectral methods for multiaxial random fatigue analysis of metallic structures, International journal of fatigue, 2000

thermoelastic()[source]#

Converts the stress tensor at one node to equivalent, scalar psd stress, using the thermoelasticity based criterion, simulating the equivalent stress, detected with the thermal camera


  • Šonc J, Zaletelj K and Slavič J;

    Application of thermoelasticity in the frequency-domain multiaxial vibration-fatigue criterion, Mechanical Systems and Signal Processsing, 2025

liwi()[source]#

Converts the stress tensor at one node to equivalent stress, using the LiWI approach.

ONLY WORKS WITH BIAXIAL AMPLITUDE SPECTRUM (f,3) - single point or (N,f,3) - multiple points


  • Alexander T. Schmidt, Nimish Pandiya,

    Extension of the static equivalent stress hypotheses to linearly vibrating systems using wave interference – The LiWI approach, International Journal of Fatigue, 2021,

coin_liwi(k_a, k_phi)[source]#

Converts the stress tensor at one node to equivalent stress, using the COIN-LiWI method.

ONLY WORKS WITH 3D AMPLITUDE SPECTRUM (f,6) - single point or (N,f,6) - multiple points

Parameters:
  • k_a – float Tension shear strength ratio. (from article: 1.70 for aluminum alloy, 1.64 for structural steel, 1.43 for cast iron)

  • k_phi – float Phase influence factor (from article: 0.90 for aluminum alloy, 0.85 for structural steel, 1.10 for cast iron)


  • Alexander T. Schmidt, Jan Kraft,

    A new equivalent stress approach based on complex invariants: The COIN LiWI method, International Journal of Fatigue, 2023

EVMS_out_of_phase()[source]#

Converts the stress tensor at one node to equivalent stress, using the phase-sensitive EVMS criterion, adjusted for out-of-phase components.

ONLY WORKS WITH BIAXIAL PSD (f,3,3) - single point or (N,f,3,3) - multiple points


  • Bonte, Martijn HA and de Boer, Andries and Liebregts R

    Determining the von Mises stress power spectral density for frequency domain fatigue analysis including out-of-phase stress components, Journal of Sound and Vibration, 2007

Nieslony(s_af, tau_af, coefficient_load_type='tension')[source]#

Converts the stress tensor at one node to equivalent, scalar psd stress, using the Nieaslony criterion, combining von Mises and hydrostatic stresses.

Parameters:
  • s_af – float Fully reversed torsion-fatigue limit.

  • tau_af – float Fully reversed torsion-fatigue limit.

  • coefficient_load_type – str Type of load with which the material fatigue properties were determined. Options are ‘tension’ for tension-compression load or ‘torsion’.


  • Adam Niesłony, Michał Böhm, Robert Owsiński, Artur Dziura, Karol Czekaj,

    Integrating von Mises and hydrostatic stresses in frequency domain multiaxial fatigue criteria for vibration fatigue analysis, Mechanical Systems and Signal Processing, 2025

Lemaitre(poisson_ratio)[source]#

Converts the stress tensor at one node or multiple nodes to equivalent, scalar psd stress, using ther equivalent Lemaitre stress in frequency domain


  • Jingran Ge, Yi Sun, Song Zhou;

    Fatigue life estimation under multiaxial random loading by means of the equivalent Lemaitre stress and multiaxial S–N curve methods. International Journal of Fatigue, 2015

Visualize#