2. 基于CNN的故障诊断
任务说明
本案例面向旋转机械振动信号的故障分类问题。输入为不同健康状态下采集的一维振动时序信号,目标是构建并训练一个一维卷积神经网络(1D-CNN),使其能够自动区分正常状态与多种典型故障类型(如不平衡、不对中、轴承故障)。案例使用公开可获取的CWRU轴承数据集子集作为示例输入,完整代码可直接运行并输出分类准确率。
数据准备与预处理
振动信号按固定窗口长度(每样本1024个采样点)进行分割,每个样本对应一个故障类别标签。数据集按7:3划分为训练集与测试集,并对原始信号做零均值标准化以加速收敛。类别映射为:0-正常,1-滚动体故障,2-内圈故障,3-外圈故障。
模型实现
模型采用两层卷积池化结构提取振动信号局部特征,后接全连接层完成分类。卷积核尺寸为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替换为实际数据加载逻辑,保持后续预处理与模型结构不变即可。