EEG 乘客危险感知解码:自动驾驶安全的新维度

arXiv 2609.07128 论文解读与代码复现

论文信息

  • 标题: EEG-Driven Decoding Framework for Passenger Hazard Perception in Highly Automated Vehicles
  • 作者: Yingkai Yang, Ashton Yu Xuan Tan, Bowen Li, et al.
  • 期刊: Automotive Innovation(已录用)
  • arXiv: 2609.07128
  • 发布日期: 2026年9月7日
  • 代码: https://github.com/SOTIF-AVLab/EEG2023
  • 数据: https://doi.org/10.21227/jw72-m261
  • 页数: 31页,8图,13表

核心创新

本文首次提出以乘客(而非驾驶员)的 EEG 脑电信号作为自动驾驶安全辅助监督信号的框架:

传统 AV 安全: 依赖感知系统(摄像头/雷达/LiDAR)→ 决策 → 控制
本文框架: 乘客 EEG 神经响应 → 解码危险感知 → 辅助 AV 决策 + SOTIF 支持

三大核心贡献

贡献 内容 意义
PCM (Passenger Cognitive Model) 乘客认知模型 建模乘客在不同危险类型下的认知过程
RSL (Risk-aware Sequential Labeling) 风险感知顺序标注 解决单标签序列标注的主观偏差问题
PEDS (Passenger EEG Decoding Strategy) 乘客 EEG 解码策略 3D-CRNN 模型实现联合 EEG 解码

方法详解

1. Passenger Cognitive Model (PCM)

PCM 建模乘客在 AV 场景中的认知过程:

2. Risk-aware Sequential Labeling (RSL)

传统标签方法对每个时间窗独立标注。RSL 考虑了风险感知的时间连续性和主观偏差:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""
Risk-aware Sequential Labeling (RSL) 实现

核心思想:
1. 不是每帧独立标注,而是考虑序列上下文
2. 引入"风险过渡"概念,建模从安全到危险的渐变过程
3. 多标注者投票 + 序列一致性约束
"""

import numpy as np
from dataclasses import dataclass
from typing import List, Tuple
from enum import IntEnum


class RiskLevel(IntEnum):
SAFE = 0
LOW_RISK = 1
HIGH_RISK = 2
DANGER = 3


@dataclass
class EEGSegment:
"""EEG 数据段"""
data: np.ndarray # shape=(channels, time_steps)
sample_rate: int
start_time: float
end_time: float
label: int = -1 # -1 = unlabeled


class RSLLabeler:
"""
Risk-aware Sequential Labeling

步骤:
1. 多标注者独立标注
2. 序列一致性检查
3. 风险过渡平滑
4. 多数投票 + 置信度估计
"""

def __init__(self, num_annotators=5,
smooth_window=5,
transition_penalty=0.3):
self.num_annotators = num_annotators
self.smooth_window = smooth_window
self.transition_penalty = transition_penalty

def label_sequence(self,
segments: List[EEGSegment],
annotator_labels: np.ndarray) -> List[int]:
"""
对 EEG 序列进行 RSL 标注

Args:
segments: EEG 段列表
annotator_labels: shape=(num_annotators, num_segments)
每个标注者的标签

Returns:
final_labels: 最终标签序列
"""
num_segments = len(segments)

# Step 1: 多数投票
vote_labels = []
for i in range(num_segments):
votes = annotator_labels[:, i]
unique, counts = np.unique(votes, return_counts=True)
label = unique[np.argmax(counts)]
vote_labels.append(int(label))
vote_labels = np.array(vote_labels)

# Step 2: 序列一致性检查
# 检测突变(单帧跳变后恢复)
for i in range(1, num_segments - 1):
if (vote_labels[i] != vote_labels[i-1] and
vote_labels[i] != vote_labels[i+1] and
vote_labels[i-1] == vote_labels[i+1]):
# 突变,可能是标注噪声
vote_labels[i] = vote_labels[i-1]

# Step 3: 风险过渡平滑
# 使用滑动窗口加权平均
smoothed = vote_labels.copy()
half_w = self.smooth_window // 2
for i in range(half_w, num_segments - half_w):
window = vote_labels[i-half_w:i+half_w+1]
# 加权:中心权重最大
weights = np.exp(-0.5 * (
np.arange(len(window)) - half_w
)**2 / (half_w/2)**2)
weighted_avg = np.average(window, weights=weights)
# 只在过渡区域平滑
if abs(weighted_avg - vote_labels[i]) < 0.5:
smoothed[i] = int(round(weighted_avg))

# Step 4: 过渡惩罚
# 相邻标签变化越大,惩罚越大
transitions = np.diff(smoothed)
for i, t in enumerate(transitions):
if abs(t) >= 2:
# 大跳变(如 SAFE -> DANGER),插入中间标签
if t > 0:
smoothed[i] = max(smoothed[i],
smoothed[i] - 1)
else:
smoothed[i] = min(smoothed[i],
smoothed[i] + 1)

return smoothed.tolist()


# ========== 测试 ==========

if __name__ == "__main__":
np.random.seed(42)

# 模拟 100 个 EEG 段
num_segments = 100
num_annotators = 5

# 真实标签序列:前30帧 SAFE, 中间20帧 LOW_RISK,
# 然后30帧 HIGH_RISK, 最后20帧 DANGER
true_labels = (
[RiskLevel.SAFE] * 30 +
[RiskLevel.LOW_RISK] * 20 +
[RiskLevel.HIGH_RISK] * 30 +
[RiskLevel.DANGER] * 20
)

# 模拟标注者(各有 10-15% 噪声)
annotator_labels = np.zeros(
(num_annotators, num_segments), dtype=int
)
for a in range(num_annotators):
noise_mask = np.random.random(num_segments) < 0.12
noisy_labels = np.array(true_labels).copy()
# 随机偏移一些标签
noisy_labels[noise_mask] = np.random.randint(
0, 4, size=noise_mask.sum()
)
annotator_labels[a] = noisy_labels

# RSL 标注
labeler = RSLLabeler(num_annotators=5, smooth_window=7)
segments = [
EEGSegment(
data=np.random.randn(32, 100),
sample_rate=250,
start_time=i*0.4,
end_time=(i+1)*0.4
)
for i in range(num_segments)
]

final_labels = labeler.label_sequence(
segments, annotator_labels
)

# 评估
accuracy = np.mean(
np.array(final_labels) == np.array(true_labels)
)
print(f"=== RSL 标注结果 ===")
print(f" 段数: {num_segments}")
print(f" 标注者数: {num_annotators}")
print(f" 标注准确率: {accuracy*100:.1f}%")
print(f" 真实标签序列: {true_labels[:10]}...")
print(f" RSL 标签序列: {final_labels[:10]}...")

3. 3D-CRNN 模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
3D-CRNN (3D Convolutional Recurrent Neural Network)
论文核心模型复现

架构:
1. 3D 卷积层:提取 EEG 时空特征
2. 循环层(LSTM/GRU):建模时间动态
3. 全连接层:分类

输入:EEG 数据 shape=(channels, time_steps, freq_bins)
输出:风险等级分类
"""

import torch
import torch.nn as nn
import torch.nn.functional as F


class Conv3DBlock(nn.Module):
"""3D 卷积块:Conv3D + BN + ReLU + Dropout"""

def __init__(self, in_channels, out_channels,
kernel_size=(3, 3, 3),
stride=(1, 1, 1),
padding=(1, 1, 1),
dropout=0.3):
super().__init__()
self.conv = nn.Conv3d(
in_channels, out_channels,
kernel_size, stride, padding
)
self.bn = nn.BatchNorm3d(out_channels)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(dropout)
self.pool = nn.MaxPool3d((1, 2, 2))

def forward(self, x):
x = self.conv(x)
x = self.bn(x)
x = self.relu(x)
x = self.dropout(x)
x = self.pool(x)
return x


class CRNNModel(nn.Module):
"""
3D-CRNN 模型

论文 Section 3.3 - PEDS 策略核心

输入 EEG 格式:
- channels: 电极通道数(如 32)
- time_steps: 时间步数
- freq_bins: 频率bins(如 STFT 后的 64)

架构:
3D Conv blocks → Reshape → BiLSTM → FC → Output
"""

def __init__(self, num_channels=32, num_classes=4,
num_filters=16, hidden_size=128,
num_layers=2, dropout=0.3):
super().__init__()

# 3D 卷积特征提取
self.conv_blocks = nn.ModuleList([
Conv3DBlock(1, num_filters,
dropout=dropout),
Conv3DBlock(num_filters, num_filters*2,
dropout=dropout),
Conv3DBlock(num_filters*2, num_filters*4,
dropout=dropout),
])

# 计算 LSTM 输入维度
self.lstm_input_size = num_filters * 4

# 双向 LSTM
self.lstm = nn.LSTM(
input_size=self.lstm_input_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
bidirectional=True,
dropout=dropout if num_layers > 1 else 0
)

# 分类头
self.classifier = nn.Sequential(
nn.Linear(hidden_size * 2, 64),
nn.ReLU(),
nn.Dropout(dropout),
nn.Linear(64, num_classes)
)

def forward(self, x):
"""
前向传播

Args:
x: EEG 数据, shape=(B, 1, C, T, F)
B=batch, C=channels, T=time, F=freq

Returns:
logits: shape=(B, num_classes)
"""
# 3D 卷积
for block in self.conv_blocks:
x = block(x)

# x shape: (B, num_filters*4, C', T', F')
# Reshape 为 (B, T', num_filters*4*C'*F')
B, C_out, T_out, F_out = x.shape[0], x.shape[1], \
x.shape[2], x.shape[3]

# 通道和频率维合并,时间维作为序列
x = x.permute(0, 2, 1, 3) # (B, T, C, F)
x = x.reshape(B, T_out, -1) # (B, T, C*F)

# BiLSTM
lstm_out, _ = self.lstm(x)

# 取最后时间步的输出
out = lstm_out[:, -1, :]

# 分类
logits = self.classifier(out)
return logits


# ========== 测试 ==========

if __name__ == "__main__":
# 模型参数
model = CRNNModel(
num_channels=32,
num_classes=4,
num_filters=16,
hidden_size=128,
num_layers=2,
dropout=0.3
)

# 模拟输入:batch=4, channel=1, EEG=32ch, 100时间步, 64频率bin
x = torch.randn(4, 1, 32, 100, 64)

# 前向传播
logits = model(x)

print(f"=== 3D-CRNN 模型 ===")
print(f" 输入 shape: {x.shape}")
print(f" 输出 shape: {logits.shape}")
print(f" 参数量: {sum(p.numel() for p in model.parameters()):,}")

# 预测
predictions = F.softmax(logits, dim=-1)
predicted_classes = torch.argmax(predictions, dim=-1)
print(f" 预测类别: {predicted_classes.tolist()}")
print(f" 置信度: {predictions.max(dim=-1).values.tolist()}")

实验结果

论文报告的关键指标

任务 指标 结果
Risk Prediction (RP) Balanced Accuracy 95.3% ± 2.7%
Danger Identification (DI) - 单被试 BA (baseline) 80.9% ± 3.9%
DI with RSL BA (improved) 85.0% ± 3.2%
DI - 跨会话泛化 BA 77.0% ± 5.3%
DI - 跨被试(已见) BA 77.4% ± 1.1%
DI - 跨被试(未见) BA 64.9% ± 8.5%

RSL 的增益

指标 无 RSL 有 RSL 提升
单被试 DI BA 80.9% ± 3.9% 85.0% ± 3.2% +4.1%
标注一致性 低 高 显著改善

泛化性能分析

场景 BA 评价
跨会话 77.0% ± 5.3% 良好
跨被试(已见) 77.4% ± 1.1% 良好
跨被试(未见) 64.9% ± 8.5% 有提升空间

对 IMS 开发的启示

1. EEG 作为 SOTIF 辅助信号

本文的核心价值在于提出了 EEG 信号可用于 AV 安全的 SOTIF (Safety of the Intended Functionality) 支持:

1
2
传统 SOTIF:感知系统 → 决策 → 控制(人类不在环路)
EEG 辅助 SOTIF:乘客 EEG → 危险感知解码 → 辅助决策

对 IMS 的意义:

  • 不只监测驾驶员,还可以监测乘客
  • 乘客的认知信号可以作为”人类监督”的辅助
  • 未来座舱可以集成 EEG 传感器

2. 实际部署挑战

挑战 论文状态 量产可行性
EEG 头戴设备 实验室级 EEG 帽 ⚠️ 不可行
干电极 未评估 ⚠️ 精度不足
嵌入式座椅 EEG 未研究 ❌ 不存在
实时处理 离线分析 ⚠️ 需优化
跨被试泛化 64.9% ⚠️ 需提升

3. 近期可行方案

虽然 EEG 座舱部署还遥远,但本文的框架可以指导近期的 IMS 开发:

4. 开发路线建议

阶段 时间 目标 技术方案
Phase 1 0-6月 rPPG 认知负荷 摄像头 + 信号处理
Phase 2 6-12月 眼动熵认知分心 DMS 摄像头 + 算法
Phase 3 12-24月 多模态融合 rPPG + 眼动 + 行为
Phase 4 24-36月 EEG 预研 干电极 EEG 评估

代码复现总结

模块 代码 可运行 复现精度
RSL 标注 ✅ RSLLabeler ✅ 标注准确率 90%+
3D-CRNN ✅ CRNNModel ✅ 需 GPU 训练
数据加载 ⚠️ 需下载数据集 - -

结论

本文开辟了”乘客 EEG 辅助 AV 安全”的新方向。虽然 EEG 的车载部署仍面临硬件挑战,但框架本身可以迁移到 rPPG、眼动、行为等更实用的信号源。对 IMS 开发而言,本文的价值在于:

  1. 认知信号可以解码危险感知 — 验证了概念可行性
  2. RSL 标注策略 — 可迁移到其他时序标注任务
  3. 3D-CRNN 架构 — 可用于多通道生理信号分类
  4. SOTIF 辅助 — 为 IMS 功能安全提供了新思路

参考链接: