2. 齿轮箱故障诊断的时域特征提取与分类

任务说明

本案例使用齿轮箱振动加速度信号,通过滑动窗口截取信号片段,提取均值、方差、均方根、峰值因子、峭度、波形因子、脉冲因子和裕度因子共8个时域统计特征,构建特征向量后使用随机森林分类器识别正常、齿面磨损、断齿和轴承故障4种状态。数据集由本案例代码自动生成,包含4类模拟振动信号各200个样本,其中80%用于训练,20%用于测试。

时域特征定义

设信号片段为 \(x_1, x_2, \ldots, x_N\),各特征计算方式如下:

  • 均值:\(\bar{x} = \frac{1}{N}\sum_{i=1}^{N}x_i\)
  • 方差:\(\sigma^2 = \frac{1}{N-1}\sum_{i=1}^{N}(x_i-\bar{x})^2\)
  • 均方根:\(X_{rms} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}x_i^2}\)
  • 峰值因子:\(C_f = X_{peak} / X_{rms}\),其中 \(X_{peak} = \max|x_i|\)
  • 峭度:\(K = \frac{1}{N}\sum_{i=1}^{N}(x_i-\bar{x})^4 / \sigma^4\)
  • 波形因子:\(S_f = X_{rms} / ( \frac{1}{N}\sum_{i=1}^{N}|x_i| )\)
  • 脉冲因子:\(I_f = X_{peak} / ( \frac{1}{N}\sum_{i=1}^{N}|x_i| )\)
  • 裕度因子:\(CL_f = X_{peak} / ( \frac{1}{N}\sum_{i=1}^{N}\sqrt{|x_i|} )^2\)

代码实现

import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# ---------- 1. 模拟齿轮箱振动信号 ----------
def simulate_gear_signal(fault_type, n_samples=200, fs=8192, duration=1.0):
    """生成4类齿轮箱振动信号,每类n_samples个样本"""
    t = np.linspace(0, duration, int(fs*duration), endpoint=False)
    shaft_freq = 30.0  # 轴频 30 Hz
    gear_mesh_freq = 30.0 * 23  # 啮合频率 690 Hz (23齿)
    signals = []
    labels = []
    for _ in range(n_samples):
        # 基础啮合振动
        x = 1.0 * np.sin(2*np.pi*gear_mesh_freq*t + 0.5*np.sin(2*np.pi*shaft_freq*t))
        # 随机噪声
        x += 0.15 * np.random.randn(len(t))
        if fault_type == 'normal':
            label = 0
        elif fault_type == 'wear':
            # 齿面磨损:啮合频率二次谐波幅值增大
            x += 0.6 * np.sin(2*np.pi*2*gear_mesh_freq*t)
            label = 1
        elif fault_type == 'broken_tooth':
            # 断齿:每转一周产生一次冲击
            impact = 2.5 * np.exp(-2000 * (t % (1/shaft_freq)))
            x += impact
            label = 2
        elif fault_type == 'bearing_fault':
            # 轴承故障:高频共振调制
            bearing_freq = 105.0  # 轴承故障特征频率
            x += 1.2 * np.sin(2*np.pi*3000*t) * (0.5 + 0.5*np.sin(2*np.pi*bearing_freq*t))
            label = 3
        else:
            raise ValueError('Unknown fault type')
        signals.append(x)
        labels.append(label)
    return np.array(signals), np.array(labels)

# ---------- 2. 时域特征提取 ----------
def extract_time_features(signal):
    """从单个信号片段提取8个时域统计特征"""
    N = len(signal)
    mean_val = np.mean(signal)
    var_val = np.var(signal, ddof=1)
    rms_val = np.sqrt(np.mean(signal**2))
    peak_val = np.max(np.abs(signal))
    # 峭度
    if var_val < 1e-12:
        kurtosis_val = 0.0
    else:
        kurtosis_val = np.mean((signal - mean_val)**4) / (var_val**2)
    # 整流均值
    abs_mean = np.mean(np.abs(signal))
    if abs_mean < 1e-12:
        waveform_factor = 0.0
        impulse_factor = 0.0
        margin_factor = 0.0
    else:
        waveform_factor = rms_val / abs_mean
        impulse_factor = peak_val / abs_mean
        # 裕度因子
        sqrt_abs_mean = np.mean(np.sqrt(np.abs(signal)))**2
        margin_factor = peak_val / sqrt_abs_mean if sqrt_abs_mean > 1e-12 else 0.0
    return np.array([mean_val, var_val, rms_val, peak_val,
                     kurtosis_val, waveform_factor, impulse_factor, margin_factor])

# ---------- 3. 构建数据集 ----------
fault_types = ['normal', 'wear', 'broken_tooth', 'bearing_fault']
all_features = []
all_labels = []
for ft in fault_types:
    sigs, labs = simulate_gear_signal(ft)
    for sig, lab in zip(sigs, labs):
        feat = extract_time_features(sig)
        all_features.append(feat)
        all_labels.append(lab)

X = np.array(all_features)
y = np.array(all_labels)
print(f'特征矩阵形状: {X.shape}, 标签分布: {np.bincount(y)}')

# ---------- 4. 训练与评估 ----------
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y)

clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

# ---------- 5. 输出评估结果 ----------
acc = accuracy_score(y_test, y_pred)
print(f'测试集准确率: {acc:.4f}')
print('\n分类报告:')
print(classification_report(y_test, y_pred,
      target_names=fault_types, zero_division=0))

# ---------- 6. 特征重要性排序 ----------
feature_names = ['均值', '方差', '均方根', '峰值', '峭度',
                 '波形因子', '脉冲因子', '裕度因子']
importance = clf.feature_importances_
print('\n特征重要性:')
for name, imp in sorted(zip(feature_names, importance),
                        key=lambda x: x[1], reverse=True):
    print(f'  {name}: {imp:.4f}')

落地与运行方式

本案例依赖 numpy 和 scikit-learn,安装命令:

pip install numpy scikit-learn

将上述代码保存为 gear_fault_diagnosis.py,在终端执行:

python gear_fault_diagnosis.py

验证方法与判定标准

程序运行后应依次输出特征矩阵形状(800行×8列)、4类标签各200个的分布信息、测试集准确率、分类报告以及特征重要性排序。判定标准:

  1. 特征矩阵形状为 (800, 8),标签分布为每类200个;
  2. 测试集准确率不低于0.90(由于模拟信号类间差异明显,随机森林通常能达到0.95以上);
  3. 分类报告中每个类别的精确率、召回率和F1值均不低于0.85;
  4. 特征重要性中峭度和峰值因子应排在前列,因为断齿冲击和轴承故障调制会显著改变信号峰值分布。

若准确率低于0.90,可检查模拟信号参数是否被修改,或增加随机森林的n_estimators值后重新运行。

信号特征与分类逻辑说明

本案例的模拟信号设计使4类故障在时域特征上具有可区分性:正常状态信号平稳,峭度接近3;齿面磨损引入二次谐波使波形因子和均方根增大;断齿产生周期性冲击,显著提高峰值因子和峭度;轴承故障的高频调制使方差和脉冲因子上升。随机森林基于这些特征差异构建决策边界,实现故障类型识别。

齿轮箱故障诊断时域特征提取与分类流程 振动信号采集 fs=8192Hz, 1s/样本 4类状态 正常 (0) 齿面磨损 (1) 断齿 (2) 轴承故障 (3) 时域特征提取 均值 方差 均方根 峰值因子 峭度 波形因子 脉冲因子 裕度因子 特征矩阵 800 × 8 样本数 × 特征维度 80%训练 20%测试 随机森林 100棵树 分类器 故障类型 0/1/2/3 评估:准确率 ≥ 0.90,各类别 F1 ≥ 0.85