V C编程实现对波形数据的频谱分析文档编制序号:[KKIDT-LLE0828-LLETD298-POI08]到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中并没有现成的可用于表示复数的数据类型,可以自己定义一个含有两个成员变量的数据结构来表示复数,这两个成员变量可分别用于表示复数的实部与虚部:注:在此,FFT运算结果都倍乘了系数10毫秒(秒)。
在分析结果中产生了误差,是由于待分析的连续时间信号不具备离散性或周期性,也可能有无限长度。
为了适应FFT方法的需要,对波形进行了抽样和截断,这样再用程序分析采样数据必然会引入误差,从分析结果可以看出,频率越高,误差波动也越大,此分析结果产生的误差在允许范围之内,是一个可以满意的近似。
实践证明,本程序的算法是正确可靠的。
小结:DFT尤其是FFT的应用已遍及各个科学领域,"DFT的应用"与 "FFT的应用"几乎成为同义语。
通过本文介绍和程序示例可以清楚的看到FFT方法在直接处理离散信号数据的作用,而且也可以很好的用于对连续时间信号分析的逼近。
本程序在Windows 2000 Professional下、由Microsoft Visual C++ 编译通过用VB实现数字波形显示程序减小字体增大字体作者:佚名来源:本站整理发布时间:2009-07-15 18:03:17id=126063>摘要:本文详细介绍了在VB集成环境下数字波形高速显示的方法,同时对双通道波形显示和数字滤波方法也进行了介绍。
关键词:数字;波形;显示;滤波1 前言:随着计算机技术及电子技术的发展,数字采集技术在检测领域的应用越来越广泛,检测速度越来越高,检测的数据量越来越大,特别是在无损检测领域,将检测数据通过计算机处理后绘制出波形,并实时显示,对及时发现伤损、分析伤损具有重要意义。
2 波形显示检测数据通常是离散的数据,将离散的数据绘制出波形,可通过在两点间连接线段的方法实现。
用Line方法显示波形VB提供了Line画直线方法,可在窗体上增加一个图片框控件,适当设置图片的大小和背景颜色,用Line方法将离散数据按检测顺序连接成线段,即可将波形显示在图片框中。
但该方法显示波形速度较慢,不适合高速显示的应用。
Windows API函数显示波形在VB中两点间连线的另一种方法是用Windows API函数,Win32 API提供了以下两个函数,联合使用可实现波形的快速显示,经过测试,显示速度比使用Line方法快70%以上。
LineTo函数:函数功能:画出由数组定义的点连接的一系列线段。
函数原型:BOOL LineTo(HDC hdc,int nXEnd,int nYEnd);参数:hdc:设备环境句柄。
nXEnd:定义线段终点的X坐标。
nYEnd:定义线段终点的Y坐标。
返回值:若函数调用成功,则返回非0值;若函数调用失败,则返回值为0。
MoveToEx函数:函数功能:将当前位置更新为指定的点,并有选择的返回原先的位置。
函数原型:BOOL MoveToEx (HDC hdc,int X,int Y,LPPOINT lpPoint);参数: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))实时波形显示界面程序代码:COLORREF m_crTextColor;用编程运用该控件在VS2008环境下的编程步骤如下:1.建立一个对话框的MFC工程,在对话框上按照上图所示的界面布置控件。
其中波形控件那里布置一个Picture Control控件将其Modal Frame和Type均属性设置为true,其他均设置为False。
注意给Picture Control取的ID!后面编程将会用到。
2.将波形控件类的定义文件和实现文件拷贝至你的工程目录下。
但这实际上并没有将该类真正添加到你的工程下,需手动添加类。
常规操作,不详述。
3.在对话框的定义和实现文件中分别添加如下代码:程序代码:#include ""4.在对话框定义文件中(我给的供下载的例程中的是这个文件)中定义一个该控件类的变量:程序代码:private:C2DPushGraph m_PushGraph;5.在对话框的实现文件中(我给的供下载的例程中的是这个文件)的对话框初始化函数中添加如下代码:程序代码:(IDC_REALCTRL, this); 在不妨试着运行以下该程序,应该可以观察到那个控件显示出来了吧。
在添加以下代码:程序代码:(m_sin, RGB(255,255,255));(m_tra, RGB(255,0,0))这两行代码分别添加了一个正弦波形,ID号为m_sin,一个三角波形,ID号为m_tra。
不过运行之后并没有数据点绘制出来。
那是应为还没有调用bool Push( int nMagnitude, UINT uiLineID )函数添加数据点。
试着添加几个数据点再运行即可观察到波形。
7.还有一些控件的响应代码看看那个下载的例程吧。
四.结束语成功了吧,Any Problem,Contact me please!控件设计]Nobi's StatusChart - 野比的状态波形图控件从构思到实现Nobi's StatusChart - 野比的状态波形图控件从构思到实现野比着源程序下载: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 参数传入//网格数(不计边缘)float div;float pos = 0F;//先画垂直方向//可以少画一根线div = (float)w / (float)gridWidth + 1;for (int i = 0; i < (int)div; i++){pos += gridWidth;(penGrid, pos - offset, 0, pos - offset, h);}//画水平方向div = (float)h / (float)gridHeight;pos = 0F;for (int i = 0; i < (int)div;i++){pos += gridHeight;(penGrid, 0, pos, w, pos);}对于波形,传入其波形值数组作为参数//从 0 到 w 绘制int len = w;//根据绘制方式if (chartMode == for (int i = 0; i < len; i++){(p, i, h - val[i], i, h);}(p, len, h - val[len - 1], len, h);}else{len--;for (int i = 0; i < len; i++){(p, i, h - val[i], i + 1, h - val[i + 1]);}len++;(p, len - 1, h - val[len - 2], len, h - val[len - 1]);}如何平移,是一个难点,需要在内部定时器的Tick()事件中加以处理//更新网格偏移//只有启用了网格移动才处理if (gridShiftting){iOffset += gridShifttingIncrement;iOffset %= gridWidth;}//更新图形(整体左移)//必须在这里而不能在画图的同时移动,//若在画图中移动,则当画面被遮挡(OnPaint)事件不发生时无法更新int len = w;for (int i = 0; i < len; i++){//判断数组越界if (i < len - 1){val[i] = val[i + 1];}else{val[len - 1] =currentValue;//break;}}//val[len] = currentValue;Invalidate();最后引发控件的Invalidate() 方法使控件重绘自身。