news 2026/9/23 1:07:50

雨流计数法原理与Python实现:从载荷谱到疲劳寿命分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
雨流计数法原理与Python实现:从载荷谱到疲劳寿命分析

简介:雨流计数法(又称塔顶法)是疲劳设计与疲劳试验中应用最广泛的计数方法之一,能够将随机或非平稳的载荷时间历程转化为若干独立的应力-应变循环,为机械工程、航空航天、结构工程等领域的疲劳寿命评估提供关键数据。文档系统阐述该方法的原理、实现步骤及力学基础,包括载荷离散化、迟滞回线闭合循环提取,并说明其与变程对–均值法计数结果一致,且能有效处理非对称、非线性循环与多轴载荷简化,比单纯峰值法或变程法更贴近材料实际疲劳行为,适合机械、航空、土木等领域工程师、科研人员及高年级学生查阅。资源包内含1个doc文件,压缩后约213KB,内容精炼集中;目前已有1105人学习浏览,可作为理解载荷谱循环计数、评估结构疲劳损伤的实用参考资料。

1. 雨流计数法:从一段载荷谱里数出完整循环

现场拿到的载荷谱很少是光滑正弦波。风机叶片挥舞弯矩、汽车悬架加速度、起重机吊臂应力,都是几秒钟一次波动的随机序列。疲劳分析的第一问题不是算应力,而是先回答“这段波形里有几次加载/卸载”。雨流计数法解决的就是这件事:把一个任意波形的时序信号,拆成一组“谷-峰-谷”的完整循环,并保留每个循环的幅值和均值。有了循环表,Miner线性累积损伤、S-N曲线估算寿命才有输入。这个方法常用于结构疲劳、焊接寿命、风电叶片设计校核,也大量出现在数据分析和可靠性工程的后处理脚本里。读完这篇,你能徒手写出一个可运行的雨流计数函数,并对结果做验证。

2. 雨流计数法的判据:迟滞回线、三点法与四点法

2.1 先看雨流在数什么:能从峰谷画成封闭回路的那些段

材料在交变载荷下,应力-应变曲线会形成迟滞回线。一个完整的“拉伸-卸载-反向压缩-再卸载”过程,会在应力应变平面里画出一个闭合环,这个闭合环对应疲劳损伤;而开放路径则对应不完整的半循环。雨流计数法的思想就是把这些闭合环找出来。判据上是看折线的局部关系,而不是对复杂波形做频域变换,所以它对任意随机载荷谱都适用,不需要假设周期性。

具体做法是把时域信号压缩成峰谷交替的序列,再按顺序把点压入一个栈。每当新点进入后,检查最近几个点是否形成“被两侧包住”的折段;若形成,就把该折段认定为一个全循环并取出,删除这段数据,让前后波形继续配对。下面两节讲最常见的两种检查方式。

2.1.1 峰谷序列:雨流计数法的输入格式

输入不能是原始高频采样点,必须先做极值提取。原始信号里的等值点、单调段中间点都不会改变循环结构,但会让判据做多余判断。我一般的做法是:先删除相邻相等点,再保留每个上升/下降趋势的端点,得到严格交替的峰值和谷值。第 3 章会给这段可直接运行的代码。

2.2 三点法:边采边数的在线式判据

三点法看栈内最后三个点:设三个值依次为 v1、v2、v3。如果 v2 在 v1 与 v3 之间(即 v1<v2<v3 或 v1>v2>v3),说明中间这个折点是可被包含的拐点,它没法作为最终极值,于是把(v1,v2)作为一个循环取出,删掉 v2,让 v1 直接与 v3 配对。

这个方法实现简单、内存小,适合用在实际设备上边采样边统计,比如车桥疲劳测试仪。缺点是它对极端点的保留策略比较激进,容易在大循环还没完全落定前就提前拆出小循环,导致全循环与半循环分配和标准后处理结果不完全一致。

2.3 四点法:离线后处理里的主流选择

四点法也叫四点判据,是离线后处理里更常见的选择。它每次取栈内最后四个点:v1、v2、v3、v4。当同时满足“v2 被 v1 和 v3 包住,且 v3 被 v2 和 v4 包住”时,中间段 v2-v3 确定闭合,取出一个全循环,再从栈里删掉 v2、v3。删除后原来的 v4 变成新的末端点,可能继续和前面的点组成新的四点组合,因此能处理“大循环套小循环、小循环被取出后大循环重新配对”的情况,比三点法更符合实际损伤累积。

我一般用四点法做离线计算,三点法留给实时统计场景。两点对比如下:

判断方式看几个点内存占用适用场景
三点法3少量状态实时统计、嵌入式设备
四点法4需保留完整栈离线后处理、寿命分析

3. 用 Python 复现雨流计数法:峰谷提取与四点法实现

3.1 第一步:把离散波形压缩成峰谷序列

先写一个极值提取函数:

def to_peak_valley(series): # 删除相邻等值点 cleaned = [series[0]] for v in series[1:]: if v != cleaned[-1]: cleaned.append(v) # 删除单调段中间点,只保留峰/谷 pts = [cleaned[0]] for i in range(1, len(cleaned) - 1): if (cleaned[i - 1] < cleaned[i] and cleaned[i] > cleaned[i + 1]) or ( cleaned[i - 1] > cleaned[i] and cleaned[i] < cleaned[i + 1] ): pts.append(cleaned[i]) pts.append(cleaned[-1]) return pts

逻辑说明:第一部分去掉等值点,避免雨流判据把零幅值变动当作有效转折;第二部分保留每个局部极值点,因为单调段中间点不会改变任何未来的配对关系。要注意这个函数会把首尾点都保留,即使它们不是严格极值。

参数说明:series 是一维应力或应变序列,单位不影响计数结果;但后续幅值阈值、损伤计算都需要与材料参数的单位保持一致。返回的 pts 是峰值/谷值交替的列表,这是雨流计数唯一需要的输入结构。

3.2 第二步:用四点法提取循环

def rainflow_4point(pts): # pts: 峰谷交替序列 stack = [] # 栈内元素为 [value, count] cycles = [] # 全循环: (min_value, max_value, count) for v in pts: stack.append([v, 1.0]) while len(stack) >= 4: v1 = stack[-4][0] v2 = stack[-3][0] v3 = stack[-2][0] v4 = stack[-1][0] # 四点判据:v2 被 v1/v3 包含,v3 被 v2/v4 包含 if (v2 >= v1 and v3 <= v4) or (v2 <= v1 and v3 >= v4): cycles.append((min(v2, v3), max(v2, v3), 1.0)) del stack[-3:-1] # 删除 v2、v3 else: break return cycles, stack

逻辑说明:每次推入一个新点,就循环检查栈内最后四个点。满足判据时,把 v2、v3 之间形成的封闭折段记成一个全循环,并从栈中删除这两个点。删除后,v4 成为栈的末端点,下一次 while 迭代继续检查新的最后四点,这样嵌套的小循环被取出后,外层大循环能立即重新配对。

参数说明:栈内元素用[value, count]的形态,count 统一取 1.0,是为了和后面半循环的 0.5 统一参与 Miner 损伤累加。del stack[-3:-1]删除的是倒数第 3、倒数第 2 两个点,也就是 v2、v3;不要写成del stack[-2:],那会误删 v4。

3.3 第三步:从残余栈里拆半循环

四点法跑完后,栈里剩下的点不能组成任何全循环,但这些开放路径仍然是疲劳载荷的一部分,通常按半循环处理:

def residual_half_cycles(stack): half = [] for i in range(len(stack) - 1): lo = min(stack[i][0], stack[i + 1][0]) hi = max(stack[i][0], stack[i + 1][0]) half.append((lo, hi, 0.5)) # 0.5 表示半个循环 return half

逻辑说明:残余栈里的相邻点构成一个未封闭的上升或下降段,每段贡献 0.5 次循环。首尾两个端点如果参与多段,最终在 Miner 计算里会自动配成整数次寿命消耗,不需要人为补一个对称波形。

参数说明:返回元组 (min_value, max_value, 0.5)。后续统计幅值、均值时,半循环的计数取值 0.5,而不是 1。很多人在这里直接把 0.5 四舍五入,高周疲劳计算会偏乐观。

3.4 三个容易写错的边界条件

  1. 栈起始点数太少:while len(stack) >= 4保证了栈不足四点时不判断;但如果直接用负数索引访问栈顶,必须先确认栈长度,防止 IndexError。
  2. 判据里的等于号:v2 >= v1v3 <= v4同时成立时,说明有水平段。水平段本身不产生损伤,但会影响后续极值配对,严谨做法是在峰谷提取阶段把相邻等值点删干净。
  3. 删除点的位置:删除 v2、v3 后,之前的 v1 变成新的倒数第三点,v4 变成倒数第一点,而不是回到循环开始重新压入,这一点和栈的常规操作不同。实测时用[0, 2, -1, 3, -2, 1]这类短序列手算一遍最可靠。

4. 雨流计数法的参数怎么定:门槛、截断与修正

4.1 幅值门槛:直接影响损伤结果的第一个参数

实测信号里总有噪声和小幅抖动。如果不设门槛,雨流计数法会数出大量幅值接近零的循环,这些循环在 Miner 计算里几乎不消耗寿命,却把循环表做得很大,也容易掩盖真正的大循环。常见做法是在峰谷提取之后、雨流计数之前,把幅值小于阈值的峰谷合并掉。

我一般这样合并小峰谷:如果相邻两个点的差值小于门槛,而且这个点是凸点,则直接弹出栈顶,让新点与前一个点配对。这样等效于把小幅“驼峰”压平成一次单调变化。阈值选多大,要结合载荷量程定,常用最大峰谷差的 1%~5%。

def merge_small_peaks(pts, gate): if len(pts) < 2: return pts out = [pts[0]] for v in pts[1:]: while len(out) >= 2 and abs(v - out[-1]) < gate: # 只合并“凸点”,保留整体趋势 if (out[-2] < out[-1] and v < out[-1]) or (out[-2] > out[-1] and v > out[-1]): out.pop() else: break if v != out[-1]: out.append(v) return out

逻辑说明:while 条件里abs(v - out[-1]) < gate负责识别小幅变化,内层 if 判断 out[-1] 是否为凸点。凸点被弹出后,v 继续和新的栈顶比较,这样连续的小锯齿能被一次合并。不需要合并时把 gate 设成 0,函数退化为普通去重。

参数说明:gate 只影响幅值小于它的局部波动,不影响大循环。设置过大(超过量程 10%)会把真实小载荷事件抹掉;设置过小则门槛失去意义。建议先用不合并的结果算一遍,把循环表按幅值分布画出来,再根据分布曲线里的“噪声平台”边界选 gate。

4.2 半循环与平均应力修正

雨流计数得到的循环包含幅值和均值两个量。材料 S-N 曲线通常只给交变应力幅,但实际载荷集中在某一平均应力附近时,必须修正平均应力。常见做法是 Goodman 修正:

S_ae = S_a * S_u / (S_u - S_m)

其中 S_a 是循环交变应力幅,S_m 是平均应力,S_u 是材料极限强度。修正后的等效幅值更高,对应寿命更短。修正应该发生在雨流计数之后、Miner 损伤累加之前。

半循环在修正时同样按 0.5 计。注意半循环的平均应力不能只用端点平均值,要与全循环同样使用两端应力的算术平均,即 (v_i + v_{i+1}) / 2,而不是取幅值。

4.3 不同载荷工况下的参数配置参考

工况门槛平均应力修正半循环处理注意点
螺栓预紧/松动1%~2% 量程Goodman合并首尾半循环关注最大载荷,防止松动
焊缝热点应力2%~5% 量程Goodman 或 Smith保留所有半循环注意应力集中系数
风电叶片弯矩2% 量程Goodman 或 FKM保留半循环长期统计,需要按小时聚合
一般机械结构5% 量程可忽略或 Goodman半循环按损伤值取半门槛不要超过真实小幅载荷

表格里的门槛值一般按载荷量程比例给出。就我接触到的工程数据,多数项目用 2%~5%,很少超过 10%。半循环处理上,我建议不主动舍掉半循环,因为 Miner 累加时半循环只消耗 0.5 的寿命,舍掉会让最终寿命偏大。参数固化之前,最好用试验或标准算例做一次对拍。

5. 雨流计数法的结果验证:Miner 损伤值与三个自查技巧

5.1 把循环表换算成 Miner 损伤值

雨流计数本身不产生寿命结论,它只给循环表。寿命计算还要接上 S-N 曲线:N = C / S_a^m,其中 C、m 由材料试验拟合。把所有循环的损伤累加:

D = Σ (n_i / N_i)

D >= 1 表示疲劳寿命耗尽。下面代码把雨流输出转成损伤值:

def miner_damage(cycles, C=1e12, m=4.0, Su=None): D = 0.0 for lo, hi, count in cycles: amp = (hi - lo) / 2.0 mean = (hi + lo) / 2.0 if Su: amp = amp * Su / (Su - mean) N = C / (amp ** m) D += count / N return D

逻辑说明:cycles 里既包含全循环(count 为 1.0),也包含半循环(count 为 0.5)。m 通常取 3~5,焊接结构常见取 3,一般金属取 5 左右;C 的单位与 amp 的单位配套,工程上常用 MPa 和“次”。

5.2 验证技巧一:用 ASTM E1049 的标准算例对拍

ASTM E1049 标准里有用于校验计数算法的简单波形。可以拿带符号的折线序列,如[0, 1, -2, 3, -4, 5, -2, 0],跑一遍自己的函数,把循环表与标准给出的结果对照。第一次实现时建议直接输出完整的 (lo, hi, count) 列表,而不是只输出损伤值,这样能逐条核对哪一段被错误配对。

5.3 验证技巧二:波形重构测试

把雨流结果按原始顺序重新“播放”一次:从第一个点出发,见上升段走上升、见下降段走下降,所得的包络应能覆盖原始峰谷序列的骨架。如果某个大循环被错误提前关闭,重构波形会在中途产生不相连的跳跃,肉眼就能看出来。这个测试不验证幅值分布,但能快速定位判据方向写反、删除位置错乱这一类实现问题。

5.4 验证技巧三:符号对称性测试

雨流计数法不关心载荷的整体正负,只关心峰谷相对差。把原始序列乘 -1 后重新计数,循环表应一模一样,只是谷和峰互换。这是一个成本极低的回归测试:如果你修改过判据,跑一遍正反序列比对;若结果不同,说明判据里混入了绝对值或符号方向判断。建议把“取负后结果一致”写进函数的单元测试,每次改动都跑一遍,这个测试能拦住绝大多数判据实现错误。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 1:07:48

分步傅里叶法解NLS方程:从源码到孤子模拟全解析

简介&#xff1a;分步傅里叶法解非线性薛定谔方程的源代码&#xff0c;面向光纤通信、非线性光学方向的研究生与工程师&#xff0c;用于模拟光脉冲在光纤中的传输演化。包内共1个docx文档&#xff0c;压缩包仅13KB&#xff0c;文档内嵌完整Matlab源代码&#xff0c;包含输入参数…

作者头像 李华
网站建设 2026/9/23 1:07:47

3步搞懂关闭redis,源码解析带你避坑实战

3步搞懂关闭redis,源码解析带你避坑实战 看了一堆教程还是不会写项目?别急,这锅不全是你的。很多文章只讲怎么启动,却对“如何优雅关闭”一笔带过,导致你在生产环境重启服务时,经常遇到连接池报错或者数据丢失。今天我们就从 源码解析…

作者头像 李华
网站建设 2026/9/23 1:07:46

一文搞懂惞:市政公用工程前端的晋升与薪资全解析

一文搞懂惞:市政公用工程前端的晋升与薪资全解析 看了一堆教程还是不会写项目?别急,这不仅是代码问题,更是认知偏差。很多做市政公用工程数字化的前端开发,卡在“懂语法”却不懂“业务逻辑”的死胡同里。今天咱们不聊虚的,直接一文搞懂【惞】这个在市政项目里常被忽略却又至关重要的技术细节。…

作者头像 李华
网站建设 2026/9/23 1:07:37

华为连接电脑保姆级教程:3步搞定环境配置与开发实战

华为连接电脑保姆级教程:3步搞定环境配置与开发实战 配置环境就卡半天?别慌,这份保姆级教程带你彻底告别“连接不上”、“驱动报错”的崩溃现场。很多转岗的朋友一上手华为设备开发,最头疼的不是代码逻辑,而是开发环境搭建时各种玄学问题。明明照着官方文档敲,结果IDEA报红、命令行连不上、ADB识别不到设备,…

作者头像 李华
网站建设 2026/9/23 1:06:50

28awg铜线性能优化:解决大电流发热痛点与高频面试题实战

28awg铜线性能优化:解决大电流发热痛点与高频面试题实战 你是不是也遇到过这种情况?代码语法倒背如流,LeetCode刷得飞起,可一旦要把项目落地,或者在面试中被问到具体的工程化细节,脑子就一片空白。特别是涉及到硬件资源限制、物理传输特性这种“硬骨头”时,很多人只会背定义,却不知怎么在实际项目中规…

作者头像 李华