1. 牵引试验原始数据通道映射与时间对齐
任务拆解:从多通道原始记录到统一时间基准数据集
城轨牵引性能试验中,采集系统通常同时记录牵引指令、牵引电机电流、牵引力(或力传感器电压)、车辆速度、网压、制动缸压力等通道。这些通道可能来自不同采集卡、不同总线周期,甚至不同起始触发时刻,直接拿来计算加速度或牵引特性会引入时间错位误差。本案例要完成两件事:通道语义映射(把采集系统里的通道编号/别名绑定到物理量与单位)和时间对齐(以牵引指令上升沿为 t=0,把各通道重采样到统一采样率),最后验证对齐后各通道首末时刻一致。
对齐基准约定:以牵引指令通道由 0 变为 1 的第一个采样点作为 t=0(单位 s)。所有通道时间戳统一换算为相对该时刻的秒值,正方向为试验进行方向。重采样采用线性插值,统一采样率取 100 Hz(周期 10 ms),该值应不小于原始各通道中最低采样率的 2 倍,否则需先降采样目标或改用保持插值。
通道映射配置表
映射配置是后续所有处理的唯一入口,必须显式记录原始通道名、物理量、单位、符号约定与量程,避免后续量纲混乱。下面是一份可直接套用的配置示例(示例参数,按实际采集系统替换):
| 原始通道名 | 物理量 | 单位 | 符号约定 | 量程 | 原始采样率 |
|---|---|---|---|---|---|
| AI0_TractCmd | 牵引指令 | —(0/1) | 1=牵引有效 | 0~1 | 50 Hz |
| AI1_MotorCurr | 牵引电机电流 | A | 牵引为正 | -1000~1000 | 200 Hz |
| AI2_TractForce | 牵引力 | kN | 牵引为正 | -200~200 | 100 Hz |
| CAN_VehSpeed | 车辆速度 | km/h | 前进为正 | 0~120 | 20 Hz |
| AI3_LineVolt | 网压 | V | — | 0~2000 | 100 Hz |
注意 CAN_VehSpeed 原始采样率仅 20 Hz,若目标统一为 100 Hz,插值会引入较大平滑误差,实际工程中应把统一采样率降到 20 Hz 或对该通道单独标注“低采样率通道,插值仅供参考”。本例为演示对齐流程,统一采样率取 20 Hz 更稳妥,下面代码按 20 Hz 实现。
对齐实现(Python,可直接运行)
下面代码用 pandas 完成映射、基准定位、重采样与首末时刻校验。示例数据由代码内构造,用于演示流程,不代表真实试验结果。
import numpy as np
import pandas as pd
# 1) 通道映射配置:原始通道名 -> (物理量, 单位, 符号)
channel_map = {
"AI0_TractCmd": ("牵引指令", "0/1", 1),
"AI1_MotorCurr": ("牵引电机电流", "A", 1),
"AI2_TractForce": ("牵引力", "kN", 1),
"CAN_VehSpeed": ("车辆速度", "km/h", 1),
"AI3_LineVolt": ("网压", "V", 1),
}
# 2) 构造示例原始数据:各通道起始时刻与采样率不同
rng = np.random.default_rng(0)
def make_channel(t0, fs, dur, base, noise):
n = int(dur * fs)
t = t0 + np.arange(n) / fs
v = base + noise * rng.standard_normal(n)
return pd.DataFrame({"t": t, "v": v})
raw = {
"AI0_TractCmd": make_channel(0.00, 50, 10, 0.0, 0.01),
"AI1_MotorCurr": make_channel(0.30, 200, 10, 120.0, 2.0),
"AI2_TractForce": make_channel(0.60, 100, 10, 45.0, 0.5),
"CAN_VehSpeed": make_channel(0.90, 20, 10, 8.0, 0.1),
"AI3_LineVolt": make_channel(0.45, 100, 10, 1500.0, 5.0),
}
# 让牵引指令在 t=2.0 s 处由 0 变 1
cmd = raw["AI0_TractCmd"]
cmd.loc[cmd["t"] >= 2.0, "v"] = 1.0
# 3) 定位基准时刻:牵引指令首个 v>=0.5 的采样点
cmd_sorted = cmd.sort_values("t")
t0 = cmd_sorted.loc[cmd_sorted["v"] >= 0.5, "t"].iloc[0]
print(f"基准时刻 t0 = {t0:.3f} s")
# 4) 统一采样率(取各通道最低采样率,避免过度插值)
fs_target = 20.0
t_end = min(df["t"].max() for df in raw.values()) - t0
t_grid = np.arange(0.0, t_end, 1.0 / fs_target)
# 5) 各通道重采样到统一时间网格
aligned = pd.DataFrame({"t": t_grid})
for name, df in raw.items():
df = df.sort_values("t").copy()
df["t_rel"] = df["t"] - t0
aligned[name] = np.interp(t_grid, df["t_rel"], df["v"])
# 6) 首末时刻一致性校验
print("对齐后各通道首末时刻:")
for name in raw:
print(f" {name}: 首={aligned['t'].iloc[0]:.3f}s, 末={aligned['t'].iloc[-1]:.3f}s")
assert aligned["t"].iloc[0] == 0.0
assert aligned["t"].iloc[-1] == t_grid[-1]
print("首末时刻一致性校验通过")
结果判读与常见问题
- 基准定位失败:若牵引指令通道全程为 0,说明触发未发生或通道映射错误,应先核对映射表再重跑。
- 末时刻不一致:各通道原始记录时长不同,取最短公共区间作为对齐终点,避免尾部插值外推产生虚假数据。
- 低采样率通道:CAN_VehSpeed 仅 20 Hz,若强行插值到 100 Hz 会掩盖真实波动,本例统一取 20 Hz 是更稳妥的选择。
- 符号约定:映射表中显式记录“牵引为正”,后续量纲统一与异常识别都依赖这一约定,不能省略。
对齐完成后建议立即输出一份对齐审计表:记录基准时刻、统一采样率、各通道原始首末时刻与对齐后首末时刻、插值方法。这份表是后续牵引力计算与异常识别的可追溯依据。