段从武,李亭亭,赵世平
(四川大学 制造科学与工程学院,四川 成都 610065)
数据采集系统(dataacquisitionsystem,DAS)是允许被测对象经过传感器采集和调理,转变为诸如电压、电流、脉冲或其他易被采集的信号之后,再通过特定的方式送入计算机或者微处理器供处理或存储的测量系统。数据采集是工业自动化技术的前提,在工业控制和科学研究中具有举足轻重的作用,而数据采集系统的软件模块是保证试验台自动、可靠、高效运行的关键。
根据四川某军工单位的某型飞机特殊零件的测试需求,研制了一套机电液一体化的测控系统。该测控系统中,根据试验要求,存在多种需要采集的信号,包括模拟信号、数字信号、脉冲信号等,根据其采集信号的不同采用不同采集标准的采集卡获取数据是设计该系统的关键所在。本文根据相应的技术协议书的要求,对数据采集系统的软件模块进行了分析,然后采用适配器模式、装饰者模式和单例模式对其进行具体实现,通过这3种设计模式的实际应用效果表明数据采集系统软件模块除拥有较高的可拓展性外,其可靠性、灵活性与复用性也得到了极大的提高。
设计模式是软件设计经验的总结,它允许直接复用他人已经成功使用过的设计和体系结构,并能快速做出有利于系统复用、扩展的选择[1]。
适配器模式属于结构型模式,它将一个类的接口转换成用户需要的接口[2],并让原本接口不兼容的类协同工作[3]。适配器模式可以分为对象适配器和类适配器,由于类适配器需要适配器继承目标类与适配者类,而对象适配器对适配者类应用动态组合的方式使代码具备了更大的灵活性,因此在Java、C#等不能支持多重继承的静态语言中主要使用对象适配器。
适配器模式由Target(目标抽象类)、Adapter(适配器类)和Adaptee(适配者类)三部分组成,其中,Target类中定义了客户所需的接口[4];Adaptee定义了一个已经存在的接口,它包含了客户希望使用的业务方法,此接口需要适配;而Adapter是此模式的核心,它将对Adaptee和Target进行适配。
装饰者模式属于结构型模式,它可以动态地给一个对象增加一些额外的职责[5]。装饰者模式是继承方式的替代手段之一,它使得需要装饰的类和用于装饰的类均可独立变化,增加新的构建类和具体装饰者类都非常方便,较好地遵循面向对象设计的开闭原则[4]。
装饰者模式包含Component(抽象构建)、ConcreteComponent(具体构建)、Decorator(抽象装饰类)和ConcreteDecorator(具体装饰类)。Component是ConcreteComponent和Decorator的共同基类,借助它可以使客户端以一致的方式处理装饰前后的对象;ConcreteComponent是Component的子类;Decorator是Component的子类,用于给具体构建类增加职责,同时它维护一个指向Component的引用,通过该引用可以调用装饰之前构件对象的方法,并通过子类扩展该方法,以达到装饰的目的;ConcreteDecorator是Decorator的子类,负责向构建添加新的职责。
单例模式属于创建型模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例[6]。借助此模式,不但可以方便对实例个数进行控制,而且可避免系统同一时刻存在多个状态。单例模式按其实现形式可以分为“饿汉式”单例模式和“懒汉式”单例模式两类,其中,“饿汉式”单例模式在类加载时就实例化单例类,而“懒汉式”单例模式则在第一次调用时才实例化单例类[7]。因此,对系统初始化时就需要的资源而言一般采用“饿汉式”单例模式[6]。
单例模式仅由一个类组成。它能够自行创建程序中唯一的实例,并让客户端通过一个共有的静态方法使用这个唯一的实例[8]。
在某试验台的DAS系统中需要采集多种不同类型的信号,且同一类型的信号还有不同的采集速率的要求,因此采用了多个生产厂家的采集卡构建了此系统。不同的采集卡厂商提供了各式各样的API让用户通过编程操作设备,但是,如果让测控软件直接调用API函数,则程序会依赖于底层的采集模块,如果出现采集信号频率发生变化等原因导致需求改变进而更换相应的采集卡时,则程序有大量代码需要重新编写,不利于保证程序的可维护性和扩展性,也不符合面向对象的依赖倒置原则。因此,设计中采用了适配器模式对厂家提供的API函数进行封装,以便软件的其他模块进行调用,并让程序其他模块依赖于抽象接口。
基于适配器模式的采集模块类图如图1所示,在此仅以HSLAI16AO2为例进行说明。HSL类是凌华公司提供的操控采集设备的API,属于Adaptee;AbstractDevice类为Target,高层模块通过操作该抽象类提供的接口来操作底层的采集设备。在AbstractDevice类中定义了Open、IsReady、Read等5种虚方法作为高层模块操作底层采集设备的接口,其中,Open方法中封装了采集卡的初始化、参数配置等方法,通过调用此方法可以完成采集设备的启动工作;IsReady方法用于判断采集卡是否可以开始工作;Read方法用于获取采集卡的数据,其中,data用于存放读到的数据,length用来表示需要获取数据的长度;Write方法用于向采集卡输出数据进而控制外接设备;Close方法
图1 基于适配器模式的采集模块类图
中封装了停止采集和关闭采集设备等方法,用于程序退出之前关闭采集卡。DeviceHSLAI16AO2类为Adapter,它继承自AbstractDevice并持有一个对HSL类的引用,通过调用HSL中的相应方法来重写AbstractDevice中的5种方法,进而实现操作采集卡的最终目的。若DAS中需要加入新的采集卡,则只需添加一个新类,让其继承AbstractDevice并引用厂家提供的库函数来重写以上5种虚方法即可,无需对上层软件代码进行修改。
通过采用适配器模式对采集模块进行封装设计之后,首先,避免了该测控系统的高层模块直接依赖于采集卡厂商提供的库函数,当需要更换采集卡或增加新的采集卡时,不需要对代码进行大范围的修改,从而增强了此试验台测控系统软件的灵活性和维护性;其次,可以同时对上层软件和底层适配器进行编写,极大提高了软件的开发效率。
试验台的采集卡采集到数据之后需要对其按照一定的换算关系式进行运算处理;与此同时,在工厂环境中模拟信号采集卡采集到的数据含有噪声信号,为减少噪声信号对试验台控制的影响,不仅需要从硬件上对其进行隔离,而且软件上也需要使用相应的滤波算法进行处理;此外,随着新的需求出现,今后可能需要对采集卡采集到的数据进行校准等操作。因此,DAS的软件模块应该具备在不影响整个程序结构的前提下应对今后新需求的能力。
采用装饰者模式的类图如图2所示,其中DeviceHSLAI16AO2与DeviceDataProcess均继承自AbstractDevice类,DeviceDataProcess类中的dataProcessObject持有一个AbstractDevice的引用,Filter类则继承自DeviceDataProcess并重写基类中的ReadData方法,程序运行时当需要对数据进行滤波处理时则用Filter类包装DeviceHSLAI16AO2类的数据,然后调用ReadData方法即可。若以后需要添加新的数据处理功能时只需要添加一个新类,并让其继承DeviceDataProcess并重写ReadData方法即可。
通过采用装饰者模式对采集模块进行设计之后,可以较灵活地对采集到的数据进行必要的处理;同时,在不改变原有代码结构体系的情况下,允许今后对数据进行进一步的运算处理和改变数据处理方法的调用顺序,符合了面向对象的“开闭原则”。
图2 基于装饰者模式的数据处理方法类图
试验台的测控系统中每一块采集卡的实例应该只有一个,否则,如果测控系统中存在多个独立的对象,则会造成采集设备的误操作和数据采集、设备管理的混乱,进而影响试验台的正常运行。因此,为了避免此类问题,采用单例模式是最佳的选择。
在DAS模块中,设计了一个DeviceManager类对所有采集设备进行管理,由于设备管理一直贯穿整个测控软件的整个生命周期,所以采用饿汉单例模式进行设计,使其在DeviceManager类加载时就实例化唯一的一个对象。按单例模式设计的类图如图3所示。当高层模块需要对采集卡进行读写操作时,可以通过调用GetInstance方法直接使用DeviceMangaer的实例对采集设备进行间接操作,该类包含了一个私有容器类(deviceIndex)用于存储实例化的设备,将其类型声明为ImmutableDictionary
通过采用单例模式对数据采集系统软件模块进行设计之后,可以保证采集卡的对象只有开始时实例化一次并容易对它们进行统一管理,同时又方便高层组件获取设备对象进行相应操作[9]。
最终数据采集系统软件模块的类图如图4所示,此DAS软件模块充当低层组件,高层软件模块持有一个对DeviceManager的引用,通过此引用可以调用相应采集卡对象进行对应的数据读取操作,其关键伪代码如下:
doubledata=0;
AbstractDeviceai16AO2=newDeviceHSLAI16AO2(); //实例化采集卡
ai16AO2.Open(null); //null表示使用默认参数启动采集卡
AbstractDevicefilter=newFilter(ai16AO2); //用滤波算法来装饰采集卡采集的数据
filter.Type=EnumDevice.AI16AO2;
DeviceManager.GetInstance().Add(filter); //添加采集设备
DeviceManager.GetInstance().DeviceAtIndex(EnumDevice.AI16AO2).ReadData(refdata,1); //设备调用,获得经过滤波处理的数据
图3 基于单例模式的设备管理类图
图4 DAS软件模块最终类图
设计模式是解决软件开发过程中常见问题的有效手段,开发人员可以直接借鉴已有的成熟解决方案来解决实际编程问题。通过软件的开发和实际使用效果表明对DAQ系统软件模块采用适配器模式、装饰者模式和单例模式进行综合设计。首先,成功解决了系统上层软件模块对采集设备对应的库函数耦合度高、使用复杂、管理混乱的问题,为构建高可靠、易维护、可扩展的测控系统软件夯实了基础;其次,为今后数据处理留下了较大的扩展空间,方便添加新的数据处理功能;最后,若今后的测控系统开发中采用相同的采集设备,则可直接使用此模块,实现了代码的有效复用。