2. 基于CNN的故障诊断

任务说明

本案例面向旋转机械振动信号的故障分类问题。输入为不同健康状态下采集的一维振动时序信号,目标是构建并训练一个一维卷积神经网络(1D-CNN),使其能够自动区分正常状态与多种典型故障类型(如不平衡、不对中、轴承故障)。案例使用公开可获取的CWRU轴承数据集子集作为示例输入,完整代码可直接运行并输出分类准确率。

数据准备与预处理

振动信号按固定窗口长度(每样本1024个采样点)进行分割,每个样本对应一个故障类别标签。数据集按7:3划分为训练集与测试集,并对原始信号做零均值标准化以加速收敛。类别映射为:0-正常,1-滚动体故障,2-内圈故障,3-外圈故障。

原始振动信号 采样率12kHz 多工况采集 滑窗分割 窗口=1024点 步长=512点 标准化 零均值单位方差 按训练集统计 数据集划分 训练集70% 测试集30% 1D-CNN 网络结构 Conv1D 32×3 MaxPool 2×1 Conv1D 64×3 MaxPool 2×1 Flatten Dense(100) Dense(4) Softmax 4类输出

模型实现

模型采用两层卷积池化结构提取振动信号局部特征,后接全连接层完成分类。卷积核尺寸为3,激活函数使用ReLU,池化层采用最大池化。为防止过拟合,全连接层后加入Dropout(比率0.5)。损失函数为交叉熵,优化器使用Adam(学习率0.001)。

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# ---------- 1. 生成模拟振动数据(演示用,实际可替换为CWRU数据) ----------
def generate_vibration_data(n_samples=2000, n_points=1024, seed=42):
    """生成4类模拟振动信号:0-正常,1-滚动体故障,2-内圈故障,3-外圈故障"""
    np.random.seed(seed)
    t = np.linspace(0, 1, n_points)
    X = np.zeros((n_samples, n_points))
    y = np.zeros(n_samples, dtype=int)
    
    for i in range(n_samples):
        cls = i % 4
        y[i] = cls
        # 基频及谐波成分
        f_base = 30 + np.random.randn() * 2
        signal = 0.5 * np.sin(2 * np.pi * f_base * t)
        signal += 0.2 * np.sin(4 * np.pi * f_base * t + 0.5)
        
        if cls == 1:  # 滚动体故障:高频冲击
            for k in range(0, n_points, 128):
                signal[k:k+20] += 0.8 * np.exp(-5 * np.arange(20) / 20) * np.sin(2*np.pi*800*t[:20])
        elif cls == 2:  # 内圈故障:调制边带
            signal += 0.4 * np.sin(2 * np.pi * 120 * t) * (1 + 0.5*np.sin(2*np.pi*f_base*t))
        elif cls == 3:  # 外圈故障:周期性脉冲
            for k in range(0, n_points, 256):
                signal[k:k+15] += 0.6 * np.exp(-3 * np.arange(15) / 15)
        
        X[i] = signal + 0.05 * np.random.randn(n_points)  # 添加噪声
    
    return X, y

# ---------- 2. 数据加载与预处理 ----------
X, y = generate_vibration_data(n_samples=2000)
X = X.reshape(-1, 1024, 1)  # 增加通道维度

# 划分训练/测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

# 标准化(按训练集统计量)
scaler = StandardScaler()
X_train_flat = X_train.reshape(-1, 1024)
X_test_flat = X_test.reshape(-1, 1024)
scaler.fit(X_train_flat)
X_train = scaler.transform(X_train_flat).reshape(-1, 1024, 1)
X_test = scaler.transform(X_test_flat).reshape(-1, 1024, 1)

# ---------- 3. 构建1D-CNN模型 ----------
def build_cnn_model(input_shape=(1024, 1), num_classes=4):
    model = models.Sequential([
        layers.Conv1D(filters=32, kernel_size=3, activation='relu', 
                      input_shape=input_shape, padding='same'),
        layers.MaxPooling1D(pool_size=2),
        layers.Conv1D(filters=64, kernel_size=3, activation='relu', padding='same'),
        layers.MaxPooling1D(pool_size=2),
        layers.Flatten(),
        layers.Dense(100, activation='relu'),
        layers.Dropout(0.5),
        layers.Dense(num_classes, activation='softmax')
    ])
    return model

model = build_cnn_model()
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.summary()

# ---------- 4. 模型训练 ----------
history = model.fit(X_train, y_train, epochs=10, batch_size=64,
                    validation_split=0.1, verbose=1)

# ---------- 5. 模型评估 ----------
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"测试集准确率: {test_acc:.4f}")

# 预测示例
predictions = model.predict(X_test[:5])
pred_classes = np.argmax(predictions, axis=1)
print("前5个测试样本预测类别:", pred_classes)
print("真实类别:            ", y_test[:5])

运行与验证

运行方式:将上述代码保存为cnn_fault_diagnosis.py,在已安装TensorFlow 2.x、NumPy、scikit-learn的Python环境中执行python cnn_fault_diagnosis.py。

验证方法:观察训练过程中损失值是否持续下降、验证准确率是否逐步提升。训练结束后,程序输出测试集准确率。由于代码内置了模拟数据生成器,无需额外下载数据集即可复现完整流程。

判定标准:若测试集准确率高于0.95,且前5个测试样本的预测类别与真实类别基本一致,则说明CNN模型成功完成了振动信号的故障分类任务。若需使用真实CWRU数据,可将generate_vibration_data替换为实际数据加载逻辑,保持后续预处理与模型结构不变即可。