第1章:信号读取与可视化——从数据到波形图
各位同学好,我是老张。做轴承故障诊断这些年,我最大的体会就是:拿到数据别急着上算法,先看看波形长什么样。这就像医生看病,总得先望闻问切吧?
今天咱们就聊聊,怎么用Python把振动信号读进来,再画成时域波形图。别小看这一步,我见过太多人模型跑得飞起,结果数据读进来就是错的——嗯,那后面的分析全白搭。
1.1 振动数据长什么样?
先说说数据格式。实际项目中,振动数据最常见的就是两种:
- CSV格式:纯文本,用逗号分隔。简单,通用。
- MAT格式:Matlab的二进制格式。实验室里用得特别多。
我个人习惯,拿到数据先看一眼文件大小和结构。举个例子,一个典型的轴承振动CSV文件,大概长这样:
time, vibration
0.000, 0.0123
0.001, -0.0089
0.002, 0.0156
...
第一列是时间,第二列是加速度值。单位通常是秒和g(重力加速度)。
核心要点:振动信号本质上是时间序列。每个采样点对应一个时刻的振动幅值。采样率决定了时间间隔——比如10kHz采样,相邻点间隔0.0001秒。
1.2 用Pandas读取CSV
Python里读CSV,我首选Pandas。为什么?因为它自带数据结构,处理起来太顺手了。
import pandas as pd
import numpy as np
# 读取CSV文件
df = pd.read_csv('bearing_vibration.csv')
# 看看前5行
print(df.head())
# 提取时间和振动列
time = df['time'].values
vibration = df['vibration'].values
# 看看数据基本信息
print(f"采样点数: {len(vibration)}")
print(f"采样率: {1/(time[1]-time[0]):.1f} Hz")
这里有个坑,我曾经踩过:CSV文件里可能有表头注释行。有些数据采集软件会在文件开头加几行说明,比如设备型号、测试条件。这时候直接读会报错。解决办法是加个skiprows参数:
df = pd.read_csv('bearing_vibration.csv', skiprows=2) # 跳过前2行注释
我的小技巧:读数据前先用文本编辑器打开看一眼,确认文件结构。这花不了30秒,但能省下半小时的调试时间。
1.3 读取MAT格式文件
MAT文件稍微麻烦点。需要用scipy.io模块。我记得第一次读MAT文件时,死活找不到变量名——后来才发现,MAT文件里存的变量名和Matlab工作区里看到的不一样。
from scipy.io import loadmat
# 读取MAT文件
mat_data = loadmat('bearing_data.mat')
# 查看所有变量名
print(mat_data.keys())
# 提取振动数据(假设变量名叫'vibration')
vibration = mat_data['vibration'].flatten()
# 如果有时间轴
time = mat_data['time'].flatten() if 'time' in mat_data else None
注意.flatten()这个操作。MAT文件读出来通常是二维数组,哪怕它只有一列。不压平的话,后面画图会出问题。
避坑指南:我曾经遇到过MAT文件版本不兼容的问题。Python的scipy只能读取MATLAB 5.0及以上版本。如果你用的是老版本Matlab(比如7.3之前),需要先转换成新格式,或者用h5py库读取。
1.4 用Matplotlib画时域波形
数据读进来了,接下来就是画图。时域波形图说白了就是横轴时间、纵轴幅值的折线图。但别小看这张图,它能告诉你很多信息:
- 信号有没有明显的周期性?
- 有没有冲击成分?
- 噪声水平怎么样?
- 有没有异常尖峰?
来看看代码:
import matplotlib.pyplot as plt
# 设置中文字体(防止乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建画布
plt.figure(figsize=(12, 4))
# 画波形
plt.plot(time, vibration, 'b-', linewidth=0.5)
# 添加标签
plt.xlabel('时间 (s)')
plt.ylabel('振动幅值 (g)')
plt.title('轴承振动信号时域波形')
# 添加网格
plt.grid(True, alpha=0.3)
# 显示
plt.tight_layout()
plt.show()
这里我用了linewidth=0.5。为什么线要这么细?因为振动信号采样点很多,线太粗会糊成一团,看不清细节。你想想看,10kHz采样率下,1秒钟就是1万个点,线宽了根本没法看。
1.5 画图的几个实用技巧
做项目这么多年,我总结了几条画图的经验:
- 先看整体,再看局部。先画整段信号,了解大致情况。然后截取一小段(比如0.1秒)放大看细节。
- 多画几个子图对比。正常状态和故障状态的波形放在一起,差异一目了然。
- 注意坐标轴范围。有时候信号里有个异常大的尖峰,会导致纵轴自动缩放,其他细节全被压扁了。这时候可以手动设置
ylim。
来看一个截取局部信号的例子:
# 截取前0.1秒的数据
sample_rate = 1 / (time[1] - time[0])
points_to_show = int(0.1 * sample_rate)
plt.figure(figsize=(12, 4))
plt.plot(time[:points_to_show], vibration[:points_to_show], 'b-', linewidth=1)
plt.xlabel('时间 (s)')
plt.ylabel('振动幅值 (g)')
plt.title('前0.1秒波形细节')
plt.grid(True, alpha=0.3)
plt.show()
为什么这么做? 整段信号可能几秒钟甚至几分钟,你根本看不清单个冲击的形态。截取一小段,才能看到波形的真实形状——是正弦波?是冲击衰减?还是杂乱无章的噪声?这些细节对故障诊断至关重要。
1.6 本章知识体系
来,我画了一张图,把本章的核心逻辑串起来:
这张图把整个流程串起来了。从数据来源开始,到读取方法,再到数据检查,最后是可视化。可视化又分整体和局部两个角度。说白了,就是先宏观再微观,先看全貌再看细节。
1.7 避坑总结
最后,我把这些年踩过的坑整理一下:
| 常见问题 | 表现 | 解决办法 |
|---|---|---|
| CSV有注释行 | 读取报错或数据错位 | 用skiprows跳过 |
| MAT版本不兼容 | loadmat报错 | 用h5py或转换格式 |
| 数据维度不对 | 画图时报维度错误 | 用.flatten()压平 |
| 中文显示乱码 | 标题、标签显示方框 | 设置rcParams字体 |
| 波形太密看不清 | 整段信号糊成一团 | 截取局部放大看 |
嗯,今天就到这儿。记住一句话:数据读不对,后面全白费。花点时间把数据读好、波形画好,后面的分析才能站得住脚。