- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
基于Python的虚拟仪器技术研究及实现
随着计算机技术、测量仪器技术以及软件技术的高速发展,微机以及DSP提供了强大的计算能力使得在一定的实时性要求下,软件可以代替许多原来由硬件完成的功能,这标志着“软件即仪器(The software is the instrument)”时代的到来。它的出现彻底改变了传统的仪器观,开辟了测量技术的新纪元。
虚拟仪器的基本思想是利用计算机来管理仪器、组织仪器系统,进而逐步取代仪器完成各种功能,最终取代传统电子仪器。虚拟仪器实质上是软硬件结合、虚实结合的产物,利用高性能的模块化硬件,结合高效灵活的软件来完成各种测试、测量和自动化的应用。在虚拟仪器系统中,硬件通常仅仅是为了解决信号输入输出,软件才是整个仪器系统的核心所在。
与传统仪器相似,虚拟仪器一般由3部分组成,即数据采集与控制、数据处理与分析、数据显示。传统仪器只是将这3部分功能的部件放在一个仪表机箱里,而虚拟仪器则是功能意义上的仪器,是具有仪器功能的软硬件的组合体,它并不强调物理上的实现形式。虚拟仪器的功能由用户自己定义,仪器制造商只需提供基本的软硬件,如信号调节器、信号转换器等,真正需要什么样的仪器功能是用户自己的事情。虚拟仪器不像传统仪器那样几乎完全依赖硬件。硬件在这里只是为了解决信号的输入输出,软件才是虚拟仪器的关键。虚拟仪器减少了信号每次经过硬件引起的误差,从而测量结果更准确。虚拟仪器价格低,开发和维护费用也比传统仪器低得多,而且技术更新快。
1 基于Python的虚拟仪器开发
美国NI公司推出的图形化虚拟仪器专业开发平台Labview采用独特的图形化编程方式,编程过程简单方便,已经成为目前最受欢迎的虚拟仪器交流开发平台。另外还有惠普公司的HPVEE以及微软开发的Visual C++。但是往往上述的软件在虚拟仪器开发中做不到图像和数据处理两方面兼得。比如Labview在界面开发上有很大的优势,但在数据处理方面不尽人意。而且很多仪器在处理复杂信号的时候需要借助Matlab强大的信号分析处理能力,但是一般仪器厂家提供的分析软件不支持与Matlab的接口,将两者功能进行结合也有难度。另外LabVIEW后期修改程序比较麻烦,一旦要改,改动的地方就比较大,这对于较大型的程序是很不利的。虚拟仪器的使用者更希望能够方便的修改软件配置,满足不同个体的需求,Labview在这一点上有局限性。
Python是一种开源的脚本编程语言,由可移植的ANSI C编写,可以轻松驾驭windows、Linux、Mac等主流操作系统,可移植性极强。同时Python具有强大的扩展性,可以嵌入C/C++编程的程序中,所以也能实现多种语言的混合编程。Python是面向对象(OOP)的编程语言,结构化的或过程性编程可以让我们把程序组织成逻辑块,重复或重用,这一特性应用于虚拟仪器的开发正好可以弥补Labview后期修改程序复杂这一致命问题,同时也是一项有益的探索。Python拥有着丰富的扩展模块和函数库。PYQT可以轻松开发出优质的GUI界面。NumPy相当于Matlab的Python版本,它提供了矩阵、线性代数、傅里叶变换等的解决方法,包含:N维矩阵对象、性代数运算功能、傅里叶变换、Fortran代码集成的工具、C++代码集成的工具。下面主要从对象分解,GUI开发,以及数据处理3个方面进行研究探讨Python在开发虚拟仪器方面的优势及可能潜在的问题。
1.1 对象分解
用面向对象的思想来看待客观事物时会把一个整体看成由许多不同种类的对象组合而成。每一个对象本身有他自己的内部状态和动作,称之为对象本身的属性和操作。不同的对象之间都是相互联系,相互作用的,由此构成了一个完整的整体。
在虚拟仪器的开发过程中我们也可以运用这种思想将一个待开发的仪器整体分解成多个对象的组合,对每一个对象划归为一个整类,然后由这个类衍生出实例类,最后再把一个个的对象个体整合成一个整体,如图1所示。
比如在虚拟仪器开发过程中,通常需要设计各式各样的按钮,包括波形调节、通道选择、波形显示、数据处理等等。如果一个一个地去设计编程,必然大大复杂化了开发进度。在这里,运用面向对象的思想,我们可以把按钮抽象为一个按钮类,并定义其各种一般性的特性,不同大小,不同功能,不同形式的按钮无非只是这个普遍按钮类的一个特殊性实例化。数据处理也是同样的道理,不管是滤波,FFT,卷积,都可以看成是一种数据处理方法类的实例化。这样,一个仪器的开发就被分割成N个对象的设计,最后只需实现各个对象之间的协调作用即可。
1.2 基于PYQT的GUI开发
人性化的用户操作界面(GUI)是虚拟仪器必不可少的一个组成部分。PYQT是Python与QT库的混合体,拥有近300多个类和接近6 000多个函数与方法,于面向对象思想的虚拟仪器开发过程中,对象与对象之间的信息交流、互动尤为重要,也就是所谓的事件处理。任何GUI程序中,事件都是最重要的部分。在PYQT中,采用信号和插槽这一机制来处理事件。当用户点击按钮,拖动滑块等操作时都会产生信号,同时环境也会产生信号,比如时钟的信号,插槽是一种针对信号进行处理的方法。所有从QObject或其子类派生的类都能包含信号和槽,当某个对象的状态发生改变时,相应的信号就由该对象发射(emit)出去,并不需要知道另一端是谁在接受这个信号,从而真正意义上实现信息封装。PY QT的信号与槽机制相当灵活,可以讲多个信号与单个槽相连,也可以将单个信号与多个槽进行相连,甚至一个信号还能与另一个信号相连。 PYQT中将信号与槽相连只需用到QObject类中的connect()方法。创建PYQT界面的几个步骤:
1)使用QtDesigner创建GUI,
2)在属性编辑器中修改部件的名字,
3)通过pyuic4工具生成一个Python类,
4)通过GUI对应的类来运行程序,
5)通过设置自己的slots来扩展功能。
先用QtDesigner生成整体GUI框架,保存为Form.ui文件。Windows下运行cmd,在C根目录调用pyuic4命令:pyuic4 Form.ui>Form.py,将PYQT生成的UI文件转成py文件,然后自定义start.py直接调用生成的py文件,运行start.py就可以显示创建的GUI界面。然后对GUI的每一个控件编辑其对应的信号与槽,比如在文中实例中的“关闭”按钮,调用connect()方法绑定点击按钮的“clicked()”信号与槽函数"close()”,这样当我们鼠标点击“关闭”按钮的时候程序就会退出。与此类似,绑定其余按钮的功能。这里还可以调用:
PyQt4.QtCore.pyqtSignal(types[,name])
创建一个或多个重载绑定信号作为类属性。其中type确定信号的C++识别标志,类型可以是Python类型或C++类型名称的字符串,也可以是类型的一组列表,在列表情况下,每一项定义了不同重载方法,第一项为默认值。Name是信号的名称,如果省略则使用属性的类的名称,这只能作为一个关键字参数。
槽函数(slots)的设置是整个GUI的核心,基于Python面向对象的优势,我们可以调用各种父类,父类方法,自定义类,自定义方法等等作为槽函数与相应的信号相绑定,实现程序的重复利用,并且可以在后期较容易的扩展程序的功能,通过这种代码复用可以大大缩短虚拟仪器开发周期。
1.3 NumPy的数据处理
虚拟仪器一般都会带有显示屏幕,有的仪表显示数字,有的仪表则显示图形。通过软件的形式显示测量结果,一般需要对采集数据进行大量的数学运算,比如信号调幅、调频、滤波、数字信号处理等等,数据处理是虚拟仪器不可或缺的一部分,而且数据处理一般要求高效准确。NumPy相当于Matlab的Python版本,继承了Matlab的强大数据处理能力。NumPy提供两种基本的对象ndarray (N-dimensional arrayobie ct)和ufunc(universal function object)。ndarray是存储单一数据类型的多维数组,而ufunc则是能够对数组进行处理的函数。NumPy的核心是ndarray对象,它是一个封装好的,只能存储同个类型数据的多维数组。NumPy里,数组元素对数组元素的操作是用C写的,并预先编译好了以提高操作速度。NumPy不仅能保证足够快速的计算处理,还继承了Python语言代码简洁的特性。比如需要对一个给定的多维数组x进行FFT变换,只需调用np.fft.fft(x)就可以得到变换的结果。
2 方案设计与验证
基于上述的讨论,设计完成了一个虚拟频谱分析仪,该仪器的工作原理是通过设置仪器相关的参数对采集信号进行实时显示,而后通过滤波加窗等处理进行频域分析,得到幅值谱、相位谱、自相关函数、相干函数等的过程。仪器系统的处理流程如图2所示。
在仪器的波形显示部分,这里调用了Tabwidget控件,通过控制Tabchange()信号实现时域波形和频域波形的显示及切换。Tabwidget本身无法充当画布功能,也就是说不能直接在上面显示波形。因此,在Tabwidget的2个tab标签中分别嵌入一个QwtPlot控件,它可以提供一个二维的坐标图,让我们在上面绘制曲线、刻度值等我们想要表达的图形数据信息。调用setAxisTitlle(xBottom,String)方法和setAxisTitlle(vLeft,Str4ng)方法可以改变坐标轴横坐标及纵坐标的名称。同时还需要创建一个QwtPlotCurve用来控制QwtPlot上的曲线类型,它可以设定线的样式(实线或虚线)、线宽、颜色等。取得需要显示的波形数据后,通过setData()方法,先将数据给予QwtPlotCurve,然后由QwtPlot Curve通过调用attach()方法将波形绘制到QwtPlot上,最后通过QwtPlot类的repoh()方法将波形显示在GUI界面的Tabwidget控件中。
输入信号后,调用combobox控件的GetWindowText()方法取得采样频率,采样点数等参数信息,通过绑定“开始采样”的“clicked()”信号触发相关槽函数将波形显示在窗口上。这里放置了3个RadioButton,并把他们嵌入到Gmup Box里作为一个整体,通过他们的Checked属性,获取相应窗函数信息对信号进行加窗处理,分析。
仪器界面的效果图如图3所示。
3 结束语
Python是一门年轻、开源、充满活力的脚本编程语言。文中以Python为核心,结合PYQT把面向对象思想应用于虚拟仪器开发,使用户可以根据自身需求方便地修改程序以增减仪器的系统功能或规模,而且可以充分实现程序的重复利用。用Python开发虚拟仪器层次清晰,周期短,代码易修改。在一定程度上比LabvIEW具有更大的优势,具有广泛的研究前景。