2. 基于CNN的故障分类
任务说明
本案例使用一维卷积神经网络(1D-CNN)对旋转机械的振动信号进行故障类型识别。输入为原始振动加速度时序数据,输出为故障类别(正常、不平衡、不对中、轴承磨损)。通过端到端的卷积池化结构自动提取振动特征,完成分类任务。
数据集构造
由于公开振动数据集体积较大且下载不稳定,本案例采用仿真信号生成四类振动数据,每类包含不同故障特征频率成分,确保类别可分且代码可独立运行。每类生成200个样本,每个样本为1024点的振动波形,训练集与测试集按8:2划分。
代码实现
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,则本案例实现通过。若准确率明显偏低,可检查信号生成参数或增加训练轮次。