Fraunhofer SensAI:认知分心检测的数字孪生方案

多模态AI融合摄像头/音频/生命体征/车辆数据,构建驾驶员认知状态数字孪生

项目概览

属性 详情
项目名 SensAI
主导机构 Fraunhofer IOSB(协调方)
合作机构 Fraunhofer IDMT(音频)、其他合作方(生命体征)
阶段 开发阶段(传感器系统集成+数据处理准备中)
目标 实时、隐私合规的认知分心检测
官网 Fraunhofer IOSB SensAI

核心问题:为什么认知分心是DMS的终极挑战

认知分心 vs 视觉分心

类型 定义 检测难度 当前方案
视觉分心 视线离开道路 容易 眼动追踪,视线落点估计
认知分心 视线在道路上但注意力不在 极难 无成熟方案
身体分心 手离开方向盘 容易 姿态检测,手机检测
听觉分心 注意力被声音吸引 中等 音频场景分析

认知分心的核心挑战: 驾驶员眼睛看着道路,但大脑在处理其他事情(白日梦、内心对话、情绪波动)。传统DMS完全无法检测这种情况。

SensAI 的解决思路

SensAI 提出多模态数字孪生方案:不依赖单一信号,而是融合四种数据源构建驾驶员认知状态的数字孪生模型。

技术架构详解

1. 视觉模块(Fraunhofer IOSB 贡献)

IOSB 负责计算机视觉和驾驶员状态建模,从座舱摄像头中提取以下信号:

视觉信号 检测方法 认知分心相关性
凝视行为 眼睛关键点 + 视线回归 扫视减少、注视固定化
身体姿态 骨架关键点检测 微姿态僵化
活动/交互 动作识别 无关动作增加
物体交互 物体检测 + 关系推理 手机/中控屏交互

2. 音频模块(Fraunhofer IDMT 贡献)

音频信号 检测方法 认知分心相关性
声学场景 环境声音分类 识别对话/广播/电话
语音特征 语音情感/韵律分析 语速变化、停顿增加
呼吸模式 呼吸频率和深度 呼吸变浅/变快(压力)
注意力声学 头部相关传输函数 声源方向注意力

3. 生命体征模块

生理信号 检测方法 认知分心相关性
心率(HR) 接触式或rPPG 心率变异性降低与认知负荷相关
心率变异性(HRV) 时域/频域分析 HRV降低 → 认知负荷增加
皮肤电活动(EDA) 皮肤电导 EDA升高 → 情绪波动/压力
呼吸率 胸带/雷达 异常呼吸模式

4. 车辆数据模块

车辆信号 认知分心相关性
方向盘微操作 认知分心时微修正减少
踏板操作模式 加减速不平稳
车道保持精度 认知分心时车道偏移增加
前车距离 跟车距离变化增大

多模态融合模型

专用编码器架构

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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import torch
import torch.nn as nn
from typing import Dict

class ModalityEncoder(nn.Module):
"""单模态编码器基类"""

def __init__(self, input_dim: int, hidden_dim: int = 128):
super().__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU(),
nn.Linear(hidden_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU()
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.encoder(x)


class VisualEncoder(ModalityEncoder):
"""
视觉模态编码器

输入特征向量:
- gaze_xy: (2,) 视线方向
- gaze_confidence: (1,) 置信度
- head_pose: (6,) 头部姿态 (pitch, yaw, roll + 角速度)
- body_activity: (4,) 身体活动量 (4个身体部位)
- interaction_score: (3,) 物体交互评分 (手机/中控/方向盘)

总输入维度: 16
"""

def __init__(self, hidden_dim: int = 128):
super().__init__(input_dim=16, hidden_dim=hidden_dim)

# 时序建模
self.temporal = nn.LSTM(
input_size=hidden_dim,
hidden_size=hidden_dim,
num_layers=2,
batch_first=True,
bidirectional=False
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, T, 16) 时序视觉特征
Returns:
encoded: (B, hidden_dim) 模态级嵌入
"""
B, T, _ = x.shape
feat = self.encoder(x.reshape(B * T, -1))
feat = feat.reshape(B, T, -1)
_, (hn, _) = self.temporal(feat)
return hn[-1] # 最后一层最后时刻步


class AudioEncoder(ModalityEncoder):
"""
音频模态编码器

输入特征向量:
- scene_embedding: (8,) 声学场景嵌入
- speech_features: (6,) 语音韵律 (语速/停顿/音高/能量)
- breathing_rate: (2,) 呼吸频率和方差
- attention_score: (1,) 注意力声学评分

总输入维度: 17
"""

def __init__(self, hidden_dim: int = 128):
super().__init__(input_dim=17, hidden_dim=hidden_dim)
self.temporal = nn.LSTM(
input_size=hidden_dim, hidden_size=hidden_dim,
num_layers=1, batch_first=True
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
B, T, _ = x.shape
feat = self.encoder(x.reshape(B * T, -1)).reshape(B, T, -1)
_, (hn, _) = self.temporal(feat)
return hn[-1]


class VitalSignEncoder(ModalityEncoder):
"""
生命体征模态编码器

输入特征向量:
- heart_rate: (2,) 心率和变化率
- hrv_features: (5,) HRV时域频域特征
- eda_features: (3,) 皮肤电活动特征
- respiration: (2,) 呼吸率和方差

总输入维度: 12
"""

def __init__(self, hidden_dim: int = 128):
super().__init__(input_dim=12, hidden_dim=hidden_dim)
self.temporal = nn.LSTM(
input_size=hidden_dim, hidden_size=hidden_dim,
num_layers=1, batch_first=True
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
B, T, _ = x.shape
feat = self.encoder(x.reshape(B * T, -1)).reshape(B, T, -1)
_, (hn, _) = self.temporal(feat)
return hn[-1]


class VehicleDataEncoder(ModalityEncoder):
"""
车辆数据模态编码器

输入特征向量:
- steering_micro: (3,) 方向盘微操作 (角度/速度/加速度)
- pedal_pattern: (2,) 踏板操作平稳度
- lane_keeping: (2,) 车道偏移和方差
- headway: (2,) 前车距离和变化率

总输入维度: 9
"""

def __init__(self, hidden_dim: int = 128):
super().__init__(input_dim=9, hidden_dim=hidden_dim)
self.temporal = nn.LSTM(
input_size=hidden_dim, hidden_size=hidden_dim,
num_layers=1, batch_first=True
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
B, T, _ = x.shape
feat = self.encoder(x.reshape(B * T, -1)).reshape(B, T, -1)
_, (hn, _) = self.temporal(feat)
return hn[-1]


class SensAIFusionModel(nn.Module):
"""
SensAI 多模态融合模型

架构:
1. 四个专用编码器提取各模态嵌入
2. Cross-Attention 融合层实现跨模态交互
3. 认知状态解码器输出认知分心评估

输出:
- cognitive_state: (B, 3) [正常, 轻度分心, 严重分心] 概率
- contributing_factors: (B, 4) 各模态贡献度
"""

def __init__(self, hidden_dim: int = 128, num_heads: int = 4):
super().__init__()

# 模态编码器
self.visual_enc = VisualEncoder(hidden_dim)
self.audio_enc = AudioEncoder(hidden_dim)
self.vital_enc = VitalSignEncoder(hidden_dim)
self.vehicle_enc = VehicleDataEncoder(hidden_dim)

# Cross-Attention 融合
self.cross_attn = nn.MultiheadAttention(
embed_dim=hidden_dim,
num_heads=num_heads,
batch_first=True
)

# 模态权重学习
self.modality_weights = nn.Sequential(
nn.Linear(hidden_dim * 4, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 4),
nn.Softmax(dim=-1)
)

# 认知状态解码器
self.state_decoder = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU(),
nn.Linear(hidden_dim, 3), # 3类认知状态
nn.Softmax(dim=-1)
)

# 贡献因素解释器
self.factor_explainer = nn.Sequential(
nn.Linear(hidden_dim * 4, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 4),
nn.Sigmoid()
)

def forward(self, visual: torch.Tensor, audio: torch.Tensor,
vital: torch.Tensor, vehicle: torch.Tensor) -> dict:
"""
Args:
visual: (B, T, 16)
audio: (B, T, 17)
vital: (B, T, 12)
vehicle: (B, T, 9)

Returns:
dict with 'cognitive_state', 'contributing_factors'
"""
# 各模态编码
v_emb = self.visual_enc(visual) # (B, hidden_dim)
a_emb = self.audio_enc(audio) # (B, hidden_dim)
s_emb = self.vital_enc(vital) # (B, hidden_dim)
c_emb = self.vehicle_enc(vehicle) # (B, hidden_dim)

# 堆叠为序列
stacked = torch.stack([v_emb, a_emb, s_emb, c_emb], dim=1) # (B, 4, hidden)

# Cross-Attention
fused, _ = self.cross_attn(stacked, stacked, stacked)
fused_repr = fused.mean(dim=1) # (B, hidden_dim)

# 模态权重
concat_emb = torch.cat([v_emb, a_emb, s_emb, c_emb], dim=-1)
weights = self.modality_weights(concat_emb) # (B, 4)

# 加权融合
weighted_emb = (stacked * weights.unsqueeze(-1)).sum(dim=1)
final_repr = fused_repr + weighted_emb

# 解码
cognitive_state = self.state_decoder(final_repr)
contributing_factors = self.factor_explainer(concat_emb)

return {
'cognitive_state': cognitive_state,
'contributing_factors': contributing_factors,
'modality_weights': weights
}


# 测试
if __name__ == "__main__":
model = SensAIFusionModel(hidden_dim=64, num_heads=4)

B, T = 2, 30 # batch=2, 30帧序列

# 模拟输入
visual = torch.randn(B, T, 16)
audio = torch.randn(B, T, 17)
vital = torch.randn(B, T, 12)
vehicle = torch.randn(B, T, 9)

output = model(visual, audio, vital, vehicle)

print("=== SensAI 融合模型输出 ===")
print(f"认知状态: {output['cognitive_state'].shape}")
print(f" 正常概率: {output['cognitive_state'][0, 0]:.3f}")
print(f" 轻度分心: {output['cognitive_state'][0, 1]:.3f}")
print(f" 严重分心: {output['cognitive_state'][0, 2]:.3f}")
print(f"\n模态权重: {output['modality_weights'][0].tolist()}")
print(f" 视觉: {output['modality_weights'][0, 0]:.3f}")
print(f" 音频: {output['modality_weights'][0, 1]:.3f}")
print(f" 生命体征: {output['modality_weights'][0, 2]:.3f}")
print(f" 车辆: {output['modality_weights'][0, 3]:.3f}")

total_params = sum(p.numel() for p in model.parameters())
print(f"\n模型参数量: {total_params:,}")
print(f"模型大小: {total_params * 4 / 1024 / 1024:.1f} MB (FP32)")

上下文敏感的警告系统

SensAI 的核心创新是上下文敏感警告——不基于固定阈值,而是根据当前驾驶场景调整:

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
class ContextSensitiveWarning:
"""
SensAI 上下文敏感警告系统

与传统DMS的区别:
- 传统:PERCLOS > 30% → 警告(不看场景)
- SensAI:PERCLOS > 30% + 高速公路 + 直道 → 不警告
PERCLOS > 30% + 城市路口 + 行人 → 紧急警告

避免不必要或不当的警告
"""

SCENE_WEIGHTS = {
'highway_straight': 0.3, # 低风险场景
'highway_traffic': 0.6, # 中风险
'urban_intersection': 1.0, # 高风险
'urban_pedestrian': 1.2, # 最高风险
'parking_lot': 0.2, # 低风险
'night_rural': 0.5, # 中风险
}

def evaluate(self, cognitive_state: dict,
driving_scene: str,
vehicle_speed: float) -> dict:
"""
评估是否需要发出警告

Args:
cognitive_state: {'normal': float, 'mild': float, 'severe': float}
driving_scene: 场景类型
vehicle_speed: km/h

Returns:
{'should_warn': bool, 'level': str, 'reason': str}
"""
scene_weight = self.SCENE_WEIGHTS.get(driving_scene, 0.5)

# 速度调整因子
speed_factor = min(vehicle_speed / 60.0, 1.5)

# 综合风险评分
risk_score = (
cognitive_state.get('mild', 0) * 0.3 +
cognitive_state.get('severe', 0) * 1.0
) * scene_weight * speed_factor

if risk_score > 0.7:
return {'should_warn': True, 'level': 'urgent',
'reason': f'高风险场景({driving_scene})+认知分心',
'risk_score': risk_score}
elif risk_score > 0.4:
return {'should_warn': True, 'level': 'moderate',
'reason': f'中风险:{driving_scene}场景下的认知分心',
'risk_score': risk_score}
elif risk_score > 0.2:
return {'should_warn': True, 'level': 'mild',
'reason': '轻度认知分心提示',
'risk_score': risk_score}
else:
return {'should_warn': False, 'level': 'none',
'reason': '认知状态正常或场景风险低',
'risk_score': risk_score}


# 测试
if __name__ == "__main__":
warning_sys = ContextSensitiveWarning()

test_cases = [
# (认知状态, 驾驶场景, 车速)
({'normal': 0.7, 'mild': 0.2, 'severe': 0.1}, 'highway_straight', 90),
({'normal': 0.3, 'mild': 0.4, 'severe': 0.3}, 'urban_intersection', 30),
({'normal': 0.2, 'mild': 0.3, 'severe': 0.5}, 'urban_pedestrian', 20),
({'normal': 0.8, 'mild': 0.15, 'severe': 0.05}, 'parking_lot', 10),
]

for state, scene, speed in test_cases:
result = warning_sys.evaluate(state, scene, speed)
print(f"场景={scene}, 速度={speed}km/h → {result['level']} ({result['risk_score']:.2f})")

项目交付物

SensAI 计划交付三个关键成果:

交付物 描述 行业价值
集成演示器 安装在测试车辆中的完整系统 端到端验证
多模态验证数据集 含认知分心标注的多模态数据 行业首个认知分心基准数据集
经验性测量定义 认知分心的标准化测量方法 使DMS可系统开发/比较/测试

与现有认知分心研究对比

方案 模态 认知分心检测 实时性 量产可行性
SensAI 视觉+音频+生命体征+车辆 ✅ 多模态融合 ✅ 实时 中(需多传感器)
传统DMS 仅视觉 ❌ 仅视觉分心 ✅ ✅ 高
EEG头环 仅EEG ✅ 直接但不可行 ❌ ❌ 极低
车辆数据 仅CAN总线 ⚠️ 间接 ✅ ✅ 高
arXiv 2610.02971 EEG+生理+行为 ✅ 研究级 ❌ ❌ 研究阶段

arXiv 2610.02971 关联分析

SensAI 的思路与 arXiv 2610.02971(Tracking Human Daily Cognitive Activity from EEG and Biometric Data)高度互补:

对比维度 SensAI arXiv 2610.02971
应用场景 驾驶座舱 日常活动
EEG 不使用(座舱不可行) 核心模态
可穿戴要求 不需要 需要EEG头环
实时性 实时 离线分析
认知活动类型 认知分心 9类日常活动
关键发现 待验证 动机与唤醒(r=0.78)/注意(r=0.74)强相关

arXiv 论文的关键发现可指导 SensAI 的特征设计:

  • 动机与唤醒(τ=0.78)和注意力(τ=0.74)强相关
  • 压力与动机弱负相关(τ=-0.33)
  • 前期能量水平正向预测后续动机(时间依赖性)
  • 线性回归 R²=0.76 预测动机

IMS 开发启示

1. 认知分心检测技术路线

阶段 目标 核心技术 周期
Phase 1 视觉认知分心 眼动熵 + 注视模式 + 反应延迟 6个月
Phase 2 视觉+车辆融合 视觉特征 + 方向盘微操作 + 车道偏移 4个月
Phase 3 视觉+音频融合 + 语音韵律 + 呼吸模式 6个月
Phase 4 全模态融合 + rPPG心率 + 完整数字孪生 12个月

2. 可落地的子方案

Phase 1(纯视觉+车辆数据)是最现实的第一步:

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
class PracticalCognitiveDistractionDetector:
"""
面向量产的认知分心检测方案(Phase 1-2)

仅使用现有DMS摄像头 + CAN总线数据
无需额外传感器

核心特征:
1. 眼动熵(gaze entropy)— 认知分心时降低
2. 扫视频率(saccade rate)— 认知分心时降低
3. 方向盘微操作频率 — 认知分心时降低
4. 车道保持标准差 — 认知分心时增加
5. 反应延迟代理 — 眼动变化率
"""

def __init__(self, fps: int = 30):
self.fps = fps
self.window = 30 * fps # 30秒窗口
self.baselines = {
'gaze_entropy': 2.5,
'saccade_rate': 3.0,
'steer_micro_rate': 0.5, # Hz
'lane_dev_std': 0.15, # m
}

def detect(self, gaze_sequence: np.ndarray,
steering_data: np.ndarray,
lane_data: np.ndarray) -> dict:
"""
从现有DMS和CAN数据检测认知分心

Args:
gaze_sequence: (N, 2) 视线序列
steering_data: (N,) 方向盘角度序列
lane_data: (N,) 车道偏移序列

Returns:
{'cognitive_distraction': float, 'confidence': float, 'indicators': dict}
"""
indicators = {}

# 1. 眼动熵
hist, _, _ = np.histogram2d(
gaze_sequence[:, 0], gaze_sequence[:, 1], bins=5
)
hist_norm = hist / (hist.sum() + 1e-8)
indicators['gaze_entropy'] = -np.sum(
hist_norm * np.log(hist_norm + 1e-8)
)

# 2. 扫视频率
gaze_diff = np.diff(gaze_sequence, axis=0)
gaze_speed = np.linalg.norm(gaze_diff, axis=1)
indicators['saccade_rate'] = np.sum(
gaze_speed > 0.15
) / (len(gaze_sequence) / self.fps)

# 3. 方向盘微操作
steer_diff = np.diff(steering_data)
micro_corrections = np.sum(np.abs(steer_diff) < 0.5)
indicators['steer_micro_rate'] = micro_corrections / (
len(steering_data) / self.fps
)

# 4. 车道保持
indicators['lane_dev_std'] = np.std(lane_data)

# 综合评分
deviations = {}
for key, val in indicators.items():
baseline = self.baselines.get(key, 1.0)
deviations[key] = abs(val - baseline) / baseline

score = np.mean(list(deviations.values()))

return {
'cognitive_distraction': float(min(score, 1.0)),
'confidence': float(min(score * 1.5, 0.95)),
'indicators': indicators,
'deviations': deviations
}


# 测试
if __name__ == "__main__":
detector = PracticalCognitiveDistractionDetector(fps=30)

N = 900 # 30秒数据

# 模拟正常驾驶
normal_gaze = np.column_stack([
np.random.uniform(-0.4, 0.4, N),
np.random.uniform(-0.2, 0.2, N)
])
normal_steer = np.cumsum(np.random.normal(0, 0.3, N))
normal_lane = np.random.normal(0, 0.1, N)

# 模拟认知分心(眼动范围收窄、方向盘微操作减少)
distracted_gaze = np.column_stack([
np.random.uniform(-0.1, 0.1, N),
np.random.uniform(-0.05, 0.05, N)
])
distracted_steer = np.cumsum(np.random.normal(0, 0.5, N)) # 大幅修正多,微修正少
distracted_lane = np.random.normal(0, 0.3, N) # 车道偏移增大

normal_result = detector.detect(normal_gaze, normal_steer, normal_lane)
distracted_result = detector.detect(distracted_gaze, distracted_steer, distracted_lane)

print("=== 正常驾驶 ===")
print(f"认知分心评分: {normal_result['cognitive_distraction']:.3f}")
print(f"眼动熵: {normal_result['indicators']['gaze_entropy']:.3f}")
print(f"扫视频率: {normal_result['indicators']['saccade_rate']:.2f}/s")

print("\n=== 认知分心 ===")
print(f"认知分心评分: {distracted_result['cognitive_distraction']:.3f}")
print(f"眼动熵: {distracted_result['indicators']['gaze_entropy']:.3f}")
print(f"扫视频率: {distracted_result['indicators']['saccade_rate']:.2f}/s")

3. SensAI 数据集对行业的价值

SensAI 计划发布的多模态验证数据集将是行业首个认知分心基准数据集。对 IMS 团队的价值:

数据集内容 IMS 应用
认知分心标注的多模态数据 训练和验证IMS认知分心模型
标准化测量定义 建立IMS内部认知分心评估标准
测试场景设计 指导IMS测试用例开发
传感器配置方案 参考IMS传感器选型

参考资源


总结: Fraunhofer SensAI 是认知分心检测领域最有前途的系统级方案。其核心创新在于:(1) 多模态数字孪生替代单信号检测;(2) 上下文敏感警告替代固定阈值;(3) 行业首个认知分心基准数据集。对 IMS 团队而言,Phase 1 纯视觉+车辆数据方案是最现实的落地路径,可在6个月内实现原型验证。