2. 基于CNN的故障分类

任务说明

本案例使用一维卷积神经网络(1D-CNN)对旋转机械的振动信号进行故障类型识别。输入为原始振动加速度时序数据,输出为故障类别(正常、不平衡、不对中、轴承磨损)。通过端到端的卷积池化结构自动提取振动特征,完成分类任务。

数据集构造

由于公开振动数据集体积较大且下载不稳定,本案例采用仿真信号生成四类振动数据,每类包含不同故障特征频率成分,确保类别可分且代码可独立运行。每类生成200个样本,每个样本为1024点的振动波形,训练集与测试集按8:2划分。

振动信号生成 4类 × 200样本 预处理 归一化 + 标签编码 数据集划分 训练320 / 测试80 1D-CNN Conv1D×2 + 全连接 1D-CNN 结构 Conv1D 16核, k=3 MaxPool 池化2 Conv1D 32核, k=3 MaxPool 池化2 Flatten + Dense 64 → 4 (Softmax) 输入: (None, 1024, 1) 输出: 4类概率 激活: ReLU (卷积层) / Softmax (输出层) | 优化器: Adam | 损失: 交叉熵

代码实现


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 LabelEncoder
from sklearn.metrics import classification_report

# ========== 1. 仿真振动信号生成 ==========
def generate_vibration_signal(fault_type, length=1024, fs=2000):
    """生成带故障特征的振动信号"""
    t = np.arange(length) / fs
    rng = np.random.default_rng(42)

    # 基频与谐波
    f0 = 30  # 转频 30Hz
    signal = 0.5 * np.sin(2 * np.pi * f0 * t)

    if fault_type == 'normal':
        pass  # 仅基频
    elif fault_type == 'unbalance':
        signal += 0.8 * np.sin(2 * np.pi * f0 * t + 0.5)  # 1倍频幅值增大
    elif fault_type == 'misalignment':
        signal += 0.6 * np.sin(2 * np.pi * 2 * f0 * t)    # 2倍频明显
        signal += 0.3 * np.sin(2 * np.pi * 3 * f0 * t)    # 3倍频
    elif fault_type == 'bearing_wear':
        # 轴承故障特征频率 (BPFO ≈ 4.3×转频)
        bpfo = 4.3 * f0
        signal += 0.7 * np.sin(2 * np.pi * bpfo * t)
        # 周期性冲击
        for i in range(0, length, 200):
            idx = i + rng.integers(0, 50)
            if idx < length:
                signal[idx] += 1.5 * np.exp(-20 * (t[idx] - t[i])**2)

    # 添加噪声
    signal += rng.normal(0, 0.1, length)
    return signal

# ========== 2. 构建数据集 ==========
fault_types = ['normal', 'unbalance', 'misalignment', 'bearing_wear']
samples_per_class = 200
X, y = [], []

for label, ftype in enumerate(fault_types):
    for _ in range(samples_per_class):
        X.append(generate_vibration_signal(ftype))
        y.append(label)

X = np.array(X, dtype=np.float32).reshape(-1, 1024, 1)
y = np.array(y)

# 归一化
X = (X - X.mean()) / X.std()

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

print(f"训练样本: {X_train.shape[0]}, 测试样本: {X_test.shape[0]}")

# ========== 3. 构建1D-CNN模型 ==========
model = models.Sequential([
    layers.Input(shape=(1024, 1)),
    layers.Conv1D(16, 3, activation='relu', padding='same'),
    layers.MaxPooling1D(2),
    layers.Conv1D(32, 3, activation='relu', padding='same'),
    layers.MaxPooling1D(2),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(4, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.summary()

# ========== 4. 训练与评估 ==========
history = model.fit(X_train, y_train, epochs=15, batch_size=32,
                    validation_split=0.1, verbose=1)

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

# 分类报告
y_pred = np.argmax(model.predict(X_test, verbose=0), axis=1)
print("\n分类报告:")
print(classification_report(y_test, y_pred,
      target_names=fault_types, digits=4))

运行与验证

依赖安装:


pip install numpy tensorflow scikit-learn

运行方式:将上述代码保存为 cnn_fault_classifier.py,在终端执行 python cnn_fault_classifier.py。

验证方法:观察训练过程中验证集准确率是否逐步上升并收敛;训练结束后查看测试集准确率与分类报告。由于仿真信号类别特征差异明显,预期测试准确率应高于95%。分类报告中各类别的精确率、召回率与F1值应接近且无类别被完全错分。

判定标准:若测试集准确率≥90%,且四类故障的F1值均≥0.85,则本案例实现通过。若准确率明显偏低,可检查信号生成参数或增加训练轮次。