VC编程实现对波形数据的频谱分析.docx
《VC编程实现对波形数据的频谱分析.docx》由会员分享,可在线阅读,更多相关《VC编程实现对波形数据的频谱分析.docx(17页珍藏版)》请在冰豆网上搜索。
VC编程实现对波形数据的频谱分析
Documentserialnumber【NL89WT-NY98YT-NC8CB-NNUUT-NUT108】
VC编程实现对波形数据的频谱分析
VC++编程实现对波形数据的频谱分析
摘要:
本文介绍了采用离散傅立叶变换(DFT)实现对采样得到的波形数据文件进行频谱分析的一般方法,并且为了提高运算效率、节省中间存储单元,最终采用了"时间抽选奇偶分解"的"库利-图基算法"实现快速离散傅立叶变换,对采样数据进行了高效的频谱分析,并用MicrosoftVisualC++编写实现。
关键字:
MicrosoftVisualC++、离散傅立叶变换、快速傅立叶变换、采样
一、引言
频谱分析是电子工程上一个非常重要的手段,许多计算机辅助电路分析(CAA)类软件都具备这种分析能力,以便电子工程师能清楚的看到某波形的频谱分布情况。
而要对一个输入信号源作频谱分析,将其由时域信号转变为频域信号,就必然要用到傅立叶分析,而无论是在时域还是在频域,都要对连续函数进行积分运算。
很显然,要通过计算机实现此变换必须预先通过抽样将原始的连续数据转变为离散数据,并将计算范围收缩到一个有限区间。
因此在允许一定程度近似的条件下,可以使用"离散傅立叶变换(DFT)"对波形数据进行频谱分析。
二、快速傅立叶变换(FFT)算法构成原理
要计算一个N点的离散傅立叶变换需要同一个N*N点的W矩阵(关于W矩阵请参阅信号与系统方面的书籍)相运算,随着N值的增大,运算次数显着上升,当点数达到1024时,需要进行复数乘法运算1,048,576次,显然这种算法在实际运用中无法保证当点数较大时的运算速度,无法满足对信号的实时处理。
根据W矩阵中W元素的周期性和对称性我们可以将一个N点的DFT运算分解为两组N/2点的DFT运算,然后取和即可,为进一步提高效率,将上述两个矩阵按奇偶顺序逐级分解下去。
当采样点数为2的指数次方M时,可分解为M级子矩阵运算,全部工作量仅为:
复数乘法:
M*N/2次
复数加法:
N*M次
而直接DFT需要的运算量为:
复数乘法:
N*N次
复数加法:
N*(N-1)次
当点数N为几十个点时FFT的优势还不明显,而一旦达到几千、几百个点时优势是十分明显的:
N=1024时:
DFT需1048576次运算,FFT仅需5120次运算,改善比。
N=2048时:
DFT需4194304次运算,FFT仅需11264次运算,改善比达到。
三、"时间抽选奇偶分解快速离散傅立叶变换"的程序实现
当采样点数较多时,如变换前和变换后的序列都按自然顺序排列,则中间运算过程会占用大量的中间存储单元,造成效率的低下和存储单元的浪费。
根据FFT的实现原理我们可以对采样序列进行逐次奇偶抽选,打乱以前的次序重新排序,然后按此顺序参加运算,可以实现"即位运算"提高存储单元的利用率。
(一)复数的描述方法
进行傅立叶变换时不可避免的要用到复数,而在VC中并没有现成的可用于表示复数的数据类型,可以自己定义一个含有两个成员变量的数据结构来表示复数,这两个成员变量可分别用于表示复数的实部与虚部:
typedefstructtagComplex{
floatRe;e*[IP-1].Im*;e*+A[IP-1].Im*;
A[IP-1].Re=(float)A[I-1].;m=(float)A[I-1].;
A[I-1].Re+=;m+=;
I+=LE;
}
floattemp=;
=(float)*计算复数运算U*W
=(float)temp*+*;
J++;
}
L++;
}……
上述代码执行完毕时,原先存放着时域数值的复变量数组内存放的就是经过分析后的频域值了,对此数据可以通过绘图将频域波形直观的显示出来,也可以将其存成数据文件,以备进一步使用。
四、测试及运算结果分析
编译运行程序,打开一三角脉冲的数据文件,并将分析结果保存,该三角脉冲幅度为1,持续时间2毫秒,采样时抽样时间间隔是20微秒,延拓周期(数据记录长度)为10毫秒,采样点数目500点,取2的整数次幂512个样点。
下附该三角脉冲频谱的计算结果及误差分析:
频率(Hz)FFT求得 X(f) 误差
注:
在此,FFT运算结果都倍乘了系数10毫秒(秒)。
在分析结果中产生了误差,是由于待分析的连续时间信号不具备离散性或周期性,也可能有无限长度。
为了适应FFT方法的需要,对波形进行了抽样和截断,这样再用程序分析采样数据必然会引入误差,从分析结果可以看出,频率越高,误差波动也越大,此分析结果产生的误差在允许范围之内,是一个可以满意的近似。
实践证明,本程序的算法是正确可靠的。
小结:
DFT尤其是FFT的应用已遍及各个科学领域,"DFT的应用"与"FFT的应用"几乎成为同义语。
通过本文介绍和程序示例可以清楚的看到FFT方法在直接处理离散信号数据的作用,而且也可以很好的用于对连续时间信号分析的逼近。
本程序在Windows2000Professional下、由MicrosoftVisualC++编译通过
用VB实现数字波形显示程序减小字体增大字体作者:
佚名来源:
本站整理发布时间:
2009-07-1518:
03:
17
id=126063>
摘要:
本文详细介绍了在VB集成环境下数字波形高速显示的方法,同时对双通道波形显示和数字滤波方法也进行了介绍。
关键词:
数字;波形;显示;滤波
1前言:
随着计算机技术及电子技术的发展,数字采集技术在检测领域的应用越来越广泛,检测速度越来越高,检测的数据量越来越大,特别是在无损检测领域,将检测数据通过计算机处理后绘制出波形,并实时显示,对及时发现伤损、分析伤损具有重要意义。
2波形显示
检测数据通常是离散的数据,将离散的数据绘制出波形,可通过在两点间连接线段的方法实现。
用Line方法显示波形
VB提供了Line画直线方法,可在窗体上增加一个图片框控件,适当设置图片的大小和背景颜色,用Line方法将离散数据按检测顺序连接成线段,即可将波形显示在图片框中。
但该方法显示波形速度较慢,不适合高速显示的应用。
WindowsAPI函数显示波形
在VB中两点间连线的另一种方法是用WindowsAPI函数,Win32API提供了以下两个函数,联合使用可实现波形的快速显示,经过测试,显示速度比使用Line方法快70%以上。
LineTo函数:
函数功能:
画出由数组定义的点连接的一系列线段。
函数原型:
BOOLLineTo(HDChdc,intnXEnd,intnYEnd);
参数:
hdc:
设备环境句柄。
nXEnd:
定义线段终点的X坐标。
nYEnd:
定义线段终点的Y坐标。
返回值:
若函数调用成功,则返回非0值;若函数调用失败,则返回值为0。
MoveToEx函数:
函数功能:
将当前位置更新为指定的点,并有选择的返回原先的位置。
函数原型:
BOOLMoveToEx(HDChdc,intX,intY,LPPOINTlpPoint);
参数:
hdc:
设备环境句柄。
X:
定义新位置的X坐标(逻辑坐标)。
Y:
定义新位置的Y坐标(逻辑坐标)。
lpPoint:
指向一个POINT结构,结构中存放原先的位置。
若此参数为NULL,则不返回原先的位置
返回值:
若函数调用成功,则返回非0值;若函数调用失败,则返回值为0。
在连接线段时,首先将检测数据放入一个数组中,用MoveToEx函数定位画线的起始点坐标,然后用LineTo函数画出起始点至下一个点之间的线段,再用MoveToEx将画线的起始点定位到下一个点,继续用LineTo函数画线,如此循环,即可将离散点连接成波形。
例:
zz=MoveToEx,i,Mwave(i),LpPoint1)
zz=LineTo,i,Mwave(i+1))
实时波形显示界面
通常计算机需要接收外部实时发送的数据并用十分形象的方式显示出来。
例如柱状图、饼图等等。
本应用程序则采用波形的形式显示,并接将之设计为可以接收多路数据的波形显示界面。
本应用程序在VS2008环境下调试通过,源码下载连接如下。
一.程序界面
点击该图放大
上图中显示了两路波形即三角波和正弦波,当然这两路波形是由程序计算出来的并不是从外部接收的。
实际工作中则可以配合串口通讯设备接收它发来的数据并显示出来。
二.波形控件类介绍
本程序的实现主要依赖于那个波形显示控件。
从下载连接那里可以下载该源码,里面的文件中,和即是该控件的类的定义文件和实现文件。
分析之后得到该类的一些信息。
其成员函数包括:
程序代码:
COLORREFm_crTextColor;
用编程
运用该控件在VS2008环境下的编程步骤如下:
1.建立一个对话框的MFC工程,在对话框上按照上图所示的界面布置控件。
其中波形控件那里布置一个PictureControl控件将其ModalFrame和Type均属性设置为true,其他均设置为False。
注意给PictureControl取的ID!
后面编程将会用到。
2.将波形控件类的定义文件和实现文件拷贝至你的工程目录下。
但这实际上并没有将该类真正添加到你的工程下,需手动添加类。
常规操作,不详述。
3.在对话框的定义和实现文件中分别添加如下代码:
程序代码:
#include""
4.在对话框定义文件中(我给的供下载的例程中的是这个文件)中定义一个该控件类的变量:
程序代码:
private:
C2DPushGraphm_PushGraph;
5.在对话框的实现文件中(我给的供下载的例程中的是这个文件)的对话框初始化函数中添加如下代码:
程序代码:
(IDC_REALCTRL,this);
在不妨试着运行以下该程序,应该可以观察到那个控件显示出来了吧。
在添加以下代码:
程序代码:
(m_sin,RGB(255,255,255));(m_tra,RGB(255,0,0))
这两行代码分别添加了一个正弦波形,ID号为m_sin,一个三角波形,ID号为m_tra。
不过运行之后并没有数据点绘制出来。
那是应为还没有调用boolPush(intnMagnitude,UINTuiLineID)函数添加数据点。
试着添加几个数据点再运行即可观察到波形。
7.还有一些控件的响应代码看看那个下载的例程吧。
四.结束语成功了吧,AnyProblem,Contactmeplease!
控件设计]Nobi'sStatusChart-野比的状态波形图控件从构思到实现
Nobi'sStatusChart-野比的状态波形图控件
从构思到实现
野比着
源程序下载:
Demo
控件
背景
目前比较流行的WinForm程序设计都会提供形象的可视化数据流动记录功能,如FlashGet及其衍生软件的悬浮窗网速监视图,Windows任务管理器的CPU、内存使用图等。
构思
为了在我们自己的程序中实现这种效果,就需要研究、分析它们的原理,掌握其规律,然后加以实现。
很明显,从软件可重用性以及各种随之而来的好处考虑,我们要求将这个“波形显示”效果做成一个控件(Control)。
分析还是以FlashGet的悬浮窗和Windows任务管理器作为研究对象。
仔细观察它们的工作方式,发现它们有以下的共同点:
在右边更新当前的波形值
更新后的波形不消失,而是整体向左平移
可以设置波形颜色、更新速度等
而通过深入研究,发现二者不同点如下:
不同的显示方式,有曲线显示和直方图显示
有无定位网格
各部分颜色可自定义
设计通过分析,可以决定如下:
凡是二者共同点,加以重点实现;凡二者不同之处,通过设置属性(Property)进行更改。
最后绘制时,基于所设置的属性,使用共同方法加以实现。
因此自定义属性如下:
BackColor(重写基类属性)
Enabled(重写)
ForeColor(重写)
GridColor网格颜色
GridHeight网格每格高度
GridShiftting是否平移网格
GridWidth网格每格宽度
Interval波形刷新间隔(单位:
毫秒)
Mode波形显示方式(曲线/直方图)
Range数值范围
ShifttingIncrement向左平移增量
Value当前值
控件因为要定时更新,因此具有一个内部的Timer对其进行定时,其Interval由控件的Interval属性指定。
对于此自定义控件,需要每次更新时在其OnPaint()事件中对整个控件进行绘制。
绘制顺序为:
背景-网格-波形,如此保证所有部分均正确画出且无遮挡。
从波形看,很明显,我们需要一个长度至少等于波形控件宽度的数组来存放每时刻波形的值,因此可以确定这个数组是和控件绘图画布宽度一致的。
算法
绘图最重要的是算法部分,如何计算如网格位置,如何将图形整体平移,如何设置波形值是本控件的重点和难点部分。
计算网格位置,以上面的ShifttingIncrement为offset参数传入
//网格数(不计边缘)
floatdiv;floatpos=0F;//先画垂直方向
//可以少画一根线
div=(float)w/(float)gridWidth+1;for(inti=0;i<(int)div;i++){pos+=gridWidth;(penGrid,pos-offset,0,pos-offset,h);}//画水平方向
div=(float)h/(float)gridHeight;pos=0F;for(inti=0;i<(int)div;i++){pos+=gridHeight;(penGrid,0,pos,w,pos);}
对于波形,传入其波形值数组作为参数
//从0到w绘制
intlen=w;//根据绘制方式
if(chartMode==(inti=0;i
如何平移,是一个难点,需要在内部定时器的Tick()事件中加以处理
//更新网格偏移
//只有启用了网格移动才处理
if(gridShiftting){iOffset+=gridShifttingIncrement;iOffset%=gridWidth;}//更新图形(整体左移)
//必须在这里而不能在画图的同时移动,
//若在画图中移动,则当画面被遮挡(OnPaint)事件不发生时无法更新
intlen=w;for(inti=0;iif(i}}//val[len]=currentValue;
Invalidate();
最后引发控件的Invalidate()方法使控件重绘自身。
效果
最后的控件运行效果如下图所示:
总结通过设计并实现StatusChart控件,我们研究了波形状态监控的相关现象和原理,复习并使用了控件的设计生成,最后使用GDI+技术对其进行了实现。
VC++编程实现对火焰的计算机动态仿真
摘要:
本文通过对真实火焰物理特性的分析,建立了火焰动态燃烧的数学模型,并在此数学模型基础之上借助于DirectDraw技术对图形显示的加速,在VC++下对火焰作了效果非常逼真的计算机动态仿真。
关键词:
火焰;DirectDraw;计算机仿真
引言
计算机仿真技术的基本原理都是一样的,神秘复杂的核爆同水波、火焰、烟雾等非常平常的自然现象在仿真处理过程中并没有什么太大的区别。
都是经历了从实体对象到物理特性的总结,再由此建立数学模型并在数学模型基础之上提出仿真算法,最后通过计算机将其动态仿真出来等一系列步骤。
本文以火焰作为仿真对象,通过对热源、热扩散以及对流等特性的分析对其建立了数学模型及仿真算法,为了能充分发挥计算机对图形的硬件加速,使用DirectDraw技术对仿真结果显示进行了加速,使之能逼真、流畅地对火焰的燃烧过程实行动态模拟。
简单近似模型设计
虽然火焰在自然界是一种极普通的自然现象,但根据流体力学的相关知识,火焰可以表达为一个相当复杂的三维动态流体系统。
如要在计算机中对这样一个复杂的流体系统做出精确的仿真将需要有相当庞大复杂的数学模型为基础,而且运算量将非常巨大,在现有的微型计算机中几乎很难保证其动态实时性,这也就失去了仿真的意义。
因此,在仿真时应用尽可能简单的模型来实现尽可能逼真的效果。
从物理角度分析,要产生火焰,首先要有火源,其次为了产生"焰"的效果,需要以火源为中心向上、向四周扩散,而且由于在扩散过程中逐渐远离火源,温度会逐渐下降,表现在视觉上就是火焰的冷却变暗。
另外,由于火焰的高温使周围空气受热膨胀比重下降,因此会有空气的对流出现,这将把火焰向上"吹"起,使火焰向四周扩散的距离要远小于向上扩散的距离。
基于以上几点认识,可以采取对应的仿真措施:
对火源的设置可以用一幅二值位图来标识,非火源以低亮度像素填充、火源点则设以高亮度像素,通过对位图像素值的判别可以断定当前点是否为火源。
对于火源的温度高低可用其所在点的亮度来描述;对于火焰扩散的模拟,为尽量减少运算量,在此简单地用某火源点(x,y)及其前后左右邻近四点的均值来近似,即Pixel(x,y)=(Pixel(x,y)+Pixel(x,y-1)+Pixel(x,y+1)+Pixel(x-1,y)+Pixel(x+1,y))/5,虽然该近似算法没有采取正余弦的方法精确,但运算速度极快,而且在后续的实验效果上同采用正余弦的方法几乎没有任何差别;由于在仿真过程中对火焰的温度是通过改变其亮度值来实现的,因此对于扩散过程的冷却可对像素点降低一个固定的亮度值来实现。
衰减值的大小需要视所希望火焰冷却速度的快慢而定;对流对火焰产生的直接影响就是使火焰始终保持向上燃烧,因此可通过将当前火焰上滚一至两个像素来加以实现。
根据前面描述的仿真运算法则,可将火焰的扩散和对流融合在一起实现,这将在一定程度上减少运算量,使产生的火焰在视觉上更加真实。
实现上述近似模型的伪代码可大致设计如下:
ARRAY_OF_BYTES:
buffer1(xsize*ysize),buffer2(xsize*ysize)
While(TRUE){
for(y=1;y for(x=1;x n1=buffer1(x+1,y)//读取4相临像素值
n2=buffer1(x-1,y)
n3=buffer1(x,y+1)
n4=buffer1(x,y-1)
p=((n1+n2+n3+n4+p)/5);//四临像素均值
p=p-c;//同一固定冷却衰减值相减
if(p<0)
p=0
buffer2(x,y-1)=p
}
}
copybuffer2tothescreen;//显示下一帧
copybuffer2tobuffer1;//更新Buffer1}
火焰非均匀冷却的改进模型
根据上述近似模型可对火焰进行一定程度上的仿真,但由于没有引入随机分布火焰往往看上去相当单调规则,而且火焰总呈线性上升,冷却速度也严格地保持统一速率。
要消除以上问题,可通过引入随机非均匀因素来解决。
一种途径是随机布置各点冷却值使火焰冷却过程非均匀化。
但由于火焰的模拟过
普通字符串与二进制字符串互转的函数-支持中文
作者:
佚名设计来源:
本站原创点击数:
607更新时间:
2007-12-27
焦点:
普通字符串与二进制字符串互转的函数-支持中文
'把二进制字符串转换成普通字符串函数
Functionbin2str(binstr)
Dimvarlen,clow,ccc,skipflag,i
'中文字符Skip标志
skipflag=0
ccc=""
IfNotIsNull(binstr)Then
varlen=LenB(binstr)
Fori=1Tovarlen
Ifskipflag=0Then
clow=MidB(binstr,i,1)
'判断是否中文的字符
IfAscB(clow)>127Then
'AscW会把二进制的中文双字节字符高位和低位反转,所以要先把中文的高低位反转
ccc=ccc&Chr(AscW(MidB(binstr,i+1,1)&clow))
skipflag=1
Else
ccc=ccc&Chr(AscB(clow))
EndIf
Else
skipflag=0
EndIf
Next
EndIf
bin2str=ccc
EndFunction
'把普通字符串转成二进制字符串函数
Functionstr2bin(varstr)
dimi,varchar,varasc
str2bin=""
Fori=1ToLen(varstr)
varchar=mid(varstr,i,1)
varasc=Asc(varchar)
'asc对中文字符求出来的值可能为负数,
'加上65536就可求出它的无符号数值
'-1在机器内是用补码表示的0xffff,
'其无符号值为65535,65535=-1+655