第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 画图的几个实用技巧

做项目这么多年,我总结了几条画图的经验:

  1. 先看整体,再看局部。先画整段信号,了解大致情况。然后截取一小段(比如0.1秒)放大看细节。
  2. 多画几个子图对比。正常状态和故障状态的波形放在一起,差异一目了然。
  3. 注意坐标轴范围。有时候信号里有个异常大的尖峰,会导致纵轴自动缩放,其他细节全被压扁了。这时候可以手动设置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 本章知识体系

来,我画了一张图,把本章的核心逻辑串起来:

信号读取与可视化核心流程 数据来源 CSV文件 / MAT文件 读取方法 pd.read_csv / loadmat 数据检查 形状 / 采样率 / 异常值 可视化 时域波形图 整体波形(宏观观察) 看趋势、看周期性、看异常 局部波形(微观分析) 看冲击形态、看噪声特征 数据预处理 去均值 / 滤波

这张图把整个流程串起来了。从数据来源开始,到读取方法,再到数据检查,最后是可视化。可视化又分整体和局部两个角度。说白了,就是先宏观再微观,先看全貌再看细节。

1.7 避坑总结

最后,我把这些年踩过的坑整理一下:

常见问题 表现 解决办法
CSV有注释行 读取报错或数据错位 skiprows跳过
MAT版本不兼容 loadmat报错 h5py或转换格式
数据维度不对 画图时报维度错误 .flatten()压平
中文显示乱码 标题、标签显示方框 设置rcParams字体
波形太密看不清 整段信号糊成一团 截取局部放大看

嗯,今天就到这儿。记住一句话:数据读不对,后面全白费。花点时间把数据读好、波形画好,后面的分析才能站得住脚。

蓝海数据掘金营,专注资料整理