Giter Site home page Giter Site logo

rainflow's People

Contributors

cwe0 avatar denis-jasselette-jc avatar gsokoll avatar iamlikeme avatar jfcorbett avatar oysteoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rainflow's Issues

Count fails for small series

Hello,

While testing an application of mine, I innocently tried to count cycles on very small vectors (size < 3). To my surprise, it yielded a few different obscure exceptions depending on the size of the series. I figured it was not supported and I even understand why, as no results would really make sense in those edge cases. So I just checked the size of my vector to guard from these exceptions.

However, the exceptions were not very helpful about the source of the problem and I couldn't find any documentation stating that there was such a limit on the input. So maybe, it could be documented somewhere, or maybe we could change slightly the reversals function with these edge cases in mind...

Here is a quick illustration of what I am suggesting:

import unittest
import rainflow

def _reversals(series):
    """Iterate reversal points in the series.
    A reversal point is a point in the series at which the first derivative
    changes sign. Reversal is undefined at the first (last) point because the
    derivative before (after) this point is undefined. The first and the last
    points are treated as reversals.
    Parameters
    ----------
    series : iterable sequence of numbers
    Yields
    ------
    Reversal points as tuples (index, value).
    """
    series = iter(series)

    x_last, x = next(series, None), next(series, None)
    if x_last is None or x is None:
        return
        
    d_last = (x - x_last)

    yield 0, x_last
    index = None
    for index, x_next in enumerate(series, start=1):
        if x_next == x:
            continue
        d_next = x_next - x
        if d_last * d_next < 0:
            yield index, x
        x_last, x = x, x_next
        d_last = d_next

    if index is not None:
        yield index + 1, x_next

rainflow.reversals = _reversals

class TestRainflow(unittest.TestCase):
    def test_reversals_small_series(self):
        assert list(rainflow.reversals([])) == []
        assert list(rainflow.reversals([1])) == []
        assert list(rainflow.reversals([1, 2])) == [(0, 1)]
        assert list(rainflow.reversals([1, 2, 3])) == [(0, 1), (2, 3)]

    def test_extract_cycles_small_series(self):
        assert list(rainflow.extract_cycles([])) == []
        assert list(rainflow.extract_cycles([1])) == []
        assert list(rainflow.extract_cycles([1, 2])) == []
        assert list(rainflow.extract_cycles([1, 2, 3])) == [(2, 2.0, 0.5, 0, 2)]

The result of extract_cycles or count_cycles would be an empty list, which makes some sense at least.

Any thoughts?

Functionality Rainflow: Neglection of first and last half circle

I discovered a bug which is replicate using following example:

import numpy as np
import rainflow  # https://pypi.org/project/rainflow/
x = np.linspace(0, (4.0)*np.pi, num=19)
y = [np.cos(i) for i in x]
RFC_output = rainflow.count_cycles(y, binsize=0.5)

RFC_output = [(0.5, 0), (1.0, 0), (1.5, 0), (2.0, 1.0)]

As the example is two periods of the cosine function, the output should be the following:

RFC_correct = [(0.5, 0), (1.0, 0), (1.5, 0), (2.0, 2.0)]

I checked with other functions as well and found out that in general the first and last half circle are neglected in the rainflow algorithm.

Inconsistent behaviour of binsize and nbins

Hi @gsokoll. I think that binning with parameters nbins and binsize yields inconsistent results. Since you contributed the feature (#22) I thought I will check with you first.

In the unit tests we have the following cycle counts for series [-2, 1, -3, 5, -1, 3, -4, 4, -2]:

range count
3 0.5
4 1.5
6 0.5
8 1.0
9 0.5

With binsize=3 or nbins=3 the current behavious results in:

range bin count
3 [0, 3) 0.0
6 [3, 6) 2.0
9 [6, 9] 2.0

Since the cycle with range 9 went into bin (6 to 9) I would expect cycle with range 3 to go to bin (0 to 3). However, it went to bin (3, 6). More generally, the bins are inconsistent with respect to which edges are included in the bins. The first two bins are closed on the left side and open on the right,
while the last bin is closed on both sides.

I think the result should be:

range bin count
3 (0, 3] 0.5
6 (3, 6] 2.0
9 (6, 9] 1.5

Here, each bin is open on the left side and closed on the right.

Do you agree that the unit tests should be updated? If yes, I have a working implementation that I could merge.

ndigits parameter does not work for numpy float types

Apparantly rainflow.count_cycles has issues with numpy float types.

import json

y = json.load(open('data.json'))

print('Works ..')
rainflow.count_cycles(y, ndigits=4)

print('Does not work ..')
rainflow.count_cycles(np.asarray(y), ndigits=4)

Converting the array to a numpy array makes count_cycles deliver not the desired result.

Output:

Works ..
[(0.0015, 14.0),
 (0.0016, 1.0),
 (0.0031, 15.0),
 (0.0046, 20.0),
 (0.0062, 14.0),
 (0.0077, 16.0),
 (0.0093, 12.0),
 (0.0108, 15.0),
 (0.0124, 16.0),
 (0.0139, 12.0),
 (0.0154, 11.0),

Does not work ..
[(0.0015, 14.0),
 (0.0016000000000000001, 1.0),
 (0.0030999999999999999, 15.0),
 (0.0045999999999999999, 20.0),
 (0.0061999999999999998, 14.0),
 (0.0077000000000000002, 16.0),
 (0.0092999999999999992, 12.0),
 (0.010800000000000001, 15.0),

See data.json.zip

inconsistent behavior between small and large values?

Hi,
perhaps there's something I don't quite understand, but when I'm taking the unit test and multiplying the series with a high value the RFC algorithm gives back very different counting results.

The unittest is as follows:

series = np.array([-2, 1, -3, 5, -1, 3, -4, 4, -2])
print(count_cycles(series, ndigits=None, nbins=None, binsize=None))

output: [(3, 0.5), (4, 1.5), (6, 0.5), (8, 1.0), (9, 0.5)]

by modifying the unittest slightly the number of cycles changes:

series = np.array([-2, 1, -3, 5, -1, 3, -4, 4, -2])
series *= 100000
print(count_cycles(series, ndigits=None, nbins=None, binsize=None))

output: [(200000, 0.5), (500000, 0.5), (700000, 0.5)]

thoughts?

edit:
I figured it out. the above code uses int32 which results in horrible calculation errors in the reversal function. by making sure the values are float before counting produces expected results.

For reference if anyone else is reading this down the road. the following produce expected results:

series = np.array([-2.0, 1.0, -3.0, 5.0, -1.0, 3.0, -4.0, 4.0, -2.0])
series *= 100000
print(count_cycles(series, ndigits=None, nbins=None, binsize=None))

output: [(300000.0, 0.5), (400000.0, 1.5), (600000.0, 0.5), (800000.0, 1.0), (900000.0, 0.5)]

Feature: Computing in Chunks

It would be useful to have a method for computing rainflow on some timeseries, and then it storing just enough information, for you to be able to append and the computation to be updated.
I.e.
cycles = rainflow.count_cycles(ts1)
cycles = cycles.update_cycle_count(ts2)
How hard is this to do within the library?

I'd be happy to work on a PR for it, but I have only just started using this lib and rainflow, so seeking guidance.

Why First and Last Point was not yielded?

It is a question, not a issue. It is noticed "The generator never yields the first and the last points in the series."
Would it be better to yield first and last point as well?

Remaining one-half cycles is reversed?

I'm currently implementing some analysis which are using the rainflow algorithm. I've tried a couple, and it seems all gives the same result. But - it seems like your code yields the remaining one half cycles in reversed order.. ? Or - it could be yours is the one which is correct, but then there is several others which gives wrong result... ( extract_cycles method )

Made a pull-request which proves and fix the error.

Question on : Conversion of i_start - i_end to duration and Tp and Frequency

for rng, mean, count, i_start, i_end in rainflow.extract_cycles(signal): print(rng, mean, count, i_start, i_end)
Using the provided example above, can you confirm the following assumption :
Tp = i_end - i_start
Frequency = 1/Tp

i.e the damage count can be returned to a time series graph using these i_end and i_start values.

Indexes of the counted cycle range

Hello,

I am in search of a rainflow counting algorithm in Python that provides the indexes of the counted ranges (similar to the rainflow counting in Matlab) also. Would this implementation rainflow() (rainflow 2.2.0 by PyPI) provide the indexes? If not, is there a way to modify this rainflow() code to obtain the indexes?
Are there any other Python based rainflow implementations that provide indexes?
Thank you!

Rainflow Matrix

Not really an issue but a request for feature addition to get the rainflow matrix with cycles, mean and range into defined number of bins. This will make it convenient for fatigue calculation. The function count_cycle partially fulfills this need except that it does not produce corresponding means.
For calculating bins for the mean one has to take care of weighing the means with number of cycles as explained here:http://www.vibrationdata.com/tutorials2/rainflow_counting_revB.pdf

Repeated bins for binsize option with float

The following script:

from rainflow import count_cycles
import math

def amplitude(t):
    return (0.54*math.sin(2.*math.pi*0.5*t)+
            0.27*math.sin(2.*math.pi*1.6*t)+
            0.09*math.sin(2.*math.pi*9.7*t))

signal = [amplitude(i*0.01) for i in range(1000)]

cyc = count_cycles(signal,binsize=0.2)

for c in cyc:
    print('{0:f} : {1:f}'.format(c[0],c[1]))

produces:

0.200000 : 81.000000
0.400000 : 9.000000
0.600000 : 2.000000
0.800000 : 1.000000
1.000000 : 0.000000
1.200000 : 0.000000
1.400000 : 0.000000
1.600000 : 0.000000
1.600000 : 2.000000
1.800000 : 0.000000
1.800000 : 2.500000

The reason is that rng in line 154-157 is computed via summation while it is computed via the product n*binsize above. Due to round-off the keys are not identical.

New BUG

Hi,

I found a bug in this module:
image

Python plot similar to Matlab's stackedplot()

Hello,
Is there a plot function available in Python that is same as Matlab's stackedplot()? stackedplot() in Matlab can line plot several variables with the same X axis and are stacked vertically. Additionally, there is a scope in this plot that shows the value of all variables for a given X value just by moving the cursor (please see the attached plot). I have been able to generate subplots in Python with no issues, however, not able to add a scope like this that shows the value of all variables by moving the cursor. Is this feature available in Python?

Thanks much for your help in advance!

stackedplot scope2

counting_cycles does not produce correct results

The rainflow counting does not produce the same results as per the example given in ASTM E1049:85 - 2011.

The ASTM example uses the follow series:
y = [-2, 1, -3, 5, -1, 3, -4, 4, -2]

which results into:
count = [(1.0, 0.0), (2.0, 0.0), (3.0, 0.5), (4.0, 1.5), (5.0, 0.0), (6.0, 0.5), (7.0, 0.0), (8.0, 1.0), (9.0, 0.5), (10.0, 0)]

the count_cycles function should therefore produce:
count = [(3, 0.5), (4, 1.5), (6, 0.5), (8, 1.0), (9, 0.5)]

the current result from the count_cycles function:
count = [(4, 1.5), (8, 1.0), (9, 0.5)]

below is a simple unittest which reproduces the error.

import unittest
import rainflow

class Test_rainflow(unittest.TestCase):
    def setUp(self):
        pass

    def test_astm_example(self):
        self.y = [-2, 1, -3, 5, -1, 3, -4, 4, -2]
        astm_result = [(3, 0.5), (4, 1.5), (6, 0.5), (8, 1.0), (9, 0.5)]
        self.assertEqual(rainflow.count_cycles(self.y), astm_result)


if __name__ == '__main__':
    unittest.main()

for else in extract_cycles

Hi,
I was looking to your code especially the function extract_cycles in the file rainflow.py.
I don't understand why there is an else statement on the same level of the for cycle (line 65), infact the break statement is on the while level.
Reading/running the code seems that with or without that ````else``` the code returns exactly the same results.
Is it a typo or there a much deeper technical reason due to a specific case?

Thanks

Issue requiring workaround when including package into an executable built with pyinstaller

No package metadata is found for rainflow.

Traceback (most recent call last):
  File "importlib\metadata\__init__.py", line 563, in from_name
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "exe_interface.py", line 24, in <module>
  File "rainflow.py", line 15, in <module>
  File "importlib\metadata\__init__.py", line 1008, in version
  File "importlib\metadata\__init__.py", line 981, in distribution
  File "importlib\metadata\__init__.py", line 565, in from_name
importlib.metadata.PackageNotFoundError: No package metadata was found for rainflow

Runtime error: Stop Iteration

Hi Piotr,

Thanks for your work with this excellent package. I ran into this error while using this package on a time series of about 3 million entries. I changed the 'yield' parts of the code to have

except StopIteration:
return
However this did not seem to work. I know this might b more of a stackoverflow question but I was wondering if you knew any quickfix.

Many thanks

Possible bug where two cycles are either mis identified or not detected

Hi there!

Python 3.8

  • rainflow==3.1.1
  • pandas==1.2.1
  • plotly==4.14.3

I'm using rainflow.extract_cycles(sample_data) to detect cycles in a profile and return the start and end indices for each cycle. Things were working pretty well until I noticed:

  1. The boundaries of one of the half cycles (cycle 4, highlighted by green below) are much wider than they should be, as if rainflow.extract_cycles() failed to detect the true end of the half cycle

Screen Shot 2022-02-09 at 10 33 27 AM

  1. Some half cycles that I would expect to be detected are not detected:

Screen Shot 2022-02-09 at 10 37 55 AM

I have added this sample data to pastebin and the code to reproduce this and create the figures is:

import rainflow
import pandas as pd
import copy
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default = "browser"

# import the sample data
sample_data = pd.read_csv('https://pastebin.com/raw/L4daxpg8', index_col=0, parse_dates=True)

# extract the cycle data and save for plotting
extract_cyc = [
    {
        'Range': rng,
        'Mean': mean,
        'Count': count,
        'Index Start': i_start,
        'Index End': i_end
    } for rng, mean, count, i_start, i_end in rainflow.extract_cycles(sample_data['Data'])
]

# Create a base figure to show the sample data
base_fig = make_subplots(rows=1, cols=1)

base_fig.add_trace(
    go.Scatter(
        x=sample_data.index,
        y=sample_data['Data'],
        mode='lines',
        line=dict(width=0.5)
    ), row=1, col=1
)

# For each cycle highlight and view the cycle's area
for i, cycle in enumerate(extract_cyc):
    this_fig = copy.copy(base_fig)
    # add green highlight over this cycle's area
    this_fig.add_vrect(x0=sample_data.index[cycle['Index Start']], x1=sample_data.index[cycle['Index End']], row=1,
                       col=1, line_width=1, fillcolor='green', opacity=0.1)

    this_fig.update_layout(
            title='Cycle %d' % i
        )
    this_fig.show()

Please let me know if I'm doing something wrong here or if you need any more information. Thank you in advance!

rainflow rng and mean question

Hi Team,

I need some help to understand the process. I am running time based data through rainflow 3.0.1 and seeing cycles counted for values that do not show up in the time based data.

Example the highest pk to pk reversal cycle is 150.24 with a mean of 35 but the processor extract_cycles appears to also count the very max and min recorded in the time domain as a rng output at 174.85 with a mean of 23.

Let me know if you can help.

Thank you, B

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.