1.背景
- 在实际工业生产设备工作时,旋转机械很可能不会以恒定转速持续运行,或者存在比较大的转速波动,电机升降速或者调速过程中转速也会处于时刻变化的动态状态。
- 在实际工况中,转速通常会发生变化。标准的频域分析(如FFT)在处理非稳态条件下(转速变化时)会失去精确性。而阶次分析通过基于转速进行重采样,能够保持频率与转速的同步,因此可以消除转速变化对频谱分析的影响,提供更准确的故障信息。
2.基本原理
阶次分析(Order Analysis)是一种用于分析旋转机械中周期性振动信号的频谱分析技术,特别适用于变速机械(如发动机、涡轮机、压缩机、变速箱等)中的信号处理。这种方法可以识别和量化与转速相关的振动现象,通过分析机械的旋转运动,将其产生的振动信号分解为多个不同阶次(harmonic orders)对应的频率成分。
3.基本方法
等角度采样的实现是阶次跟踪分析的主要难题,有两种方法实现等角度采样:转速脉冲触发采样和等时重采样。
- 转速脉冲触发采样是通过严格的转速脉冲触发采样。在要分析的发动机上固定转速盘,发动机每旋转一定角度,转速表从固定盘获取上脉冲信号,同时触发振动采样。此种方法能实现严格的同步触发,但实际操作存在困难。根据奈奎斯特定律,信号的采样频率必须是分析频率的两倍以上。假设我们要进行32阶的阶次谱,则至少需要64个以上的触发信号。对较小的转速盘进行64等份,再保证转速测量比较难实现。
- 等时重采样有两个采样过程。第一个过程是等时间间隔采样过程,对原始的噪声或振动信号和转速脉冲信号分两路以恒定的采样率进行等时间间隔采样,得到同步采样信号。等时采样时,采样率一般比较高。第二个过程是插值重采样过程,根据转速脉冲序列计算等角度采样发生的时刻序列,在等角度采样时刻附近的时间区间内对同步采样的原始噪声信号进行插值重采样,从而得到阶次分析所需的角度域稳态信号。通过插值法可减少转速触发,但插值不能保证严格的转速同步,对测量精度存在影响。
4.阶次分析代码
4.1Python代码
'''
:@Author: zkw
:@LastEditors: zkw
:Description:
:Copyright: Copyright (©) 2024 XXXX有限公司. All rights reserved.
'''
import scipy.io
import numpy as np
import matplotlib.pyplot as plt
from get_ftt import get_fft
from tacho2rpm import tacho2rpm
from angle_resample import angle_resample
from scipy.signal import hilbert
# 读取MAT格式数据
fs = 200000
mat_data = scipy.io.loadmat('O-D-3.mat')
vib_data = np.array(mat_data["Channel_1"].flatten().tolist()[10:fs*10])
speed_data = np.array(list(mat_data["Channel_2"])[10:fs*10])
time_data = np.arange(len(vib_data)) / fs
_, rpm_data = tacho2rpm(speed_data, fs, PPR=1024, NewFs=fs, Filter=10)
rpm_data_s = rpm_data / 60
fs_r = 100
theta, x_theta = angle_resample(vib_data, fs, rpm_data_s, fs_r)
x_hht = hilbert(x_theta)
# 调用自定义的FFT分析函数
YL, f = get_fft(np.abs(x_hht), fs_r) # type: ignore
# 创建一个4行1列的子图布局,从上到下堆叠
fig, axs = plt.subplots(4, 1, figsize=(10, 6))
# 绘制各个数据
axs[0].plot(time_data, vib_data)
axs[0].set_title('Vibration Data')
axs[0].set_ylabel('Amplitude')
axs[1].plot(time_data, speed_data)
axs[1].set_title('Speed Data')
axs[1].set_ylabel('Speed')
axs[2].plot(time_data, rpm_data)
axs[2].set_title('RPM Data (Raw)')
axs[2].set_ylabel('RPM')
axs[3].plot(f, YL)
axs[3].set_title('Order Spectrum')
axs[3].set_ylabel('HTT')
axs[3].set_xlabel('Order')
# 调整子图间距
plt.subplots_adjust(hspace=2)
plt.show()
4.2代码解读
这段代码是一个 Python 脚本,用于处理和分析振动数据。以下是对每个部分的详细解读:
- 导入库
import scipy.io
import numpy as np
import matplotlib.pyplot as plt
from get_ftt import get_fft
from tacho2rpm import tacho2rpm
from angle_resample import angle_resample
from scipy.signal import hilbert
scipy.io
:用于读取 MATLAB 文件。numpy
:用于数值计算和数组操作。matplotlib.pyplot
:用于绘制图形。get_fft
、tacho2rpm
、angle_resample
:自定义函数,分别用于傅里叶变换、转速计算和角度重采样。scipy.signal.hilbert
:用于计算信号的 Hilbert 变换。
- 读取数据
fs = 200000
mat_data = scipy.io.loadmat('O-D-3.mat')
vib_data = np.array(mat_data["Channel_1"].flatten().tolist()[10:fs*10])
speed_data = np.array(list(mat_data["Channel_2"])[10:fs*10])
time_data = np.arange(len(vib_data)) / fs
fs
:设定采样频率为 200,000 Hz。loadmat
:读取 MATLAB 格式的文件'O-D-3.mat'
。- 从
Channel_1
中提取振动数据,并将其转为一维数组,同时排除前 10 个采样点。 - 从
Channel_2
中提取速度数据,并做相同处理。 time_data
计算时间轴,以秒为单位。
- 转速计算
_, rpm_data = tacho2rpm(speed_data, fs, PPR=1024, NewFs=fs, Filter=10)
rpm_data_s = rpm_data / 60
- 使用
tacho2rpm
函数计算转速数据(RPM),其中PPR
是每转脉冲数,NewFs
是新的采样频率,Filter
用于平滑处理。 rpm_data_s
将 RPM 转换为每秒转数(Hz),通过除以 60。
- 角度重采样
fs_r = 100
theta, x_theta = angle_resample(vib_data, fs, rpm_data_s, fs_r)
fs_r
设定重采样频率为 100 Hz。- 使用
angle_resample
函数对振动数据进行角度重采样。
- Hilbert 变换
x_hht = hilbert(x_theta)
- 计算重采样后振动信号的 Hilbert 变换,生成解析信号。
- 傅里叶变换
YL, f = get_fft(np.abs(x_hht), fs_r) # type: ignore
- 使用自定义的
get_fft
函数对信号的幅度进行傅里叶变换,返回频谱和频率。
- 绘制图形
fig, axs = plt.subplots(4, 1, figsize=(10, 6))
axs[0].plot(time_data, vib_data)
axs[0].set_title('Vibration Data')
axs[0].set_ylabel('Amplitude')
axs[1].plot(time_data, speed_data)
axs[1].set_title('Speed Data')
axs[1].set_ylabel('Speed')
axs[2].plot(time_data, rpm_data)
axs[2].set_title('RPM Data (Raw)')
axs[2].set_ylabel('RPM')
axs[3].plot(f, YL)
axs[3].set_title('Order Spectrum')
axs[3].set_ylabel('HTT')
axs[3].set_xlabel('Order')
plt.subplots_adjust(hspace=2)
plt.show()
- 创建一个 4 行 1 列的子图布局。
- 分别绘制振动数据、速度数据、转速数据和订单谱图。
- 调整子图间距,最后显示图形。
4.3转速计算
import numpy as np
from scipy import signal
def tacho2rpm(x, fs, TLeveL=4, Slope=1, PPR=1, NewFs=None, Filter=5):
time = len(x)
x1 = np.arange(0, time, 1)
t = x1 / fs
xDiff = np.diff(np.sign(x - TLeveL).flatten())
tDiff = t[1:]
NewFs = fs
if Slope > 0:
tTacho = tDiff[np.where(xDiff == 2)]
else:
tTacho = tDiff[np.where(xDiff == -2)]
rpmt = 60 / PPR / np.diff(tTacho)
rpmt = (rpmt[0:-1] + rpmt[1:]) / 2
tTacho = tTacho[1:-1]
# 平滑处理
if Filter > 1:
a = 1
b = 1 / Filter * np.ones((1, Filter)).flatten()
rpmt = signal.filtfilt(b, a, rpmt)
else:
pass
t = np.arange(0, t[-1] + 1 / NewFs, 1 / NewFs)
rpm = np.interp(t, tTacho, rpmt)
return t, rpm
4.4等角度采样
import numpy as np
from scipy.interpolate import interp1d
from scipy.integrate import cumulative_trapezoid
def angle_resample(signal, time_sampling_rate, rpm, angle_sampling_rate):
"""
计算根据随时间变化的转速得到的角度样本对应的信号值
参数:
signal (ndarray): 信号数组
time_sampling_rate (float): 时间采样率,单位为Hz
rpm (ndarray): 随时间变化的转速序列,单位为r/s
angle_sampling_rate (float): 角度采样率,单位为rad/s
返回:
theta (ndarray): 角度序列
x_theta (ndarray): 对应于角度序列的信号插值值
"""
# 计算时间序列
N = len(signal)
t = np.arange(N) / time_sampling_rate
# 积分计算随时间转过的总转数(弧度),此处修正为从scipy.integrate导入cumtrapz
theta_t = cumulative_trapezoid(rpm, t)
theta_t = list(theta_t)
theta_t.insert(0, 0)
theta_t = np.array(theta_t)
# 生成角度序列
theta = np.arange(0, theta_t[-1], 1/angle_sampling_rate)
# 在角度序列上对原始信号进行插值
f_interp = interp1d(theta_t, signal, kind='linear')
x_theta = f_interp(theta)
return theta, x_theta
4.5傅里叶变换
import numpy as np
def get_fft(X, Fs):
# 获取信号长度
L = len(X)
# 对信号X进行快速傅里叶变换(FFT)
Y = np.fft.fft(X)
# 对FFT结果进行归一化处理,使其表示为振幅谱
YL2 = np.abs(Y) / L
# 由于FFT结果的对称性(对于实数输入),我们只需要一半的数据
half_L = int(np.floor(L / 2)) + 1
YL1 = YL2[:half_L]
# 处理FFT结果:
# - 将直流分量(频率为0的部分)设置为0
YL1[0] = 0
# - 除最后一个频率成分外,其余频率成分的幅度加倍(因为频谱的后半部分是对称的,前半部分的非零元素在对称位置有对应点)
YL1[1:-1] *= 2
# 计算频率轴的值,范围从0到采样率的一半(奈奎斯特频率)
f = Fs * np.arange(np.floor(L/2) + 1) / L
# 返回归一化且处理过的幅度谱和对应的频率轴
return YL1, f