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
| """ 二值接触感知坐姿识别系统
论文核心实现:10个接触开关 → 4种坐姿分类 """
import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score import json
class BinaryContactPosture: """ 二值接触感知坐姿识别 硬件:10个机械接触开关(5×2阵列) 信号:10-bit 二进制向量 分类器:决策树 / 逻辑回归 """ SWITCH_LAYOUT = { 'S1': {'row': 0, 'col': 0}, 'S2': {'row': 0, 'col': 1}, 'S3': {'row': 0, 'col': 2}, 'S4': {'row': 1, 'col': 0}, 'S5': {'row': 1, 'col': 1}, 'S6': {'row': 1, 'col': 2}, 'S7': {'row': 2, 'col': 0}, 'S8': {'row': 2, 'col': 1}, 'S9': {'row': 2, 'col': 2}, 'S10': {'row': 3, 'col': 1} } POSTURE_SIGNATURES = { 'normal': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'leaning_back': [1, 1, 1, 0, 0, 0, 0, 0, 0, 0], 'leaning_left': [1, 0, 0, 1, 0, 0, 1, 0, 0, 0], 'leaning_right': [0, 0, 1, 0, 0, 1, 0, 0, 1, 0], } def __init__(self, classifier: str = 'tree'): if classifier == 'tree': self.clf = DecisionTreeClassifier( max_depth=5, criterion='entropy' ) elif classifier == 'logistic': self.clf = LogisticRegression(max_iter=200) else: raise ValueError(f"Unknown classifier: {classifier}") self.is_trained = False def generate_training_data(self, n_samples: int = 200) -> tuple: """生成带噪声的训练数据""" X, y = [], [] for posture, signature in self.POSTURE_SIGNATURES.items(): for _ in range(n_samples // len(self.POSTURE_SIGNATURES)): noisy = np.array(signature, dtype=float) noise_idx = np.random.choice(10, size=np.random.randint(0, 2), replace=False) noisy[noise_idx] = 1 - noisy[noise_idx] X.append(noisy) y.append(posture) return np.array(X), np.array(y) def train(self, X: np.ndarray, y: np.ndarray): """训练分类器""" self.clf.fit(X, y) self.is_trained = True scores = cross_val_score(self.clf, X, y, cv=5) print(f"训练完成 - 5折交叉验证准确率: {scores.mean():.1%} ± {scores.std():.1%}") return scores def predict(self, switch_states: list) -> str: """ 实时预测坐姿 Args: switch_states: 10个开关状态 (0/1) Returns: posture: 坐姿类别 """ if not self.is_trained: raise RuntimeError("模型未训练") X = np.array(switch_states).reshape(1, -1) return self.clf.predict(X)[0] def shap_analysis(self, X: np.ndarray) -> dict: """ SHAP 分析:哪些开关最重要? 论文发现:中央接触点(S2, S5, S8)最有信息量 """ if hasattr(self.clf, 'feature_importances_'): importances = self.clf.feature_importances_ else: importances = np.abs(self.clf.coef_[0]) switch_names = list(self.SWITCH_LAYOUT.keys()) sorted_idx = np.argsort(importances)[::-1] result = {} for idx in sorted_idx: result[switch_names[idx]] = float(importances[idx]) return result
if __name__ == "__main__": np.random.seed(42) system = BinaryContactPosture(classifier='tree') X, y = system.generate_training_data(200) print(f"训练数据: {X.shape}") print(f"类别: {np.unique(y)}") scores = system.train(X, y) test_cases = [ ([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "正常坐姿"), ([1, 1, 1, 0, 0, 0, 0, 0, 0, 0], "后仰"), ([1, 0, 0, 1, 0, 0, 1, 0, 0, 0], "左倾"), ([0, 0, 1, 0, 0, 1, 0, 0, 1, 0], "右倾"), ] print("\n" + "=" * 50) print("坐姿预测测试") print("=" * 50) for switches, expected in test_cases: prediction = system.predict(switches) print(f" 开关: {switches}") print(f" 预期: {expected}") print(f" 预测: {prediction}") print() print("=" * 50) print("特征重要性分析(SHAP近似)") print("=" * 50) importances = system.shap_analysis(X) for name, imp in importances.items(): pos = system.SWITCH_LAYOUT[name] print(f" {name} (行{pos['row']},列{pos['col']}): {imp:.4f}")
|