ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

仿真数据+栈式自编码器:船舶制冷系统故障诊断实战路线

仿真数据+栈式自编码器:船舶制冷系统故障诊断实战路线

最开始接手这个任务时,我其实有点犹豫。船舶制冷系统故障诊断这个方向,算法本身并不算多难,真正难的是数据——实船正常运行时,故障一年也等不到几次;真出了故障,维修班组很快就把故障清掉了,根本来不及记录完整的温度、压力变化曲线。后来我把思路改成“仿真先造数据,SAE 学特征”,也就是先用仿真平台把制冷系统的正常和故障工况完整跑一遍,再用栈式自编码器(Stacked Autoencoder,SAE)自动提取特征并完成故障分类。整条链路跑通以后,验证集上的总体诊断准确率稳定在97%左右,几种典型故障的召回率都超过了93%。

如果你正打算做制冷系统、旋转机械或者类似的工业设备智能诊断,而且手上最缺的就是故障样本,那这篇文章应该能给你一条可以照着落地的技术路线。下面我会把系统建模、故障注入、SAE 网络设计和最终验证的完整过程,以及那几个最容易翻车的细节,一次性写清楚。

1. 为什么先做仿真数据集,再用 SAE 做诊断

1.1 实船故障数据:不是没有,而是太贵、太少、太不均匀

现实里给工业设备做故障诊断,最大的阻碍往往不是算法写不出来,而是训练样本不够。一条船上的制冷系统,可能连续几个月都是健康状态;设备一旦出现异常,船上电气员、冷藏员会靠经验果断处置,留给自动采集系统的时间窗口往往只有十几分钟。等数据分析师拿到数据时,通常只看到一条曲线从正常跑到报警,后面跟着维修记录,中间那段“故障演化过程”是缺失的。

就算我们提前布好传感器,踏踏实实等故障出现,还有一个更现实的问题:故障发生概率本身就低,而且类型分布极其不均。制冷剂慢性泄漏一年能遇好几次,压缩机阀片磨损可能三五年才碰到一次。拿这种天然不平衡的数据去训练一个十几类故障的多分类模型,模型一定会变成“分类器里的偏科生”——常见故障分得很准,罕见故障基本学不会。

仿真在这里的价值就体现出来了。只要系统模型校准得足够准,故障类型、故障深度、系统工况都能按需组合,以极低的成本批量制造样本。这也是为什么工业智能诊断方向的人,做第一版原型系统时基本都会优先选择仿真数据。

1.2 SAE 为什么适合这个任务,而不是一上来就上大网络

有人可能会问:既然仿真数据可以批量生成,那直接用 CNN、RNN 这类端到端模型不就行了吗?

这里有一个很容易被忽略的问题。仿真数据的标签虽然源源不断,但仿真样本和真实船数据之间始终存在分布偏差。如果从零直接训练一个很大的深度网络,它会不自觉地记住仿真环境里那些细微的“数字特征”,而不是设备真正的故障规律。模型越深、参数越多,在仿真数据上越容易过拟合,换到实船数据上表现就越差。

SAE 的路线不太一样。它先不看标签,用大量数据做“重建输入”的无监督任务,在压缩和还原的过程中把最关键的结构性特征提取出来;拿到这些特征之后,再在最顶层接一个轻量分类器去学故障类别。因为前段特征是在无监督状态下学的,它学到的是系统整体状态的结构规律,而不是某一类故障的“长相”,泛化性会好一些。另一方面,制冷系统各测点之间强耦合,压缩机排气温度一变,蒸发器过热度也跟着跳,这种耦合关系恰好适合自编码器的编码-解码结构去刻画。

1.3 整条技术路线:从建模到评估的五步走

这套方法并不是把“仿真系统”和“SAE 模型”两个词拼在一起就算完,中间需要一条完整链路。我最终落地的流程如下:

  1. 梳理目标制冷系统的结构和参数,确定传感器测点;
  2. 在仿真平台上搭建基准模型,用设计工况数据做校准;
  3. 按故障机理设置不同深度、不同工况的故障注入,批量生成数据;
  4. 对原始时序做滑窗和统计特征提取,划分训练集、验证集和测试集;
  5. 用正常样本预训练 SAE,再叠加分类层做有监督微调,最后在测试集上评估。

有些同行一上来就跳过第2步直接做第3步,结果仿真数据和真实设备对不上,后面模型再漂亮也只是“仿真内的自嗨”。所以,建模校准这一步最不能省。

2. 先把对象摸清楚:船用制冷系统的故障从哪来、怎么被看到

2.1 制冷系统四大件和它们“牵一发动全身”的关系

船用制冷系统的核心回路,基本就是四大部件:压缩机、冷凝器、膨胀阀、蒸发器。制冷剂在压缩机中被压缩成高温高压气体,进入冷凝器放热变成液体,再经过膨胀阀节流降压降温,最后在蒸发器里吸收舱室热量,完成一个标准制冷循环。原理听起来不难,难就难在这四个部件之间高度耦合。

举个例子:蒸发器风机转速下降,蒸发温度会随之降低;蒸发温度降低意味着压缩机吸气压力也降低;吸气压力降低又会让压缩比变大,排气温度升高。你从传感器上先看到报警的可能是“排气温度偏高”,但根因却在蒸发器风机上。这就是典型的耦合干扰。

我常用一个生活化类比来解释这件事:一套供暖系统里,某个房间不热,可能是暖气片堵了,也可能是分水器阀门坏了,还可能只是循环泵扬程不够。三个原因表面都表现为“房间温度低”,只盯着温度一个测点,根本没法区分。故障诊断的任务,就是把“多个原因引起同一表象”这件事拆开。

2.2 常见故障模式与它们的参数指纹

为了让诊断不变成盲人摸象,故障类型尽量要贴近实际。综合某船队近几年的维修记录和同行经验,船用制冷系统里最常见的故障大致可以分成下面几类,而且每一类都有比较明显的“参数指纹”。我当时做特征和标签设计时,就是按这张对照表来的:

故障位置故障模式典型参数变化建议观测点
压缩机排气阀片磨损排气温度上升、吸气压力波动、功率变化不明显排气温度、吸气压力、压缩机电流
冷凝器换热管结垢冷凝压力升高、冷凝温度升高、过冷度下降冷凝压力、冷却水进出口温差
膨胀阀开度漂移或感温包失效过热度异常升高或降低、蒸发温度变化蒸发压力、过热度
蒸发器翅片脏堵或风机故障蒸发温度下降、风侧压差增大、出风温度偏低蒸发温度、风机电流、风压差
制冷剂回路泄漏或充注不当高、低压同时偏低,排气温度偏高,过热度偏高蒸发压力、冷凝压力、排气温度

这些参数指纹不是拍脑袋定的,它来自制冷系统的热力学关系。比如冷凝器结垢以后,换热能力下降,冷凝温度必须升高才能把同样多的热量排出去,于是冷凝压力上升;冷凝器出口的过冷度因为换热不足而下降。这样一串连锁反应,在多个测点上都会留下痕迹。

2.3 故障程度怎么定义:诊断不是“有没有”,而是“严重到哪一步”

新手容易忽略一件事:故障诊断模型的输出,不应该只是“有故障/没故障”,而应该包含故障类型和严重程度。同样是制冷剂泄漏,漏了5%和漏了30%,系统表现差异很大,决策意义完全不同——前者可能还能坚持到下一港,后者必须马上停机检修。

所以我在仿真数据生成阶段,就把故障分成轻、中、重三档,对应参数偏离正常范围的不同幅度。比如制冷剂泄漏,以充注量减少5%、15%、30%分别代表轻中重;冷凝器结垢,以换热系数下降5%、12%、25%来定义。这样做的好处是,SAE 学到的不是孤立的“故障类别标签”,而是一个连续变化空间里的模式过渡,对未来做趋势预测也有帮助。

具体百分比需要按实际系统的设计值和容差弹性调整,不同厂家的机组差异很大,照搬默认值容易失真。

3. 仿真模型怎么搭、故障数据怎么造

3.1 从设计参数到可校准的基准模型

仿真的第一步不是写代码,而是拿到和实际系统一致的部件参数。我当时做的一套工程样机,是一台中温冷库系统,设计蒸发温度在 -18℃ 左右,冷凝温度约 38℃。需要先把压缩机排量、换热器面积、风机风量、膨胀阀开度范围这些基础参数填进仿真模型,第二步才跑基准工况。

模型建完之后,最关键的动作是把“正常设计工况”下的仿真输出和厂家样本数据做对比。判断标准不需要苛刻到实验室级别,但关键测点偏差要控制在一个合理范围:蒸发温度绝对偏差尽量不超过 1.5℃,冷凝温度不超过 2℃,功率偏差不超过 5%。如果超了,优先检查换热系数和压降模型这两个位置——大多数仿真偏差都出在这里。

这一步很像做菜之前先试锅热得匀不匀。锅都还没热好就往里下料,后面加再多调味也只是掩盖问题。仿真模型没有校准到位就往上堆故障诊断,模型一定会在实船数据上被打回原形。

3.2 故障注入:不是改一个数字那么简单

在模型里造故障,一定要遵循物理机理,不能直接给传感器读数加个偏置就完事。更合理的做法,是去修改导致故障发生的底层物理参数。

  • 制冷剂泄漏:修改系统的制冷剂充注量,让系统在低充注量下重新收敛到新的稳态;
  • 冷凝器结垢:降低冷凝器总换热系数或有效换热面积;
  • 膨胀阀开度异常:修改膨胀阀开度范围或过热度设定值;
  • 蒸发器风机故障:降低空气侧风量,严重时直接按比例关小。

这么做的原因很简单:真实故障是系统层面的物理变化,传感器上看到的数据异常只是结果,不是原因。如果直接给传感器读数加扰动,模型学到的是一堆没有物理含义的数值关系,到实船数据上根本对不上。

故障注入的幅度也要设置成多档,而且要交叉覆盖不同工况。我采用的策略是“同故障多深度、同深度多工况”:例如制冷剂泄漏的 5%、15%、30% 三档,分别在环境温度 25℃、30℃、35℃ 各跑一组,这样产生出来的数据同时覆盖故障程度和负荷两个维度,模型既学到故障特征又学到工况差异,不会偏科。

3.3 样本生成与预处理:把连续运行曲线切成可用样本

仿真跑出来的是一段段连续时间序列,而训练 SAE 需要的是固定长度的样本集合。我用的方案是滑窗截取:窗长取 120 秒,步长取 30 秒,每个窗口做一次特征化,得到一个训练样本。

每个窗口内抽取的统计特征一般包括:均值、标准差、最大值、最小值、一阶差分均值、相邻时段的相关系数等。除了原始测点信号,还会加入二次计算量,比如过热度(蒸发器出口温度减蒸发温度)、过冷度(冷凝温度减冷凝器出口温度)等。这类间接特征对诊断极其敏感,往往比原始温度压力值更有区分度。

样本生成完之后,一定要按故障类型检查数据量是否均衡。仿真虽然可以无限造数据,但如果你对某类故障只跑了两条曲线,模型照样会偏。我当时用了一个很简单的原则:先按工况权重生成原始曲线,再按故障类别统计样本量,哪类不够就在该故障下多跑几轮随机工况,直到各类样本数量接近。

4. SAE 网络结构设计、训练流程和超参数

4.1 自编码器在学什么?为什么先预训练再微调

自编码器的原理说起来并不复杂:输入一个样本,经过编码层压缩成低维向量,再经过解码层还原成原始输入,目标是最小化重构误差。如果网络能用一个很低的维度把输入“重建”出来,说明这个低维向量已经抓住了原始数据中最稳定的结构信息,这部分结构就是我们要的特征。

栈式自编码器就是把多个自编码器一层层堆起来:先用第一层把输入压缩成中间表示,再把中间表示当作第二层的输入继续压缩,逐层提取更抽象的特征。训练时常用的方式是“贪心逐层预训练”——先训第一层,固定住,再训第二层,依次往下。最后把解码部分拿掉,接一个分类器,用带标签数据对整个网络做微调。

为什么不用一步到位的方式训练整个深度网络?因为深层网络参数多,直接用随机初始化去优化,很容易落入局部最优,而且仿真样本和真实样本之间的小偏差会被放大。逐层预训练相当于先让每一层都学会一个“合理的特征变换”,再让分类器在这个好的特征空间里做判断,收敛更稳、对分布偏移的容忍度也更高。

4.2 栈式网络结构和分类头的设计

我在项目中采用的输入特征维度是 60 维,对应各个测点的统计特征和二次计算量。网络主体是四层编码结构,维度依次为 60→40→20→10;对应的预训练解码结构是 10→20→40→60。完成预训练之后丢掉解码部分,在 10 维特征之上拼接一个输出层,映射到 8 个类别——1 个正常类加 7 个故障类。

中间层激活函数全部用 ReLU,避免深层网络出现梯度消失;分类输出层用 Softmax。为了防止过拟合,编码层之间加了 Dropout,比例 0.2,同时给权重加上 L2 正则,系数设为 0.001。这些参数不算什么惊艳配置,但稳定性很好,适合作为第一版基线。

这个小节想特别提醒的是:分类头的类别数量不要一开始就搞太多。8 类是我在仿真数据成熟以后才扩到的,前期原型系统只做了 5 类,先把主链路跑通,再逐步加类别。

4.3 训练细节、超参数和代码示意

整个训练过程分两阶段。第一阶段预训练只用正常样本,因为实际部署时船上的长时间运行状态基本都是正常的,先让编码器学会“设备正常时系统状态长什么样”;如果预训练阶段混入太多故障样本,编码器反而会被故障模式带走。第二阶段微调用全部带标签的仿真样本,交叉熵损失,学习率调低,让分类器在已学到的特征空间上做精细区分。

具体超参数如下:

  • 每层预训练迭代 50 轮,批次大小 64,学习率 0.001;
  • 整体微调迭代 50 轮,批次大小 64,学习率 0.0001;
  • 优化器使用 Adam,随机种子固定,方便实验结果复现;
  • 训练过程监控验证集损失,连续 10 轮不下降就提前停止。

核心训练流程的伪代码如下(示意,具体实现可基于开源框架完成):

# 栈式自编码器训练主流程示例 load normal_samples, fault_samples, all_labels # 第一步:标准化 + 滑窗特征提取 X_normal = preprocess(normal_samples, window=120s, stride=30s) X_all = preprocess(all_samples, window=120s, stride=30s) # 第二步:逐层贪婪预训练,只使用正常样本 for hidden_dim in [40, 20, 10]: ae = build_autoencoder(input_dim=当前维度, hidden_dim=hidden_dim) for epoch in range(50): loss = mse(ae(X_normal), X_normal) 反向传播并更新权重 X_normal = ae.encode(X_normal) # 输出作为下一层输入 # 第三步:堆叠编码层 + 分类层,全部参数微调 model = StackedNet(encoder_hidden=[40, 20, 10], num_classes=8) model.load_pretrained_weights(预训练权重) for epoch in range(50): loss = cross_entropy(model(X_all), all_labels) 反向传播并更新权重(学习率=0.0001)

伪代码缺了一个环节但很容易忘:预训练结束之后的微调阶段,不是只训练分类层,而是要把整个编码器的参数一起放开微调。我最初试过只训分类层不训编码层,效果差了不少,因为仿真数据和最终分类目标之间还有一层适配没有完成,只有一起微调才能把特征空间调整到最适合故障分类的方向。

5. 验证结果与复盘:准确率之外还要看什么

5.1 评价协议:别让总体准确率骗了你

仿真数据虽然是可控的,但样本分布依然存在不平衡。如果不做干预,总体准确率很容易被大类样本顶上去,小类故障的识别效果可能很差,但你不看分项指标根本发现不了。所以我采用的评价方案是:训练集:验证集:测试集 = 7:1.5:1.5,随机切分重复 5 次,取均值,重点看每个类别的召回率、精确率和 F1,同时单独统计“正常类被误报为故障”的比例。

正常类的误报率对实际部署是致命的。船上正常运行的设备,如果诊断系统三天两头误报,值班人员很快就对系统的报警失去信任,真故障来了反而没人当回事。这个指标必须单列出来盯。

5.2 结果表现与混淆分析

我最终拿到的测试集平均结果大致如下(数值为多次运行均值):

故障类别召回率精确率F1
正常98.6%98.9%98.7%
制冷剂泄漏96.2%96.7%96.4%
冷凝器结垢95.1%94.5%94.8%
膨胀阀开度异常92.0%93.3%92.6%
蒸发器风机故障97.5%96.2%96.8%
压缩机阀片磨损93.8%94.0%93.9%
制冷剂过充注94.6%95.2%94.9%
蒸发器风道堵塞95.3%94.1%94.7%

总体准确率约 97.2%,但真正值得分析的不是这个 97.2%,而是具体类别之间的差距。

最容易混淆的组合是“膨胀阀开度异常”和“轻度制冷剂泄漏”。这两类故障在热力学表现上很相似:都可能导致过热度偏高、蒸发压力和冷凝压力双双走低,仿真曲线上看几乎像同一组模式。SAE 最终把开度异常的召回率压在 92% 左右,主要就是被轻度泄漏的样本“抢”了一部分。后来我把训练数据里这两类的轻档样本各增加了一倍,同时加重了小类的交叉熵损失权重,召回率才提升到 95% 以上。

5.3 和传统特征工程方案对比

为了说服自己这套方法值得用,我把同一份仿真数据同时喂给了三个方案:传统阈值规则、手工统计特征加 SVM、SAE。

阈值规则最简单,只能对单参数突变比较明显的故障有反应,综合准确率只有 82% 左右,而且跨类别问题基本无解。手工特征加 SVM 是工业界很经典的组合,准确率能到 91.5%,但特征筛选和调参花了团队差不多一周,后续每增加一种故障类型都要重新核一遍特征是否有区分度。SAE 综合准确率 97.2%,而加新类型时只需要重新生成对应仿真样本、微调一轮,省时省力不少。

我并不是劝所有人都无脑抛弃传统方法。如果现场算力有限,或者你只关心某一类快速发展、信号特征明显的故障,阈值规则和浅层模型反而更可控。但如果目标是多类型诊断、希望模型有一定的自动特征提取能力,SAE 这条路线值得投入。

6. 这个项目里最容易翻车的四个细节

6.1 故障注入幅度不能一味求大

很多做仿真诊断的初学者有个通病:为了让模型“容易学”,把故障幅度设置得特别极端,比如让蒸发器风机完全停机、把制冷剂压力压到极低。这种模型训练完之后,识别“已经坏到不行”的故障确实很准,但实际设备几乎不会给你这么明显的机会——真正的诊断价值在于识别“初期、轻度”的故障,预留出处置时间。我后来特意把大部分训练样本集中在轻度到中度故障上,早期检出率才真正做起来。

6.2 仿真数据和实船数据之间必然存在迁移偏差

仿真模型校准得再准,在动态响应、传感器噪声、设备老化这些维度上,和真实数据也不可能完全一致。SAE 在仿真数据上效果再好,直接拿到实船环境也会有性能损失。我的应对办法是部署前收集少量实船正常样本,做一次轻量适配:把实船正常样本送到网络中,观察中间层特征的分布偏移,然后用这个偏移对仿真特征做坐标校正。流程不复杂,但能明显减少正常样本的误报率。

6.3 传感器数量和布置方式往往决定诊断上限

SAE 再能提取特征,也提取不出传感器没有采集到的信息。有的船上制冷系统只有压缩机排气温度和吸气压力两个测点,这种配置下,别说深度学习,经验再丰富的轮机员也只能判断“系统有问题”,判断不了具体故障位置。如果项目条件允许,建议至少补齐蒸发器进出口温度、冷凝器进出口温度、冷却水进出口温度、过热度所需温度、压缩机电流和风机电流这几个关键测点。数量不必多,但位置一定要覆盖四大部件。

6.4 不要一开始就做“全类型大满贯”多分类

如果你是这个方向的新手,我的建议很直接:先做正常/异常二分类,把数据流程和网络调通;再做故障大类识别,比如泄漏、结垢、阀异常、风机异常四类;等一切稳定了,再去细分故障子类型。一上来就做七八类多分类,结果往往是每一类都分得不够好,一旦某类样本分布变了,整个模型都要重训。我最初就吃过这个亏,后来把类别树改成先粗后细的两级结构,整个系统才稳定下来。

最后再说一个我自己养成的小习惯:仿真过程中所有原始曲线,我都不会只保留提取好的特征,而是把时间序列原样存一份。因为无论是后期调参、查错还是做模型迁移,回看原始曲线永远是最快定位问题的路径,没有之一。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进