VB.NET中基于声卡和DirectX的虚拟仪器设计

前端之家收集整理的这篇文章主要介绍了VB.NET中基于声卡和DirectX的虚拟仪器设计前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
摘要:本文在VB.NET环境中使用声卡和DirectX实现虚拟仪器的数据采集。使用DirectX技术从声卡采集数据,使用多线程技术实现数据的不间断采集,并给出了直流信号的数据采集方案。本文主要介绍系统的硬件设计、采集数据的DirectSound类、多线程和数据存储等。 @H_403_0@

关键词:VB.NET;声卡;DirectX;虚拟仪器 @H_403_0@

0 引言 @H_403_0@

虚拟仪器是使用传感器、A/D转换芯片和计算机实现许多传统仪器的所有功能,应用在自动化仪表的各个方面。但是由于通用的虚拟仪器要考虑高速信号,往往采用高速低分辨率的A/D、D/A芯片。一般转换芯片分辨率只能达到8至12位,而计算机声卡集成有16位的A/D和 D/A转换芯片,采样频率为44.1/48KHz,因此可以将声卡作为虚拟仪器数据采集的A/D转换装置。 @H_403_0@

VB.NET是一种跨平台的面向对象编程语言,有运行速度快、多线程、安全可靠性高等优点。VB.NET的DirectX为软件开发者提供硬件无关性,为硬件开发提供策略。微软的DirectX软件开发工具包(SDK)提供了一套优秀的应用程序编程接口(APIs),这个编程接口可以提供给你开发高质量、实时的应用程序所需要的各种资源。将上述二者结合起来设计虚拟动态数据分析仪,可实现双通道实时波形显示、信号谱分析和传递函数分析等功能。 @H_403_0@

1 基于声卡虚拟仪器系统的硬件电路设计 @H_403_0@

@H_403_0@系统的硬件电路设计如图1所示。分为常规(a)和低频(b)两个部分。两部分信号切换通过手动开关转换。

@H_403_0@

@H_403_0@

@H_403_0@

@H_403_0@图1 采集系统的硬件

@H_403_0@

常规部分(a)是指信号频率在1KHz以上。此时因为声卡的输入阻抗低、声卡的电压输入在5V内,因此传感器与声卡之间需要加保护电路,实现信号的网络衰减和过压抑制。经过保护电路的传感器信号通过声卡的的Line in接口或MIC接口进入计算机。 @H_403_0@

低频部分(b)是处理频率在1KHz以下信号。因为声卡不能很好地测量低频信号,系统使用V/F器件LM331将输入信号电压的幅值转换成频率与输入电压幅值成正比的脉冲串。LM331有温度补偿能隙基准电路,同时该器件的脉冲输出与声卡兼容。声卡采集脉冲串,并根据脉冲频率算出信号的电压值,转换公式为f=Vi*Rs/(2.09*Rt*Ct*RL)。电路由计算机的USB口提供5V的电源。 @H_403_0@

@H_403_0@2、虚拟仪器系统的设计原理

因为系统在通过声卡采集数据的同时需要将数据显示显示器或保存到文件,因此系统采用多线程实现该功能。多线程子任务可以并发执行,可以更好地充分利用了cpu的空闲时间片,可极大地改善程序的响应时间。 @H_403_0@

@H_403_0@建立两个线程,定义采集的数据存放数组CaptureData和准备显示的数据数组ShowData

@H_403_0@线程1根据设置的参数,使用DirectSound采集数据,并存放在aptureData,同时计算出显示数据,存放在ShowData数组

@H_403_0@线程2根据ShowData数组值,显示采集数据的波形

@H_403_0@根据需要可以将其存储到文件,也可以将其读出进行分析。

@H_403_0@

@H_403_0@

@H_403_0@

@H_403_0@图2系统程序的设计思想

@H_403_0@多线程允许设置线程的优先级别,本系统将数据采集线程的优先级设置高与其他线程,保证采集数据的速度。

@H_403_0@程序设计思想如图2所示,系统建立两个线程,一个进行数据采集,一个进行图形显示,使用静态数组进行两个线程之间的通信。通过鼠标事件可以修改采样频率、图形显示、是否存储数据等参数。

@H_403_0@采集系统图形界面应包括波形显示区、参数设置、控制按钮等。VB.NET有丰富的图形用户界面控件及画图函数,可以方便地编程设计出该界面。由于图形界面很容易编程实现,本文不讨论图形界面的设计。

@H_403_0@3 使用DirectSound从声卡采集信息

@H_403_0@程序使用了DirectSound、I/0、线程等类,需要引用的程序集如下:

@H_403_0@Imports Microsoft.DirectX.DirectSound

@H_403_0@Imports System.IO

@H_403_0@Imports System.Threading

@H_403_0@DirectSound对录音的支持类如下:

@H_403_0@①Capture,录音设备对象(声卡);

@H_403_0@②CaptureBuffer,存放采集数据的缓冲区对象;

@H_403_0@③Notify,事件通知对象,由于录音是一个长时间的过程,因此使用一个缓冲队列(多个缓冲区)接收数据,每当一个缓冲区满的时候,系统使用这个对象通知应用程序取走这个缓冲区,并继续录音;

@H_403_0@④WaveFormat,描述了进行录制的声音波形的格式,如采样频率、声道数、采样位数等;

@H_403_0@⑤AutoResetEvent,通知的事件,当缓冲区满的时候,使用该事件作为通知事件。

@H_403_0@根据上面的类定义对象如下:

@H_403_0@Dim Cap As Capture?声音接收设备对象

@H_403_0@Dim CapFormat As New WaveFormat

@H_403_0@Dim CapBuf As CaptureBuffer = Nothing

@H_403_0@Dim SBufdsc As New CaptureBufferDescription

@H_403_0@Public applicationNotify As Notify = Nothing

@H_403_0@Dim CaptureData As Byte() = Nothing?采集的数据存放数组

@H_403_0@Dim ShowData As Byte() = Nothing ?准备显示的数据数组

@H_403_0@Dim VgaShow As Boolean?是否需要刷新显示内容

@H_403_0@3.1 获得声音接收设备对象

@H_403_0@windows把音频设备分成2个部分,录音设备Capture和回放设备PlayBack。使用Capture能够创建录音设备,创建时需要用户指定或用枚举的办法逐个测试是否支持这种格式。

@H_403_0@首先用Dim CapList As New CaptureDevicesCollection得到声音接收设备列表后,用Dim info As DeviceInformation得到可以使用的信息,然后通过循环语句①For Each info In CapList②ListBox1.Items.Add(info.Description)③Next枚举出所有设备并添加到ListBox1中显示。最后利用Cap = New Capture(CapList(ListBox1.SelectedIndex).DriverGuid)语句测试,选择出可用的设备。

@H_403_0@3.2 设置接收数据信息的格式和CaptureBuffer缓冲区对象

@H_403_0@With CapFormat ?设定录音格式

@H_403_0@.BitsPerSample = 8?采样位数,8或16位

@H_403_0@.Channels = 1?声道数,1或2

@H_403_0@.BlockAlign = 1 ?=Channels*BitsPerSample/8

@H_403_0@.SamplesPerSecond = 44100

@H_403_0@?设置采样频率,8.0、11.025、22.05、44.1kHz

@H_403_0@.AverageBytesPerSecond = 44100

@H_403_0@?=BlockAlign*SamplesPerSecond

@H_403_0@.FormatTag = WaveFormatTag.Pcm

@H_403_0@End With

@H_403_0@上面参数表示数据采集时的参数(频率、位数),可以根据现场实际情况修改,设计的操作界面中有相应的修改操作。

@H_403_0@With SBufdsc

@H_403_0@.Format = CapFormat

@H_403_0@.BufferBytes = 100000 ?2 * CapFormat.AverageBytesPerSecond

@H_403_0@.ControlEffects = True

@H_403_0@.ControlFrequency = True

@H_403_0@.ControlPan = True

@H_403_0@.ControlVolume = True

@H_403_0@.GlobalFocus = True

@H_403_0@End With

@H_403_0@上面参数是对接收缓冲区的描述。

@H_403_0@3.3 创建DirectSound对象采集数据

@H_403_0@CapBuf = New CaptureBuffer(BufDesc,Cap) ?创建DirectSound对象;

@H_403_0@CapBuf.Start(True)’开始采集数据

@H_403_0@也可以使用CapBuf.Stop()语句停止数据采集。

@H_403_0@3.4 从CapBuf缓冲区读取数据子程序

@H_403_0@Sub RecordCapturedData()

@H_403_0@CaptureData = CType(CapBuf.Read(0,GetType(Byte),LockFlag.None,1),Byte())

@H_403_0@CapBuf.Dispose()

@H_403_0@CapBuf = Nothing

@H_403_0@……?根据需要保存到文件

@H_403_0@……?根据需要计算数据

@H_403_0@……?将需要显示的数据保存到ShowData数组

@H_403_0@VgaShow= True?通知需要刷新显示内容

@H_403_0@End Sub

@H_403_0@CapBuf.Read()是从CapBuf缓冲区读取数据,四个参数分别是:从缓冲区什么地方开始读、返回数据的类型、LockFlag标记、每次读几个。

@H_403_0@3.5 图形显示

@H_403_0@图形显示就是将采集到的数据转换成坐标并显示到计算机屏幕上, 用DirectDraw把ShowData的内容图像化,即连续画线,使用DirectDraw可以保证速度。子程序代码如下:

@H_403_0@Sub RecordShow()

@H_403_0@If VgaShow= True Then

@H_403_0@……?将ShowData数组内容画线

@H_403_0@VgaShow= False ?刷新显示完毕

@H_403_0@End If

@H_403_0@End Sub

@H_403_0@4 多线程实现不间断数据采集

@H_403_0@创建两个工作线程,t1线程进行数据采集,t2线程进行图形显示代码如下:

@H_403_0@Dimt1AsNewThread(AddressOfWaitThread)

@H_403_0@Dimt2AsNewThread(AddressOfRecordShow)

@H_403_0@t1.Start()

@H_403_0@t2.Start()

@H_403_0@建立线程时,两个线程执行的子程序分别是WaitThread()和RecordShow()。

@H_403_0@设置两个线程的优先级,采集数据线程优先级高于屏幕显示线程,优先级线程的更迅速地响应请求,代码如下:

@H_403_0@t1.Priority = ThreadPriority.AboveNormal

@H_403_0@t2.Priority = ThreadPriority.Normal

@H_403_0@下面是建立通知事件,当缓冲区满的时候,使用该事件作为通知事件。

@H_403_0@Public PNotify(16) As BufferPositionNotify

@H_403_0@NEvent = New AutoResetEvent(False) ?通知的事件

@H_403_0@CapBufNotify = New Notify(CapBuf) ?事件通知对象

@H_403_0@……?循环使PNotify(i).EventNotifyHandle = NEvent.Handle

@H_403_0@CapBufNotify.SetNotificationPositions(PNotify,16)

@H_403_0@Private Sub WaitThread()

@H_403_0@ While Created ?

@H_403_0@ NotificationEvent.WaitOne(Timeout.Infinite,True) ?等待接收缓冲区满

@H_403_0@RecordCapturedData()

@H_403_0@ End While

@H_403_0@End Sub

@H_403_0@5 将信息存储到文件和从文件读取数据

@H_403_0@采集数据的容量很大,只在需要的时候将其存储到文件,通过按钮控制是否进行存储。存储的格式为文本文件。VB.NET的输入输出是通过流实现的,VB.NET有文件相关的FileStream类,支持对本地文件的顺序和随机读写操作,可以很简单地读写字节数组。假如将数组a()数据存入文件代码如下:

@H_403_0@Dim WFile As FileStream = New FileStream("文件名",FileMode.OpenOrCreate)

@H_403_0@Writer = New BinaryWriter(WFile)

@H_403_0@Writer.Write(a) ?a是要写的字节数组

@H_403_0@Writer.Close()’ 关闭对象

@H_403_0@文件包括路径及名子,FileMode.OpenOrCreate表示如果文件存在则打开文件,否则创建新文件。采用BinaryWriter写文件,该对象以二进制形式将基元类型写入流,并支持用特定的编码写入字符串,其Write方法可以将一数组数据写入文件中。

@H_403_0@分析数据需要将保存的文件数据读取出来并在进行分析,分析结果显示在另一个窗口中。假如定义数组b(),读取文件数据到数组的代码如下:

@H_403_0@Dim RFile As FileStream = New FileStream("文件名",FileMode.Read)

@H_403_0@Dim Rreader As BinaryReader = New BinaryReader (RFile)

@H_403_0@Rreader.BaseStream.Seek(0,SeekOrigin.Begin)

@H_403_0@Dim Bytes As Byte()

@H_403_0@Bytes = Rreader.ReadBytes(个数) ?Bytes是读出的字节数组

@H_403_0@Rreader.Close()

@H_403_0@FileMode.Read表示对只读操作,BinaryReader是用特定的编码将基元数据类型读作二进制值。

@H_403_0@不使用文件时,将文件对象关闭代码为:

@H_403_0@RFile.Close()

@H_403_0@WFile.Close()

@H_403_0@6 结束语

@H_403_0@本系统使用声卡作为A/D转换装置,使用VB.NET实现数据采集、多媒体界面设计、图型显示功能,开发高性能的虚拟仪器数据采集系统。本系统充分利用了VB.NET的多线程的并行处理特性,使系统具有很高的采集性能。系统实现简单、性价比高、操作方便,并且可以根据用户的需求进行功能扩充。

猜你在找的VB相关文章