The ThreePointDetector class

class pylife.stress.rainflow.ThreePointDetector(recorder)[source]

Classic three point rainflow counting algorithm.

from pylife.stress.timesignal import TimeSignalGenerator
import pylife.stress.rainflow as RF

ts = TimeSignalGenerator(10, {
    'number': 50,
    'amplitude_median': 1.0, 'amplitude_std_dev': 0.5,
    'frequency_median': 4, 'frequency_std_dev': 3,
    'offset_median': 0, 'offset_std_dev': 0.4}, None, None).query(10000)

rfc = RF.ThreePointDetector(recorder=RF.LoopValueRecorder())
rfc.process(ts)

rfc.recorder.collective
from to
0 1.199894 -7.534372
1 2.413771 -8.805802
2 2.871239 4.003646
3 -6.863778 8.219477
4 2.132024 -6.850550
... ... ...
1038 9.382757 -8.061816
1039 -2.904863 0.110520
1040 -7.500223 -7.620241
1041 -4.411239 2.260093
1042 -5.787369 3.992524

1043 rows × 2 columns

Alternatively you can ask the recorder for a histogram matrix:

rfc.recorder.histogram(bins=16)
from                                        to                                        
(-21.921022953057896, -19.433334268196553]  (-21.969043120479753, -19.563628543413763]    0.0
                                            (-19.563628543413763, -17.158213966347773]    0.0
                                            (-17.158213966347773, -14.75279938928178]     0.0
                                            (-14.75279938928178, -12.34738481221579]      0.0
                                            (-12.34738481221579, -9.9419702351498]        0.0
                                                                                         ... 
(15.394307319862268, 17.881996004723614]    (4.490517227246148, 6.895931804312138]        0.0
                                            (6.895931804312138, 9.301346381378128]        0.0
                                            (9.301346381378128, 11.706760958444121]       0.0
                                            (11.706760958444121, 14.112175535510112]      0.0
                                            (14.112175535510112, 16.5175901125761]        0.0
Length: 256, dtype: float64

We take three turning points into account to detect closed hysteresis loops.

  • start: the point where the loop is starting from

  • front: the turning point after the start

  • back: the turning point after the front

A loop is considered closed if following conditions are met:

  • the load difference between front and back is bigger than or equal the one between start and front. In other words: if the back goes beyond the starting point. For example (A-B-C) and (B-C-D) not closed, whereas (C-D-E) is.

  • the loop init has not been a loop front in a prior closed loop. For example F would close the loops (D-E-F) but D is already front of the closed loop (C-D-E).

  • the load level of the front has already been covered by a prior turning point. Otherwise it is considered part of the front residuum.

When a loop is closed it is possible that the loop back also closes unclosed loops of the past by acting as loop back for an unclosed start/front pair. For example E closes the loop (C-D-E) and then also (A-B-E).

Load -----------------------------
|        x B               F x
--------/-\-----------------/-----
|      /   \   x D         /
------/-----\-/-\---------/-------
|    /     C x   \       /
--\-/-------------\-----/---------
|  x A             \   /
--------------------\-/-----------
|                    x E
----------------------------------
|              Time
__init__(recorder)[source]

Instantiate a ThreePointDetector.

Parameters:

recorder (subclass of AbstractRecorder) – The recorder that the detector will report to.

process(samples, flush=False)[source]

Process a sample chunk.

Parameters:
  • samples (array_like, shape (N, )) – The samples to be processed

  • flush (bool) –

    Whether to flush the cached values at the end.

    For explanations see process()

Returns:

self – The self object so that processing can be chained

Return type:

ThreePointDetector