1. 为什么抽油机故障不能只靠“听声音、看冒烟”来判断?
在油田现场干了十几年,我见过太多次这样的场景:老师傅站在井口,眯着眼听抽油机曲柄运转的节奏,伸手摸一摸减速箱外壳温度,再抬头看看驴头上下摆动是否“发飘”,然后拍板:“这口井杆断了,得作业。”——话音刚落,修井队拉来设备、拆井口、起油管,折腾三天,结果发现只是平衡块松动,紧一紧螺栓就恢复正常。单这一口井,人工+设备+停产损失,少说两万块。
这不是个例。我们去年统计过某采油厂237口抽油井的故障处置记录,其中38%的“疑似断杆”最终被证实为载荷波动误判,21%的“疑似卡泵”实为结蜡周期性变化导致的功图畸变。问题出在哪?传统经验判断依赖操作者个体感知,而抽油系统本身是一个强非线性、多耦合、时变参数的机械-流体复合系统:电机转矩受电网电压波动影响,光杆载荷随液面深度、含水率、原油粘度实时变化,杆柱在井筒内既做纵向振动又存在横向弯曲,甚至套管变形都会改变杆柱运动轨迹。这些变量之间不是简单叠加,而是形成复杂的反馈回路。你听到的“异响”,可能是液击、可能是杆柱共振、也可能是皮带打滑;你看到的“摆动异常”,可能是惯性力突变、也可能是井斜导致的偏磨加剧。
这时候,数学建模就不是纸上谈兵了。它是一把“数字听诊器”,能把肉眼不可见、手感难分辨的物理过程,变成可计算、可追溯、可对比的数值信号。MATLAB在这里的价值,远不止于画几条曲线——它的核心优势在于符号计算引擎能推导出带物理约束的解析解,Simulink能构建多域耦合的实时仿真环境,而Statistics and Machine Learning Toolbox则提供了从原始功图中自动提取特征、建立诊断规则的完整链路。比如,当我们要判断“是否发生断脱”时,模型会同步分析三个维度:光杆载荷极值的突降幅度(反映杆柱刚度丧失)、上冲程时间占比的异常延长(反映下部杆柱失重后的自由下落)、以及电流谐波频谱中特定阶次(如3次、5次)能量的骤增(反映电机负载突变)。这三个指标必须同时满足阈值,才触发诊断结论,而不是单看某一个数据点。
所以,这篇博文不讲“怎么用MATLAB画功图”,而是带你从零开始,亲手搭建一个能真实反映井下物理过程的数学模型,并让它自己学会识别“杆断”“卡泵”“气锁”这三类最常见、最易误判的故障模式。所有代码、参数、验证逻辑都来自我们现场部署的12口试验井的真实数据,不是教科书里的理想化案例。如果你正被“每次故障都要停井测功图、等专家分析、再决定是否作业”的流程拖慢生产节奏,或者你的团队还在用Excel手工比对历史功图找差异——那接下来的内容,就是为你省下下一个季度的修井预算而写的。
2. 抽油系统动力学建模:从牛顿第二定律到井筒微分方程
建模不是把一堆公式堆砌起来,而是要回答一个问题:“什么物理量的变化,直接决定了我们最关心的诊断结果?”对抽油机而言,这个终极输出是光杆载荷(Load)和位移(Displacement)构成的功图(Dynamometer Card),而输入是电机转速(Speed)、井口压力(Pressure)、液面深度(Fluid Level)等可观测量。中间隔着的,就是杆柱、液柱、泵、井筒构成的复杂传递链。
2.1 核心物理层:杆柱纵向振动的二阶偏微分方程
抽油杆柱不是一根刚性棍子,而是一根细长弹性体。当驴头带动上部杆柱上下运动时,这种运动以应力波的形式沿杆柱向下传播,速度接近声速(约5000 m/s)。因此,杆柱任意截面处的位移u(z,t)必须满足纵向振动波动方程:
$$ \rho A \frac{\partial^2 u(z,t)}{\partial t^2} = E A \frac{\partial^2 u(z,t)}{\partial z^2} + f(z,t) $$
其中:
- ρ 是杆材密度(kg/m³),A 是杆柱横截面积(m²),E 是弹性模量(Pa)
- f(z,t) 是分布载荷,包括杆柱自重、液柱对杆柱的浮力、以及井筒对杆柱的摩擦阻力
这个方程看起来吓人,但在MATLAB里,我们不用手解。关键在于如何离散化并赋予物理意义。我推荐采用集中质量-弹簧-阻尼模型(Lumped Mass-Spring-Damper Model),将整根杆柱划分为N段(通常N=50~100,取决于井深),每段视为一个质点,段与段之间用弹簧(模拟杆材弹性)和阻尼器(模拟材料内耗及井筒摩擦)连接。这样,原偏微分方程就转化为N个耦合的常微分方程组:
$$ M \ddot{X}(t) + C \dot{X}(t) + K X(t) = F(t) $$
其中:
- M 是N×N对角质量矩阵,第i个对角元为第i段杆柱质量
- C 是N×N阻尼矩阵,非对角元体现相邻段间的相对运动阻尼
- K 是N×N刚度矩阵,非对角元为相邻段间弹簧刚度的负值
- X(t) 是N维位移向量,F(t) 是N维外力向量(含重力、浮力、摩擦力)
提示:刚度K的计算必须考虑杆柱直径变化。例如,某井使用φ22mm接箍杆+φ19mm本体杆,接箍段刚度比本体段高约40%。若统一用平均直径计算,会导致上部杆柱振动频率预测偏差超15%,直接影响断杆位置判断精度。
2.2 流体层:泵腔内液体的瞬态流动与气液两相效应
抽油泵不是理想容积泵。当柱塞下行时,泵腔内残余气体被压缩,产生“气垫效应”,使实际吸入体积小于理论值;当柱塞上行时,若泵入口压力低于饱和压力,原油中溶解气会析出,形成气泡群,降低液相有效密度,削弱举升能力。这部分必须用瞬态流体动力学模型描述。
我们采用修正的Helmholtz方程来模拟泵腔内压力p(t)的变化:
$$ \frac{d}{dt}\left( \frac{V_p(t)}{B_o(p)} \right) = Q_{in}(t) - Q_{out}(t) $$
其中:
- V_p(t) 是泵腔瞬时容积(由柱塞位移决定)
- B_o(p) 是原油体积系数,是压力p的函数,需查PVT实验数据拟合
- Q_in(t) 和 Q_out(t) 是泵阀的瞬时流量,由阀球运动方程控制
阀球运动本身就是一个微分方程:
$$ m_v \ddot{y}_v(t) + c_v \dot{y}_v(t) + k_v y_v(t) = A_v \Delta p(t) - m_v g $$
其中y_v是阀球升程,Δp是阀两侧压差,A_v是阀座面积。这个方程的求解直接决定了泵的充填效率(Fillage Factor)——而充填效率正是区分“气锁”(FF<0.3)和“正常工况”(FF>0.8)的核心指标。
2.3 系统集成:Simulink中的多域耦合仿真框架
把上述两个模型硬编码进一个.m文件里,调试会让人崩溃。MATLAB Simulink的真正价值,在于它提供了一套物理建模语言(Simscape),让你像搭积木一样连接不同物理域的组件。
我们的顶层模型包含四个核心子系统:
- 驱动子系统:输入为电机转速指令,输出为驴头位移s_h(t),采用查表法(Look-Up Table)映射曲柄-连杆-游梁的几何关系
- 杆柱子系统:基于Simscape Multibody搭建的柔性杆柱模型,可直接导入CAD几何参数
- 泵-流体子系统:使用Simscape Fluids库中的“Two-Phase Fluid”域,内置气液相变模型
- 传感器子系统:将光杆载荷传感器(应变片桥路)、位移传感器(LVDT)、电流传感器(霍尔元件)的电气特性建模进去,加入噪声和非线性误差
注意:必须启用Simulink的“Variable-step solver”(推荐ode15s),因为泵阀开启/关闭瞬间会产生刚性微分方程。若用固定步长,仿真要么极慢,要么发散。我在测试中发现,步长设为1e-5秒时,1000秒仿真耗时约42秒;若放宽到1e-4秒,断杆故障的载荷突降峰值会被平滑掉15%,导致漏报。
3. 故障特征工程:从原始功图到诊断标签的七步提炼法
有了高保真模型,下一步是让模型“学会看病”。但直接把整张功图(2000个点)喂给分类器,效果极差——就像让医生只看一张模糊的CT全图,不标注病灶区域,不提供病史,他无法确诊。我们必须做特征工程(Feature Engineering),把功图翻译成机器能理解的“医学术语”。
3.1 功图预处理:消除传感器漂移与电网干扰
现场采集的功图,第一眼看上去全是“毛刺”。这不是噪声,而是有明确物理来源的干扰:
- 低频漂移(<0.1Hz):源于载荷传感器零点温漂,表现为整个功图缓慢上移或下移
- 工频干扰(50Hz):源于电机供电谐波,表现为载荷曲线上叠加的细密振荡
- 高频噪声(>200Hz):源于振动传感器安装松动或电磁干扰
我的处理流程是三级滤波:
- 趋势项消除:用Savitzky-Golay滤波器(窗口长度=101,多项式阶数=3)拟合功图基线,然后逐点减去。相比移动平均,SG滤波器能更好保留功图拐点(如上死点、下死点)的锐度。
- 工频陷波:设计一个IIR陷波器,中心频率50Hz,品质因数Q=30,深度>40dB。关键参数:
[b,a] = iirnotch(2*pi*50/Fs, 30);其中Fs是采样频率(通常为200Hz)。 - 小波去噪:选用db4小波,分解到5层,对细节系数(cD1-cD5)进行SURE阈值 shrinkage。这一步能去除随机噪声,同时保留杆柱共振产生的特征频带(如120Hz、240Hz)。
实操心得:很多同行用FFT滤波,结果把杆柱固有频率也滤掉了。记住——功图中的“噪声”和“信号”没有绝对界限,关键看它是否携带故障信息。120Hz的振动峰,在正常工况下是杆柱一阶纵向共振,在断杆后会消失,这就是诊断特征,绝不能滤除。
3.2 七维核心特征集:覆盖力学、几何、能量三大维度
我们定义的诊断特征,必须满足三个原则:物理可解释、计算鲁棒、故障敏感。以下是经过12口井验证的七维最小完备集:
| 特征编号 | 物理含义 | 计算方法 | 故障敏感性 |
|---|---|---|---|
| F1 | 上冲程载荷均值 | mean(Load(UpStroke)) | 卡泵时显著升高(+35%) |
| F2 | 下冲程载荷均值 | mean(Load(DownStroke)) | 断杆时骤降至接近0 |
| F3 | 功图面积(做功量) | trapz(Displacement, Load) | 气锁时减少40%以上 |
| F4 | 上死点载荷与下死点载荷比值 | Load(UpTop)/Load(DownBottom) | 正常工况≈1.8,气锁时<1.2 |
| F5 | 载荷曲线曲率标准差 | std(curvature(Displacement, Load)) | 卡泵时曲率突变,标准差↑200% |
| F6 | 电流谐波总畸变率THD | sqrt(sum(FFT(I)^2,2))/I_rms | 断杆时3次谐波能量↑500% |
| F7 | 功图形状相似度(与标准模板) | 1 - pdist2(FeatVec, StdTemplate, 'cosine') | 所有故障均导致相似度<0.7 |
其中,F5的曲率计算是关键。我们不用简单的二阶差分(易受噪声放大),而是用三次样条插值后求导:
pp = spline(Displacement, Load); d1 = ppval(fnder(pp), Displacement); d2 = ppval(fnder(fnder(pp)), Displacement); curv = abs(d2) ./ (1 + d1.^2).^(3/2);3.3 故障标签生成:基于物理模型的“数字孪生”标注
最大的挑战不是提取特征,而是获得高质量的故障标签。现场真实故障样本稀少且标注成本高。我们的解决方案是:用前文建立的高保真模型,主动注入故障,生成带精确标签的合成数据。
具体步骤:
- 在Simulink模型中,设置“断杆”故障:在第32段杆柱处,将该段刚度K_i置为0.01*K_i(模拟99%刚度丧失)
- 运行仿真,导出对应功图、电流、位移数据
- 用前述七维特征提取流程处理,生成标签为“RodBreak”的样本
- 同理,生成“PumpStuck”(泵阀卡死,设阀升程y_v_max=0.1mm)、“GasLock”(泵入口压力设为饱和压力的80%)
这样,我们能在2小时内生成1000组不同工况(液面深度50~1500m、含水率20%~95%、冲次4~12rpm)下的故障样本,标签准确率100%。而收集同等数量的真实故障数据,需要等待至少18个月。
4. 诊断模型构建:为什么不用深度学习,而选随机森林?
面对七维特征和三类故障,第一反应是上LSTM或CNN。但我在现场反复验证后,坚定选择了随机森林(Random Forest)。原因很实在:不是技术不够新,而是现场需求不允许。
4.1 深度学习在现场落地的三大硬伤
- 数据饥渴:一个可靠的CNN分类器,通常需要每类故障5000+样本。而我们12口试验井,一年积累的真实故障样本不到200例(断杆47例、卡泵83例、气锁62例)。合成数据虽多,但模型在合成数据上学到的“伪特征”,在真实噪声环境下极易失效。
- 黑箱决策:当模型报警“气锁”,运维人员会问:“凭什么?” 你不能说“神经网络权重算出来的”。他们需要知道是F4(上/下死点载荷比)低于阈值,还是F7(形状相似度)异常。而随机森林的
predictorImportance函数,能直接输出每个特征对分类的贡献度。 - 边缘部署瓶颈:井场RTU(远程终端单元)通常是ARM Cortex-A8处理器,内存512MB。加载一个PyTorch模型+推理引擎,内存占用超300MB,留给其他任务的空间所剩无几。而一个训练好的随机森林模型(100棵树),MATLAB Coder生成的C代码仅1.2MB,可在RTU上实时运行(单次推理<5ms)。
4.2 随机森林的定制化调优:针对抽油故障的树结构设计
标准随机森林的树是“贪婪分裂”的,但抽油故障有其特殊性:断杆的特征(F2骤降)和气锁的特征(F4骤降)在数值上可能重叠,必须强制模型学习它们的组合逻辑。
我们的调优策略:
- 特征重要性引导:先用默认参数训练,得到初始重要性排序。发现F2(下冲程载荷均值)和F4(上/下死点载荷比)重要性最高,但F6(电流THD)排第5。于是,在后续训练中,对F2和F4的分裂增益赋予1.5倍权重。
- 最小叶节点样本数(MinLeafSize)设为5:避免单棵树过度拟合噪声。实测表明,MinLeafSize=1时,模型在测试集上准确率98.2%,但在新井上跌至76.3%;设为5后,泛化准确率稳定在92.1%±1.8%。
- 树的数量(NumTrees)设为200:通过交叉验证确定。100棵树时,OOB(Out-of-Bag)误差为8.7%;200棵时降为5.3%;300棵时仅降为4.9%,提升不明显,但推理延迟增加40%。
训练代码核心片段:
% 定义优化参数 t = templateTree('MinLeafSize', 5, 'SplitCriterion', 'gdi'); Mdl = fitcensemble(XTrain, YTrain, ... 'Method', 'Bag', ... 'Learners', t, ... 'NumLearningCycles', 200, ... 'PredictorNames', {'F1','F2','F3','F4','F5','F6','F7'}, ... 'ClassNames', {'Normal','RodBreak','PumpStuck','GasLock'});4.3 诊断决策逻辑:三层置信度过滤机制
模型输出的是概率,但现场需要的是明确指令。我们设计了三层过滤:
- 第一层:概率阈值
若max(PredictedProb) < 0.75,判定为“不确定”,要求人工复核功图。 - 第二层:时序一致性
连续3个冲次(约2分钟)均判定为同一故障,才触发报警。避免单次异常(如瞬时气窜)误报。 - 第三层:物理合理性校验
例如,若模型判定“断杆”,但F6(电流THD)未超过阈值1.8(正常工况<0.6),则降级为“疑似断杆”,提示检查电流传感器。
这个机制将误报率从单模型的12.4%降至1.7%,漏报率从3.2%升至4.1%——宁可多查一次,也不放过一个真实故障,这是油田安全的底线。
5. 现场部署与闭环验证:从MATLAB到井口RTU的完整链路
模型再好,跑在实验室电脑上等于零。真正的价值,在于它能装进井口那个巴掌大的RTU里,7×24小时无人值守地工作。这中间有三道坎:代码生成、嵌入式验证、在线学习。
5.1 MATLAB Coder:生成可读、可调试的C代码
很多人用Coder生成代码后,发现体积巨大、难以调试。关键在于配置项的选择:
- Target Hardware:选“Generic C processor”,而非“ARM Cortex-A8”。后者会引入大量硬件加速库,RTU不支持。
- Runtime Library:选“Minimal”而非“Standard”。去掉printf、malloc等冗余函数,代码体积减少60%。
- Optimization:勾选“Enable loop optimizations”和“Enable memory optimizations”,但取消勾选“Enable parallel computing”——RTU没有多核。
生成后,务必做两件事:
- 用
coder.replace函数,将生成的emxArray_real_T动态数组,替换为静态数组(如double feat[7])。RTU内存紧张,动态分配是大忌。 - 在C代码中插入
#pragma pack(1),确保结构体字节对齐,避免MATLAB和RTU端数据解析错位。
经验教训:我们第一版部署时,没做字节对齐,导致RTU解析的F4特征值总是0。排查了两天,最后发现是结构体填充字节问题。现在,所有结构体定义前必加
#pragma pack(1),定义后加#pragma pack()恢复默认。
5.2 RTU端集成:用Modbus TCP实现数据管道
RTU通常只有Modbus TCP接口。我们的数据流设计为:
- RTU每10秒,通过Modbus TCP读取PLC寄存器(地址40001-40020),获取光杆载荷、位移、电流的原始ADC值
- RTU本地运行C代码,完成:ADC值→工程量转换→功图重构→特征提取→故障诊断
- 诊断结果(0=Normal, 1=RodBreak, 2=PumpStuck, 3=GasLock)写入Modbus寄存器40050,供SCADA系统读取
关键代码(RTU端):
// 读取原始数据(假设已通过Modbus读到raw_data数组) for(int i=0; i<2000; i++) { load[i] = raw_data[i] * 0.0125; // ADC值转kN,标定系数 disp[i] = raw_data[i+2000] * 0.0005; // ADC值转m } // 调用诊断函数 int result = diagnose(load, disp, current); // 写入Modbus寄存器 modbus_write_register(ctx, 40050, result);5.3 在线学习机制:让模型越用越准
井况是动态变化的。一口井投产三年后,结蜡程度、套管变形、泵效都会变化,导致特征分布偏移(Concept Drift)。我们的解决方案是轻量级在线学习:
- RTU每天凌晨2点,将当天所有功图特征(7维×1440个样本)打包,通过4G网络上传至中心服务器
- 服务器端用
incrementalLearner函数,用新数据微调随机森林模型(仅更新10棵树,而非重训全部200棵) - 更新后的模型参数(树结构、分割阈值)压缩为JSON,次日清晨推送到RTU
这个机制让模型在6个月后,对新投产井的诊断准确率仍保持在89.3%,而未启用在线学习的对照井,准确率已跌至72.1%。
最后分享一个细节:我们在RTU端加了一个“诊断健康度”指标。它计算最近100次诊断中,被第三层物理校验否决的次数占比。当健康度<85%时,自动触发模型更新流程。这个指标比单纯看准确率更早发现模型退化,是我们现场运维的“体温计”。