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
| import numpy as np import torch import torch.nn as nn from torch.utils.data import Dataset, DataLoader from typing import Tuple
class VirtualCO2Dataset(Dataset): """ 虚拟CO₂传感器数据集 论文: 445,017样本, 123小时真实驾驶 输入: CAN总线信号 输出: CO₂浓度 (ppm) """ CAN_FEATURES = [ 'vehicle_speed', 'acceleration', 'fan_speed_rpm', 'hvac_mode', 'target_temp_c', 'ambient_temp_c', 'engine_rpm', 'passenger_count', 'window_status', ] def __init__(self, can_data, co2_labels, physics_equilibrium, sequence_length=60): """ Args: can_data: CAN总线信号, shape=(N, 9) co2_labels: CO₂浓度标签, shape=(N,) physics_equilibrium: 物理模型输出, shape=(N,) sequence_length: 时序窗口(60秒@1Hz) """ self.can_data = torch.FloatTensor(can_data) self.co2_labels = torch.FloatTensor(co2_labels) self.physics_eq = torch.FloatTensor(physics_equilibrium) self.seq_len = sequence_length def __len__(self): return len(self.can_data) - self.seq_len def __getitem__(self, idx): x = self.can_data[idx:idx+self.seq_len] physics = self.physics_eq[idx:idx+self.seq_len] x_with_physics = torch.cat([x, physics.unsqueeze(-1)], dim=-1) y = self.co2_labels[idx+self.seq_len-1] return x_with_physics, y
class TCN_LSTM(nn.Module): """ Hybrid TCN-LSTM模型(论文最优架构) TCN: 时序卷积网络,提取局部模式 LSTM: 长短期记忆,捕获全局依赖 混合: TCN输出→LSTM→全连接 论文MAPE: 7.93%(含物理特征) 论文MAPE: 8.35%(纯数据驱动) """ class TemporalBlock(nn.Module): def __init__(self, in_ch, out_ch, kernel_size, stride, dilation, dropout=0.2): super().__init__() padding = (kernel_size - 1) * dilation self.conv = nn.Conv1d(in_ch, out_ch, kernel_size, stride=stride, padding=padding, dilation=dilation) self.chomp = padding self.dropout = nn.Dropout(dropout) self.net = nn.Sequential( self.conv, nn.ReLU(), self.dropout ) self.downsample = nn.Conv1d(in_ch, out_ch, 1) if in_ch != out_ch else None def forward(self, x): out = self.net(x) out = out[:, :, :-self.chomp].contiguous() res = x if self.downsample is None else self.downsample(x) return torch.relu(out + res) def __init__(self, input_dim=10, hidden_dim=64, n_layers=3, kernel_size=3, dropout=0.2): super().__init__() tcn_layers = [] for i in range(n_layers): dilation = 2 ** i in_ch = input_dim if i == 0 else hidden_dim tcn_layers.append(self.TemporalBlock( in_ch, hidden_dim, kernel_size, 1, dilation, dropout )) self.tcn = nn.Sequential(*tcn_layers) self.lstm = nn.LSTM( input_size=hidden_dim, hidden_size=hidden_dim, num_layers=2, batch_first=True, dropout=dropout ) self.fc = nn.Sequential( nn.Linear(hidden_dim, 32), nn.ReLU(), nn.Dropout(dropout), nn.Linear(32, 1) ) def forward(self, x): """ Args: x: CAN信号+物理特征, shape=(B, seq_len, input_dim) Returns: co2_pred: shape=(B, 1) 单位ppm """ x_t = x.transpose(1, 2) tcn_out = self.tcn(x_t) lstm_in = tcn_out.transpose(1, 2) lstm_out, _ = self.lstm(lstm_in) last_out = lstm_out[:, -1, :] co2_pred = self.fc(last_out) return co2_pred
class PhysicsCO2Model: """ 物理质量平衡模型 论文方法: 简化质量平衡 dC/dt = (C_out * Q_in + C_prev * Q_recirc - C * Q_out) / V + G * n 其中: - C: 车内CO₂浓度 - C_out: 外界CO₂浓度 (~400ppm) - Q_in/Q_out: 通风流量 - V: 车厢容积 - G: 每人CO₂产生率 (~0.005 L/s) - n: 乘员数量 """ def __init__(self): self.C_OUTDOOR = 400 self.CABIN_VOLUME_L = 3000 self.CO2_PROD_PER_PERSON = 0.005 self.AIR_FLOW_RATE = 50 def compute_equilibrium(self, hvac_mode, passenger_count, vehicle_speed): """ 计算物理平衡CO₂浓度 Args: hvac_mode: 0=外循环, 1=内循环 passenger_count: 乘员数 vehicle_speed: 车速 km/h Returns: equilibrium_co2: 平衡CO₂浓度 (ppm) """ q_in = self.AIR_FLOW_RATE + vehicle_speed * 0.5 if hvac_mode == 1: q_in *= 0.1 generation = self.CO2_PROD_PER_PERSON * passenger_count if q_in > 0: c_eq = self.C_OUTDOOR + generation * self.CABIN_VOLUME_L / q_in else: c_eq = self.C_OUTDOOR + 1000 return min(c_eq, 5000)
if __name__ == "__main__": print("=== 虚拟CO₂传感器测试 ===\n") physics = PhysicsCO2Model() scenarios = [ ("外循环+1人+60km/h", 0, 1, 60), ("内循环+2人+30km/h", 1, 2, 30), ("内循环+4人+0km/h(堵车)", 1, 4, 0), ("外循环+2人+100km/h", 0, 2, 100), ] print("物理模型平衡CO₂预测:") for name, mode, n, speed in scenarios: co2 = physics.compute_equilibrium(mode, n, speed) print(f" {name}: {co2:.0f} ppm {'⚠️' if co2 > 1000 else '✅'}") print(f"\n关键阈值: 1000 ppm") print(f" > 1000 ppm: 驾驶员警觉性下降") print(f" > 1500 ppm: 决策能力显著降低") print(f" > 2500 ppm: 相当于3杯啤酒的认知影响") print(f"\n=== 论文性能 ===") print(f" 纯数据驱动 TCN-LSTM: MAPE = 8.35%") print(f" 混合方案 TCN-LSTM+物理: MAPE = 7.93%") print(f" 物理模型单独: MAPE = 12-15%") print(f" 样本数: 445,017 (123小时)") print(f" 采样率: 1 Hz")
|