import sys
import numpy as np
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton
from PySide2.QtCore import QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import random
import time
class DataSimulator:
"""模拟ADXL345传感器数据生成器"""
def __init__(self, file_path=None):
self.file_path = file_path
if file_path:
try:
with open(file_path, 'r') as f:
self.data_lines = f.readlines()
self.index = 0
print(f"从文件加载了{len(self.data_lines)}条模拟数据")
except FileNotFoundError:
print("模拟数据文件未找到,将生成随机数据")
self.data_lines = None
else:
self.data_lines = None
def read_data(self):
"""读取模拟数据点"""
if self.data_lines and self.index < len(self.data_lines):
line = self.data_lines[self.index].strip()
self.index += 1
if self.index >= len(self.data_lines):
self.index = 0 # 循环读取
try:
return [float(x) for x in line.split()]
except Exception as e:
print(f"数据解析错误: {e}, 行内容: {line}")
return [0.0, 0.0, 0.0]
else:
# 生成包含多种频率成分的随机数据
t = time.time()
return [
0.5 * np.sin(2 * np.pi * 5 * t) + 0.3 * np.random.randn(),
0.8 * np.sin(2 * np.pi * 12 * t) + 0.2 * np.random.randn(),
1.0 * np.sin(2 * np.pi * 2 * t) + 0.4 * np.random.randn()
]
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("ADXL345数据采集系统")
self.setGeometry(100, 100, 1200, 800)
# 初始化参数
self.sampling_rate = 100 # 采样率 (Hz)
self.buffer_size = 100 # 数据缓冲区大小(显示1秒数据)
self.is_collecting = False
self.data_buffer = [] # 存储原始数据
self.last_fft_update = 0 # 上次FFT更新时间
# 创建模拟数据源
self.data_simulator = DataSimulator("sensor_data.txt")
# 创建UI
self.init_ui()
# 初始化数据缓冲区
self.reset_buffers()
# 设置定时器
self.timer = QTimer()
self.timer.timeout.connect(self.update_data)
def init_ui(self):
"""初始化用户界面"""
main_widget = QWidget()
main_layout = QVBoxLayout()
# 按钮区域
btn_layout = QHBoxLayout()
self.start_btn = QPushButton("开始采集数据")
self.stop_btn = QPushButton("停止采集数据")
self.start_btn.clicked.connect(self.start_collection)
self.stop_btn.clicked.connect(self.stop_collection)
self.stop_btn.setEnabled(False)
btn_layout.addWidget(self.start_btn)
btn_layout.addWidget(self.stop_btn)
main_layout.addLayout(btn_layout)
# 图表区域
fig_layout = QHBoxLayout()
# 原始数据图表
self.raw_fig = Figure(figsize=(10, 4))
self.raw_canvas = FigureCanvas(self.raw_fig)
self.ax_raw = self.raw_fig.add_subplot(111)
self.ax_raw.set_title("原始加速度数据")
self.ax_raw.set_xlabel("时间 (ms)")
self.ax_raw.set_ylabel("加速度 (g)")
self.ax_raw.grid(True)
# 初始化三条曲线
self.raw_lines = [
self.ax_raw.plot([], [], 'r-', label='X轴')[0],
self.ax_raw.plot([], [], 'g-', label='Y轴')[0],
self.ax_raw.plot([], [], 'b-', label='Z轴')[0]
]
self.ax_raw.legend()
fig_layout.addWidget(self.raw_canvas)
# FFT数据图表
self.fft_fig = Figure(figsize=(10, 4))
self.fft_canvas = FigureCanvas(self.fft_fig)
self.ax_fft = self.fft_fig.add_subplot(111)
self.ax_fft.set_title("FFT频谱分析")
self.ax_fft.set_xlabel("频率 (Hz)")
self.ax_fft.set_ylabel("幅度")
self.ax_fft.grid(True)
# 初始化FFT曲线
self.fft_lines = [
self.ax_fft.plot([], [], 'r-', label='X轴')[0],
self.ax_fft.plot([], [], 'g-', label='Y轴')[0],
self.ax_fft.plot([], [], 'b-', label='Z轴')[0]
]
self.ax_fft.legend()
fig_layout.addWidget(self.fft_canvas)
main_layout.addLayout(fig_layout)
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
def reset_buffers(self):
"""重置数据缓冲区"""
# 使用列表存储三轴数据
self.data_x = np.zeros(self.buffer_size)
self.data_y = np.zeros(self.buffer_size)
self.data_z = np.zeros(self.buffer_size)
# 正确的时间轴计算(单位:毫秒)
self.time_axis = np.linspace(0, 1000, self.buffer_size) # 1秒时间范围
self.last_fft_update = 0
def start_collection(self):
"""开始数据采集"""
self.is_collecting = True
self.start_btn.setEnabled(False)
self.stop_btn.setEnabled(True)
self.reset_buffers()
# 初始绘图
self.update_plots()
# 根据采样率设置定时器 (100Hz => 10ms间隔)
self.timer.start(10)
def stop_collection(self):
"""停止数据采集"""
self.is_collecting = False
self.start_btn.setEnabled(True)
self.stop_btn.setEnabled(False)
self.timer.stop()
def update_data(self):
"""更新数据并刷新图表"""
if not self.is_collecting:
return
# 获取新数据点
new_data = self.data_simulator.read_data()
# 更新数据缓冲区 (先进先出)
self.data_x = np.roll(self.data_x, -1)
self.data_y = np.roll(self.data_y, -1)
self.data_z = np.roll(self.data_z, -1)
self.data_x[-1] = new_data[0]
self.data_y[-1] = new_data[1]
self.data_z[-1] = new_data[2]
# 更新图表
self.update_plots()
# 每0.5秒更新一次FFT (避免频繁计算)
current_time = time.time()
if current_time - self.last_fft_update > 0.5:
self.update_fft()
self.last_fft_update = current_time
def update_plots(self):
"""更新原始数据图表"""
# 更新原始数据曲线
self.raw_lines[0].set_data(self.time_axis, self.data_x)
self.raw_lines[1].set_data(self.time_axis, self.data_y)
self.raw_lines[2].set_data(self.time_axis, self.data_z)
# 调整坐标轴范围
self.ax_raw.set_xlim(0, 1000) # 1秒时间范围
self.ax_raw.set_ylim(-3, 3)
self.raw_canvas.draw()
def update_fft(self):
"""计算并更新FFT图表"""
# 计算FFT
n = len(self.data_x)
freq = np.fft.rfftfreq(n, d=1.0/self.sampling_rate)
# 更新FFT图表
for i, data in enumerate([self.data_x, self.data_y, self.data_z]):
# 移除直流分量
data_no_dc = data - np.mean(data)
# 计算FFT并取绝对值
fft_result = np.abs(np.fft.rfft(data_no_dc))
# 归一化处理
fft_result = fft_result / n * 2
# 更新曲线数据
self.fft_lines[i].set_data(freq, fft_result)
# 调整坐标轴范围
self.ax_fft.set_xlim(0, self.sampling_rate / 2)
# 动态调整Y轴范围
max_amp = max(
np.max(fft_result) if len(fft_result) > 0 else 0,
np.max(self.fft_lines[0].get_ydata()) if len(self.fft_lines[0].get_ydata()) > 0 else 0,
np.max(self.fft_lines[1].get_ydata()) if len(self.fft_lines[1].get_ydata()) > 0 else 0,
np.max(self.fft_lines[2].get_ydata()) if len(self.fft_lines[2].get_ydata()) > 0 else 0
)
y_max = max(0.1, max_amp * 1.2) # 设置合理的Y轴范围
self.ax_fft.set_ylim(0, y_max)
# 重绘图
self.fft_canvas.draw()
def generate_test_data(filename="sensor_data.txt", num_points=5000):
"""生成测试数据文件"""
print(f"生成测试数据到 {filename}...")
with open(filename, 'w') as f:
for i in range(num_points):
# 生成包含多种频率成分的测试数据
t = i / 100.0 # 采样率100Hz
x = 0.5 * np.sin(2 * np.pi * 5 * t) + 0.3 * np.random.randn()
y = 0.8 * np.sin(2 * np.pi * 12 * t) + 0.2 * np.random.randn()
z = 1.0 * np.sin(2 * np.pi * 2 * t) + 0.4 * np.random.randn()
f.write(f"{x:.4f} {y:.4f} {z:.4f}\n")
print(f"已生成 {num_points} 条测试数据")
if __name__ == "__main__":
# 生成测试数据文件
generate_test_data()
# 启动GUI应用
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
以上程序,对应的相关配置是:Python 3.7.9、PyCharm、Qt 5.12.12、Anaconda、PySide2库、numpy库、matplotlib库等相关依赖库。如果,相关配置修改为是:Python 3.9、PyCharm、Qt 5.15.2、Anaconda、PySide2 5.15.2.1、numpy库、matplotlib 3.7.3等相关依赖库。那么,程序需要对应修改吗?请完整输出程序,并详细注释。
最新发布