frequency_filter.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import pandas as pd
  2. import matplotlib.pyplot as plt
  3. import warnings
  4. from pandas.errors import SettingWithCopyWarning
  5. from scipy.signal import butter, filtfilt
  6. from scipy.signal import welch
  7. from scipy.fft import fft, fftfreq
  8. import numpy as np
  9. warnings.filterwarnings("ignore", category=SettingWithCopyWarning)
  10. plt.rcParams['font.sans-serif'] = ['SimHei']
  11. plt.rcParams['axes.unicode_minus'] = False
  12. def butter_lowpass_filter(data, cutoff, fs, order=5):
  13. nyq = 0.5 * fs # Nyquist频率
  14. normal_cutoff = cutoff / nyq
  15. b, a = butter(order, normal_cutoff, btype='low', analog=False)
  16. y = filtfilt(b, a, data)
  17. return y
  18. def butter_bandpass_filter(data, cutoff_low, cutoff_high, fs, order=5):
  19. nyq = 0.5 * fs # Nyquist频率
  20. high_cutoff = cutoff_high / nyq
  21. low_cutoff = cutoff_low / nyq
  22. b, a = butter(order, [low_cutoff, high_cutoff], btype='band', analog=False)
  23. y = filtfilt(b, a, data)
  24. return y
  25. def apply_fft(x, fs):
  26. n = len(x)
  27. t = 1.0 / fs
  28. fft_cof = fft(x - np.mean(x)) # Obtain FFT coefficients after removing the mean (DC component) from the signal.
  29. xf = fftfreq(n, t)[:n // 2] # Taking positive spectrum only.
  30. # Multiply abs(FFT coefficients) by 2 to compensate for positive spectrum and normalize by signal length.
  31. fft_positive = 2.0 / n * np.abs(fft_cof[0:n // 2])
  32. return xf, fft_positive
  33. # Function to compute PSD
  34. def compute_psd(signal, length, fs):
  35. seg_length = length / 10000 # Segment length.
  36. overlap = seg_length / 20 # overlap between segments (in number of samples)
  37. nfft_length = 2 ** 14 # FFT length
  38. frequencies, psd = welch(signal, fs=fs, window='han', nperseg=seg_length, noverlap=overlap, nfft=nfft_length)
  39. return frequencies, psd
  40. def tower_cal(data, start_points, end_points, fs):
  41. """
  42. 计算测量叶片数据的塔筒测量距离
  43. :param data: cycle_calculate计算完成后的数据。
  44. :param start_points: 所有每个周期开始点,叶片前缘突变点。
  45. :param end_points: 叶片后缘突变点。
  46. :param fs: 采样频率。
  47. """
  48. cutoff_low = 0.01 * fs # 设置低通滤波截止频率
  49. combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time') # 合并DataFrame并按 'time' 列排序
  50. # 检查排序后的数据从end开始,start结束
  51. if combined_df_sorted.iloc[0].equals(start_points.iloc[0]):
  52. combined_df_sorted = combined_df_sorted.iloc[1:]
  53. if combined_df_sorted.iloc[-1].equals(end_points.iloc[-1]):
  54. combined_df_sorted = combined_df_sorted.iloc[:-1]
  55. combined_df_sorted.reset_index(drop=True, inplace=True)
  56. # 将 start_points 中的时间点转换为列表
  57. start_times = combined_df_sorted['time'].tolist()
  58. fft_positive_filters = []
  59. tower_dists = []
  60. # 遍历所有起始时间点
  61. for i in range(0, len(start_times), 2):
  62. # 获取当前起始和结束时间点
  63. start_time = start_times[i] + 0.01 * (start_times[i + 1] - start_times[i])
  64. end_time = start_times[i + 1] - 0.01 * (start_times[i + 1] - start_times[i])
  65. # 根据当前起始时间点和结束时间点对数据进行分段
  66. segment = data[(data['time'] > start_time) & (data['time'] <= end_time)]
  67. mean_point = segment['distance'].mean()
  68. tower_dists.append(mean_point)
  69. tower_dist = np.mean(tower_dists)
  70. return tower_dist
  71. def process_fft(data, fs):
  72. """
  73. 塔筒数据每组低通滤波,求平均得振动分析;
  74. 叶片数据分组高通滤波
  75. :param data: tower_cal计算完成后的数据。
  76. :param fs: 采样频率。
  77. """
  78. cutoff_low = 0.001 * fs # 设置低通滤波截止频率
  79. segment = data.head(int(len(data) * 0.95))
  80. # 确保segment的长度是2的n次幂
  81. desired_length = 2**((len(segment) - 1).bit_length() - 1)
  82. segment = segment.head(desired_length)
  83. segment.loc[:, 'distance_filtered'] = butter_lowpass_filter(segment['distance'], cutoff_low, fs)
  84. # 提取时间序列数据
  85. time_series_filter = segment['distance_filtered'].values # 使用滤波后的距离数据
  86. xf_filter, fft_positive_filter = apply_fft(time_series_filter, fs)
  87. fft_positive_filters_truncated = fft_positive_filter[0:1000]
  88. xf_filter_truncated = xf_filter[0:1000]
  89. # 将 NumPy 数组转换为 Python 列表
  90. fft_y = fft_positive_filters_truncated.tolist()
  91. fft_y_scaled = [x * 1000 for x in fft_y]
  92. fft_y_scaled = [0] + fft_y_scaled
  93. fft_x = xf_filter_truncated.tolist()
  94. fft_x = [0] + fft_x
  95. fft_y_scaled = [0 if a_val < 0.1 else b_val for a_val, b_val in zip(fft_x, fft_y_scaled)]
  96. max_value = max(fft_y_scaled)
  97. max_index = fft_y_scaled.index(max_value)
  98. '''
  99. plt.plot(fft_x, fft_y_scaled, label='Filtered Signal')
  100. plt.xlabel('频率 (Hz)', fontsize=8)
  101. plt.ylabel('振幅 (m)', fontsize=8)
  102. plt.tick_params('x', labelsize=8)
  103. plt.tick_params('y', labelsize=8)
  104. plt.title('Frequency Spectrum', fontsize=12)
  105. plt.legend(fontsize=7)
  106. plt.grid(True)
  107. plt.savefig(f"filter_fft1.png", dpi=110, pil_kwargs={"icc_profile": False})
  108. plt.close()
  109. plt.plot(segment['time'], segment['distance_filtered'], label='Filtered Signal')
  110. plt.xlabel('时间 (s)', fontsize=8)
  111. plt.ylabel('振幅 (m)', fontsize=8)
  112. plt.tick_params('x', labelsize=8)
  113. plt.tick_params('y', labelsize=8)
  114. plt.title('Time-Domain Waveform', fontsize=12)
  115. plt.legend(fontsize=7)
  116. plt.grid(True)
  117. plt.savefig(f"filter_fft2.png", dpi=110, pil_kwargs={"icc_profile": False})
  118. plt.close()
  119. '''
  120. return segment, fft_x, fft_y_scaled, round(fft_x[max_index], 2), round(max_value, 2)