2. 方向盘转角传感器信号采集与预处理

任务说明

本案例针对SBW线控转向系统中方向盘转角传感器(SAS)的标定与数据预处理环节,完成以下闭环目标:

  • 建立传感器原始码值到物理转角(度)的线性映射模型,包含零点偏移与比例系数标定;
  • 实现针对原始信号的预处理流程:剔除跳变野值、滑动均值滤波、以及跨±180°边界的方向角连续性处理;
  • 提供可独立运行的Python实现,并给出验证方法。

标定模型与预处理算法

方向盘转角传感器输出为数字码值N,物理转角θ(单位:度)通过两点标定法确定线性关系:

θ = (N - Nzero) × (θref2 - θref1) / (Nref2 - Nref1)

其中Nzero为方向盘居中时的零点码值。预处理流程依次为:

  1. 野值剔除:相邻采样角度差超过设定阈值(如10°)时,判定为跳变野值,用前一有效值替代;
  2. 滑动均值滤波:窗口宽度为5的移动平均,抑制高频噪声;
  3. 角度连续性处理:将滤波后角度映射到(-180°, 180°]区间,并处理跨边界时的跳变(如179°→-179°应视为+2°变化而非-358°)。

代码实现

import numpy as np

class SteeringAngleSensor:
    """方向盘转角传感器标定与预处理"""
    
    def __init__(self, n_zero, n_ref1, theta_ref1, n_ref2, theta_ref2):
        """
        参数:
            n_zero: 零点码值
            n_ref1, theta_ref1: 标定点1 (码值, 角度°)
            n_ref2, theta_ref2: 标定点2 (码值, 角度°)
        """
        self.n_zero = n_zero
        # 线性比例系数: 度/码值
        self.scale = (theta_ref2 - theta_ref1) / (n_ref2 - n_ref1)
        self.offset = theta_ref1 - self.scale * (n_ref1 - n_zero)
        
    def raw_to_angle(self, raw_code):
        """原始码值转物理角度(未滤波)"""
        return self.scale * (raw_code - self.n_zero) + self.offset
    
    @staticmethod
    def remove_outliers(angles, threshold_deg=10.0):
        """剔除跳变野值: 相邻差超阈值则用前值替代"""
        clean = np.array(angles, dtype=float)
        for i in range(1, len(clean)):
            if abs(clean[i] - clean[i-1]) > threshold_deg:
                clean[i] = clean[i-1]
        return clean
    
    @staticmethod
    def moving_average(angles, window=5):
        """滑动均值滤波"""
        kernel = np.ones(window) / window
        # 使用'valid'模式保持长度一致(边缘用原值)
        filtered = np.convolve(angles, kernel, mode='same')
        # 修正边缘效应: 前window//2和后window//2个点用原值
        half = window // 2
        filtered[:half] = angles[:half]
        filtered[-half:] = angles[-half:]
        return filtered
    
    @staticmethod
    def unwrap_angle(angles):
        """角度连续性处理: 消除±180°边界跳变"""
        wrapped = np.array(angles, dtype=float)
        # 将角度映射到(-180, 180]
        wrapped = (wrapped + 180.0) % 360.0 - 180.0
        # 处理跨边界跳变: 相邻差大于180°时修正
        for i in range(1, len(wrapped)):
            delta = wrapped[i] - wrapped[i-1]
            if delta > 180.0:
                wrapped[i] -= 360.0
            elif delta < -180.0:
                wrapped[i] += 360.0
        return wrapped
    
    def process(self, raw_codes):
        """完整预处理流水线"""
        # 1. 码值转角度
        angles = np.array([self.raw_to_angle(c) for c in raw_codes])
        # 2. 野值剔除
        angles = self.remove_outliers(angles)
        # 3. 滑动均值滤波
        angles = self.moving_average(angles)
        # 4. 角度连续性处理
        angles = self.unwrap_angle(angles)
        return angles

# ===== 标定与验证示例 =====
if __name__ == "__main__":
    # 标定数据: 两点标定法
    # 点1: 码值1000对应-120°, 点2: 码值4000对应+120°
    sas = SteeringAngleSensor(
        n_zero=2500,          # 居中码值
        n_ref1=1000, theta_ref1=-120.0,
        n_ref2=4000, theta_ref2=120.0
    )
    
    # 模拟原始码值序列: 包含正常转动、野值跳变、跨±180°边界
    raw_sequence = [
        2500, 2520, 2540, 3000, 2580, 2600,   # 正常小幅度转动(含野值3000)
        2620, 2640, 2660, 2680, 2700, 2720,   # 持续右转
        2740, 2760, 2780, 2800, 2820, 2840,   # 接近+180°
        2860, 2880, 2900, 2920, 2940, 2960,   # 跨过+180°边界
        2980, 3000, 3020, 3040, 3060, 3080    # 继续转动(应显示为负角)
    ]
    
    # 执行预处理
    processed = sas.process(raw_sequence)
    
    # 打印前10个点的对比
    print("原始码值 → 预处理后角度(°)")
    for i in range(10):
        raw = raw_sequence[i]
        ang = processed[i]
        print(f"{raw:6d} → {ang:8.2f}")
    
    # 验证跨边界连续性
    print("\n跨边界检查(索引20-25):")
    for i in range(20, 25):
        print(f"  码值{raw_sequence[i]:5d} → 角度{processed[i]:8.2f}°")

落地与验证

运行方式:将代码保存为sas_calibration.py,在Python 3.6+环境执行python sas_calibration.py(需安装NumPy)。

验证方法与判定标准:

  • 标定正确性:输入码值1000时输出应接近-120°,码值4000时输出接近+120°,码值2500时输出接近0°;
  • 野值剔除:序列中第4个点码值3000(相对前后跳变约460码值≈27.6°)应被修正为接近前一值2520对应的角度;
  • 滤波效果:输出曲线应比原始转换角度更平滑,无阶跃突变;
  • 边界连续性:当码值从2900(约+168°)继续增大到2960时,输出角度应连续从约+168°过渡到约-168°(即跨边界后显示为负角),而非跳变到+192°。观察索引20-25的输出应呈现连续变化。

预期输出(部分):前3个点码值2500/2520/2540对应角度约为0.00°/1.44°/2.88°,第4个点(野值3000)输出仍接近2.88°而非27.6°,后续点按约1.44°步进连续变化;跨边界区域角度从约+168°连续过渡到-168°附近。

方向盘转角传感器标定与预处理流程 原始码值 N (数字量) 标定映射 θ = k·(N-N₀)+θ₀ 两点标定法 (N_ref1,θ_ref1)(N_ref2,θ_ref2) 野值剔除 相邻差 > 10° → 前值替代 滑动均值滤波 窗口 = 5 抑制高频噪声 角度连续性处理 映射到(-180°, 180°]区间 | 消除跨边界跳变(179°→-179°视为+2°变化) 预处理后角度 θ(°) 标定参数: N₀=2500, (1000,-120°), (4000,+120°) → k=0.08°/码值