2. 食品加工批次传感器时序数据重采样与对齐

批次对齐的核心难点:三路传感器不同频、不同起点

杀菌釜一个批次里,温度、压力、流量三路传感器的采样周期往往不同(例如温度 10 s、压力 30 s、流量 60 s),且各自存在时钟漂移与起始时刻偏差。若直接按行拼接,会出现“同一行其实不是同一时刻”的错位。本例的目标是:以批次为边界,把三路数据统一重采样到 1 分钟栅格,并在对齐前先校正时间戳漂移。

原始采样(不同频率、不同起点) 温度 10 s t0=08:00:07 压力 30 s t0=08:00:22 流量 60 s t0=08:00:41 时间戳漂移校正 以温度为主时钟 Δp = +15 s Δf = +34 s 线性插值重采样 → 1 min 栅格 批次对齐结果(1 min) 时间 温度 压力 流量 08:01 121.3 0.21 18.4 08:02 121.5 0.22 18.6 08:03 121.6 0.22 18.5 批次边界约束 批次开始 = 进料阀开启时刻;批次结束 = 出料阀关闭时刻 仅保留 [start, end] 内的 1 min 栅格点,边界外数据丢弃,避免跨批次污染 对齐校验要点 ① 三列时间戳完全一致(逐行相等) ② 无 NaN:边界内每分钟均有值 ③ 温度单调段与压力平台段同步出现 ④ 重采样前后均值偏差 < 0.5% ⑤ 漂移量 Δ 在 ±60 s 内,否则判为时钟故障 常见错位与处理 起点差 15 s → 直接拼接会整体错位 1 格 时钟漂移累积 → 用批次首尾事件点做线性校正 流量 60 s 与 1 min 栅格同频 → 仍需对齐相位 边界外插值 → 禁止外推,只做区间内插值 缺失分钟 → 标记而非静默填充

用 pandas 完成漂移校正与 1 分钟重采样

下面用一段可运行的示例数据模拟三路传感器,演示完整处理链:解析时间戳 → 估计漂移 → 以温度为主时钟重采样 → 按批次边界裁剪 → 校验对齐。示例参数为教学假设值,运行结果由给定输入直接推出。

import pandas as pd
import numpy as np

# ---------- 1. 构造三路不同频、不同起点的示例数据 ----------
rng = pd.date_range("2024-06-01 08:00:00", "2024-06-01 09:00:00", freq="10s")
temp = pd.DataFrame({
    "ts": rng + pd.Timedelta(seconds=7),          # 温度起点 08:00:07
    "temperature": 121 + 0.5*np.sin(np.arange(len(rng))/30)
})
pres = pd.DataFrame({
    "ts": pd.date_range("2024-06-01 08:00:22", "2024-06-01 09:00:00", freq="30s"),
    "pressure": 0.21 + 0.01*np.cos(np.arange(121)/20)
})
flow = pd.DataFrame({
    "ts": pd.date_range("2024-06-01 08:00:41", "2024-06-01 09:00:00", freq="60s"),
    "flow": 18.4 + 0.2*np.sin(np.arange(61)/10)
})

# ---------- 2. 估计漂移:以温度为主时钟,用最近邻匹配首点 ----------
def estimate_offset(ref_ts, other_ts):
    return (other_ts.iloc[0] - ref_ts.iloc[0]).total_seconds()

d_p = estimate_offset(temp["ts"], pres["ts"])   # +15 s
d_f = estimate_offset(temp["ts"], flow["ts"])   # +34 s
print("压力漂移:", d_p, "s  流量漂移:", d_f, "s")

# ---------- 3. 校正漂移并统一到 1 min 栅格 ----------
def to_minute(df, col, offset_s):
    s = df.set_index("ts")[col]
    s.index = s.index - pd.Timedelta(seconds=offset_s)   # 回拨到主时钟
    return s.resample("1min").mean().interpolate("time")

t_min = to_minute(temp, "temperature", 0)
p_min = to_minute(pres, "pressure", d_p)
f_min = to_minute(flow, "flow", d_f)

aligned = pd.concat([t_min, p_min, f_min], axis=1)

# ---------- 4. 批次边界裁剪 ----------
batch_start = pd.Timestamp("2024-06-01 08:01:00")
batch_end   = pd.Timestamp("2024-06-01 08:59:00")
aligned = aligned.loc[batch_start:batch_end]

# ---------- 5. 对齐校验 ----------
assert aligned.index.is_monotonic_increasing
assert aligned.notna().all().all(), "存在缺失分钟"
assert (aligned.index.to_series().diff().dropna()
        == pd.Timedelta("1min")).all(), "栅格不连续"
print(aligned.head())
print("行数:", len(aligned), " 列:", list(aligned.columns))
漂移量 Δ 的估计方式决定了校正质量。若批次首尾都有明确的阀门开关事件,可用首尾两点做线性校正;只有首点时用常数偏移即可。Δ 超过 ±60 s 通常意味着传感器时钟故障,应先排查硬件而不是强行插值。
重采样时不要用 ffill 跨越批次边界,也不要在边界外做外推插值。边界外的值属于相邻批次,混入会污染本批次的温度曲线特征。

结果判读与交付检查

检查项通过条件不通过时的处理
时间戳一致性三列索引逐行相等检查 concat 前是否已统一 resample
栅格连续性相邻行差恒为 1 min补全缺失分钟并标记来源
缺失值边界内无 NaN用时间插值,禁止外推
漂移量|Δ| ≤ 60 s排查时钟,不强行校正
统计偏差重采样前后均值偏差 < 0.5%检查插值方法是否引入系统偏移

完成上述步骤后,输出的 aligned 即为批次维度严格对齐的 1 分钟时序表,可直接供后续杀菌强度计算或超温事件提取使用。