雨流计数后的小幅值滤波:原理、阈值与Python实现

发布时间:2026/10/16 4:36:29

雨流计数后的小幅值滤波:原理、阈值与Python实现 前段时间帮一位做功率循环测试的同事调寿命评估脚本他在台架上连续跑了两个多月的结温数据我把它丢进雨流计数程序出来三十七万个循环。可当我按幅值简单排个序就发现真正对疲劳损伤有贡献的循环不到两万个其余全是温度控制波动、散热风扇起停、传感器噪声制造出来的小幅值抖动。那一刻我很确定雨流计数之后的小幅值滤波不是锦上添花是绕不开的一步。这篇文章想把这件事彻底讲透为什么功率循环、疲劳分析里雨流计数完成后还要专门做小幅值滤波滤波阈值怎么定才不是拍脑袋用 Python 怎么落地以及我实际踩过的几个坑。不管你做的是电力电子器件可靠性、结构疲劳寿命还是偶尔要处理一段随机载荷谱这套思路都可以直接搬走。1. 为什么雨流计数做完之后还要专门滤一遍小幅值循环1.1 功率循环与疲劳分析里的载荷谱到底长什么样功率循环测试说白了就是给功率器件周期性通电、断电让结温反复升降封装内部各层材料因为热膨胀系数不一致而产生热机械应力。测试产出的核心数据是一条结温随时间变化的曲线看着像方波或者梯形波可一旦放大局部全是锯齿和毛刺。结构疲劳分析里也类似桥梁承受风载、车辆部件承受路面激励采集到的是一串随机应力时间序列。工程上习惯叫它“载荷谱”但这个词很容易误导人因为它不是一段干净的谱线而是一长串参差不齐的峰和谷既有缓慢的大幅摆动又有高频的微小抖动。做寿命评估的第一步都是把这串不规则的时间历程变成一组组“循环”。雨流计数干的就是这件事。它把峰谷之间的路径按迟滞回线的闭合规则拆开最终输出一条条记录每条记录包含四个关键信息循环的范围峰谷差除以二就是幅值、均值、循环次数、在原始时间序列里的起止位置。这些循环按幅值分布通常呈“长尾”形态数量最大的是贴着零轴的那一片小循环中幅值循环只有一小撮真正大幅度主循环往往一只手数得过来。如果拿未滤波的结果直接画二维雨流矩阵整个图会被左下角密密麻麻的小幅值循环填满真正的损伤大户反而被淹没了。1.2 那些小幅值循环到底是从哪里冒出来的我把小幅值循环总结成四类来源对应关系不一样处理时的态度也不一样。第一类是测量噪声。热电偶本身有电噪声应变片连接线有电磁干扰采集卡的量化误差也不小。这些噪声幅值不大但数量惊人。第二类是台架控制回路的波动。功率循环设备通常用反馈控制把壳温或结温维持在某一个目标附近控制参数整定不好的时候温度会在目标值上下反复小幅振荡产生大量内部闭合的小环。第三类是环境扰动冷却水温度波动、风扇转速不稳、空调气流变化都会在温度曲线或应力曲线上遗留次级小循环。第四类最容易被忽略雨流计数在“拆”大循环的时候会留下一些残片。一个理想的大冷却斜坡是从高温直线降到低温但真实冷却过程往往叠着轻微波动。雨流算法会先闭合掉局部的小迟滞回线再把这些闭合后的轨迹继续当作大循环的一部分。于是一个大循环旁边总是坠着一串小闭环。这些小闭环不是独立物理事件却真实存在于计数结果里。所以小幅值滤波本质上是对循环列表做一次“安检”把物理上真实但微小、对损伤几乎没有贡献的循环和噪声、伪事件一起剔除只留下对寿命评估有意义的那部分。1.3 为什么滤波必须放在雨流计数之后而不是之前我见过不少人在原始时间序列上直接做过滤比如“温度变化小于 1℃就不记录”或者“先用滑动平均把曲线抹平再计数”。看起来都能减少计算量但都踩了同一个坑改变了载荷路径本身。雨流计数非常依赖峰谷的先后顺序。一个 45℃ 的冷却过程哪怕只是中间多了几个 1℃ 的小毛刺雨流算法也会先把小毛刺对应的局部回线闭合掉再继续处理剩下的半循环。如果你在原始数据上设了死区把这个 45℃ 的斜坡截断成好几段 15℃、20℃ 的碎块最后计数出来的主循环幅值就会从 45℃ 变成十几摄氏度。你滤掉的不是噪声而是大循环的完整性。低通平滑也一样它会把一批真实的、幅值有意义的循环抹成缓变趋势导致损伤被系统性低估。正确的顺序应该是先完整保真地把原始时间序列喂给雨流计数让算法按峰值序列把所有迟滞回线都提取出来得到一个未经过任何人为裁剪的循环列表然后在这个列表上再做小幅值滤波。这样原始路径没有被破坏滤波规则也可复现、可调整、可审计阈值选错了随时可以改回来重算。2. 小幅值滤波阈值怎么定三种工程路线2.1 基于材料疲劳极限的物理阈值每个循环对材料造成的损伤与应力幅值、平均应力、循环次数三者强相关。其中有一条公认的规律对很多铁基材料当应力幅值低于某个“疲劳极限”时理论上可以承受无限次循环而不断裂。既然这些循环不产生损伤那把它从载荷谱里删掉物理上是站得住脚的。实际操作时阈值可以写为S_th S_e / SFS_e 是材料疲劳极限SF 是安全系数通常在 1.3 到 2 之间取。如果载荷谱中平均应力不高低于这个阈值的循环全部省略对寿命预测几乎没有影响。但这个方法有边界。铝合金、焊接结构、受腐蚀表面、存在微动磨损的部位往往没有严格意义的疲劳极限应力再小也可能通过裂纹扩展的方式累积损伤。直接用疲劳极限法过滤可能做出偏乐观的预测。另外功率循环里面的焊料层属于典型的延性材料也没有传统概念的疲劳极限我更倾向于把它当成一个初始参考线而不是最终结论。2.2 基于最大幅值比例的经验阈值这是工程界用得最多的方法取整个载荷谱里最大循环幅值的一定比例作为门槛通常取 5% 到 15%最常听到的起点就是 10%。这个“10%”不是随便拍出来的。它背后是损伤与幅值的幂次关系。如果寿命模型写成 N ∝ ΔT⁻ᵐm 一般在 3 到 8 之间幅值降到最大幅值的十分之一单次循环的损伤就只有最大循环的 10⁻³ 到 10⁻⁷ 量级。即使小循环数量是主循环的一千倍累积损伤也不过是主循环的百分之一量级。删掉它们换来的却是载荷谱规模断崖式下降。我用过不少数据这个比例的适用范围是载荷谱比较规则主循环明显幅值分层清楚。如果载荷谱本身是纯随机过程没有明显的“最大幅值”按比例法就会很尴尬因为阈值会跟着极端偶发事件走把一批中幅值循环误伤。实操建议从 5% 开始试探。如果阈值加到 5% 后循环数几乎没减少说明小循环本来就少不用滤如果循环数掉了一大截但损伤保留率还在 99% 以上可以继续微调一旦损伤保留率跌破 99%阈值就得往下压。2.3 基于损伤贡献的自适应阈值比例法和疲劳极限法都是“先定幅值再看后果”。还有一种更严谨的做法思路完全反过来先算出每个循环的损伤贡献按贡献排序再决定删掉哪些。步骤很直接用一条合适的寿命曲线给每个循环计算单次损伤乘以循环次数得到该循环在整个载荷谱里的总损伤贡献把所有循环按损伤贡献从大到小排序逐个累加当累计损伤已经达到总损伤的 99.5% 或 99.9% 时剩下那些贡献极小、还没加入累加的循环就可以安全删除。这个方法的优点是不用拍脑袋阈值不再是“幅值是多少度”而是变成了“我允许丢多少损伤”这个更有物理意义的指标。适合载荷谱随机、数据量大、又找不到明显主循环的场景。代价是它完全依赖寿命曲线参数的准确性。如果寿命曲线的指数选错了筛选结果也会跟着错。但至少整个筛选过程是可解释、可追溯的比“我凭经验设了个阈值”有说服力得多。2.4 功率循环场景下如何结合温度定阈值功率循环的数据有自己的脾气单纯套疲劳极限或者比例法都不够还要额外考虑两点测量噪声下限以及平均温度对损伤的放大作用。第一温度测量精度决定阈值下限。热电偶噪声常在 ±0.5℃ 到 ±1℃ 之间红外测温可能更高。如果你的阈值设置得比噪声幅度还小滤波后留下来的其实是一堆噪声循环等于白滤。我通常要求阈值至少是噪声幅度的两倍噪声 ±1℃阈值就往 2℃ 以上取。第二平均温度不能忽略。同样 1℃ 的波动发生在室温基板和发生在 125℃ 结温附近对焊料层的损伤完全不是一个量级。高温下蠕变速率更快小幅值循环也会被放大。所以功率循环里更合理的做法是先把每个循环的平均温度折进等效幅值里再做滤波筛选。等效幅值考虑了平均温度的影响能避免“幅值很小但高温下其实很要命”的循环被误删。如果只是要一个工程初值我常用 1℃ 到 3℃ 作为初步门槛。碰到主循环很大、器件封装又大的测试可以放宽到 5℃之后再通过损伤保留率验证。注意这只是一个起点不是终点。3. 实操一套可直接改用的小幅值滤波流程3.1 先看清雨流计数的输出结构用 Python 处理时我一般直接借助现成的开源库输入是温度或应力时间序列输出是循环列表。每一条循环由五个字段组成range峰谷差也就是循环范围幅值等于它除以二mean循环均值count循环次数通常为 1.0 或者 0.50.5 表示半循环start 和 end该循环在原始序列中的起止索引。滤波前必须先理解 count 的意义。count 等于 1 的是完整闭合循环count 等于 0.5 的是尚未闭合的半循环。半循环在后续重新配对成完整循环时是有用的所以我的习惯是只有当半循环的范围也低于阈值时才一并删除否则尽量保留。大多数时候半循环数量占比很小留着它对载荷谱瘦身没有太大影响但能避免破坏后续配对逻辑。3.2 Python 滤波代码示例环境准备很简单需要 numpy 和一个 rainflow 库pip install numpy rainflow下面这段代码完成整条链路读温度序列、完整雨流计数、按小幅值滤波、对比滤波前后的总损伤。import numpy as np import rainflow def load_temperature(path): # 假设CSV第一列是时间第二列是结温单位为℃ data np.loadtxt(path, delimiter,, skiprows1) return data[:, 1] def basquin_damage(delta_t, mean_t, m4.0, k1000.0): # 用幂函数寿命模型算单次损伤 # N k / (delta_t ** m)损伤等于 1/N # 这里的k和m需要根据真实材料/焊料层数据标定 if delta_t 0: return 0.0 n_cycles k / (delta_t ** m) return 1.0 / n_cycles # 1. 读取温度时间序列 temp load_temperature(junction_temperature.csv) # 2. 完整雨流计数先不碰原始数据 cycles list(rainflow.count_cycles(temp)) # 每一项是 (range, mean, count, start_index, end_index) # 3. 计算滤波前的基准损伤 total_damage_raw 0.0 for rng, mean, cnt, _, _ in cycles: total_damage_raw basquin_damage(rng, mean) * cnt # 4. 按幅值阈值滤波 cutoff 2.0 # ℃幅值门槛等于range的一半 filtered [ (rng, mean, cnt, s, e) for rng, mean, cnt, s, e in cycles if rng / 2.0 cutoff ] # 5. 计算滤波后的损伤 total_damage_filtered 0.0 for rng, mean, cnt, _, _ in filtered: total_damage_filtered basquin_damage(rng, mean) * cnt # 6. 输出关键指标 print(f原始循环数: {len(cycles)}) print(f滤波后循环数: {len(filtered)}) print(f循环保留率: {len(filtered) / len(cycles) * 100:.2f}%) print(f损伤保留率: {total_damage_filtered / total_damage_raw * 100:.3f}%)代码里 basquin_damage 函数是我为了演示临时写的用 m4 和 k1000 只是示意。真实项目里一定要根据焊料层或结构材料的寿命试验数据去标定这两个参数否则滤波筛选的排序依据就是错的。3.3 阈值敏感性曲线找到拐点再动手阈值选多少合适与其拍脑袋不如直接画一条敏感性曲线。做法很简单从 0.1℃ 到 10℃每隔 0.5℃ 取一个阈值分别计算滤波后的循环保留率和损伤保留率。然后把曲线画出来。循环保留率大概率会随阈值单调下降损伤保留率一开始几乎不变到某个点后才开始快速下跌。那个“膝盖”位置就是合理的滤波阈值。我曾经拿一组功率循环数据做过一版对比结果长这样阈值 (℃)保留循环数循环保留率损伤保留率0.518533049.2%99.95%2.0192035.1%99.76%5.079502.1%96.7%10.026000.7%83.2%这组数据很有意思阈值从 0.5℃ 升到 2℃循环数砍掉了近一半损伤只损失 0.2 个百分点非常值得。可一旦阈值升到 5℃、10℃循环数确实更少了但损伤也丢了 3% 到 17%这时候就要警惕继续往上走就是拿寿命预测精度换表面上的“干净”。所以每换一组数据我都会重新画一遍这条曲线而不是沿用上次的经验值。3.4 滤波安全验证留一个“损伤误差”指标滤波做减法减完之后必须回头验证不能只盯着循环数说“速度快了”。我给自己定了个固定流程完整雨流计数后先算出未滤波总损伤作为基准应用滤波规则对保留循环重新计算总损伤计算损伤保留率要求不低于 99%关键场景要求 99.9%如果损伤保留率低于 99%说明阈值太大或者寿命模型的非线性太强需要下调阈值把阈值、原始循环数、滤波后循环数、损伤保留率全部写进分析记录。这个习惯帮我挡掉了两次阈值设得过大导致的寿命预测偏差。滤波到底安不安全不看图漂不漂亮只看损伤保留率这一个数字。4. 实战踩坑记录这几个问题我基本都栽过4.1 在雨流计数前加死区大循环被“大卸八块”有一回我想省事在采集程序里给温度记录加了个 1℃ 死区意思是温度变化不足 1℃ 就不更新数据点。原始数据量确实小了很多但等我跑完雨流计数就傻眼了原本该是一个 45℃ 的完整冷却循环死区把斜坡切成了好几段雨流计数结果里的主循环幅值从 45℃ 掉到了十几摄氏度。原因不难理解。死区过滤的是时间序列里的“微小变化”可大循环本身就是由无数微小变化累积出来的。数据被切碎以后迟滞回线的闭合关系被打乱雨流算法再也拼不出那个完整的大循环。寿命预测结果一下子从合理区间跑到了明显偏乐观的区域。从那以后我再也没在原始数据层面做过任何形式的死区过滤。要滤就等雨流计数完成之后在循环列表上滤。4.2 只按幅值过滤、忽略均值会漏掉最危险的小循环只按幅值一刀切是新手最容易犯的错。功率循环里同样 2℃ 的幅值在 40℃ 结温附近和在 120℃ 结温附近对焊料层的损伤可能差出一个数量级。高温下蠕变速度更快哪怕循环幅值再小累积起来也能造成不可忽视的损伤。结构疲劳里也有一样的现象高平均应力区域小幅值应力循环可能刚好跨过门槛引发裂纹扩展。光按幅值把它们删掉等于把真正致命的磨损过程从载荷谱里抹掉了。我的修正方案是先做一次平均应力修正把每个循环折算成等效幅值再按等效幅值过滤。具体折算式子取决于材料但思路是共通的让“小但危险”的循环在筛选时露出原形。如果不想引入修正模型至少也要用“幅值阈值 均值区间”的双条件过滤给高温段的小循环留一条生路。4.3 半循环被误删之后配对逻辑直接崩了雨流法输出里有一批半循环count 等于 0.5。它们代表尚未闭合的迟滞回线后续如果要做循环重构或者配对这些半循环是需要被重新组合的。早期我没有在意半循环滤波时统一按幅值阈值全删结果在后续做迟滞回线重构时发现一批大循环怎么也拼不起来因为构成它边缘的半循环早被我删掉了一半。现在我的规则很简单半循环在范围低于阈值时同样删除但一旦后续流程需要做循环重构就只删除那些已经完全闭合的小幅值全循环半循环一律保留。大多数时候半循环数量很少留它们不会妨碍载荷谱瘦身却能保住后路的可操作性。4.4 阈值过大之后雨流矩阵“看着很干净”其实是错觉有一段时间我追求数据处理效率把阈值设到了最大幅值的 20%。滤波后的雨流矩阵非常干净只剩两三千条循环画出来赏心悦目。可当我按流程算损伤保留率时发现损伤丢了整整 27%。拿这个载荷谱去做寿命评估结果会显著高估真实寿命。那一刻我才彻底明白滤波的收益必须用“损伤保留率”来验收而不是用“循环数减少比例”来验收。循环数降得再多如果损伤也跟着降那只是自欺欺人的“假干净”。我现在对任何滤波方案只有一个底线要求循环可以删掉九成损伤保留率必须在 99% 以上。做不到就调低阈值或者换筛选规则。5. 滤波之后的载荷谱除了变小还带来了什么5.1 循环数从几十万跌到几千后续计算量才谈得上“可行”未滤波的循环列表有三十七万条做逐循环有限元分析想在合理时间内跑完是不现实的。很多团队直接把计算方案降级成“只挑最大循环”结果精度牺牲得没道理。滤波后循环数降到不到两万逐循环分析变得可行再配合损伤贡献法把阈值微调一下几千条主循环足矣。同样的分析程序运行时间从“跑一晚上第二天看结果”变成“出去接杯水回来就出完了”。在批量处理多组试验数据的时候这个收益会被放得更大。5.2 滤波后的雨流矩阵一眼就能讲清损伤源在哪未滤波的雨流矩阵左下角一大片深色区域全是小幅值循环真正的损伤大户藏在里面看不出来。滤波之后矩阵里只剩少数几簇清晰的主循环叠加损伤等值线一眼就能看出哪些循环贡献了绝大部分损伤。这个图放到功率循环测试报告里非常有说服力左边是原始矩阵右边是滤波后矩阵再配一个损伤保留率 99.7% 的标注审阅者不用听你多解释自己就能得出结论。5.3 滤波参数值得固化形成可复用的验证模板我后来把整套流程写成了固定函数输入是温度或应力时间序列输出是滤波后的循环列表、损伤保留率、敏感性曲线图。阈值和寿命模型参数都放在配置文件里同一类测试数据进来直接跑不用每次重复解释“为什么 2℃ 是合理的”。这样一来不同工程师处理同一批数据只要参数一致结果高度一致不会出现“你用 1℃ 我用 10℃两边结论对不上”的扯皮局面。最后分享一个我自己的习惯无论阈值选得多有理有据我都会把未滤波的原始循环文件单独存档。哪怕损伤保留率已经验证到 99.9%也留着原始数据。被同事质疑、被评审追问的时候直接打开两份文件对比着解释比任何公式都有说服力。滤波是对数据做减法做减法之前想清楚删掉的是什么删完之后还能原样拿回来这比什么都重要。
延伸阅读

更多相关文章

2026/10/16 4:31:29

Data Pipeline设计实战:从确定性、可观测性到可演进性

1. 项目概述:这不是“管道”,而是一条数据流动的高速公路“Data Pipeline”这个词,最近在技术社区、招聘JD和内部立项文档里出现频率高得有点反常——但它绝不是什么新造概念,更不是某个厂商包装出来的营销话术。我带过不下二十个…

2026/10/16 4:31:29

R语言ggpointdensity密度散点图:解决大数据过绘制问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 4:31:29

Python进阶路线图:从基础语法到专家思维的关键跃迁

“写了三年Python,却连一个像样的项目都拿不出手”这句话,我听过太多次了。日常被问得最多的不是“这个语法怎么写”,而是“我到底该怎么从入门走到精通”。很多人买书、看视频、刷题,忙活了几个月甚至几年,回头一看&a…

2026/10/16 5:41:32

弱监督语义分割新范式:端到端粗到细网络WCESN解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 5:41:32

pigz并行压缩:让gzip多线程加速,备份与日志处理效率倍增

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 5:41:32

告别收藏吃灰:学习资源筛选与高效使用指南

看到“全网最全学习资源合集”这种标题,我的第一反应不是点进去收藏,而是先判断它到底值不值得。做了这么多年内容整理和自学规划,我见过太多打着“最全”旗号的资源包,标题一个比一个响亮,打开以后发现要么是重复搬运…

2026/10/16 5:41:32

Solidity收款合约接入Chainlink预言机:实现美元计价ETH收款

最近有个做业务系统的朋友问我,想做一个接受加密货币付款的页面,合约应该怎么写。我说这事儿看着简单,真正动手你会发现,一个能在生产环境里用的收款合约,要操心的事情比想象中多得多:怎么接收以太币、怎么…

2026/10/16 5:41:32

PPO算法实战:手把手调出稳定月球着陆器

1. 项目概述:这不是教科书里的PPO,是亲手调出能稳稳落地的月球着陆器“浅谈PPO算法-玩转月球登陆”——光看标题,你可能以为这是某篇泛泛而谈的强化学习科普文。但实际操作过的人知道,这六个字背后,是一场从理论公式到…

2026/10/16 5:36:32

用 N_m3u8DL-RE 完整下载 DASH/HLS 流媒体

用 N_m3u8DL-RE 完整下载 DASH/HLS 流媒体 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8DL-RE N_m3u8DL-RE 是一款 …

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑