Code examples

Note

More examples will be provided on request.

Plot time series and power spectral density

Import the time series database, load data from file and plot all time series.

 1"""
 2Example of using the time series database class
 3"""
 4import os
 5from qats import TsDB
 6
 7db = TsDB()
 8
 9# locate time series file
10file_name = os.path.join("..", "..", "..", "data", "mooring.ts")
11
12# load time series from file
13db.load([file_name])
14
15# plot everything on the file
16db.plot()

You can also select a subset of the timeseries (suports wildcards) as shown below.

15# plot only specific time series identified by name
16db.plot(names=["surge", "sway"])

You can also plot the power spectral density of the selected time series. Because the ‘surge’ time series was sampled at a varying time step the the time series are resampled to a constant time step of 0.1 seconds before the FFT.

15# plot the power spectral density for the same time series
16db.plot_psd(names=["surge", "sway"], resample=0.1)

Count cycles using the Rainflow algorithm

Note

Some of the syntax shown below is not applicable for version <= 4.6.1, in particular the unpacking of cycles. The changes implemented since 4.6.1 are backwards compatible, however; the syntax suggested below is recommended due to better performance. One may also experience minor changes in rebinned cycles. Finally, the mesh established by qats.fatigue.rainflow.mesh() (and used by TimeSeries.plot_cycle_rangemean3d()) was not correct for version <= 4.6.1. For more details, please refer to the CHANGELOG.

Fetch a single time series from the time series database, extract and visualize the cycle distribution using the Rainflow algorithm.

 1"""
 2Example on working with cycle range and range-mean distributions.
 3"""
 4import os
 5from qats import TsDB
 6
 7# locate time series file
 8file_name = os.path.join("..", "..", "..", "data", "simo_p_out.ts")
 9
10# load time series directly on db initiation
11db = TsDB.fromfile(file_name)
12
13# fetch one of the time series from the db
14ts = db.get(name='tension_2_qs')
15
16# plot its cycle ranges as bar diagram
17ts.plot_cycle_range(n=100)
18
19# plot its cycle-range-mean distribution as scatter
20ts.plot_cycle_rangemean(n=100)
21
22# ... or as a 3D surface.
23ts.plot_cycle_rangemean3d(nr=25, nm=25)
24
25# you can also collect the cycle range-mean and count numbers (see TimeSeries.rfc() and TimeSeries.get() for options)
26cycles = ts.rfc()
27
28# unpack cycles to separate 1D arrays if you prefer
29ranges, means, counts = cycles.T
_images/ts_cycle_range.png

Single cycle range distribution.

_images/ts_cycle_range_mean.png

Single cycle range-mean distribution.

_images/ts_cycle_range_mean_3d.png

Single 3D cycle range-mean distribution

Compare the cycle range and range-mean distribution from several time series using the methods on the TsDB class.

30
31# The TsDB class also has similar methods to ease comparison
32# compare cycle range distribution (range versus count) grouped in 100 bins
33db.plot_cycle_range(names='tension*', n=100)
34
_images/tsdb_cycle_range.png

Comparison of several cycle range distributions.

_images/tsdb_cycle_range_mean.png

Comparison of several cycle range-mean distributions.

Calculate fatigue damage in mooring lines

Using a traditional S-N curve with constant slope and intercept.

 1"""
 2Calculate mooring line fatigue.
 3"""
 4import os
 5import numpy as np
 6from math import pi
 7from qats import TsDB
 8from qats.fatigue.sn import SNCurve, minersum
 9
10# load time series
11db = TsDB.fromfile(os.path.join("..", "..", "..", "data", "simo_p_out.ts"))
12
13# initiate SN-curve: DNVGL-OS-E301 curve for studless chain
14sncurve = SNCurve(name="Studless chain OS-E301", m1=3.0, a1=6e10)
15
16# Calculate fatigue damage for all mooring line tension time series (kN)
17for ts in db.getl(names='tension_*_qs'):
18    # count tension (discarding the 100s transient)
19    cycles = ts.rfc(twin=(100., 1e12))
20
21    # unpack cycle range and count as separate lists (discard cycle means)
22    ranges, _, counts = cycles.T
23
24    # calculate cross section stress cycles (shown here: 118mm studless chain, with unit [kN] for tension cycles)
25    area = 2. * pi * (118. / 2.) ** 2.          # mm^2
26    ranges = [r * 1e3 / area for r in ranges]   # MPa
27
28    # calculate fatigue damage from Palmgren-Miner rule (SCF=1, no thickness correction)
29    damage = minersum(ranges, counts, sncurve)
30
31    # print summary
32    print(f"{ts.name}:")
33    print(f"\t- Max stress range = {max(ranges):12.5g} MPa")
34    print(f"\t- Total number of stress ranges = {sum(counts)}")
35    print(f"\t- Fatigue damage = {damage:12.5g}\n")
36

Apply low-pass and high-pass filters to time series

Initiate time series database and load time series file in one go. Plot the low-passed and high-passed time series and the sum of those.

 1"""
 2Example showing how to directly initiate the database with time series from file and then filter the time series.
 3"""
 4import os
 5import matplotlib.pyplot as plt
 6from qats import TsDB
 7
 8# locate time series file
 9file_name = os.path.join("..", "..", "..", "data", "mooring.ts")
10db = TsDB.fromfile(file_name)
11ts = db.get(name="Surge")
12
13# Low-pass and high-pass filter the time series at 0.03Hz
14# Note that the transient 1000 first seconds are skipped
15t, xlo = ts.get(twin=(1000, 1e12), filterargs=("lp", 0.03))
16_, xhi = ts.get(twin=(1000, 1e12), filterargs=("hp", 0.03))
17
18# plot for visual inspection
19plt.figure()
20plt.plot(ts.t, ts.x, "r", label="Original")
21plt.plot(t, xlo, label="LP")
22plt.plot(t, xhi, label="HP")
23plt.plot(t, xlo + xhi, "k--", label="LP + HP")
24plt.legend()
25plt.grid(True)
26plt.show()

Merge files and export to different format

Todo

Coming soon