结构图如图 22所示。 ? 图22? 自然伽马探测结构图 ? 软件系统设计 下位机软件设计 主程序流程图 图23? 主程序流程图 ? 主程序进入之后首先对各模块进行初始化,包括全局变量、单片机I/O口、CAN总线等模块。其后进入系统工作状态判断,根据不同的工作状态,系统执行不同的内容。系统的工作状态由系统和上位机控制切换,上位机是通过命令帧给下位机发送命令。 ? 测井流程图 ? 图24? 测井流程图 在测井状态中,单片机控制IGBT全桥电路产生125ms的正向脉冲,根据不同的时刻控制可编程放大的倍数并进行A/D采样。采样结束后单片机控制IGBT全桥电路再次产生125ms的负向脉冲,同时通过CAN总线向上位机发送测井数据帧,如果100ms内未发送成功则返回发送失败标志并推出发送。负向脉冲后重复放大和采样,并发送测井数据帧。最后判断是否有发送失败的测井数据帧,并发送失败的数据帧。 ? CAN总线数据处理流程图 系统采用PIC32MX的CAN1模块,波特率设为100kbps,分别使用2个32个报文深的FIFO作为发送和接收FIFO,采用接收中断的方式来接收上位机的数据。在接收中断服务程序中对接收到的数据进行处理。如图 25为CAN总线数据处理的流程图。 ? 图25? CAN总线数据处理的流程图 ? 系统在接收到一个完整的数据帧之后,且校验和正确,会对接收缓存数据进行处理,会根据不同的类型的数据帧做相应的操作。当发生未能正确接收一个完整的数据帧时,下位机会返回错误类型,并回复NAK应答帧。 ? 实时时钟 PIC32MX 器件上提供的实时时钟和日历(Real-Time Clock and Calendar,RTCC)硬件模块及其操作。RTCC是为需要长时间维持精确时间的应用设计的,无需或只需最少的CPU干预。该模块为低功耗使用进行了优化,以便在跟踪时间的同时延长电池的使用寿命。使用RTCC模块的要求是需要一个外部32.768 kHz时钟晶振。 ? 测井数据帧的当前时间使用RTCC模块提供,该模块只需要初始化并设置起始时钟和日历即可自动运行。 ? 上位机软件设计 概述 需求概述 本软件的功能主要为接收本系统硬件部分发送的数据,通过一定的协议解析,提取并分析信息,计算管壁厚度,绘制厚度可视化的图形,为工程人员提供直接的和有效的资料。 ? 由于本系统在探伤的同时,着重分析损伤位置,因此必须对远近有所分离,另外最好能够绘制从远到近的厚度谱图,因此,本软件需要绘制两种图线,一种划分为远场近场两条曲线,另一种给出彩色的厚度谱图。 ? 由于测井时间很长,工程人员很难全程跟踪,为了便于从存储的信息中恢复信息以便日后查阅,还需要给本软件增加文件存储和图像存储的功能。 ? 最后,工程人员还需要实施观测现场状况,随时得到从井下传递来的信息,这样随时观测的方法,可以有效的节省测井时间,对于损伤过大的井可不必测完。 ? 软硬件支持环境 本软件采用VS2008编译通过,在编写中使用了.net3.5架构,因此运行本软件需要Microsoft .net3.5运行时库的支持。 ? 另外,本系统采用USBCAN模块进行通信,由于厂商没有给出其在Windows Vista和Windows 7下的驱动,因此,本软件只能工作在Windows XP系统下,且需要安装USBCAN模块驱动。 ? 程序建模 本程序采用面向对象程序设计方法,其中的多数功能被封装在对象中,程序有较好的移植性和安全性。程序主要封装在以下几个类中 ? 类 用途 ? 记录测井全程信息、 ? 文件存储和读出 ? 由下位机传来的8字节信息 ? 由下位机传来的数据包 ? 其中包括一正一反两个数据包,记录其平均值和其他的数据处理结果 ? 测井曲线图 ? 衰减曲线图 ? 总线通信 ? 另外本软件采用了多线程处理技术,主程序负责按键响应、图形显示等处于主线程中,而信息处理算法由子进程执行。这样有效的提升了数据处理算法的效率和独立性,使得又原先的每包处理时间1000ms左右大幅降至14ms左右。 ? 界面设计 下图为一软件运行时截图,可以看到程序右左上方的文件/设备控制区,右上方图形控制区,左下方的信息显示区以及右下方的图形显示区组成。而其中最重要的,也是占用面积最大部分是图形显示区,较大的面积保证了观看的方便。另外,为了观察直观的一手数据,我们还专门设置了显示由采样设备直接传来的未经处理的衰减信号,以便工程人员直接判断测井系统是否正常工作,以及管壁是否发生严重损伤。这个衰减曲线是可以隐藏的,因为它毕竟不是主要需要显示的内容,而且占用屏幕空间较大。如果你觉得图像显示空间还不够大,甚至可以隐藏图例。这里图例被设计成悬浮于绘图之上,可以跟随滚动条滑动而动。 ? 图26? 电磁测井工具软件界面 ? USBCAN接收模块 由于采用了USBCAN-2A模块,因此,这里的使用了厂商提供的驱动程序和dll程序,但是提供的程序是基于c++的,我们的C#程序还需要进行适用于.Net架构的封装。这其中包括数据类型的转换,结构体重写和函数的引用。 ? 函数引用使用DllImport语句,以打开设备函数为例: ? [DllImport("ControlCAN.dll")] public static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved); ? 这里引用的是ControlCAN.dll中的函数,使用静态和外部的引用方式。 ? 第二个要重新封装的的是数据类型,由于.Net架构和C++的数据类型不同,因此需要进行大量的改写。如Dword类型应转换为Uint32类型,这种转换往往比较模式化,具体转换这里不再赘述。 ? 第三个也是最重要的就是结构体的重写。例如 public struct VCI_CAN_OBJ ??????? { ??????????? public UInt32 ID; ??????????? public UInt32 TimeStamp; ??????????? public Byte TimeFlag; ??????????? public Byte SendType; ??????????? public Byte RemoteFlag;//是否是远程帧 ??????????? public Byte ExternFlag;//是否是扩展帧 ??????????? public Byte DataLen; ??????????? [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] ??????????? public Byte[] Data; ??????????? [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] ??????????? public Byte[] Reserved; ??????? }; ? 这个结构体,需要在类中重新描述,其中的数据类型应按照标准数据类型转换,另外其中的数组应使用MarshalAs修饰符修饰,表示在托管代码和非托管代码之间传送数据。驱动程序中的代码被托管,这里要收集其数据,必须使用MarshalAs方法。 ? 最后,由于我们程序使用的数据格式比较固定,因此本类中也对一些常用的方法进行了封装,使得CAN模块对上层程序透明,上层程序在接收数据的时候好像没有底层方法一样。例如CAN模块定义了打开设备,初始化设备,开始CAN三个方法,但是由于我们的参数是规定好的,因此在程序中就将这三个方法进行了一层封装,每当建立USBCAN实例的时候在构造函数中自动打开设备。 ? 数据分析模块 CAN模块接收过来的数据需要对其进行分析。这里我们采用的是正则表达式分析方法。正则表达式在C#方便易用,效率高,功能强大。 ? 每次接收过来的数据时8字节的小字符串,实际上是8个0-255的数,由于ASCII码最大只允许到127,超过127的数值都被转化成为值为63的”?”字符,因此这里采用ISO8859-1中规定的扩展ASCII码进行转码。 ? 小字符串分为五种,分别用以下五种正则表达式进行匹配:@"^EMISTART$"、@"^FSTA((.|\n){4})$"、@"^((.|\n){8})$"、@"^EMITOEND$"、@"^((.|\n){4})FEND$",分别表示“测井开始”、“数据包开始”、“内容数据”,“测井结束”,“数据包结束”。分析出五种帧的不同,则可以进行相应的操作。如接收到测井开始帧,则创建新的测井实例,重置图片,重置存储文件。如果接收到测井结束,则销毁测井实例。收到数据包开始的标志时应创建新的消息实例,收到内容帧应在最后创建的消息包实例后附加信息。如果收到了数据包结束标志则开始数据的处理。 ? 收到了数据包结束标志,马上开始的应该是数据处理的部分。其算法流程如下: ? ? 第一步是判断大小,一个标准的数据包大小是512字节,如果不是,则应该抛弃,这一步的判断大大节省了判断的时间,毕竟校验和还是比较麻烦的判别方法,很多错误的数据会由于大小不一致被抛弃。 ? 第二步的校验和判断,这里采用的每四个字节拼合成一个32位整形数据,再进行加和的方式,最后得到数据和传递来的数据比较,一致则认为传递没有错误。经实测,传递错误率不足千分之一。 ? 第三步是发送ACK和NAK信息。 ? 第四步对数据进行分拆,从字符型数据得到有意义的整形或浮点型数据。分拆的过程同样使用的是正则表达式的技术,其表达式为:@"^FSTA((.|\n){3})D((.|\n){4})((.|\n){4})((.|\n){4})((.|\n){2})((.|\n){2})((.|\n){288})((.|\n){96})((.|\n){96})((.|\n){4})FEND$" ? 接受下来的数据采用移位递加的方式求其相应的整形值,如温度值为4字节32位数据,接收时首先加其最左侧字节,右移8位后加左数第二字节,依以此类推得到其整型值,由于我们规定传送的是其1000倍的数据,因此再除以1000即可。其他数据的计算方式类似。 ? 软件滤波 由于AD采样的不确定性,很有可能造成某几个数据的偏差或整体偏差,因此我们采用一些方法来消除测量中产生的偶然因素。 ? 首先由于发送激励信号时候如果电流只有一个方向,则可能因为几何因素造成较大的差异,因此,在激励时我们采用双极性方波,正采样一次再负采样一次,两次的绝对值取平均则可得到良好的数据结果。 ? 另外除了消除了几何结构造成的偏差,仍不能达到我们的要求,对于近场区的值,如果我们只相信一个采样点的值则会造成偏差,因此我们对进场数据采平均值,对远场平均取平均值。