以下是小编帮大家整理的如何用XML实现高效管理数据.net,本文共10篇,供大家参考借鉴,希望可以帮助到您。

篇1:如何用XML实现高效管理数据.net
XML数据是Web上数据交换和表达的标准形式,和关系 数据库 相比,XML数据可以表达具有复杂结构的数据,比如树结构的数据,正因为此,在信息集成系统中,XML数据经常被用作信息转换的标准。 管理三大领域数据 基于XML数据的特点,XML数据的高效管理通常有着以
XML数据是Web上数据交换和表达的标准形式,和关系数据库相比,XML数据可以表达具有复杂结构的数据,比如树结构的数据。正因为此,在信息集成系统中,XML数据经常被用作信息转换的标准。
管理三大领域数据
基于XML数据的特点,XML数据的高效管理通常有着以下的应用。
1.复杂数据的管理
XML可以有效地表达复杂的数据。这些复杂的数据虽然利用关系数据库也可以进行管理,但是这样会带来大量的冗余。比如说文章和作者的信息,如果利用关系数据库,需要分别用关系表达文章和作者的信息,以及这两者之间的关系,这样的表达,在文章和作者关系的关系中分别需要保存文章和作者对应的ID,如果仅仅为了表达文章和作者之间的关系,这个ID是冗余信息,在XML数据中对象之间的关系可以直接用嵌套或者ID-IDREF的指向来表达。此外XML数据上的查询可以表达更加复杂的语义,比如XPath可以表达比SQL更为复杂的语义。因此利用XML对复杂数据进行管理是一项有前途的应用。
2.互联网中数据的管理
互联网上的数据与传统的事务数据库与数据仓库都不同,其特点可以表现为模式不明显,经常有缺失信息,对象结构比较复杂。因此在和互联网相关的应用,特别是对从互联网采集和获取的信息进行管理的时候,如果使用传统的关系数据库,存在着产生过多的关系,关系中存在大量的空值等问题。而XML可以用来表达半结构数据,对模式不明显,存在缺失信息和结构复杂的数据可以非常好的表达。特别在许多web系统中,XML已经是数据交换和表达的标准形式。因此XML数据的高效管理在互联网的系统中存在着重要的应用。
3.信息集成中的数据管理
现代信息集成系统超越了传统的联邦数据库和数据集成系统,需要集成多种多样的数据源,包括关系数据库、对象-关系数据库以及网页和文本形式存在的数据。对于这样的数据进行集成,XML这样既可以表达结构数据也可以表达半结构数据的形式成为首选。 而在信息集成系统中,为了提高系统的效率,需要建立一个cache,把一部分数据放到本地。在基于XML的信息集成系统中,这个cache就是一个XML数据管理系统。因此XML数据的管理在信息集成系统中也有着重要的应用。
开发难点解决之道
在实际的XML数据库以及基于XML的信息集成系统的开发过程中,
笔者遇到了一些技术难点,在解决这些难点的过程中,有一些经验是值得借鉴的参考的。
1.关系数据库中复杂查询的优化
在基于关系数据库的XML数据管理系统中。在没有建立索引的情况下,系统的性能非常低,为了提高系统的性能,我们在编码上建立了索引,经过分析,由于在系统中最常做的操作是a.x b.y的join操作,最好的选择是建立二维索引,由于我们的后端数据库没有对二维索引的支持,我们选择了在x和y属性上分别建立B+树的方法。使得系统性能得到了提高。此外,我们发现,在对嵌套查询进行翻译的过程中,如果嵌套查询的结果可能过大,对嵌套查询的结果建立临时表可以提高系统的性能。
经验总结:对于一个数据库应用,需要对其workload进行分析,根据workload建立索引;对于执行效率很慢的查询或查询集合,可以通过分析查询计划找出系统的瓶颈进行处理。
2.复杂数据库系统的调试
在调试XML数据的管理系统中,多次出现了小规模数据执行准确,效率很高,而大规模数据执行错误或执行效率很低的情况。对于这种情况,我们采取了定位错误、猜测错误, 继而加以解决的策略,也就是首先确定出现错误的操作,使得错误的出现具有可重复性,然后通过逐步删减数据,确定数据出现在哪些数据上,这样就使得调试设计的操作和数据的规模大大减小了,然后根据经验对错误进行猜测,逐步排除错误。
经验总结:对于数据规模大、操作复杂的数据库系统的调试,首要任务是让错误可以重现,然后把次要因素逐步排除,最后发现问题的所在。
3.复杂数据库系统的测试
由于系统需要处理各种各样的XML上的查询,为了确保系统的健壮性,需要选取多种具有代表性的查询对系统进行测试。为了选取这样的查询,我们考察了XML上影响查询的不同参数,包括查询的长度、查询中包含的关系种类、查询的选择性和查询中约束条件的选择性,根据这些参数,我们分别选择有代表性的查询对系统进行测试。
经验总结:对数据库系统的测试集合的选择,必须考虑到可能查询的多种因素;在数据库系统的设计和测试过程中,对数据库系统可能用于处理的查询集合,需要有深入的了解。
【责任编辑:火凤凰 TEL:(010)68476606-8007】
原文转自:www.ltesting.net
篇2:用VC++实现对波形数据的频谱分析.net
郎锐 频谱分析是电子工程上一个非常重要的分析手段,许多计算机辅助电路分析(CAA)类软件都具备这种分析能力,以便电子工程师能清楚地看到某波形的频谱分布情况,要对一个输入信号源作频谱分析,将其由时域信号转变为频域信号,就必然要用到傅立叶变换。 这
郎锐
频谱分析是电子工程上一个非常重要的分析手段,许多计算机辅助电路分析(CAA)类软件都具备这种分析能力,以便电子工程师能清楚地看到某波形的频谱分布情况。要对一个输入信号源作频谱分析,将其由时域信号转变为频域信号,就必然要用到傅立叶变换。这样,无论是在时域还是在频域,都要对连续函数进行积分运算。很显然,要通过计算机实现这种变换就需要预先通过抽样将原始的连续数据转变为离散数据,并将计算范围收缩到一个有限区间。因此,在允许一定程度近似的条件下,可以使用“离散傅立叶变换(DFT)”对波形数据进行频谱分析。
算法构成原理
要计算一个N点的离散傅立叶变换需要同一个N×N点的W矩阵(关于W矩阵请参阅信号与系统方面或数学方面的书籍)相运算,随着N值的增大,运算次数显著上升,当点数达到1024时,需要进行复数乘法运算1048576次。显然这种算法在实际运用中无法保证当点数较大时的运算速度,无法满足对信号的实时处理要求。
根据W矩阵中W元素的周期性和对称性我们可以将一个N点的DFT运算分解为两组N/2点的DFT运算,然后取和即可。为进一步提高效率,将上述两个矩阵按奇偶顺序逐级分解下去。当采样点数为2的指数次方M时,可分解为M级子矩阵运算,全部工作量如下:
复数乘法:M×N/2次
复数加法:N×M次
直接采用DFT算法需要的运算量为:
复数乘法:N×N次
复数加法:N×(N-1)次
当点数N为几十个点时快速傅立叶交换(FFT)的优势还不明显,而一旦N达到几千时优势是十分明显的:
N=1024时:DFT需1048576次运算,FFT仅需5120次运算,改善比为204.8。
N=2048时:DFT需4194304次运算,FFT仅需11264次运算,改善比达到372.4。
当采样点数较多时,如变换前和变换后的序列都按自然顺序排列,则中间运算过程会占用大量的中间存储单元,造成效率的低下和存储单元的浪费。根据FFT的实现原理我们可以对采样序列进行逐次奇偶抽选,打乱以前的次序重新排序,然后按此顺序参加运算,以“即位运算”提高存储单元的利用率。
复数的描述方法
进行傅立叶变换时不可避免地要用到复数,而在VC中并没有现成的可用于表示复数的数据类型,因此需要自己定义一个含有两个成员变量的数据结构来表示复数,这两个成员变量可分别用于表示复数的实部与虚部:
typedef struct tagComplex{
//复数的实部
float Re;
//复数的虚部
float Im;
}Complex;
倒序的实现
在进行快速傅立叶变换时,可以将输入的时域序列和输出的频域序列都按照自然顺序排列;也可以按照“蝴蝶图”所描述的计算方法对输入的时域序列按奇偶分解后的序列排序,而输出的频域序列仍是按自然顺序排列;还有一种方式是输入的时域序列是自然序列,而输出的频域序列则是按奇偶分解后的顺序排列。这三种方式各有优缺点:第一种对输入、输出不需要进一步排序,但由于自然排序不符合“蝴蝶图”运算规律,会占用大量中间存储单元;而后两种则无需中间存储单元,但需要倒序。权衡利弊,当采样点较多时还是采用后两种方式好,多一次倒序运算对现在的高性能计算机而言并不是什么负担。下面代码用于对原始采样序列的时间抽选奇偶分解工作,其中A、N分别表示指向采样序列复数数组的指针和序列的长度。
int NV2=N/2;
int NM1=N-1;
int I,J,K=0;
//用于中介的复数变量T
Complex T;
I=J=1;
while(I<=NM1)
{
if(I< J)
{
//借助于中间变量T,将A[J-1]的内容和A[I-1]的内容互换
T=A[J-1];
A[J-1]=A[I-1];
A[I-1]=T;
}
K=NV2;
while(K< J)
{
J-=K;
K/=2;
}
J+=K;
I++;
}
时域信号的频谱分析
首先要将从外设输入或采集的时域波形数据经抽样量化后,通过CFile类的Open(……)、Read(……)等成员函数将其读取到缓存中,并将其转化为复变量存放于复变量数组A中。同时需要验证数据量的长度是否为2的整数次幂,如不是则用0来补齐,否则无法用“蝴蝶图”进行分解运算。下面代码用于完成对原始采样时域序列的快速傅立叶变换,A、M分别表示指向原始采样数据数组的指针和序列长度的2的整数次幂:
……
Complex U,W,T;
int LE,LE1,I,J,IP;
int N=(int)pow(2,M);
//由于采用时间抽选奇偶分解方式,所以在参加运算前首先要对时间序列进行倒序
ReverseOrder(A,N);
int L=1;
while(L<=M)
{
LE=(int)pow(2,L);
LE1=LE/2;
U.Re=1.0f;
U.Im=0.0f;
//计算W算子的值
W.Re=(float)cos(PI/(1.0*LE1));
W.Im=(float)-1.0*sin(PI/(1.0*LE1));
if(abs(W.Re)<1.0e-12)
W.Re=0.0f;
if(abs(W.Im)< 1.0e-12)
W.Im=0.0f;
J=1;
while(J<=LE1)
{
I=J;
while(I<=N)
{
IP=I+LE1;
//复数运算A×U
T.Re=(float)A[IP-1].Re*U.Re-A
[IP-1].Im*U.Im;
T.Im=(float)A[IP-1].Re*U.Im+A
[IP-1].Im*U.Re;
//复数运算A-T
A[IP-1].Re=(float)A[I-1].Re-
T.Re;
A[IP-1].Im=(float)A[I-1].Im-
T.Im;
//复数运算A+T
A[I-1].Re+=T.Re;
A[I-1].Im+=T.Im;
I+=LE;
}
float temp=U.Re;
//复数运算U×W
U.Re=(float)U.Re*W.Re-U.Im*
W.Im;
U.Im=(float)temp*W.Im+U.Im*
W.Re;
J++;
}
L++;
}
……
上述代码执行完毕时,原先存放着时域数值的复变量数组内存放的就是经过分析后的频域值,利用此数据可以通过绘图将频域波形直观地显示出来,也可以将其存成数据文件,以备进一步使用,
测试及运算结果分析
编译运行程序,分析一个三角脉冲的数据文件,并保存分析结果。该三角脉冲幅度为1,持续时间2毫秒,抽样时间间隔是20微秒,延拓周期(数据记录长度)为10毫秒,采样点数为500,取2的整数次幂512个采样点。下附该三角脉冲频谱的计算结果及误差分析:
频率(Hz) FFT求得 X(f) 误差
0.00 1.00006E-03 1.00000E-03 6.10352E-08
100.00 9.67593E-04 9.67531E-04 6.14332E-08
200.00 8.75203E-04 8.75150E-04 6.25092E-08
300.00 7.36904E-04 7.36849E-04 6.39413E-08
400.00 5.72852E-04 5.72787E-04 6.52926E-08
500.00 4.05351E-04 4.05285E-04 6.61362E-08
600.00 2.54638E-04 2.54572E-04 6.61847E-08
……
2700.00 9.16539E-06 9.09679E-06 6.86075E-08
2800.00 4.53216E-06 4.46500E-06 6.71550E-08
2900.00 1.21487E-06 1.15945E-06 6.44190E-08
注:此处FFT运算结果都乘以了系数10毫秒(0.01秒)。
从上述数据中可以看出,在分析结果中产生了误差。这是由于待分析的连续时间信号不具备离散性或周期性,也可能有无限长度。为了适应FFT方法的需要,先对波形进行了抽样和截断,这样再用程序分析采样数据必然会引起误差。从分析结果还可以看出,频率越高,误差波动也越大,此分析结果产生的误差在允许范围之内,是一个可以允许的近似。
本程序在Windows98、Microsoft Visual C++ 6.0下编译通过。
原文转自:www.ltesting.net
篇3:用MFC如何高效地绘图.net
显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题,而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的 解决方案 。MFC的绘图效率的确不高但也不差,而且它的绘图函数使用非常简单,只要使用方法得当,再加上一些技巧,用MFC可以得到效率很高
显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的解决方案。MFC的绘图效率的确不高但也不差,而且它的绘图函数使用非常简单,只要使用方法得当,再加上一些技巧,用MFC可以得到效率很高的绘图程序。我想就我长期(呵呵当然也只有2年多)使用MFC绘图的经验谈谈我的一些观点。
1、显示的图形为什么会闪烁?
我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏幕显示时是由OnPaint进行调用的。当窗口由于任何原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时没有背景色对原来绘制的图形进行清除,而又叠加上了新的图形。
有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的,其实这样说并不对,绘图的显示速度对闪烁的影响不是根本性的。
例如在OnDraw(CDC *pDC)中这样写:
pDC->MoveTo(0,0);
pDC->LineTo(100,100);
这个绘图过程应该是非常简单、非常快了吧,但是拉动窗口变化时还是会看见闪烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的时间与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。
比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要闪烁5次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续重画只会闪烁一次。这个也可以试验,在OnDraw(CDC *pDC)中这样写:
for(int i=0;i<100000;i++)
{
pDC->MoveTo(0,i);
pDC->LineTo(1000,i);
}
呵呵,程序有点变态,但是能说明问题。
说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么闪呢?这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要闪得厉害一些,但是闪烁频率要低。
那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,闪烁是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间的差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧,不闪才怪呢。
2、如何避免闪烁
在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC提供的背景绘制过程了。实现的方法很多,
* 可以在窗口形成时给窗口的注册类的背景刷付NULL
* 也可以在形成以后修改背景
static CBrush brush(RGB(255,0,0));
SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);
* 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE
这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有图形进行显示以外,在内存中也有图形在绘制,
我们可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。
3、如何实现双缓冲
首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
//随后建立与屏幕显示兼容的内存显示设备
MemDC.CreateCompatibleDC(NULL);
//这时还不能绘图,因为没有地方画 ^_^
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//将位图选入到内存显示设备中
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
//先用背景色将位图清除干净,这里我用的是白色作为背景
//你也可以用自己应该用的颜色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
//绘图
MemDC.MoveTo(……);
MemDC.LineTo(……);
//将内存中的图拷贝到屏幕上进行显示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
//绘图完成后的清理
MemBitmap.DeleteObject;
MemDC.DeleteDC();
上面的注释应该很详尽了,废话就不多说了。
4、如何提高绘图的效率
我主要做的是电力系统的网络图形的CAD软件,在一个窗口中往往要显示成千上万个电力元件,而每个元件又是由点、线、圆等基本图形构成。如果真要在一次重绘过程重画这么多元件,可想而知这个过程是非常漫长的。如果加上了图形的浏览功能,鼠标拖动图形滚动时需要进行大量的重绘,速度会慢得让用户将无法忍受。怎么办?只有再研究研究MFC的绘图过程了。
实际上,在OnDraw(CDC *pDC)中绘制的图并不是所有都显示了的,例如:你在OnDraw中画了两个矩形,在一次重绘中虽然两个矩形的绘制函数都有执行,但是很有可能只有一个显示了,这是因为MFC本身为了提高重绘的效率设置了裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示(往内存或者显存都叫显示)比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。但是这个裁剪区是MFC设置的,它已经为我们提高了显示效率,在进行复杂图形的绘制时如何进一步提高效率呢?那就只有去掉在裁剪区外的绘图过程了。可以先用pDC->GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。
如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高
原文转自:www.ltesting.net
篇4:用VC实现竖写汉字的方法.net
中国人自古就有自右至左、从上到下书写汉字的习惯,而当我们在自己所编写的应用程序中使用输出函数输出的总是自左至右的横排文字。 有没有可能在我们的应用程序中实现竖写汉字的效果呢?笔者偶然发现了一种利用VC实现竖写汉字效果的方法,现在就把它介绍给大
中国人自古就有自右至左、从上到下书写汉字的习惯。而当我们在自己所编写的应用程序中使用输出函数输出的总是自左至右的横排文字。有没有可能在我们的应用程序中实现竖写汉字的效果呢?笔者偶然发现了一种利用VC实现竖写汉字效果的方法,现在就把它介绍给大家。
Windows系统内置了许多名称以“@”开头的字集,这些字集有一个共同的特点,即其所包含的文字全都是平躺着的(字头朝左,字底朝右)。如果我们能将这些字逆时针旋转270度后再显示出来,就可以达到实现竖写汉字效果的目的了。
要使文字发生旋转,我们只需创建一个逻辑字体并设定该逻辑字体的显示角度,再设定其字体名称为一个以“@”开头的字集的名称即可。我们可以采用两种方式创建逻辑字体。
其一,用CFont类的成员函数CreateFont直接创建逻辑字体。CreateFont的参数定义如下:
BOOL CreateFont(
int nHeight, //字体的高度
int nWidth, //字体的宽度
int nEscapement, //字体显示的角度
int nOrientation, //字体的角度
int nWeight, //字体的磅数
BYTE bItalic, //斜体字体
BYTE bUnderline, //带下划线的字体
BYTE cStrikeOut, //带删除线的字体
BYTE nCharSet, //所需的字符集
BYTE nOutPrecision, //输出的精度
BYTE nClipPrecision, //裁减的精度
BYTE nQuality, //逻辑字体与输出设备的实际
//字体之间的精度
BYTE nPitchAndFamily, //字体间距和字体集
LPCTSTR lpszFacename //字体名称
);
其中nEscapement单位为0.1角度,方向为逆时针,所以为了使平躺的字立起来应设定其值为2700,lpszFacename则赋以“@”开头的字集的名称,如“@system”。
其二,利用LOGFONT结构,将该结构作为参数调用CFont类的成员函数CreateFontIndirect创建逻辑字体。LOGFONT结构通常被用来描述一种逻辑字体,结构内的各变量分别代表逻辑字体的各个属性,这些变量与函数CreateFont的参数相同。其结构如下:
typedef struct tagLOGFONT { // lf
LONG lfHeight; //字体的高度
LONG lfWidth; //字体的宽度
LONG lfEscapement; //字体显示的角度
LONG lfOrientation; //字体的角度
LONG lfWeight; //字体的磅数
BYTE lfItalic; //斜体字体
BYTE lfUnderline; //带下划线的字体
BYTE lfStrikeOut; //带删除线的字体
BYTE lfCharSet; //所需的字符集
BYTE lfOutPrecision; //输出的精度
BYTE lfClipPrecision; //裁减的精度
BYTE lfQuality; //逻辑字体与输出设备的
//实际字体之间的精度
BYTE lfPitchAndFamily; //字体间距和字体集
TCHAR lfFaceName[LF_FACESIZE]; //字体名称
} LOGFONT;
下面我们就以一个示例来说明竖写汉字的实现方法:
1.建立一个MFC AppWizard(exe)应用工程CHNfont。在MFC AppWizard向导的第一步中选择Single Document,再点击按键Finish->OK完成工程的建立。
2.在CMainFrame.:OnCreate函数中添加如下代码,使窗体最大化。AfxGetMainWnd()->ShowWindow(SW_SHOWMAXIMIZED);
3.添加如下代码实现竖写功能。
voidCChildView::OnPaint()
{
CPaintDC dc(this);// device context for painting
/////// 利用CFont::CreateFont(...)函数实现竖写汉字////////
CFont myFont; //创建字体对象
//创建逻辑字体
myFont.CreateFont(
56, //字体高度(旋转后的字体宽度)=56
20, //字体宽度(旋转后的字体高度)=20
2700, //字体显示角度=270°
0, //nOrientation=0
10, //字体磅数=10
FALSE, //非斜体
FALSE, //无下划线
FALSE, //无删除线
DEFAULT_CHARSET, //使用缺省字符集
OUT_DEFAULT_PRECIS, //缺省输出精度
CLIP_DEFAULT_PRECIS,//缺省裁减精度
DEFAULT_QUALITY, //nQuality=缺省值
DEFAULT_PITCH, //nPitchAndFamily=缺省值
“@system”); //字体名=@system
CFont *pOldFont=dc.SelectObject(&myFont);//选入设备描述表
CRect rtClient;
GetClientRect(rtClient); //获取客户区尺寸、位置信息
//在客户区适当位置输出文字
dc.TextOut(rtClient.Width()/2+30,rtClient.Height()/8,
“无边落木萧萧下”);
dc.SelectObject(pOldFont); //将myFont从设备环境中分离
myFont.DeleteObject(); //删除myFont对象
/////////// 利用LOGFONT结构实现竖写汉字//////////////
LOGFONT lf; //定义字体结构
lf.lfWeight=10; //字体磅数=10
lf.lfHeight=56; //字体高度(旋转后的字体宽度)=56
lf.lfWidth=20; //字体宽度(旋转后的字体高度)=20
lf.lfUnderline=FALSE; //无下划线
lf.lfStrikeOut=FALSE; //无删除线
lf.lfItalic=FALSE; //非斜体
lf.lfEscapement=2700; //字体显示角度=270°
lf.lfCharSet=DEFAULT_CHARSET; //使用缺省字符集
strcpy(lf.lfFaceName,“@system”); //字体名=@system
CFont myLogFont; //定义字体对象
myLogFont.CreateFontIndirect(&lf); //创建逻辑字体
pOldFont=dc.SelectObject(&myLogFont);//选入设备描述表
//在客户区适当位置输出文字
dc.TextOut(rtClient.Width()/2-30,rtClient.Height()/8,
“不尽长江滚滚来”);
dc.SelectObject(pOldFont); //将myFont从设备环境中分离
myLogFont.DeleteObject(); //删除myLogFont对象
}
4.编译连接,运行,
以上实例在Windows98下,以VC++6.0编译通过。
原文转自:www.ltesting.net
篇5:用VC++实现自绘按钮控制.net
四川 曾 志 Microsoft Windows 以其丰富一致的图形用户界面,简单灵便的操作,被广大用户所接受,对话框就是其中一个非常重要的界面形式,并且Windows为其应用程序的 开发 者提供了相当丰富的界面资源,许多控制可以方便地加入对话框中。 但当我们需要编写一
四川 曾 志
MicrosoftWindows以其丰富一致的图形用户界面,简单灵便的操作,被广大用户所接受。对话框就是其中一个非常重要的界面形式,并且Windows为其应用程序的开发者提供了相当丰富的界面资源,许多控制可以方便地加入对话框中。但当我们需要编写一个商业应用,需要一个更友好的图形用户界面时,就会发现资源的贫乏。
Visual C++提供了一个CBitmap Button类在一定程序上缓解了增加新资源的要求。但当我们要求在程序中能动态地改变图形时,我们就不得不考虑放弃CBitmapButton类,而坐下来自己做一点工作了。
一个可行的办法就是重载CButton类(即按钮控制)。这样对这块区域的大小、位置和ID号都可以通过AppStadio方便地制作。当然这样作最大的好处还是在于充分利用C++的特性把绘制控制的代码封装了起来,既避免了重复性开发,又使程序变得更简洁,增强了代码的可读性。
现在我们就通过创建一个名叫CColorButton的类来学习这种方法。虽然这是一个功能非常简单的类,通过调用成员函数ChangeColor可改变其颜色,鼠标点中时则高亮边框表示选中。但利用这种思路我们只需添加几个数据成员和重载一个函数就可以方便地实现你所需要的功能。
在创建这个类之前,我们必须先了解WM_DRAWITEM消息。当按钮、组合框、列表框或菜单的某一视觉状况发生变化时,系统就会发送一条WM_DRAWITEM消息给这些控制的拥有者窗口。这个消息的wParam指出这个控制的 id 号,而IParam则是一个指向DRAWITEMSTRUCT结构的指针,该结构存放有关要绘制的项的信息以及绘制所需的类型。DRAWITEM?STRUCT结构具有如下格式。
typedef struct tagDRAWITEM?STRUCT{
UINT CtlType; // 控制类型
UINT CtlID;// 控制的ID号
UNIT itemID;//菜单项的索引
UINT itemAction;// 说明需要的绘图操作
UINT itemState; // 指明绘图后的可见状态
HWND hwndItem; // 控制的窗口句柄
HDC hDC; // 相关的设备环境
RECT rcItem;//被画控制的边框
DWORD itemData;// 指定与菜单项相联系的应用程序定义的32位值
}DRAWITEMSTRUCT;
其中itemAction 和 itemState决定了需要的绘图操作。itemAction 说明需要的绘图操作,可为下列值中的一个或多个;
值 含 义
ODA_DRAWENTIRE 需要重来全部控制时
ODA_FOCUS 获得或失去输入焦点
ODA_SELECT 选择状态改变
itemState指明当前绘图动作发生之后,项的可见状态。下面是状态标志:
值 含 义
ODS_CHECKD 只用于菜单中
ODS_DISABLE 该项被屏蔽
ODS_FOCUS 该项具有输入焦点
ODS_GRAYED 只用于菜单中
ODS_SELECT 该项处于被选中状态
(上) □成都 曾志
用VC++实现自绘按钮控制
利用VC++编程会发现,当按钮控制接收到WM-DRMAWITEM消息时会调用Cbotton类的DrawItem函数。因此我们要做的就是利用C++的多态性通过重载CButton类的Drawitem函数来响应MW-DRAWITEM消息。
下面我们就实际构造一个CCol?orButton类。
class ccolorButton:public CButton
{ private:
COLORREF m-color:
public:
CColorButton:CButton(),m-color(0){}; //构造函数
void ChangeColor(COLORREF color); //改变颜色
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct
);//重载的函数
};
//重载的虚函数
void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawIt
emtruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC); //得到绘制的设备环境CDC
VERIFY( lpDrawItemStruct->CtlType==ODT-BUTTON);
if (lpDrawItemStruct->itemAction & ODA-DRAWENTIRE)
{
//重绘整个控制
CBrush brush(m-Color);
dc.FillRect(&(lpDrawItemstruct->reItem),&brush)
;
} if ((lpDrawItemStruct->itemstate & ODS-SELECTED
) &&
(lpDrawItemStruct->itemAction &
(ODA-SELECT | ODA-DRAWENTIRE))) { //选中了本控制===>高亮边框
COLORREF fc=RGB(255-GetRvalue(m-color), 255-GetG
Value(m-color), 255-GetBValue(m-color));
CBrush brush(fc);
dc.FrameRect(&(lpDrawItemStruct->rcItem),&brush
);
} if (!(lpDrawItemStruct->itemState & ODS-SELECT
ED) &&
(lpDrawItemStruct->itemAction & ODA-SELECT)){
//控制的选中状态结束===>去掉边框
CBrush brush(m-color);
dc.FrameRect(&lpDrawItemStruct->rcItem,&brush);
} dc.Detach();
} //用于改变颜色的成员函数
void CColorButton::ChangeColor(COLORREF color) { CR
ect rect;
m-color=color;
GetClientRect(&rect);
}
m-colorChangeColor(COLORREF color)color,WM-DRAWITEM上面代码中数据成员m-color和来保存按钮的颜色,
ChangeColor(COLORREF color)函数负责改变按钮颜色值为color,然后通过使控制的客户区无效而激发WM-DRAWITEM消息。现在这个按钮控制类就算搭好了。下面我们把它加入到对话框中来试验一下(中) 用VC++实现自绘按钮控制1.首先通过AppWizard创建一个单文档的应用。
2.紧接着启动AppStadio创建一个对话框。添加一个按钮控制,
并将其ID设置为 IDC-COLORBUTTON。最后一定要记住将push Button Properties对话框中的Owner Draw检查框置上检查标志。
3.在AppStadio内运行ClassWiz?zand来产生CTestDialog类。然后在CTestdialog类中加入数据成员,在CTestDialog类说明加入如下的private型数据成员:
private:
ccolorButton m-ColorButton;
4.现在剩下的问题是到底要怎样才能使m-ColorButton的DrawItem函数能响应系统发往ID值为IDC-COLORBUTTON的按钮控制的WM-DRAWITEM消息。这时就要用到CWnd类的成员函数BOOL CWnd::Subcla
ssDlgItem(UINT nID,CWnd *pParent)。通过调用这个函数,我们可以动态地接管从对话框模板产生的控制,并把它隶属于CWnd对象。即用当前的CWnd对象接管发向隶属于pParent的ID号为nID的控制的一切消息。对于按钮控制而言,它把当前的按钮控制的位置和大小也清成和nID对应的按钮控制一样。于是我们对CTestDialog的源文件进行如下的编辑:
BOOL CTestDialog::OnInitDialog()
{ CDialog::OnInitDialog();
//TODO:Add extra initialization here
m-ColorButton.SubclassDlgtem(IDC-COLORBUTTON,this)
;//接管消息
m-ColorButton.ChangeColor(RGB(255,0,0);//设置为红色(可设为任何颜色)
return(TRUE);
}
接着通过ClassWizzard在CTestDialog中加入一个响应鼠标点击IDC-COLORBUTTON按钮的消息的函数:
void CTestDialog::OnColerbutton()
{ //TODO:Add your control notification handler code
here
int r=int(((float)rand()/RAND-MAX)*255
int g=int(((float)rand()/RAND-MAX)*255
int b=int(((float)rand()/RAND-MAX)*255
m-ColorButton.ChangeColor(RGB(r,g,b));
}
5.最后,利用ClassWizzard为View加入一个响应WM-LBUTTONDOWN的函数,以便激活对话框。请按如下代码对其进行编辑。
void CTestView::OnLButton?Down(UINT nflags,POINT point)
{ CTestDialog dlg;
dlg.Domodal();
}
6.编译并测试该程序。当鼠标在落视窗中时,按下鼠标左键应能弹出一个对话框。在对话框中的红色矩形区域内按下鼠标左键就会使其边框变成高亮状态,若在这块区域内释放左键则这城区域就会改变颜色且颜色是随机的。
只需更改DrawItem函数中的重绘代码,就可以得到自己的需要图形按钮。
原文转自:www.ltesting.net
篇6:用MFC插入Excel工作表实现自动化.net
这篇文章讲述了如何使用MFC将Excel工作表插入到SDI视图中,文章包括插入工作表并将文字添加到A1单元格的详细步骤,每一步都有详细说明。 虽然你可以直接将代码插入到你的程序中,但理解这些例子你才会真正受益。 更多信息 以下是创建这个MFC应用程序的步骤:
这篇文章讲述了如何使用MFC将Excel工作表插入到SDI视图中。文章包括插入工作表并将文字添加到A1单元格的详细步骤,每一步都有详细说明。 虽然你可以直接将代码插入到你的程序中,但理解这些例子你才会真正受益。
更多信息
以下是创建这个MFC应用程序的步骤:
1.使用AppWizard创建一个新的MFC AppWizard(EXE)工程,命名为“Embed_Excel”
2.选择单文档视图(SDI)结构,在第3步中需要选中Container,以提供容器支持。
其它都为默认。
产生以下类:
应用类: CEmbed_ExcelApp in Embed_Excel.h and Embed_Excel.cpp
框架类: CMainFrame. in MainFrm.h and MainFrm.cpp
文档类: CEmbed_ExcelDoc in Embed_ExcelDoc.h and Embed_ExcelDoc.cpp
视图类: CEmbed_ExcelView in Embed_ExcelView.h and Embed_ExcelView.cpp
容器类: CEmbed_ExcelCntrItem in CntrItem.h and CntrItem.cpp
3.在VIEW菜单中,选ClassWizard,选Automation选项卡,选Add Class,选择From a TypeLibrary, 选中Microsoft Excel 97/ 类型库:Excel8.olb或Excel9.olb(在Microsoft Office\Office目录下) 会将类型库中的所有类添加到你的工程中。
4.在CntrItem.h中为CEmbed_ExcelCntrItem类添加如下函数定义:
LPDISPATCH GetIDispatch;
5.然后在CntrItem.cpp中添加GetIDispatch方法
示例代码
-----------
/*******************************************************************
* This method returns the IDispatch* for the application linked to
* this container.
********************************************************************/
LPDISPATCH CEmbed_ExcelCntrItem::GetIDispatch()
{
//The this and m_lpObject pointers must be valid for this function
//to work correctly. The m_lpObject is the IUnknown pointer to
// this object.
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
//The embedded application must be running in order for the rest
//of the function to work.
Run();
//QI for the IOleLink interface of m_lpObject.
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
//Retrieve the IUnknown interface to the linked application.
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0(“Warning: Link is not connected!\n”);
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
//QI for the IDispatch interface of the linked application.
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, (LPVOID FAR*)&lpDispatch)
!=NOERROR)
{
TRACE0(“Warning: does not support IDispatch!\n”);
return NULL;
}
//After assuring ourselves it is valid, return the IDispatch
//interface to the caller.
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
6.在Embed_ExcelView.h中为CEmbed_ExcelView类添加如下函数定义:
void EmbedAutomateExcel();
7.然后在Embed_ExcelView.cpp中添加EmbedAutomateExcel方法:
示例代码
-----------
/********************************************************************
* This method encapsulates the process of embedding an Excel
* Worksheet in a View object and automating that worksheet to add
* some text to cell A1.
********************************************************************/
void CEmbed_ExcelView::EmbedAutomateExcel()
{
//Change the cursor so the user knows something exciting is going
//on.
BeginWaitCursor();
CEmbed_ExcelCntrItem* pItem = NULL;
TRY
{
//Get the document associated with this view, and be sure it’s
//valid.
CEmbed_ExcelDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//Create a new item associated with this document, and be sure
//it’s valid.
pItem = new CEmbed_ExcelCntrItem(pDoc);
ASSERT_VALID(pItem);
// Get Class ID for Excel sheet.
// This is used in creation.
CLSID clsid;
if(FAILED(::CLSIDFromProgID(L“Excel.sheet”,&clsid)))
//Any exception will do. We just need to break out of the
//TRY statement.
AfxThrowMemoryException();
// Create the Excel embedded item.
if(!pItem->CreateNewItem(clsid))
//Any exception will do. We just need to break out of the
//TRY statement.
AfxThrowMemoryException();
//Make sure the newCContainerItem is valid.
ASSERT_VALID(pItem);
// Launch the server to edit the item.
pItem->DoVerb(OLEIVERB_SHOW, this);
// As an arbitrary user interface design, this sets the
// selection to the last item inserted.
m_pSelection = pItem; // set selection to last inserted item
pDoc->UpdateAllViews(NULL);
//Query for the dispatch pointer for the embedded object. In
//this case, this is the Excel worksheet.
LPDISPATCH lpDisp;
lpDisp = pItem->GetIDispatch();
//Add text in cell A1 of the embedded Excel sheet
_Workbook wb;
Worksheets wsSet;
_Worksheet ws;
Range range;
_Application app;
//set _Workbook wb to use lpDisp, the IDispatch* of the
//actual workbook.
wb.AttachDispatch(lpDisp);
//Then get the worksheet’s application.
app = wb.GetApplication();
//Then get the first worksheet in the workbook
wsSet = wb.GetWorksheets();
ws = wsSet.GetItem(COleVariant((short)1));
//From there, get a Range object corresponding to cell A1.
range = ws.GetRange(COleVariant(“A1”), COleVariant(“A1”));
//Fill A1 with the string “Hello, World!”
range.SetValue(COleVariant(“Hello, World!”));
}
//Here, we need to do clean up if something went wrong.
CATCH(CException, e)
{
if (pItem != NULL)
{
ASSERT_VALID(pItem);
pItem->Delete();
}
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
//Set the cursor back to normal so the user knows exciting stuff
//is no longer happening.
EndWaitCursor();
}
将下面一行添加到 Embed_ExcelView.h:
#include “excel8.h”
注意:如果使用Excel 2000, 头文件是 “excel9.h.”
看一下View类中的 OnInsertObject() 方法,对其中的注释引起了我们的兴趣,因为它和我们刚写的方法有惊人的相似,
事实上,我们刚才写的是OnInsertObject()的一个特例:允许用户从可用的OLE对象列表中选择其一插入到应用程序中。因为我们只想对Excel工作表进行自动化,所以派生这一行为。在我们的程序中,我们移去了InsertObject()内部的所有代码,用如上EmbedAutomateExcel()中的代码代替,或者你可以在InsertObject()函数中直接调用EmbedAutomateExcel()。
编译并运行我们的程序。
在编辑菜单中选择 插入新对象.
运行结果:一张Microsoft Excel 工作表插入到视图中;并且通过自动化,A1单元格被填上“Hello, World!” 字符串。
原文转自:www.ltesting.net
篇7:船员管理数据整合设计与实现
船员管理数据整合设计与实现
介绍了船员管理相关信息系统的`建设与使用情况,根据各系统间数据交换与共享需求,提出船员管理数据的整合思路.通过部署基于INFOREAI数据交换平台、基于XML的海船船员数据交换逻辑组件实现船员管理数据的交换与共享.
作 者:钱正锋 作者单位:江苏海事局,江苏,南京,210009 刊 名:中国水运(下半月) 英文刊名:CHINA WATER TRANSPORT 年,卷(期): 9(5) 分类号:U676.2 关键词:数据交换 数据整合 XML篇8:实现高效物流信息化管理 ERP不是全部
实现高效物流信息化管理 ERP不是全部
要实现高效的物流管理就必须建立有效的信息化机制。但是,在过去的实践中,对ERP系统的不准确定位影响了物流信息化的推进,“ERP就是物流信息化或ERP已经过时”的判断都是片面的。事实上,对于任何企业个体的物流信息化而言,并不是“非此即彼”那样简单。ERP的能量不可低估ERP以信息为媒介把企业多种业务领域及其职能集成起来,追求所谓的整体效能。毫不夸张地说,ERP是物流信息化的强有力工具,它通过销售和分销、物料管理、生产计划、质量管理、工厂维修等核心模块,帮助企业减少库存、缩短产品周期、降低成本、改善企业物流的整体操作。
联想的第三代电子商务包含了以ERP为基础的销售管理、以SCM为基础的供应链管理系统以及由联想自主开发的PRC系统(下游渠道关系协同系统)。依托订单系统、生产计划系统、库存管理系统、仓库管理系统、市场销售预测系统、精益制造系统、财务管理、车间管理系统和配送管理系统的紧密集成,形成了客户订单驱动的、以ERP为基础的'、完全基于网络的物流管理体系。
海尔通过设计实施基于协同电子解决方案mySAP.com的BBP(电子采购平台)项目,构建了基于后台ERP系统的完善的内部供应链,覆盖了整个集团原材料的集中采购、原材料库存、立体仓库的管理和各个事业部的生产计划、生产线工位的原材料配送、成品下线的原材料消耗倒冲以及物流本部零部件的采购等业务,大幅降低了采购成本,仓储面积减少一半,库存资金周转时间从30天降低至12天以下。
不难看出,ERP已经在物流运作过程中发挥了巨大的作用。但是,ERP系统的高复杂性,实施、应用和运营的高成本、高风险、高难度和高要求,适应变化的局限性以及供应链管理和客户关系管理能力的不足,应该引起企业的警觉,必须判断ERP是否真正适应本企业的物流信息化要求。
物流信息化不等于ERP现代物流的范畴已经扩大到生产制造领域,包括从原材料采购、加工生产到产品销售、售后服务整个物理性的流通过程,而不仅仅是从产品出厂开始。从实践层面看,物流信息化已经表现出不同层次的应用。
制鞋企业奥康集团采用网络分销管理系统,实现了以信息为基础的经营决策机制,有效解决了信息不通畅问题,对市场变化的反应更加灵活了。这种基本的信息化应用具有很强的代表性,因为从总体上来看,我国绝大部分企业,特别是中小型企业仍处于发展初期,关注的是如何用较少的投资,解决好业务各流程的信息化问题,包括信息的采集、传输、加工和共享,建立决策依赖信息和数据的机制。
当然,基本的物流信息化不能满足基础较好企业的应用要求,必须将系统论和优化技术引入物流的流程设计和改造,固化合理的流程和科学的管理制度,并在规定流程中实施优化的操作方案,如仓储存取优化方案、运输路径优化方案,以不断降低成本、加快资金周转。东风汽车股份有限公司开发的整车仓储电子化管理系统是操作过程优化的一个典型应用,通过建立数学模型,实现了在仓储面积、车型集中管理和存取顺序等多项约束条件下的仓储方案优化。
同时,物流信息化已经发展到了供应链应用阶段,超出了传统物流管理系统的范畴,它通过实现生产企业与销售企业的协同、供应商与采购商的协同,提高整个供应链的效率和竞争力。比如,某国有粮食购销企业的粮食流通链条涉及到了农户(生产者)、收储站和储备库(收储)、管理机构(调运)、农业银行(信贷)、财政部门等环节,这是以粮食流通企业为龙头的农业产供销供应链,在粮食物流中具有一定的典型性,既是一种新型的流程,更是一种企业(及有关单位)之间新型的战略伙伴关系。
显然,任何企业或企业集群不能指望,也没有必要实现完全的一步到位的物流信息化,必须依据明确的目标需求逐步推进,通过进行准确的需求分析,确定信息化的目标和要达到的信息化层次。而在实现不同层次的物流信息化时,ERP不是惟一的,更不是全部的。
专项物流系统也有用武之地:与ERP相比,实施专项物流管理系统也有明显的优势:针对性强、实用性好、投资回报率高、实施周期短、实施风险低、适用行业广等。
其中,自动化仓储及物流输送控制系统(AS/RS)是由高层立体货架、堆垛机、各种类型叉车、出入库系统、无人搬运车、控制系统及周边设备组成的自动化系统,通过计算机实现设备的联机控制,进行库存管理及数据处理,达到充分利用存储空间、迅速而合理、准确地处理物品的目的。分销管理系统(DRP)则通过互联网将供应商与经销商有机地联系在一起,为企业的业务经营及与贸易伙伴的合作提供了一种全新的模式,使企业具备对订单和供货进行快速反应和持续补充库存的能力。另外,运输管理系统(TMS)则主要是利用GPS技术、计算机技术和网络技术,增强双向信息与监控机能,实现运输的网络化管理,提高货车配置效率,降低运输成本。其他物流专项系统还包括采购管理系统(EP S)、供货商关系管理系统(SRM)、销售管理系统(SOM)等。
尽管每个专项物流系统只解决整个物流环节中一部分的问题,但只要它们能够发挥各自的专长,就能让企业各取所需。
篇9:用FPGA实现数据远距离的高精度传输
用FPGA实现数据远距离的高精度传输
摘要:详细阐述一种利用交错编码的思想,来改远距离通信质量的新设计。设计由FPGA芯片实现,能很方便加载到各种单片机有线或无线通信系统的收发接口中。通过对发、收信息的编、解码处理,增强信息在传输过程的抗干扰能力,以达到远距离高精度传输目的。关键词:FPGA远距传输高精度交错编码解码
1意义
简单的多机间数据通信在我们的设计中很普遍,一般情况下数据传输距离很短,不会超过百十m,因此仅采用双绞线加RS232或RS485标准就可以有效传输。但有时多机之间的距离也会很远,如我们所设计的一个气象项目,就要求子站遍布在基站1km范围内。因此在考虑成本、不增加很多设备的前提下,有效防止噪声干扰,保证子站与基站的数据高精确传输就很重要。
图1方案框图
通常多机短距通信中,可以在收发端加入奇校验、累加和校验等出错就重发的防噪声措施;但以上措施都只能检错,不能纠错,也就是说传输过程中不能容错。在远距离、干扰大、出错概率非常高的情况下,单纯的出错就重发措施会失去工作效率和意义。因此,我们需要一种能容错的数据传输方式,就要对数据编码。因此,不同传输环境的噪声性质不相同,对应的编码方式也不一样,所以我们设计编码时强调更多位的纠错冗余,以适合较多的环境,但相应地就降低了传输速率。另外,出于通用性和简易性的考虑,我们的设计应可直接加载于原有的有线或无线通信系统上,除数据连线外,不需对原有系统做任何改变。
在此,我们采用了交错编码技术来增加数据传输过程的容错能力。编解码设备插入加载到通信系统原来的数据收发端口。因此,微处理器要发送的数据由原先的直接经发送端(无线通信为调制器和发送器)发送,变为先经编码设备编码,然后再经原有的发送端发送;同理,接收端(无线通信为接收器和解调器)收到信息,经解码设备解码出数据,再传送给微处理器。
2设计方案
为适应多种信道,要求我们的设计能同时纠随机错和突发错,并且能有多位的纠错冗余。因此,我们基于常用的卷积码和循环码特性,自定义一种简单的线性分组码作为纠错编码,以便我们刻意去提高纠错的位数。同时我们采用交错发送技术来提高纠突发错能力,并利用FPGA去实现该方案。
(1)方案的应用范围
我们所设计的方案用于远距离的多机通信。根据实际经验,本方案默认微处理器收发的数据为8位并行数据+1位同步时钟,因此提供8位数据线和1位同步线。对于串口,则可增加串行转换的移位寄存器来转化。
图3解码器仿真图
(2)方案的实现
方案的实现如图1所示。
①在子站、基站的收发端口与微处理器之间分别加入相应的编解码设备,使得子站与基站间传输的.数据先经过编解码再传输,以达到增强容错的能力。
②用帧结构实现码字的交错。
③远距离传输,收发端最好选用同步方式,但这不是本设计的内容,不予以讨论。
图4编码器仿真器
(3)基于精度,对数据的每一位单独编码
实际应用中,对数据精确的定义并非数据的完全重合,而是要求某一个精度。完全重合只对用做标志的数据有意义,对单纯计算用的数据并没有必要。基于精度要求,显然一个数据信息的高位对精度影响远比低位大(如:FFH,当最高位出错变为7FH时,精度变化最大,而最低位出错变为FEH时,精度变化最小)。因此,我们并没有对8位数据信息进行整体编码,而是逐位分开进行编码:高数据位,采用更长的编码,以保证更高的正确率;低数据位,则可采用较短的编码,兼顾效率和设备容量。具体编码如表1所列。
表1
8位数据最低位(3,1)码0对应010,1对应101,汉明距3,纠1错8位数据第二位(3,1)码0对应010,1对应101,汉明距3,纠1错8位数据第三位(5,1)码0对应01010,1对应10101,汉明距5,纠2错8位数据第四位(5,1)码0对应01010,1对应10101,汉明距5,纠2错8位数据第五位(7,1)码0对应0101010,1对应1010101,汉明距7,纠3错8位数据第六位(7,1)码0对应0101010,1对应1010101,汉明距7,纠3错8位数据第七位(9,1)码0对应010101010,1对应101010101,汉明距9,纠4错8位数据最高位(9,1)码0对应010101010,1对应101010101,汉明距9,纠4错
表2
第1位第2位第3位第4位第5位第6位第7位最高位00100100101001010010101001010100101010100101010101101101101011010110101011010101101010101101010101
对8个位远逐位编码,8个生成矩阵为1维矢量。因此用FPGA实现编码时,采用查表法更方便,如表2所列。
之所以选用010等作为码字,是因为01相间在组合为帧发送时,可以减少连0或连1的出现概率。
(4)帧结构实现交错发送技术
为纠突发错,码字要按交错格式发送。因此,用帧实现码字的交错,数据发端按帧发送,数据收端按帧解码。8个码字共48位(6字节),加帧头2字节,所以,帧为8字节。为说明帧结构,暂以字母表示码字各位:
码字0:a2a1a0;码字3:d4d3d2ed1d0;
码字1:b2b1b0;码字4:e6e5e4e3e2e1e0;
码字2:c4c3c2c1c0;码字5:f6f5f4f3f2f1f0;
码字6:g8g7g6g5g4g3g2g1g0;
码字7:h8h7h6h5h4h3h2h1h0;
帧结构如表3所列。
图5纠突发错仿真图
利用帧头1和帧头2的重合特点来检测帧头,因为码字交错发送时相邻两字节对应位基本01相间的。由表3可得,第3字节到第8字节,相邻字节至少有6位不相同。因此可借用汉明距的纠错思想,认为帧头1和2不重合的位在2位以内,则表示正确收到帧头。
表3
帧头111010100帧头211010100第3字节a0c0e0f6f0g0g6h0第4字节a1c1e2d0f1g1g7h1第5字节a2c2e2d1f2g2g8h2第6字节b0c3e3d2f3g3h6h3第7字节b1c4e4d3f4g4h7h4第8字节b2e6e5d4f5g5h8h5
3FPGA实现设计
(1)单工条件下的实现
用两块FPGA分别实现编码器和解码器。按前面的编解码原理,编码器接收子站8位信息和1位同步,输出8字节×8位帧结构编码作远程传输,解码器收到帧结构编码,输出8位信息和1位同步给基站。(在实际应用中,子基站两MPU还要加入通常的累加和检错或偶校验检错。因不属编解码内容,不作讨论。)
单工电路原理如图2。
为检验电路设计,假设输入信号为11001010,编码输出的帧结构为表4。
表4
帧头111010100=D4帧头211010100=D4第3字节00000111=07第4字节11111000=FB第5字节00000111=07第6字节11111010=FA第7字节00000101=05第8字节10111010=BA
编码器仿真图如图3。
同步信号clk_in上升沿到来时,编码器读入数据信息11001010,并按内部的波特率clk;在下降沿产生正确的帧格式编码输出(D4、D4、07、FB、07、FA、05、BA)。
解码器的仿真图如图4所示。
当解码器判断收到帧头(两个D4),则将同步信号clk_out置高,再按内部波特率clk在上升沿收6字节的帧结构码字,在同步信号的下降沿输出译码(11001010)。
纠突发错仿真图如图5所示。
当传输过程出现突发错时,第5字节改为FF,第7字节改为00,译码器给出信息11001010。
纠突发错仿真图如图5所示。
当传输过程出现突发错时,第5字节改为FF,第7字节改为00,译码器给出信息11001010。
因为信息最低位的编码能纠1位错,最高位能纠4位错,所以,当第3~5字节、第6~8字节分别出现一个8位的突发错,译码器均能完全纠正。出现多个突发错时,相应的信息低位将出错,但信息高位因具有更多位的纠错能力而仍能保持准确性。我们设计的目标也正是尽可能保证高位的正确,以保证精度。
(2)基于单工的双工通信
此时一片FPGA内集成了编码器和解码器,与MPU相连的数据通信接口仍为8位数据线,由MPU发W/R写读信号来控制编解码,因此同一时间只能单向传送数据,编解码不能同时进行。准确地说,为半双工通信。(要改为全双工,须将MPU的数据线接口翻倍,非常占资源。)
双工电路原理如图6所示。
双工编、解码器的内部电路如图7所示。(编码器,解码器与单工的相同。)
实际上,我们对编码器和解码器的输出分别加了一个传输门(transfer_X器件)。该传输门由W/R信号控制,一旦传输门关闭,则将传输门的输出置于高阻态(“Z”),因此,编解码器的输入输出不会相互干扰,从而能在同一数据线上进行半双工传输。
MPU向FPGA写信息,FPGA编码输出。W/R=0,信息为11001010。
MPU读FPGA的信息,FPGA收帧结构并解码。W/R=1,解码得11001010。
4总结
①我们的设计目的主要在于增加数据的容错能力。FPGA设备加载于MPU的数据接口与数据通信芯片接口之间,数据仍按原系统的发送方式远距离传输,如图8所示。因此原有的通信设备不必作改动,就能很方便地加载我们的设计。同时,因为编码采用的分组码的位数可以根据实际应用场合再做简单调整,因而能够提供更大的噪声冗余。
②FPGA内部提供统一的编解码波特率,最高由FPGA时钟频率决定,仿真图中采用100ns(10MHz)。MPU收发信息的波特率最高为编码波特率的1/8,因为1字节的数据信息要转换为8字节帧结构。也就是说,我们是以降低通信的最高速率为代价来换取数据的高精度的。因此,我们的设计主要应用于不要求过高速率的通信场合。
篇10:PB中实现数据窗口动态排序的三种方法.net
在PowerBuilder中使用数据窗口检索到的数据往往是无序的,虽然可以通过设置Select语句实现排序的功能,但是数据窗口一旦生成都无法进行动态调整, 一、准备工作 设计如图1所示的示例窗口。为了更好地比较三种不同的方法,dw―1中的数据来自两个表student和c
在PowerBuilder中使用数据窗口检索到的数据往往是无序的,虽然可以通过设置Select语句实现排序的功能,但是数据窗口一旦生成都无法进行动态调整。
一、准备工作
设计如图1所示的示例窗口。为了更好地比较三种不同的方法,dw―1中的数据来自两个表student和class。student表中包含四个字段sid(学号)、sname(姓名)、saddr(住址)和cid(班号),class表中包含两个字段cid(班号)和cname(班级名称)。
javascript.:if(this.width>498)this.style.width=498;' nmousewheel = 'javascript.:return big(this)' height=183 src=“/files/uploadimg/20050921/1444070.jpg” width=200>
图1
二、三种方法的源程序
三种方法中的“执行”按钮的代码分别为:
方法1:用SetSQLselect()
string ls―oldsql,ls―newsql,ls―order ls―column
ls―oldsql=dw―1.getsqlselect()
choose case ddlb―1.text
case ″学号″ls―column=″sid″
case ″姓名″ls―column=″sname″
case ″住址″ls―column=″saddr″
case ″班号″ls―column=″class.cid″
case ″班级名称″ ls―column=″cname″
end choose
if rb―1.checked then ls―order=″ASC″
else ls―order=″DESC″
end if
ls―newsql=ls―oldsql+″ ORDER BY ″+ &
ls―column+″ ″+ls―order
if dw―1.setsqlselect(ls―newsql)=-1 then
messagebox(″警告″,″数据设置失败″,stopsign!)
else dw―1.settransobject(sqlca)
dw―1.reset()
dw―1.retrieve()
dw―1.setsqlselect(ls―oldsql)
end if
方法2:用describe()和modify()
string ls―mod, ls―order,ls―old,ls―column
ls―old=dw―1.describe(′datawindow.table.select′)
dw―1.settransobject(sqlca)
choose case ddlb―1.text
case ″学号″ls―column=″sid″
case ″姓名″ls―column=″sname″
case ″住址″ls―column=″saddr″
case ″班号″ls―column=″class.cid″
case ″班级名称″ ls―column=″cname″
end choose
if rb―1.checked then ls―order=″ASC″
else ls―order=″DESC″
end if
ls―mod=″datawindow.table.select=′ ″+ls―old+&
′ORDER BY ″ ′+ls―column+′ ″ ′+ls―order+″ ′ ″
dw―1.modify(ls―mod)
dw―1.retrieve()
dw―1.modify(″datawindow.table.select= &
′ ″+ls―old+″ ′ ″)
方法3:用setsort()和sort()
string ls―sort,ls―order,ls―column
choose case ddlb―1.text
case ″学号″ ls―column=″#1″
case ″姓名″ ls―column=″#2″
case ″住址″ ls―column=″#3″
case ″班号″ ls―column=″#4″
case ″班级名称″ ls―column=″#5″
end choose
if rb―1.checked then ls―order=″A″
else ls―order=″D″
end if
ls―sort=ls―column+′′+ls―order
dw―1.setsort(ls―sort)
dw―1.sort()
三、三种方法的比较
1.第一种和第二种方法要求数据窗口在生成时是无序的,第三种方法无此要求,
2.对于来自不同表单的相同的列名(如student.cid、class.cid)用第二种方法排序实现起来较麻烦,因为在用modify()函数时要特别注意引号的使用。但是第二种方法比第一种方法的执行速度要快。
3.第三种方法使用起来最方便,既可以引用列名也可引用列号(如#4表示第四列)来指定序列。
原文转自:www.ltesting.net
文档为doc格式