python实现一个示波器仿真,可以改参数同步效果

article/2025/8/24 20:39:43

代码

import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.animation import FuncAnimation
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QLabel, QSplitter, QGroupBox, QGridLayout, QDoubleSpinBox, QSpinBox, QCheckBox)
from PyQt5.QtCore import Qt# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]# 初始化日志列表
log_messages = []
class WaveformApp(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("动态波形图")self.resize(1000, 700)# 创建中心部件central_widget = QWidget()self.setCentralWidget(central_widget)# 创建主布局main_layout = QVBoxLayout(central_widget)# 创建水平分割器(参数面板和波形/日志)main_splitter = QSplitter(Qt.Horizontal)# 创建参数控制面板self.create_parameter_panel()main_splitter.addWidget(self.param_panel)# 创建右侧垂直分割器(波形和日志)right_splitter = QSplitter(Qt.Vertical)# 创建图形区域self.fig, self.ax = plt.subplots(figsize=(8, 5))self.canvas = FigureCanvas(self.fig)toolbar = NavigationToolbar(self.canvas, self)# 创建公式显示区域self.formula_label = QLabel()self.formula_label.setStyleSheet("font-size: 14pt; font-weight: bold;")# 波形参数self.params = {'amplitude': 1.0,       # 振幅'frequency': 1.0,       # 频率(Hz)'phase': 0.0,           # 相位(弧度)'noise': 0.5,           # 噪声强度'time_range': 10.0,     # 时间范围(秒)'num_points': 1000,     # 采样点数'speed': 0.1            # 动画速度因子}# 现在可以安全地更新公式显示self.update_formula_display()# 创建日志区域log_widget = QWidget()log_layout = QVBoxLayout(log_widget)log_label = QLabel("操作日志:")self.log_text = QTextEdit()self.log_text.setReadOnly(True)log_layout.addWidget(log_label)log_layout.addWidget(self.log_text)# 添加到右侧分割器formula_frame = QWidget()formula_layout = QVBoxLayout(formula_frame)formula_layout.addWidget(self.formula_label)right_splitter.addWidget(self.canvas)right_splitter.addWidget(formula_frame)right_splitter.addWidget(log_widget)right_splitter.setSizes([400, 50, 200])# 添加到主分割器main_splitter.addWidget(right_splitter)main_splitter.setSizes([250, 750])# 添加到主布局main_layout.addWidget(toolbar)main_layout.addWidget(main_splitter)# 初始化数据和图形self.t, self.data = self.init_data()self.line, = self.ax.plot(self.t, self.data)self.ax.set_xlabel('时间 (秒)')self.ax.set_ylabel('幅度')self.ax.set_title('动态波形图')self.fig.tight_layout()# 创建动画self.paused = Falseself.ani = FuncAnimation(self.fig, self.update, frames=range(1000), interval=100, repeat=True, blit=True)def create_parameter_panel(self):self.param_panel = QGroupBox("波形参数")param_layout = QGridLayout(self.param_panel)# 创建参数控件row = 0# 振幅param_layout.addWidget(QLabel("振幅:"), row, 0)self.amplitude_spin = QDoubleSpinBox()self.amplitude_spin.setRange(0.1, 5.0)self.amplitude_spin.setValue(1.0)self.amplitude_spin.setSingleStep(0.1)self.amplitude_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.amplitude_spin, row, 1)row += 1# 频率param_layout.addWidget(QLabel("频率 (Hz):"), row, 0)self.frequency_spin = QDoubleSpinBox()self.frequency_spin.setRange(0.1, 5.0)self.frequency_spin.setValue(1.0)self.frequency_spin.setSingleStep(0.1)self.frequency_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.frequency_spin, row, 1)row += 1# 相位param_layout.addWidget(QLabel("相位 (弧度):"), row, 0)self.phase_spin = QDoubleSpinBox()self.phase_spin.setRange(0.0, 2*np.pi)self.phase_spin.setValue(0.0)self.phase_spin.setSingleStep(0.1)self.phase_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.phase_spin, row, 1)row += 1# 噪声强度param_layout.addWidget(QLabel("噪声强度:"), row, 0)self.noise_spin = QDoubleSpinBox()self.noise_spin.setRange(0.0, 2.0)self.noise_spin.setValue(0.5)self.noise_spin.setSingleStep(0.1)self.noise_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.noise_spin, row, 1)row += 1# 时间范围param_layout.addWidget(QLabel("时间范围 (秒):"), row, 0)self.time_range_spin = QDoubleSpinBox()self.time_range_spin.setRange(1.0, 30.0)self.time_range_spin.setValue(10.0)self.time_range_spin.setSingleStep(1.0)self.time_range_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.time_range_spin, row, 1)row += 1# 采样点数param_layout.addWidget(QLabel("采样点数:"), row, 0)self.num_points_spin = QSpinBox()self.num_points_spin.setRange(100, 5000)self.num_points_spin.setValue(1000)self.num_points_spin.setSingleStep(100)self.num_points_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.num_points_spin, row, 1)row += 1# 动画速度param_layout.addWidget(QLabel("动画速度:"), row, 0)self.speed_spin = QDoubleSpinBox()self.speed_spin.setRange(0.01, 1.0)self.speed_spin.setValue(0.1)self.speed_spin.setSingleStep(0.01)self.speed_spin.valueChanged.connect(self.on_param_changed)param_layout.addWidget(self.speed_spin, row, 1)row += 1# 显示网格self.grid_check = QCheckBox("显示网格")self.grid_check.setChecked(True)self.grid_check.stateChanged.connect(self.on_param_changed)param_layout.addWidget(self.grid_check, row, 0, 1, 2)row += 1# 暂停/继续按钮self.pause_button = QCheckBox("暂停动画")self.pause_button.stateChanged.connect(self.toggle_pause)param_layout.addWidget(self.pause_button, row, 0, 1, 2)def on_param_changed(self):# 更新参数self.params['amplitude'] = self.amplitude_spin.value()self.params['frequency'] = self.frequency_spin.value()self.params['phase'] = self.phase_spin.value()self.params['noise'] = self.noise_spin.value()self.params['time_range'] = self.time_range_spin.value()self.params['num_points'] = self.num_points_spin.value()self.params['speed'] = self.speed_spin.value()# 更新网格显示self.ax.grid(self.grid_check.isChecked())# 重新初始化数据self.t, self.data = self.init_data()self.line.set_data(self.t, self.data)self.ax.set_xlim(0, self.params['time_range'])# 更新公式显示self.update_formula_display()# 重绘图形self.canvas.draw()log_msg = "参数已更新"log_messages.append(log_msg)self.update_log(log_msg)def toggle_pause(self, state):self.paused = state == Qt.Checkedlog_msg = "动画已暂停" if self.paused else "动画已恢复"log_messages.append(log_msg)self.update_log(log_msg)def update_formula_display(self):# 显示当前使用的数学公式formula = f"y(t) = {self.params['amplitude']:.1f} × sin(2π × {self.params['frequency']:.1f}t + {self.params['phase']:.1f}) + {self.params['noise']:.1f} × 随机噪声"self.formula_label.setText(formula)def init_data(self):t = np.linspace(0, self.params['time_range'], self.params['num_points'])data = self.params['amplitude'] * np.sin(2 * np.pi * self.params['frequency'] * t + self.params['phase'])data += self.params['noise'] * np.random.randn(len(t))log_msg = f"数据已重新生成: 时间范围={self.params['time_range']}秒, 点数={self.params['num_points']}"log_messages.append(log_msg)self.update_log(log_msg)return t, datadef update(self, frame):if self.paused:return self.line,# 计算新数据new_data = self.params['amplitude'] * np.sin(2 * np.pi * self.params['frequency'] * self.t + self.params['phase'] + frame * self.params['speed'])new_data += self.params['noise'] * np.random.randn(len(self.t))self.line.set_ydata(new_data)log_msg = f"第{frame}帧更新,生成新的波形数据"log_messages.append(log_msg)self.update_log(log_msg)return self.line,def update_log(self, message):self.log_text.append(message)# 滚动到底部cursor = self.log_text.textCursor()cursor.movePosition(cursor.End)self.log_text.setTextCursor(cursor)def main():app = QApplication(sys.argv)window = WaveformApp()window.show()sys.exit(app.exec_())if __name__ == "__main__":main()    


http://www.hkcw.cn/article/OjSNdYsjol.shtml

相关文章

【前端】使用grid布局封装断点式进度条

业务需求要求展示一个动态进度条,不同于第三方插件的进度条,这个ui设计的是断点式进度条,效果当然是美观大方,但是因为没有现成的第三方插件可以实现,这当然难不倒一个成熟的前端开发工程师。 根据ui设计可以看到进度条…

[ctfshow web入门] web78

信息收集 表面上没有任何过滤,自由发挥 if(isset($_GET[file])){$file $_GET[file];include($file); }else{highlight_file(__FILE__); }解题 这些解法都在web32解释过,不再详细解释,有需要点击超链接:[ctfshow web入门] web3…

小白的进阶之路系列之六----人工智能从初步到精通pytorch数据集与数据加载器

本文将介绍以下内容: 数据集与数据加载器 数据迁移 如何建立神经网络 数据集与数据加载器 处理数据样本的代码可能会变得混乱且难以维护;理想情况下,我们希望我们的数据集代码与模型训练代码解耦,以获得更好的可读性和模块化。PyTorch提供了两个数据原语:torch.utils…

Memory Repair (二)

Implementing BIRA and BISR Logic 本节介绍如何在 circuit 中插入 repair logic。重点是插入 BISR 逻辑。只要内存库文件中存在 RepairAnalysis 包装器,并且该实例的 repair_analysis_present 属性未设置为 “Off”,就会在内存 BIST 逻辑(控…

Vue 3 的路由管理

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、简易路由器二、Vue Router创建路由器使用路由器创建页面前言 路由指的是通过不同 URL 访问不同页面的方式。 根据路由管辖权的归属不同,可以分为前端路由(Client-Side Routing)和后端路由(Server-Side Routing)。…

油猴脚本开发基础

1. 油猴脚本深度解析 1.1 什么是油猴脚本? 本质:基于JavaScript的浏览器扩展脚本工作原理:在网页加载时注入自定义JS代码核心能力: 修改DOM结构拦截网络请求操作浏览器API存储本地数据 应用场景: 广告屏蔽网页功能增…

练习:对象数组 1

定义数组存储 3 个商品对象。商品的属性:商品的 id,名字,价格,库存。创建三个商品对象,并把商品对象存入到数组当中。 //对象数组 1 package demo01; public class Goods {private int goodsid;private String goodsN…

Baklib知识中台驱动业务创新

知识中台构建四库体系 Baklib通过打造知识资源库、案例库、规则库及专家库四大核心模块,构建起企业级知识中台的底层架构。其中,知识资源库采用多维度标签体系对文档、报告等结构化与非结构化数据进行分类存储;案例库通过智能抽取技术沉淀业…

“文化人”董宇辉也学会了表演 为消费者争取福利

“文化人”董宇辉也学会了表演 为消费者争取福利。董宇辉在直播间开始“表演”与品牌商谈判的戏码。最近,他在销售某品牌电视时,商家表示要收取最高200元的安装费。董宇辉当场拒绝,表示不合理,并坚持不接受收费。最终,商家负责人现场沟通后决定为所有购买电视的朋友免费安…

H5通用模态框可滚动弹框

弹框要求&#xff1a; 1、弹框图片宽高不限制&#xff0c;自适应 2、关闭按钮固定在图片下方 3、长图时弹框图片可滚动&#xff0c;遮罩层固定 4、点击遮罩层可关闭按钮&#xff0c;不冒泡 图例&#xff1a; 代码 <div class"image-modal" v-if"curSideI…

代码随想录打卡|Day51 图论(dijkstra(堆优化版)精讲、Bellman_ford 算法精讲)

图论part09 dijkstra&#xff08;堆优化版&#xff09;精讲(不熟悉) 代码随想录链接 题目链接 import java.util.*;class Edge {int to; // 邻接顶点int val; // 边的权重Edge(int to, int val) {this.to to;this.val val;} }class MyComparison implements Comparator<…

RS232/485转Profinet网关通讯气体检漏仪案例分享

RS232/485转Profinet网关通讯气体检漏仪案例分享 RS232转Profinet网关作为一种重要的工业通讯设备&#xff0c;其作用是将传统的RS232接口设备转换为现代的Profinet接口&#xff0c;从而实现与现代自动化控制系统的无缝对接&#xff0c;提高系统的集成度和性能。 气体检漏仪作…

电感专题归纳

文章目录 6.2.1 概念6.2.1x 电感电流6.2.2 储能6.2.3 伏秒原则6.2.4 电感元件6.2.5 电感充放电 6.3 换路定则6.4 储能总结6.5 串并联6.5.1 电容串联6.5.2 电容并联6.5.4 电感串联6.5.5电感并联6.5.3 电容与电导 6.6 电容与电感的滤波 电感在电路中的坐拥只有两个字&#xff0c;…

2023-ICLR-ReAct 首次结合Thought和Action提升大模型解决问题的能力

关于普林斯顿大学和Google Research, Brain Team合作的一篇文章, 在语言模型中协同Reasoning推理和Action行动。 论文地址&#xff1a;https://arxiv.org/abs/2210.03629 代码&#xff1a;https://github.com/ysymyth/ReAct.git 其他复现 langchain &#xff1a;https://pytho…

吴艳妮落泪道歉 带伤参赛憾失金牌

5月29日,在亚洲田径锦标赛女子100米栏决赛中,吴艳妮以13秒07的成绩获得铜牌。赛后她走路有些一瘸一拐。在接受采访时,吴艳妮哽咽着向大家道歉:“很感谢你们来现场为我加油,没为中国队拿到这个冠军,很对不起大家。我的伤还没养好,不想为自己过多的解释,我还是觉得我在亚…

群辉(synology)NAS老机器连接出现网页端可以进入,但是本地访问输入一样的账号密码是出现错误时解决方案

群辉&#xff08;synology&#xff09;NAS老机器连接出现网页端可以进入&#xff0c;但是本地访问输入一样的账号密码是出现错误时解决方案 老机器 装的win7 系统 登入后端网页端的时候正常&#xff0c;但是本地访问登入时输入登入网页端一样的密码时候出现问题解决方案 1.登…

力扣每日一题——连接两棵树后最大目标节点数目 ||

目录 题目链接&#xff1a;3373. 连接两棵树后最大目标节点数目 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 解法一&#xff1a;​​双树贡献分离法​​ Java写法&#xff1a; C写法&#xff1a; 运行时间 时间复杂度和空间复杂度 总结 题目链接&#xff1a;…

国芯思辰| 国产四通道24位生理电采集模拟前端AFE全面替换ADS1294R,心电贴性能再飞跃

心电贴作为一种便捷的可穿戴医疗设备&#xff0c;能够实时、连续地监测心电信号&#xff0c;为心脏健康保驾护航。其中高性能、低功耗的AFE芯片是关键核心部件&#xff0c;集成国产四通道24位AFE的三导联心电贴&#xff0c;不仅更小、更轻、还更准、续航更长、监测维度更多&…

Linux线程池(上)(33)

文章目录 前言一、线程池的概念池化技术线程池的优点线程池的使用场景 二、线程池的实现v1版本v2版本 总结 前言 终于要结束了&#xff0c;写完这篇再来篇有关锁的文章&#xff0c;我们就可以结束 Linux系统编程 部分啦&#xff01; 线程池是一种管理线程的机制&#xff0c;它可…

Python 之图片添加时间戳水印

依赖安装 pip install pillow 原图 随便找个图片作为原图即可&#xff08;比如截图一个桌面背景图&#xff09;。 test.png 添加水印 from PIL import Image, ImageDraw, ImageFont import datetimedef add_timestamp_watermark(image_path, font_size24):# 打开图片imag…