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 -6.647146 -6.452110
1 3.307209 -3.387027
2 1.291865 -2.557393
3 1.478518 -4.249459
4 -5.218207 3.659380
... ... ...
1064 -2.212179 -1.386699
1065 -7.279240 2.541472
1066 -13.426831 9.740701
1067 -14.695293 10.727515
1068 -4.358340 4.575989

1069 rows × 2 columns

Alternatively you can ask the recorder for a histogram matrix:

rfc.recorder.histogram(bins=16)
from                                       to                                        
(-17.70556733521521, -15.657252655947413]  (-16.796713688641113, -14.73429971024045]     0.0
                                           (-14.73429971024045, -12.671885731839788]     0.0
                                           (-12.671885731839788, -10.609471753439127]    0.0
                                           (-10.609471753439127, -8.547057775038464]     0.0
                                           (-8.547057775038464, -6.484643796637801]      0.0
                                                                                        ... 
(13.019152853801732, 15.067467533069529]   (5.88984007376617, 7.952254052166833]         0.0
                                           (7.952254052166833, 10.014668030567496]       0.0
                                           (10.014668030567496, 12.077082008968155]      0.0
                                           (12.077082008968155, 14.139495987368818]      0.0
                                           (14.139495987368818, 16.201909965769485]      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.

    If flush=False, the last value of a load sequence is cached for a subsequent call to process, because it may or may not be a turning point of the sequence, which is only decided when the next data point arrives.

    Setting flush=True forces processing of the last value. When process is called again afterwards with new data, two increasing or decreasing values in a row might have been processed, as opposed to only turning points of the sequence.

    Example: a)

    process([1, 2], flush=False) # processes 1 process([3, 1], flush=True) # processes 3, 1 -> processed sequence is [1,3,1], only turning points

    1. process([1, 2], flush=True) # processes 1, 2 process([3, 1], flush=True) # processes 3, 1 -> processed sequence is [1,2,3,1], “,” is not a turning point

    2. process([1, 2]) # processes 1 process([3, 1]) # processes 3 -> processed sequence is [1,3], end (“1”) is missing

    3. process([1, 2]) # processes 1 process([3, 1]) # processes 3 flush() # process 1 -> processed sequence is [1,3,1]

Returns:

self – The self object so that processing can be chained

Return type:

ThreePointDetector