摘要
示波器是一种用来将电信号转化为可视化图形的智能仪器,在物理学中尤为常见。20世纪70年代以来,微电子技术和微信计算机技术的快速发展,使电子仪器的整体水平发生了很大变化。自微处理器问世后,先后出现了独立式智能仪器及自动测试系统、个人仪器系统。随着个人计算机算力的不断增强,虚拟化成为电子仪器的一个发展方向。本文用社区版qt creator5.0.2软件设计制作了示波器虚拟软件,由于时间仓促,仅实现了部分基本功能,仅供参考。
关键词:示波器;虚拟仪器;虚拟软件;
1. Qt
Qt是常用的一种ui设计软件,包含了大量的控件类,并以直观的方式展示出来。同时,其附带的Qt Designer 可以从左边的控件类库直接拖动控件到设计面板,所见即所得,大大节省了计算坐标优化窗口界面布局的工作,而且里面的控件风格都比较现代,更有美感。
1.1 Qt Creator 5.0.2 Community
Qt是一款商业软件,所以用于商业盈利涉及版权问题。但是对于非盈利个人也有社区开源版——Qt Creator 5.0.2 Community,本人用的是5.0.2版本。不附安装教程,CSDN内相关资料很多。 Qt Creator 5.0.2 Community欢迎界面: 
1.2 创建Qt工程
点击"Project"边上的"+New"创建新的工程。 
原本是打算用C++的,但是考虑到要用到画图功能,所以改注意用Python。在新建工程中选择"Applicaton(Qt for Python)",然后再选择"Qt for Python - Window(UI file)",这是生成一个Windows桌面软件的工程,默认自带了一个空的ui文件。  这里输入工程名称、选择工程创建路径。  来到这一步,可以不改。但是我想创建一个主窗口,所以"Base class"我改成了"QMainWindow"。  后面都可以一路"Next"。
1.3 UI设计
可以使用项目自动生成的.ui文件进行设计,需要额外的ui时可以新建文件,选择ui类型的文件。如下图:  一顿操作猛如虎,就得到了如下的ui界面: 
1.4 ui文件转py文件
因为前面生成的是.ui文件,在python文件中是不能直接调用的。所以我们需要将.ui文件转为.py文件,方便import。
这时需要启动Terminal,然后cd命令转到设计好的.ui文件所在的文件目录下,输入如下指令:
pyuic5 -o filename.py filename.ui
前面filename是.ui文件名,后一个filename是目标文件名。这样我们就得到了ui界面的py文件。下面就是开始编写代码了。
2. 程序
2.1 import
from numpy import *
from matplotlib import pyplot
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5.QtWidgets import QApplication,QMainWindow,QGridLayout,QGraphicsScene,QSizePolicy,qApp
import win32api
import win32con
from PyQt5 import QtCore,QtGui
import sys
import MainWindow
2.2 窗口类
class MainWin(QMainWindow,MainWindow.Ui_MainWindow):
def __init__(self):
super(MainWin,self).__init__()
self.setupUi(self)
self.setWindowTitle("简易示波器")
开始想到将控件在main()函数里实现功能,但后来发现,面向对象编程才是最方便的,也是逻辑最清晰的,所以将控件的功能函数作为成员函数来实现。
class MainWin(QMainWindow,MainWindow.Ui_MainWindow):
def __init__(self):
super(MainWin,self).__init__()
self.setupUi(self)
self.setWindowTitle("简易示波器")
self.F=MyPicture(X1,dX,C,A)
self.setWindowIcon(QtGui.QIcon("./OSC.ico"))
self.gridlayout = QGridLayout(self.groupBox_2)
self.gridlayout.addWidget(self.F,0,1)
self.dial_4.setValue(100)
self.dial_5.setValue(20)
self.dial_6.setValue(20)
self.pushButton_3.clicked.connect(self.ResetKey)
self.horizontalSlider_3.sliderMoved.connect(self.t1_slide)
self.horizontalSlider_4.sliderMoved.connect(self.t2_slide)
self.dial_6.valueChanged.connect(self.TimerMove)
self.lineEdit.setPlaceholderText("在这里输入自定义函数")
self.dial_5.valueChanged.connect(self.AmpliMove)
self.dial_7.valueChanged.connect(self.XaxisMove)
self.dial_4.valueChanged.connect(self.YaxisMove)
self.actionExit.triggered.connect(qApp.quit)
self.actionSin_x.triggered.connect(self.actSin_x)
self.actionxsin_x.triggered.connect(self.actxsin_x)
self.actionSquare_Wave.triggered.connect(self.actSquareWave)
self.actionTriangle_Wave.triggered.connect(self.actTriangleWave)
self.actionSawtooth_Wave.triggered.connect(self.actsawtoothWave)
self.pushButton.clicked.connect(self.actMyselfWaveInput)
self.radioButton_3.clicked.connect(self.CH1Pross)
self.radioButton_4.clicked.connect(self.CH2Pross)
成员函数主要有以下内容,由于作业为提交,这里就暂不放完整源代码了。 
2.3 信号类VirtualSignal
class VirtualSignal():
def __init__(self):
def changesig(self):
def changesigA(self):
def changesigC(self):
此类在MainWin类中实现,用于描述信道信号,便于操作信号。
2.4 画布类
class MyFigure(FigureCanvas):
def __init__(self,parent=None):
fig=Figure(figsize=(77,50),dpi=100)
super(MyFigure,self).__init__(fig)
self.axes=fig.add_subplot(111)
self.compute_initial_figure()
self.setParent(parent)
FigureCanvas.setSizePolicy(self,QSizePolicy.Expanding,QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
2.5 图像类
class MyPicture(MyFigure):
def __init__(self,x1,dx,c,a):
super(MyPicture,self).__init__()
self.x1=x1
self.dx=dx
self.x2=self.x1+self.dx
CH1=VirtualSignal(a,c)
CH2=VirtualSignal(a,c)
self.CH=[CH1,CH2]
self.xindao=0
self.t1=T1
self.t2=T2
self.update_figure()
def changex(self):
def changeTimer(self):
def changeC(self):
def changeA(self):
def t1SlideChange(self):
def t2SlideChange(self):
def changesignal(self):
def update_figure(self):
这里就体现了类的优点,每个对象的函数都定义在了类里,这样就不会使main函数过于臃肿,而且当需要修改类的成员时,也不需要整个文件修改,只需要在类里修改,条理清晰,更为整洁。
2.6 全局变量
X1=0.0
dX=20.0
C=0.0
A=1.0
T1=0
T2=100
SineWave="sin(x)"
xcosWave="cos(x)*x"
xsinWave="sin(x)*x"
SquareWave="where(x%4.0<2,-1.0,1.0)"
TriangleWave="where(x%8<=4,x%8,8-x%8)"
SawToothWave="where(x%6<6,x%4,0)"
2.7 主函数
mian函数主要作用是将窗口类实现,其余相关操作都以成员函数的方式定义在了相应的类里,这样,main函数就简单了不少。
if __name__ == '__main__':
app = QApplication(sys.argv)
ui=MainWin()
ui.show()
sys.exit(app.exec_())
最终,整个程序的结构如下: 
3. 结果
 一开始的想法是制作动态的图像,但是由于让图像保持动态无法避免地导致计算机重复刷新而使其他操作的相应卡顿,所以最终选择了静态。也可以尝试动态,只需要修改图像类和画布类即可。参照这篇文章可以实现动态效果。
由于这是作业尚未提交,暂不附源代码,有问题欢迎沟通。
|