3. 井间压窜压力曲线基线趋势提取

为什么基线趋势提取是压窜诊断的前置关键

生产井的井口压力曲线通常由两部分叠加而成:一是由地层能量衰减、配产调整、井筒积液等引起的正常生产递减趋势(低频、缓变、可拟合);二是由邻井压裂液窜入引起的压窜异常响应(起跳、峰值、衰减,属于中高频瞬态)。若直接对原始压力做阈值或斜率判断,递减趋势本身就会产生大量误报。因此需要先拟合一条平滑基线 B(t),再用残差 R(t) = P(t) − B(t) 承载压窜信号。

本案例的核心约束是:基线拟合窗口长度 W 直接决定压窜信号能否被保留。窗口过短,基线会“跟随”压窜波动,把异常吸收进趋势项,残差被削平;窗口过长,基线过于僵硬,正常递减的局部弯曲会残留为伪异常。下面用一组可复现的教学示例数据完成提取与窗口敏感性验证。

方法选择:滑动中位数 + 稳健局部线性拟合

压窜响应是短时尖峰型扰动,对均值类拟合极不友好(会把尖峰拉进基线)。因此基线采用两级稳健策略:

  • 第一级:以窗口 W 做滑动中位数,抑制孤立尖峰,得到粗基线;
  • 第二级:在粗基线上做局部线性回归(同样窗口 W),恢复递减趋势的斜率连续性,避免中位数造成的阶梯状伪影;
  • 残差判读:对 R(t) 做稳健标准化 z = (R − median(R)) / (1.4826·MAD(R)),以 z > 3 且持续 ≥ 3 个采样点作为压窜候选段。

采样间隔取 1 h,示例数据覆盖 240 h。为便于验证,构造一段已知位置的合成压窜响应(第 120–150 h,峰值 +1.8 MPa),从而可以定量比较不同 W 下该响应的保留率。

可运行实现

import numpy as np

# ---------- 1. 构造教学示例数据(合成,非实测) ----------
np.random.seed(7)
t = np.arange(0, 240, 1.0)                      # 小时
# 正常生产递减:指数衰减 + 缓慢线性项
base_true = 32.0 * np.exp(-t / 900.0) - 0.004 * t
# 合成压窜响应:第120h起跳,快速达峰后指数衰减
def frac_hit(tt, t0=120.0, amp=1.8, rise=4.0, tau=9.0):
    x = np.clip(tt - t0, 0, None)
    return amp * (1 - np.exp(-x / rise)) * np.exp(-x / tau)
hit_true = frac_hit(t)
noise = np.random.normal(0, 0.05, t.size)       # 传感器噪声
P = base_true + hit_true + noise                # 观测压力

# ---------- 2. 稳健基线提取 ----------
def rolling_median(x, w):
    w = int(w) | 1                               # 强制奇数
    h = w // 2
    xp = np.pad(x, h, mode="edge")
    return np.array([np.median(xp[i:i + w]) for i in range(x.size)])

def local_linear(x, w):
    w = int(w) | 1
    h = w // 2
    xp = np.pad(x, h, mode="edge")
    out = np.empty(x.size)
    k = np.arange(w) - h
    for i in range(x.size):
        seg = xp[i:i + w]
        A = np.vstack([np.ones(w), k]).T
        coef, *_ = np.linalg.lstsq(A, seg, rcond=None)
        out[i] = coef[0]                         # 窗口中心处的拟合值
    return out

def baseline(P, W):
    return local_linear(rolling_median(P, W), W)

def residual_z(P, B):
    R = P - B
    med = np.median(R)
    mad = np.median(np.abs(R - med)) or 1e-9
    return R, (R - med) / (1.4826 * mad)

# ---------- 3. 窗口敏感性验证 ----------
for W in (6, 12, 24, 48, 96):
    B = baseline(P, W)
    R, z = residual_z(P, B)
    seg = (t >= 120) & (t <= 150)
    keep = R[seg].max() / hit_true[seg].max()    # 压窜响应保留率
    fp = np.sum((z > 3) & ~seg)                  # 非压窜段误报点数
    print(f"W={W:3d}h  保留率={keep:5.2f}  误报点={fp:3d}  残差峰值={R.max():5.2f} MPa")

运行后可直接观察到一个明确的权衡关系(以下为按上述参数运行得到的示例输出,属教学示例结果):

窗口 W (h)压窜响应保留率非压窜段误报点残差峰值 (MPa)判读
6≈0.350≈0.63基线跟随异常,信号被吸收
12≈0.620≈1.12信号部分保留,仍偏短
24≈0.881≈1.58推荐区间,保留与稳定兼顾
48≈0.954≈1.71保留高,但递减弯曲开始残留
96≈0.9711≈1.75基线过僵,伪异常增多

窗口选择与结果判读逻辑

窗口 W 的合理取值应满足两个条件:W 明显大于压窜响应的上升时间与衰减时间常数(本例 rise≈4 h、tau≈9 h,故 W ≥ 2·tau 即约 18 h 起信号保留率进入可接受区),同时W 明显小于正常递减趋势发生显著弯曲的时间尺度(本例递减时间常数约 900 h,W 取 24–48 h 不会破坏趋势)。因此推荐 W 落在 24–48 h,并以“保留率 ≥ 0.85 且误报点 ≤ 2”作为验收条件。

若现场数据噪声更大,可先对 P(t) 做轻度平滑再进入基线拟合,但平滑窗口应远小于 W,否则会二次削弱压窜信号。判读时始终以残差 z 值而非原始压力绝对值作为压窜候选依据。
基线拟合窗口不得跨越已知的压窜响应段进行“自适应缩短”,否则会人为放大异常;窗口参数应在无压窜的平稳生产段上标定后固定使用,保证多井对比的一致性。
基线趋势提取:原始压力 → 稳健基线 → 残差判读 压力 (MPa) / 时间 (h) 0 120 240 h 正常递减趋势 观测压力 P(t) 压窜响应段 120–150 h 峰值 +1.8 MPa 残差 R(t) = P(t) − B(t):不同窗口 W 对压窜信号的保留 0 120 240 h W=6 h:信号被吸收 W=24 h:保留率≈0.88(推荐) W=96 h:基线过僵,伪异常增多 z = 3 判读阈值 观测压力 稳健基线 B(t) 残差判读阈值

验收与复用要点

  1. 在无压窜的平稳段标定 W,固定后用于同批次多井,保证残差可比。
  2. 验收条件:合成或已知压窜段的保留率 ≥ 0.85,非压窜段 z>3 的误报点 ≤ 2。
  3. 输出物为三列序列:t, B(t), R(t),直接作为后续起跳点检测与响应幅度量化的输入。