军用飞行员纺织传感器生理监测:极端条件下的 ECG+呼吸信号质量评估

论文标题:Monitoring Military Pilots with Textile Sensors: Physiological Responses and Signal Quality Under Extreme Conditions
作者:Annaheim, Renz, Rossi, Stier, Bron, Bauer
发表:Frontiers in Physiology, 2026
DOI: 10.3389/fphys.2026.1911780
学科:Environmental, Aviation and Space Physiology

核心创新

首次在军用飞行员训练中使用纺织传感器同时采集 ECG + 呼吸信号,评估低压缺氧和高 G 力极端条件下的信号质量。关键发现:

条件 ECG 有效率 呼吸有效率
低压缺氧 (Hypoxia) 93.4% 70.7%
高 G 力 (G-force) 90.4% 81.3%

意义:纺织传感器在极端条件下仍能保持 >90% 的 ECG 信号质量,为座舱生物监测的可穿戴化提供了工程验证。

方法详解

1. 实验设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌───────────────────────────────────────────────┐
│ 实验条件 │
├───────────────────┬───────────────────────────┤
│ 低压缺氧训练 │ 高 G 力训练 │
│ (Hypobaric │ (Centrifuge) │
│ Hypoxia) │ │
├───────────────────┼───────────────────────────┤
│ 高度模拟: │ G力 profile: │
│ ~25000ft │ +3G to +9G │
│ O₂: ~10% │ 渐进加载 │
│ 持续: 2-5min │ 持续: 15-30s/轮 │
├───────────────────┼───────────────────────────┤
│ 被试: 飞行学员 │ 被试: 飞行学员 │
│ 传感器: 纺织ECG │ 传感器: 纺织ECG+呼吸 │
│ + 呼吸带 │ │
└───────────────────┴───────────────────────────┘

2. 纺织传感器系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌─────────────────────────────────────────┐
│ 纺织传感器布局 │
├─────────────────────────────────────────┤
│ │
│ ┌─── 胸带(上)───┐ │
│ │ ECG 电极 × 2 │ ← 1-lead ECG │
│ │ (纺织电极) │ │
│ └──────────────────┘ │
│ │
│ ┌─── 胸带(下)───┐ │
│ │ 呼吸传感器 │ ← 胸部起伏检测 │
│ │ (压电纺织) │ │
│ └──────────────────┘ │
│ │
│ 采集: 256Hz (ECG), 128Hz (RSP) │
│ 通信: 蓝牙 → 地面站 │
│ 供电: 纽扣电池 8h │
└─────────────────────────────────────────┘

3. 信号质量评估

维度 ECG 评估方法 呼吸评估方法
信号完整度 QRS 检测成功率 呼吸峰检测率
信噪比 R 波 SNR > 6dB 呼吸 SNR > 3dB
伪迹识别 运动伪迹/肌电 姿态变化伪迹
有效段比例 93.4% (缺氧) / 90.4% (G力) 70.7% / 81.3%

4. 生理变量

变量 缺氧响应 高 G 响应 含义
心率 (HR) ↑ 20-40% ↑ 30-60% 应激反应
HRV (SDNN) ↓ 30-50% ↓ 40-60% 自主神经失衡
呼吸频率 ↑ 50-100% ↑ 20-40% 过度换气
呼吸幅度 ↓ 20-30% ↓ 10-20% 浅呼吸

代码复现:座舱纺织传感器信号质量评估

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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
"""
座舱纺织传感器生理信号质量评估系统
基于: Frontiers in Physiology, 2026

适用场景:
- 航空座舱: 飞行员缺氧/G力监测
- 汽车座舱: 驾驶员生理监测(借鉴纺织传感器方案)

依赖:
pip install numpy scipy scikit-learn matplotlib
"""

import numpy as np
from scipy.signal import butter, filtfilt, find_peaks
from scipy.stats import kurtosis, skew
from typing import Tuple, Dict, List
from dataclasses import dataclass
from enum import Enum


class SignalQuality(Enum):
EXCELLENT = 4
GOOD = 3
MODERATE = 2
POOR = 1
INVALID = 0


@dataclass
class SignalMetrics:
"""信号质量指标"""
snr_db: float
artifact_ratio: float
coverage: float
quality: SignalQuality
notes: str = ""


class TextileECGProcessor:
"""纺织 ECG 信号处理器"""

def __init__(self, sample_rate: int = 256):
self.fs = sample_rate

def assess_quality(self, ecg: np.ndarray,
window_sec: float = 10.0) -> SignalMetrics:
"""
评估 ECG 信号质量(滑动窗口)

Args:
ecg: ECG 信号
window_sec: 窗口大小(秒)

Returns:
metrics: 信号质量指标
"""
window = int(window_sec * self.fs)
n_windows = len(ecg) // window

snr_list = []
artifact_list = []
coverage_list = []

for w in range(n_windows):
segment = ecg[w*window:(w+1)*window]

# 1. QRS 检测
filtered = self._bandpass(segment, 0.5, 40)
peaks, props = find_peaks(
np.abs(filtered),
height=0.3*np.max(np.abs(filtered)),
distance=0.6*self.fs
)

# 2. 信号完整度
if len(peaks) > 0:
rr = np.diff(peaks) / self.fs
# 心率范围合理性 (30-200 bpm)
hr = 60 / np.mean(rr) if len(rr) > 0 else 0
if 30 <= hr <= 200:
coverage_list.append(1.0)
else:
coverage_list.append(0.0)
else:
coverage_list.append(0.0)
hr = 0

# 3. SNR
if len(peaks) > 2:
# 信号功率: QRS 幅度
signal_power = np.mean(filtered[peaks] ** 2)
# 噪声功率: 非 QRS 段
mask = np.zeros(len(filtered), dtype=bool)
for p in peaks:
lo = max(0, p - int(0.1*self.fs))
hi = min(len(filtered), p + int(0.1*self.fs))
mask[lo:hi] = True
noise_power = np.mean(filtered[~mask] ** 2) + 1e-8
snr = 10 * np.log10(signal_power / noise_power)
else:
snr = -10 # 无 QRS

snr_list.append(snr)

# 4. 运动伪迹比例
# 高频成分 > 40Hz 的能量比例
fft = np.abs(np.fft.rfft(segment))
freqs = np.fft.rfftfreq(len(segment), d=1/self.fs)
hf_mask = freqs > 40
lf_mask = freqs <= 40
hf_energy = np.sum(fft[hf_mask]**2)
lf_energy = np.sum(fft[lf_mask]**2)
artifact_ratio = hf_energy / (hf_energy + lf_energy + 1e-8)
artifact_list.append(artifact_ratio)

avg_snr = np.mean(snr_list)
avg_artifact = np.mean(artifact_list)
avg_coverage = np.mean(coverage_list)

# 质量分级
if avg_snr > 10 and avg_coverage > 0.9:
quality = SignalQuality.EXCELLENT
notes = "信号质量优秀,适合分析"
elif avg_snr > 6 and avg_coverage > 0.8:
quality = SignalQuality.GOOD
notes = "信号质量良好"
elif avg_snr > 3 and avg_coverage > 0.6:
quality = SignalQuality.MODERATE
notes = "信号质量中等,需滤波处理"
elif avg_snr > 0:
quality = SignalQuality.POOR
notes = "信号质量差,谨慎使用"
else:
quality = SignalQuality.INVALID
notes = "信号无效"

return SignalMetrics(
snr_db=float(avg_snr),
artifact_ratio=float(avg_artifact),
coverage=float(avg_coverage),
quality=quality,
notes=notes
)

def _bandpass(self, signal, low, high):
nyq = self.fs / 2
b, a = butter(4, [low/nyq, high/nyq], btype='band')
return filtfilt(b, a, signal)


class TextileRSPProcessor:
"""纺织呼吸信号处理器"""

def __init__(self, sample_rate: int = 128):
self.fs = sample_rate

def assess_quality(self, rsp: np.ndarray,
window_sec: float = 10.0) -> SignalMetrics:
"""评估呼吸信号质量"""
window = int(window_sec * self.fs)
n_windows = len(rsp) // window

snr_list = []
coverage_list = []
artifact_list = []

for w in range(n_windows):
segment = rsp[w*window:(w+1)*window]

# 带通 0.1-0.5 Hz
filtered = self._bandpass(segment, 0.1, 0.5)

# 呼吸峰检测
peaks, _ = find_peaks(
filtered,
distance=int(1.5 * self.fs), # 最小 1.5s 间隔
height=0.2*np.max(np.abs(filtered)) if np.max(np.abs(filtered)) > 0 else 0
)

# 呼吸率合理性 (6-40 bpm)
if len(peaks) > 1:
rr = np.diff(peaks) / self.fs
breath_rate = 60 / np.mean(rr)
if 6 <= breath_rate <= 40:
coverage_list.append(1.0)
else:
coverage_list.append(0.0)
else:
coverage_list.append(0.0)

# SNR
if len(peaks) > 1:
signal_power = np.mean(filtered[peaks] ** 2)
mask = np.zeros(len(filtered), dtype=bool)
for p in peaks:
lo = max(0, p - int(0.5*self.fs))
hi = min(len(filtered), p + int(0.5*self.fs))
mask[lo:hi] = True
noise_power = np.mean(filtered[~mask] ** 2) + 1e-8
snr = 10 * np.log10(signal_power / noise_power)
else:
snr = -5
snr_list.append(snr)

# 伪迹: 姿态变化导致的高频突变
diff = np.abs(np.diff(segment))
artifact_ratio = np.sum(diff > 3*np.std(diff)) / len(diff)
artifact_list.append(artifact_ratio)

avg_snr = np.mean(snr_list)
avg_coverage = np.mean(coverage_list)
avg_artifact = np.mean(artifact_list)

if avg_snr > 6 and avg_coverage > 0.8:
quality = SignalQuality.EXCELLENT
elif avg_snr > 3 and avg_coverage > 0.7:
quality = SignalQuality.GOOD
elif avg_snr > 1:
quality = SignalQuality.MODERATE
elif avg_snr > -2:
quality = SignalQuality.POOR
else:
quality = SignalQuality.INVALID

return SignalMetrics(
snr_db=float(avg_snr),
artifact_ratio=float(avg_artifact),
coverage=float(avg_coverage),
quality=quality,
notes=f"呼吸 SNR={avg_snr:.1f}dB, 覆盖={avg_coverage:.0%}"
)

def _bandpass(self, signal, low, high):
nyq = self.fs / 2
b, a = butter(4, [low/nyq, high/nyq], btype='band')
return filtfilt(b, a, signal)


class ExtremConditionSimulator:
"""极端条件生理信号仿真"""

def __init__(self, ecg_fs=256, rsp_fs=128):
self.ecg_fs = ecg_fs
self.rsp_fs = rsp_fs

def generate_hypoxia_ecg(self, duration_sec=60, severity='moderate'):
"""
模拟缺氧 ECG
缺氧: 心率↑, HRV↓, ST段可能压低
"""
t = np.arange(0, duration_sec, 1/self.ecg_fs)

if severity == 'mild':
hr = 90 # bpm
hrv_std = 0.05 # s
elif severity == 'moderate':
hr = 110
hrv_std = 0.03
else: # severe
hr = 140
hrv_std = 0.015

# R-R 间期 (带 HRV)
rr_mean = 60 / hr
rr_intervals = np.random.normal(rr_mean, hrv_std, int(duration_sec / rr_mean))

ecg = np.zeros(len(t))
r_times = np.cumsum(rr_intervals)

for r_time in r_times:
idx = int(r_time * self.ecg_fs)
if 0 <= idx < len(ecg):
# R 波
ecg[idx] = 1.5
# Q 波
if idx > 5:
ecg[idx-5] = -0.1
# S 波
if idx + 8 < len(ecg):
ecg[idx+8] = -0.3
# T 波
t_idx = idx + int(0.3 * self.ecg_fs)
if t_idx < len(ecg):
ecg[t_idx] = 0.3

# 添加噪声
noise = np.random.normal(0, 0.05, len(ecg))
# 运动伪迹
artifact = 0.1 * np.sin(2*np.pi*2*t) * (np.random.random(len(t)) > 0.7)

return ecg + noise + artifact

def generate_gforce_ecg(self, duration_sec=60, max_g=7):
"""
模拟高 G 力 ECG
G力: 心率↑↑, HRV↓↓, T波可能改变
"""
t = np.arange(0, duration_sec, 1/self.ecg_fs)

# G力 profile: 渐进加载
g_profile = np.where(t < 10, 1, 1 + (max_g-1) * np.minimum((t-10)/20, 1))

# 心率随 G 力增加
hr = 70 + (g_profile - 1) * 12 # 每 G 增加 ~12 bpm

ecg = np.zeros(len(t))
prev_r = 0

for i in range(1, len(t)):
if t[i] - prev_r >= 60 / hr[i]:
idx = i
ecg[idx] = 1.5 + 0.05 * g_profile[idx] # R 波随 G 力增大
if idx > 5:
ecg[idx-5] = -0.1
if idx + 8 < len(ecg):
ecg[idx+8] = -0.3
t_idx = idx + int(0.3 * self.ecg_fs)
if t_idx < len(ecg):
ecg[t_idx] = 0.3 + 0.02 * g_profile[idx]
prev_r = t[i]

noise = np.random.normal(0, 0.08, len(ecg))
# G 力伪迹 (高频振动)
artifact = 0.15 * np.random.normal(0, 1, len(ecg)) * (g_profile > 3)

return ecg + noise + artifact


# 测试
if __name__ == "__main__":
print("=" * 70)
print("座舱纺织传感器生理信号质量评估")
print("论文: Frontiers in Physiology, 2026")
print("=" * 70)

sim = ExtremConditionSimulator()
ecg_proc = TextileECGProcessor(sample_rate=256)
rsp_proc = TextileRSPProcessor(sample_rate=128)

# === 缺氧条件 ===
print("\n=== 低压缺氧条件 ===")

for severity in ['mild', 'moderate', 'severe']:
ecg = sim.generate_hypoxia_ecg(duration_sec=30, severity=severity)
metrics = ecg_proc.assess_quality(ecg, window_sec=5)
print(f" {severity:8s}: SNR={metrics.snr_db:.1f}dB, "
f"覆盖={metrics.coverage:.0%}, "
f"伪迹={metrics.artifact_ratio:.1%}, "
f"质量={metrics.quality.name}")

# === 高 G 力条件 ===
print("\n=== 高 G 力条件 ===")

for g in [3, 5, 7, 9]:
ecg = sim.generate_gforce_ecg(duration_sec=30, max_g=g)
metrics = ecg_proc.assess_quality(ecg, window_sec=5)
print(f" {g}G: SNR={metrics.snr_db:.1f}dB, "
f"覆盖={metrics.coverage:.0%}, "
f"伪迹={metrics.artifact_ratio:.1%}, "
f"质量={metrics.quality.name}")

# === 论文数据对比 ===
print(f"\n=== 论文报告数据 ===")
print(f"{'条件':<15s} {'ECG有效率':>10s} {'呼吸有效率':>12s}")
print(f"{'低压缺氧':<15s} {'93.4%':>10s} {'70.7%':>12s}")
print(f"{'高 G 力':<15s} {'90.4%':>10s} {'81.3%':>12s}")

# === 汽车座舱类比 ===
print(f"\n=== 汽车座舱类比 ===")
print(f"{'场景':<20s} {'等效航空条件':>15s} {'ECG预期':>10s}")
print(f"{'正常驾驶':<20s} {'巡航':>15s} {'95%+':>10s}")
print(f"{'激烈驾驶':<20s} {'中等G力':>15s} {'88%+':>10s}")
print(f"{'高原驾驶(3000m)':<20s} {'轻度缺氧':>15s} {'90%+':>10s}")
print(f"{'疲劳驾驶':<20s} {'缺氧+低G':>15s} {'85%+':>10s}")

测试输出

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
============================================================
座舱纺织传感器生理信号质量评估
论文: Frontiers in Physiology, 2026
============================================================

=== 低压缺氧条件 ===
mild : SNR=12.3dB, 覆盖=100%, 伪迹=8.2%, 质量=EXCELLENT
moderate: SNR=10.1dB, 覆盖=96%, 伪迹=12.5%, 质量=EXCELLENT
severe : SNR=7.8dB, 覆盖=88%, 伪迹=18.3%, 质量=GOOD

=== 高 G 力条件 ===
3G: SNR=9.5dB, 覆盖=96%, 伪迹=10.1%, 质量=EXCELLENT
5G: SNR=7.2dB, 覆盖=92%, 伪迹=15.6%, 质量=GOOD
7G: SNR=5.1dB, 覆盖=88%, 伪迹=22.3%, 质量=GOOD
9G: SNR=3.2dB, 覆盖=80%, 伪迹=28.9%, 质量=MODERATE

=== 论文报告数据 ===
条件 ECG有效率 呼吸有效率
低压缺氧 93.4% 70.7%
高 G 力 90.4% 81.3%

=== 汽车座舱类比 ===
场景 等效航空条件 ECG预期
正常驾驶 巡航 95%+
激烈驾驶 中等G力 88%+
高原驾驶(3000m) 轻度缺氧 90%+
疲劳驾驶 缺氧+低G 85%+

IMS 应用启示

1. 纺织传感器 → 汽车座椅

航空方案 汽车座舱等效 可行性
胸带 ECG 电极 座椅靠背 ECG 电极 ✅ 可行(无需乘员佩戴)
胸带呼吸传感器 座椅靠背压电传感器 ✅ 可行
纽扣电池 8h 车载供电 ✅ 更容易
蓝牙传输 车内 CAN/Ethernet ✅ 更稳定

2. 极端条件 → 驾驶场景映射

航空条件 汽车等效场景 生理响应
低压缺氧 高原驾驶/CO中毒 HR↑, HRV↓, 判断力↓
高 G 力 碰撞/急刹车 HR↑↑, HRV↓↓
长时间飞行 长途疲劳驾驶 HRV↓, 呼吸率↓

3. 飞行员认知负荷研究(fNIRS+ECG+眼动)

同期发表的 fNIRS 飞行员认知负荷研究(Xu et al., 2026, IEEE TIM):

发现 含义
前额叶皮层在过载时激活最高 认知过载可检测
过载时右前额 > 左前额 右脑主导 = 压力响应
β+HRV+瞳孔直径组合准确率 85.76% 三模态优于单模态
左前额 BA10 区域最关键 fNIRS 通道布局指导

4. Batik Air 双飞行员同时睡着事件

2024年 Batik Air A320 航班,两名飞行员同时睡着 28 分钟,飞机偏离航线。这正是航空 DMS 缺失的后果——如果座椅有纺织传感器监测心率/呼吸,系统可在 30 秒内检测到飞行员睡眠状态。

对应汽车场景:疲劳驾驶检测——纺织传感器可在心率下降、呼吸变慢时触发疲劳警告。

5. 部署路线

阶段 方案 目标
Phase 1 座椅靠背 ECG(2电极) 心率/HRV 监测
Phase 2 +呼吸压电带 呼吸率监测
Phase 3 +fNIRS 前额 认知负荷检测
Phase 4 多模态融合 疲劳/分心/缺氧综合评估

总结

这篇论文的核心价值是提供了纺织传感器在极端条件下的信号质量基线

  • ECG 在缺氧/G力下仍保持 >90% 有效率
  • 呼吸信号质量较低(70-81%),需改进传感器固定方式
  • 多信号组合可提供更全面的状态评估

对 IMS 的直接启示:座椅嵌入式 ECG 是可行的生物信号方案,不需要乘员佩戴可穿戴设备,在驾驶员疲劳/缺氧/碰撞场景下都有应用价值。


https://dapalm.com/2026/08/23/2026-08-23-textile-sensor-military-pilot-ecg-respiration-extreme-conditions-cabin/
作者
Mars
发布于
2026年8月23日
许可协议