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
| """ Aumovio/trinamiX 触指红外 BAC 检测原理复现
核心技术:近红外光谱(NIR)分析间质液酒精浓度 - 酒精分子在近红外波段有特征吸收峰 - 通过多波长照射手指,分析透射/反射光谱 - 机器学习模型反推 BAC 值
参考:trinamiX NIR spectroscopy + BASF 化学分析能力 """
import numpy as np from sklearn.ensemble import GradientBoostingRegressor from sklearn.model_selection import cross_val_score from typing import Tuple
ALCOHOL_NIR_PEAKS = { "OH_stretch_1st_overtone": 1450, "OH_stretch_2nd_overtone": 1730, "CH_stretch_combination": 2300, "OH_bend_combination": 2350, }
NIR_WAVELENGTHS = np.array([ 1300, 1450, 1550, 1650, 1730, 1950, 2100, 2300, 2350, 2500 ])
def simulate_finger_nir_signal( bac_level: float, skin_thickness: float = 2.0, temperature: float = 32.0, moisture: float = 0.35 ) -> np.ndarray: """ 模拟手指 NIR 光谱信号 Args: bac_level: 血液酒精浓度 (g/dL), 0.0-0.3 skin_thickness: 皮肤厚度 (mm), 1.5-3.0 temperature: 手指表面温度 (°C), 25-37 moisture: 皮肤水分含量 (0-1) Returns: absorbance: 各波长吸光度, shape=(10,) 物理模型: - Beer-Lambert 定律: A = ε*c*l - 酒精在间质液浓度 ≈ BAC * 0.85(渗透系数) - 皮肤基底吸光度 + 酒精特征吸收 + 噪声 """ interstitial_alcohol = bac_level * 0.85 molar_absorptivity = np.zeros(len(NIR_WAVELENGTHS)) for i, wl in enumerate(NIR_WAVELENGTHS): if wl == 1450: molar_absorptivity[i] = 0.85 elif wl == 1730: molar_absorptivity[i] = 0.65 elif wl == 2300: molar_absorptivity[i] = 0.45 elif wl == 2350: molar_absorceptivity[i] = 0.40 else: molar_absorptivity[i] = 0.05 + np.random.normal(0, 0.02) baseline = (0.3 + 0.1 * moisture + 0.05 * skin_thickness) * np.ones(len(NIR_WAVELENGTHS)) temp_correction = 0.001 * (temperature - 32.0) * np.ones(len(NIR_WAVELENGTHS)) alcohol_absorption = molar_absorptivity * interstitial_alcohol * skin_thickness absorbance = baseline + alcohol_absorption + temp_correction absorbance += np.random.normal(0, 0.01, len(NIR_WAVELENGTHS)) return absorbance
def build_bac_prediction_model(): """ 构建 BAC 预测模型 使用梯度提升回归器,输入10个波长吸光度 输出 BAC 预测值 Returns: model: 训练好的模型 X_test, y_test: 测试集 """ np.random.seed(42) n_samples = 1000 X = [] y = [] for _ in range(n_samples): bac = np.random.uniform(0.0, 0.25) skin = np.random.uniform(1.5, 3.0) temp = np.random.uniform(25, 37) moisture = np.random.uniform(0.2, 0.5) signal = simulate_finger_nir_signal(bac, skin, temp, moisture) X.append(signal) y.append(bac) X = np.array(X) y = np.array(y) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) model = GradientBoostingRegressor( n_estimators=200, max_depth=5, learning_rate=0.1, subsample=0.8, random_state=42 ) model.fit(X_train, y_train) cv_scores = cross_val_score(model, X_train, y_train, cv=5, scoring='r2') y_pred = model.predict(X_test) mae = np.mean(np.abs(y_pred - y_test)) print(f"=== BAC 预测模型性能 ===") print(f"交叉验证 R²: {cv_scores.mean():.4f} ± {cv_scores.std():.4f}") print(f"测试集 MAE: {mae:.4f} g/dL") print(f"测试集 MAE: {mae*100:.1f} mg/dL") threshold = 0.08 y_binary = (y_test >= threshold).astype(int) pred_binary = (y_pred >= threshold).astype(int) from sklearn.metrics import classification_report print(f"\n=== 阈值 {threshold} g/dL 检测性能 ===") print(classification_report(y_binary, pred_binary, target_names=['未醉驾', '醉驾'])) return model, X_test, y_test
if __name__ == "__main__": model, X_test, y_test = build_bac_prediction_model() print("\n=== 模拟单次检测 ===") test_bac = 0.09 signal = simulate_finger_nir_signal(test_bac, skin_thickness=2.0, temperature=32, moisture=0.35) predicted_bac = model.predict(signal.reshape(1, -1))[0] print(f"真实 BAC: {test_bac:.3f} g/dL") print(f"预测 BAC: {predicted_bac:.3f} g/dL") print(f"误差: {abs(predicted_bac - test_bac):.4f} g/dL") print(f"判定: {'醉驾' if predicted_bac >= 0.08 else '正常'}")
|