精华内容
下载资源
问答
  • 由于桩体被输入的能量很低,桩周土体对桩身的阻力作用基本无发挥,影响应力波传播的因素基本只有桩身的完整性。影响低应变曲线的因素非常多:从大的方面来讲就三大块:桩自身、地层、测试方法。如果测试或分析不当,...

    低应变的特点是向试桩输入脉冲应力波,因为一般是人工激发,导致应力波的能量很低,桩土体系处于弹性工作范围内,桩身的状态以及桩身和桩周土体的结合状态都不会因检测而发生变化。

    由于桩体被输入的能量很低,桩周土体对桩身的阻力作用基本无发挥,影响应力波传播的因素基本只有桩身的完整性。影响低应变曲线的因素非常多:从大的方面来讲就三大块:桩自身、地层、测试方法。

    如果测试或分析不当,同一根桩在上述不同条件组合下,将会出现很多种曲线,所以如果不明确条件仅凭一根曲线就要判读准确,事实上很难。

    本文以基桩低应变检测波形影响因素的分析,总结不同因素对低应变波形的影响,为基桩低应变检测提供相应的参考。

    5de1b46ce7807547d3a9b6ad9454e966.png

    01 低应变采集影响因素分析

    1.1桩自身的影响因素

    桩自身包括桩长、桩身截面尺寸、桩身强度、成桩工艺等。桩长的限制取决于是否能够有效地识别桩底,除了检测系统性能方面的客观因素外,影响因素还有桩身截面阻抗的变化程度、桩周土的阻尼作用和桩身底部与桩底持力层的阻抗关系等。桩长越长,所选用的锤的质量越大,为了能够检测桩底,则锤击所产生的频率越低。频率越高,发射的能量越高,能量被吸收的越快,所检测的桩长越短。

    对于桩身存在的缺陷,诸如离析、疏松、均匀分布的细孔或夹泥等,会形成低质量混凝土区段而导致局部波速的显著降低。如桩身存在此类缺陷,其整桩的平均波速也将因此而明显偏低,按照基准波速推算的桩长,将会得出明显偏大的整桩长度。

    桩身截面尺寸的限制,现行的各种法定文件并没有对截面尺寸做出任何限制,根据一维波动理论的要求,桩身截面尺寸不宜超过所用应力波波长过多,因此,桩径超过2m以上时不能采用高频锤击脉冲,薄壁杆件在原则上不适用于这种检测方法,一则因为不符合平面波的要求,二则表面积大于实体的桩,桩周土体的影响更加显著而难以取得良好的检测效果。

    桩身强度的影响,一般来说,桩身强度与波速呈正相关关系,即混凝土波速强度等级越高,波速越大。

    下表为实践经验的总结:

    fa3ac9e60a397491127fd70c0e6e173c.png

    从表中可以看出,同一混凝土强度等级,其波速存在一定的波动范围,因为是混凝土波速除与其强度等级有关外,还受诸多因素的影响,包括粗集料的品种、粒径、用量、混凝土含水率、混凝土养护方式等。不同混凝土强度等级之间存在波速交叉现象,波速与混凝土只是一种粗略的对应关系。

    在实际检测中,会碰到C80的预制管桩,其波速范围在4400m/s左右,经大量的研究表明,波速与混凝土强度呈半对数关系,波速是强度的自然对数函数。波速后期虽强度的提高增长缓慢,预制管桩验证波速最好的办法就是测试躺在地表还未打入地下的完整管桩,将桩长作为以总长,实测反射波达到时间,反求波速即可。

    成桩工艺的影响,现行的成桩工艺有混凝土灌注桩、水泥搅拌桩、预制管桩等,根据检测经验,预制管桩一般波速最大,混凝土灌注桩其次,水泥搅拌桩波速最低。预制管桩成桩工艺有锤击成桩、静压桩、植桩等,根据经验检测数据,波速从小到大的顺序,锤击沉桩

    就其因,桩周土的阻抗作用并非主要原因,主因是施工作用改变了桩身混凝土材料特性,比如锤击沉桩的循环冲击加荷作用,导致混凝土材料出现微裂隙,导致桩身材料杨氏模量及密度的降低,从而出现纵波波速的降低。

    静压沉桩在成桩工艺上就要好很多,在水泥土浆液中植入管桩几乎与空气介质中的波速没有差异,因为在水泥土浆液中植桩,水泥浆对桩体有保护作用,桩身几乎不受损。需要说明,针对打入桩,如果选锤合理,锤击沉桩总锤击数控制在合理范围内,打入后桩身的波速与空气中的相差不会很大,可以忽略,否则就应该怀疑桩身是否受损,在低应变检测桩身完整性时,地下桩的波速与空气中的相比降低约20%。

    4f34545cfd3b2a98b8c077dcd884324b.png

    1.2地层的影响因素

    地层方面包含桩的支撑情况、桩侧土阻力等;桩端混凝土与桩端持力层阻抗相差越大,测试范围越大,反之相差越小。根据检测经验,支承在阻抗相近的岩石上的嵌岩端承桩,即便桩长很短,也难以获得桩底反射波。

    桩侧土阻力越小,桩土刚度比较大,能量衰减越小,测试深度越大。

    对于桩的支撑情况,从应力波传播的角度来说,在桩底应力波将遭遇一个阻抗突变的截面,因此,只要桩底的位移不大,没有出现接触介质的显著变化,桩底支承条件对桩顶实测速度信号的影响,完全可以根据这个截面阻抗突变情况用一维波动理论直接进行计算。

    即桩底为自由端是,在2L/c时刻将出现一个2倍幅值的正速度,即同向反射,而当桩底不动时,则出现一个2倍幅值的负速度,即反向反射。由于桩身的内阻尼和桩侧土体的阻力作用,实际桩底反射的幅值有可能减小许多。

    在工程检测中,为了便于看清桩底反射以及桩身各处的反射波,通常会利用指数放大等办法把桩底反射的幅值人为的调高到与初始应力波大体相等。

    对于桩侧土阻力的影响,任何桩侧的土阻力将在其作用截面处引发一个上行的压力波,幅值等于R/2。因此,沿桩身上下各处的土阻力的影响,必然将表现为依次到达检测截面的压力波而使实测的速度值以累计的方式逐渐减少或增大其负值。

    如果检测时实际激发的桩侧土阻力的分布是完全均匀的,则V -t曲线应该是一条沿时间轴向下的倾斜的直线,阻力越大,偏离程度越大;如果桩侧土阻力的分布并不均匀,则V-t曲线就会是弯曲的,如果锤击的激发作用不大,浅部桩侧土阻力较大而下部逐渐减小,则V-t曲线后部将不再递增而逐渐转到与时间轴平行的方向延伸。

    另外,桩侧土阻力还同时一个幅值等于-R/2的下行拉力波,因此,初始应力波在下行过程中必然将不断消弱,桩侧土阻力越强,实际到达桩身各截面的下行波就会变得越弱,由此引发的反射波也就会越弱。

    1.3测试方法的影响因素

    测试方法的影响因素包含采样频率、频带宽度、传感器安装位置、敲击能量、信号的后期处理等。

    采样频率的影响,采样频率越高,即采样间隔时间越小,则时域信号精度越高,但频率分辨率越低;反之,采样频率越低,即采样间隔时间越大,则时域信号精度越低,但频率分辨率越高。

    一般来说,频率越高,对短桩或长桩的浅部缺陷反射越明显,频率越低,对长桩的桩底反射及深度缺陷反射越明显。因此,为了提高时域信号的精度,要用较高的采样频率,而将信号做频谱分析时,为了提高频率分辨率,根据桩实际情况,应采用较低的采样频率。

    频带宽度的影响,在现场测试时,由于振源、桩土,系统的阻尼和衰减作用以及传感器等多方面的原因,很难有覆盖全频域的信号出现。

    在实际检测中,选择完成正常测试所需要的频率范围即可,为确保在时域分析中能完全记录缺陷两阶谐振峰,以读取频差,取一阶谐振峰2.5倍为上限频率,下限频率是在低于整桩一阶谐振频率的基础上选取,频域因不涉及波形形态,可适当放宽到30Hz。在波速为4000m/s时,根据不同检测部位的需要,完成测试所需的频带宽度如下表所示:

    68071ca1c3bf6bb81ebcee100c6d73a6.png

    传感器安装位置的影响,实心桩的激振点宜选择在桩头中心位置,传感器应粘贴在距桩心越2/3R处,需要说明的是,若为灌注桩,传感器距离桩的主筋不宜小于50mm。因敲击产生的应力波除向下传播外,也沿径向向周边传播,从周边反射回来的波与由圆心外散的波会发生叠加,在2/ 3R处波的干扰最小。空心桩的激振点及传感器安装位置应选择在桩壁厚的1/2处且应在同一水平面上,与桩中心连接线的夹角宜为90°。

    敲击能量的影响,反射波法测桩时,应准备几种不同的锤头和垫层,依据不同的检测目的而进行选用。桩越长,则选择锤的重量越大,直径越大,垫层越软,以利于激发低频信号,从而可以检测到桩底反射及深部缺陷;桩越短,则选择锤的重量越小,直径越小,垫层越硬,以利于激发高频信号,在满足检测到桩底的基础上,可以明显检测出浅部缺陷。

    敲击时应尽量使得力垂直作用于桩头,有利于抑制质点的横向振动,且应避免二次冲击,防止后续波的干扰。信号的后期处理影响,现信号处理主要有时域分析和频域分析两种处理方式。时域分析将桩假定为一维杆件,应用应力波理论,应力波的传播速度假定不变进行分析。

    由于基桩检测只能近似满足一维应力波理论,实测波速受许多因素的影响,如桩身材料黏弹性作用导致的屋里频散,入射频率越高,波速越大;桩身几何尺寸的影响,包括横向尺寸导致的几何频散及桩上部的三维效应,前者使波速降低,后者使波速增加;土体阻力的影响,阻尼的影响使相速度随入射波频率的增加而减小,静阻力的影响则相反;桩身应变幅度的影响,应变增加,波速降低。

    由于考虑以上因素,在实际进行低应变采集过程中,一般设定固定桩长和特征波速,运用时域曲线进行处理,查看所设定的速度与桩底反射的重合程度,以验证所采集波形的准确性。

    频域分析是对测试信号的做时域、频域的综合分析,是动态测试的普遍做法。在基桩检测中,要对桩身完整性做出正确判断,只进行时域分析,有时不能有效地识别和排除各种干扰频率的影响,而频域分析则可通过研究桩身振动频谱的组成情况,判断出仪器频响、测试技术及数据处理方法等对测试信号和测试结果产生的影响,并采取措施提高测试信号的质量。如时域曲线中缺陷处的多次同相反射波形包含着传感器欠阻尼的振荡信号,且不见桩底反射。

    通过频域曲线分析,找出传感器的安装谐振频率,并选择低通滤波滤掉谐振频率波,即可得到比较好的波形曲线。频域分析时,利用各种信号间谐振峰频差出现的规律,则可计算出桩长及相应的缺陷位置。

    02 结论

    低应变反射波法操作简单,费用低廉,对工程施工干扰极小,并且发现问题及时,可以查出断桩和严重的桩长不符,由此应用越来越广泛,但通过以上分析,低应变反射波法也存在一定的局限性,主要表现在如下:

    ①尚无法对缺陷定性,目前依据波阻抗的变化,仅能有把握将缺陷区分为缩颈类和扩径类,如缩颈与离析、严重离析与断桩、夹层与裂缝尚不能很好的区分。

    ②对缺陷程度的定量分析尚不理想,由于波速计算或选取不准,据此计算的缺陷位置的误差在10%左右,缺陷在桩轴向的高度及径向的分布以及缺陷质量下降的程度均难以准确计算。

    ③对波阻抗渐变类的缺陷难以判断,如缺陷程度由轻至重或由重至轻,相应波阻抗缓慢减小或增大,实测波形将无法反映这一变化。

    ④桩身存在多个缺陷时,深部缺陷容易发生漏判。因此,在基桩低应变检测中,应加强行业内交流,制定更切实可行的标准,在技术层面可以有效促进低应变反射波法测桩水平的提高。

    阿莲小姐姐整理编辑,来源于网络,侵权即删~

    展开全文
  • 示波器是一种用途十分广泛的电子测量仪器。... 影响数字示波器时间测量不确定性的因素是:采样间隔和测量间隔。  采样间隔与示波器的测量内插算法和时基短期稳定性有关。  测量间隔与示波器时基有关力科WaveMaster
  • 摘要:本文通过对影响激光焊接质量的因素中的焊接设备、工件状况和激光功率密度和光束模式、焊接速度、脉冲波形和脉宽、离焦量和保护气体等工艺参数进行分析,并分别就热导焊和深熔焊的特点作具体讨论,阐述提高激光...
  • 在这篇文章中,我们将讨论波形的基础知识,而在下一篇文章中,您将找到实践步骤,以逐步优化油墨的波形。 02. 基础 为了帮助解释波形的目的,让我们看一下打印头的喷嘴腔内部。下图描述了称为填充和喷射的喷射过程,...

    00. 目录

    01. 概述

    想更多地了解什么是波形,它们如何工作,以及为什么它们是喷墨开发中必不可少的一部分?很好,因为它们很重要,而且通常不是很了解。在这篇文章中,我们将讨论波形的基础知识,而在下一篇文章中,您将找到实践步骤,以逐步优化油墨的波形。

    02. 基础

    为了帮助解释波形的目的,让我们看一下打印头的喷嘴腔内部。下图描述了称为填充和喷射的喷射过程,该过程非常普遍地应用于设计不同的许多不同的喷头。在这种情况下,每当对PZT(压电陶瓷材料)施加电压时,其堆叠都会变形,从而改变墨水腔的容积,并使墨水在其中移动并最终喷射。将此电压施加到PZT的方法是波形
    在这里插入图片描述

    在我们的示例中,PZT仅在施加电压时才伸展,因此在插入喷头之前不会变形。一旦通电,喷头便会保持特定的电压,从而导致PZT伸展并保持其非喷射位置(左)。如果电压降低,则PZT会缩回并在腔室内产生膨胀,从而将墨水吸入其中(中)。要喷射墨滴,电压恢复到其原始值,墨水盒收缩,并挤出多余的墨水(右)。此过程每秒重复数千次。

    需要注意的是,打印头可以由正向脉冲或反向脉冲驱动,这取决于不同公司的技术考量。不管基于何种设计,波形中最重要的是波形倾斜部分的计时与保持计时。即电压保持在那个水平(高或低)多久后才回到起始位置。脉冲计时决定了当腔体的体积恢复到稳定状态时喷嘴处的喷墨状态,这是构建波形的第一步。

    03. 脉冲时序

    如果打印时你站在打印头旁边,你甚至可能会听到它“唱歌”,这取决于打印使用的频率。你能听到它的原因是因为驱动器产生声波。当然,这里面最重要的是墨水本身产生的声波,因为喷射压力的变化是由其来定义的。

    由于存在具有某些机械性能的墨水,并且由于声波反弹时会损失能量,因此腔室内的压力可以描述为阻尼共振器。压力的任何变化(例如PZT变形)都会导致特征压力变化。如此处所示,当PZT缩回并且腔室体积增大时,压力变化将导致墨水在腔室内开始来回移动。
    在这里插入图片描述

    通常,仅靠这种能量不足以使墨水喷射,只是将其拉回到腔室的另一端并弹起。通过在适当的时间使用电压脉冲增强压力,可以使液滴喷射更加有效,如此处所示。由于最佳时机,当压力超过临界值时会喷出液滴。
    在这里插入图片描述

    脉冲宽度如此关键的原因是,如果脉冲宽度太短或太长,则PZT的波动,压力和运动将不同步。如果在添加更多压力时墨水没有朝正确的方向移动,而不是平稳地增加动量,则可能会抵消动量。这类似于将孩子推到秋千上。如果在正确的时间推动它们,则动量会增加,并且它们会摆动得更高。如果在错误的时间推动它们,它们将猛烈停止。同样,如果脉冲宽度不正确,则反复进行的结果喷射将效率低下且不稳定。

    因为墨水需要在腔室的整个长度上来回移动,所以打印头可以产生的最大频率取决于打印头腔室的大小。设计有较长腔室的打印头需要更多的时间来使声波来回传播,因此无法经常喷射墨滴。

    由于喷嘴室的长度是固定的,因此您可能会认为,对于给定的打印头,正确计时压力波所需的脉冲宽度是恒定的。但是,时间也会受到该特定墨水的声音速度的影响。这就是为什么必须针对特定的墨水和打印头组合调整波形的原因,仅具有该打印头的通用波形是不够的。幸运的是,如果墨水的特性相似,则相同的波形对两者都适用。

    04. 共振现象

    在这里插入图片描述

    通常,在一个频率下工作的波形可能在另一个频率下工作的频率不佳。当墨水在腔室内来回移动时,这全部归结为脉冲的定时。随着打印频率的增加,给定脉冲产生的波和运动可以开始与前一个脉冲相互作用。在某些频率下,这将是增强的,结果是共振,如图像中的顶部示例所示。

    打印频率越高,在下一个降落和压力波来临时,压力尚未衰减到零的可能性就越大,因此,产生不良发射的可能性越大。如果墨水仍在移动,则前一个脉冲可能会增加压力(速度更高,更多的人造卫星,润湿)或降低压力(速度更低)。如果您的打印速度灵活,那么在一定频率范围内研究液滴的形成是明智的,以确保最终打印速度不会落在发生共振的频率范围内。

    05. 多个脉冲

    如果电子设备允许,则可以在每个像素处使用多个脉冲,从而使您可以创建更大,更快的墨滴。用于多脉冲的波形通常取决于压力波中的第一或第二共振。这意味着当墨水向喷嘴移动时,第一个脉冲将增加墨水的压力。一些墨水会喷出,其余的墨水会从孔口反弹并返回到对面的壁。一旦墨水再次移向喷嘴,第二个脉冲将增加其动量。脉冲应仔细调整。增强材料可能非常坚固,使压力过分驱动并造成喷嘴润湿。
    在这里插入图片描述

    如果脉冲的振幅相同,则第二个液滴将比第一个液滴更大且更快,因为它建立在前一个脉冲的共振上。它可以合并在面板或飞行中,具体取决于几个因素,包括打印头设计,脉冲到脉冲的时间,使用的电压和墨水性质。
    在这里插入图片描述

    实时查看液滴形成的能力有助于理解这些影响。在下面用JetXpert dropwatcher拍摄的照片中,您可以看到在相邻喷嘴中通过共振多脉冲波形形成了不同大小的液滴。左侧的喷嘴施加了三个脉冲波形,中央喷嘴只有最后两个脉冲,而右侧喷嘴只有最后一个脉冲。用于产生液滴的三个脉冲在时间上均匀分布,并且每个图像都是在压力波击中喷嘴开口时拍摄的。

    请注意,在脉冲结束后,喷嘴弯月面的延伸是由压力波引起的。第一个发生在韧带分离之前。喷射两次或更多次的喷嘴上的弯月面凸起较大,这表明由于先前的脉冲,已经施加了额外的压力。通过调整脉冲时序并可视化进度,可以更快地改善特定墨水的波形。

    额外的脉冲不仅用于喷射较大的液滴。通常在“关闭”数据上使用预脉冲使喷嘴挠痒,这意味着将提供足够的力以使墨水在喷嘴内移动,但不会喷射墨滴。另一个应用程序是使用后脉冲来消除弯液面的振荡,使您可以增加频率而不受先前下降的干扰。下面的波形具有许多内置的此类功能,并根据理光的台式打印机专利进行了改编。

    在这里插入图片描述

    06. 附录

    参考:https://imagexpert.com/what-is-a-waveform/

    展开全文
  • 正弦波形函数

    千次阅读 2016-10-08 18:33:10
    定义与定理 ...正弦:单位圆上的一点P,与圆心O连接出线段...余弦波可以看成是由正弦波平移适当的周期形成的波形,与正弦波的相位差为π/2+2nπ,n取整数 使用的时候通常就用正弦波函数就可以

    定义与定理
    定义:
    正弦:单位圆上的一点P,与圆心O连接出线段OP,OP与X轴的夹角为ø,在两个坐标轴上分别有投影OX和OY。那么,ø的正弦值定义为点P在Y轴上的投影 sin(ø) = OY 。
    正弦函数:当用弧度表示角度的大小时,正弦函数的定义域被影射到整个实数域R上,这样可以把正弦写成函数形式:
    ƒ(x) =sin (x)
    这个函数称为正弦函数。
    直观上,正弦函数可以看作单位圆上的一个点在旋转的时候,这个点在Y轴上的投影随角度变化的规律 。
    如果把三角函数推广到任意圆上,首先需要把函数中单位圆的半径变化考虑进来。在我们考虑到如何计算单位圆里的正弦值sin(ø)的时候,实际上忽略了正弦是一个比值。即:
    sin(ø) = OY / R;
    由于单位圆的半径 R = 1而被忽略了,当考虑到任意圆里的三角函数时,必须把半径考虑进来,才能得到和单位圆一致的结果。
    其次,圆心的位置可能不在圆心,并且旋转的点不一定从0开始。把这些因素完全考虑进来之后,我们得到的完整的正弦函数看起来是这个样子:
    ƒ(x) = a * sin(x + x0) + b
    公式中:
    a: 决定正弦函数振动幅度的大小;
    x0:表示x开始比0拖后的弧度值;
    b:表示函数偏离X轴的y方向上的距离(上加下减);


    余弦波可以看成是由正弦波平移适当的周期形成的波形,与正弦波的相位差为π/2+2nπ,n取整数

    使用的时候通常就用正弦波函数就可以



    展开全文
  • 非线性地震波形反演研究,邢文军,王永刚,地震波形反演由于其反演依据充分、可以有效的排除偶然因素影响,受到了广大地球物理工作者的关注。此外,由于非线性地震波形
  • 反射波法由于具有成本低、效率高的特点,成为一种常用的桩身完整性检测方法,完整性的判别可以通过对反射波的分析得出,而检测波形特征受现场施工条件、土层条件、采样位置、激振方式、桩身缺陷等多种因素影响.波形...
  • 目的探讨言语诱发听性脑干反应(speech evoked auditory brainstem response,s-ABR)的影响因素,揭示s-ABR更多的电生理特性。方法将24名健康成人(24耳)的s-ABR采用两种刺激率(11.1次/s、20.0次/s)和两种刺激强度(80d B...
  • 反演煤岩体内部破坏程度,采用数值计算的方法,对应力波在含单个裂隙煤岩体内的传播规律进行了研究,分析了应力波过缝前、过缝中、过缝后的波形特征,和裂隙宽度、荷载参数及岩层参数对延时规律的影响。研究结果表明...
  • 高功率激光装置的多路红外激光脉冲波形测量系统由光纤取样耦合、传输、合束、光电转换和数据采集处理单元构成,采用缩束与光学成像系统的光纤耦合方法克服了高功率激光束长距离传输后的指向漂移,针对正弦调频脉冲...
  • 研究了谐波分量对三角形光子微波信号相似度的影响。用数值模拟方法研究了三角波形的傅里叶级数保留至不同阶次时波形与理想波形的相似性。当傅里叶分量保留至三阶时,波形与理想三角波形的相似度达到0.989。提出了一种...
  • 在此从电路运行条件,即开关频率、激励波形、占空比、直流偏置,以及磁路运行条件,即磁感应强度、磁芯封装大小、气隙边缘效应两个方面对磁性元件损耗,包括磁损和铜损的影响进行了回顾和分析,指出了当前研究中存在...
  • DDR信号波形分析,完整性分析,包括信号完整性的影响因素和提高信号完整性的方法
  • 针对地铁牵引整流器内部二极管故障率高且诊断困难的...基于MATLAB/Simulink平台的仿真验证结果表明,所提地铁牵引整流器故障诊断方法不受故障位置、故障时间、系统运行负载等因素影响,具有良好的可靠性与适应性。
  • GDI 波形控件

    千次阅读 2010-07-30 13:02:00
    做了个完整的上位机软件(具体实现:根据下位机的指令,实现通过串口来操纵下位机进行实验,并将采集的数据进行处理和保存,并以图形的方式显示),整个项目边学C# WinForm边设计,这个波形显示控件就是项目中的一...

    编者记:

    09年暑假正好在学院实验室呆了一段时间,做了个完整的上位机软件(具体实现:根据下位机的指令,实现通过串口来操纵下位机进行实验,并将采集的数据进行处理和保存,并以图形的方式显示),整个项目边学C# WinForm边设计,这个波形显示控件就是项目中的一部分,也花了自己绝大多数时间。暑假一结束,也就没有再去接触C#了,主要精力放在C++,Windows编程上去了。此外,顺便将该波形显示控件当作自己毕业设计的内容,下文实际上是节选自自己的本科毕业论文的呵呵,希望对大家能有所帮助。由于自己是个C#新手,所以代码以及文章有疏漏、错误、不妥之处在所难免,欢迎交流哈(现在看着十个月前写的代码,感想颇多......)

    欢迎转载,但请注明出处(通宵整理排版 = =  很不容易的哈)http://www.cnblogs.com/xf_z1988/archive/2010/05/11/CSharp_WinForm_Waveform.html

    (写这篇文章之时,大学再一个半月就结束了,目前在学C++、Windows编程、希望能找到个适合的工作吧)

     

    “基于C#的波形显示控件”设计于09年暑假 源代码奉上呵呵:博客园下载 | CSDN下载 解压密码:CSharp_WinForm_Waveform

    《基于C#的波形显示控件的实现》写于2009年9月   跳到文章目录(注意这里是采用锚链接,订阅的朋友可能访问会失效的,例如QQ邮箱中的订阅= = 还是访问原文吧)

    “基于C#的波形显示控件的演示程序”为配套控件使用而设计的(演示程序源代码同控件源代码一起奉上了)

     

    下面先上几张图,大家可以先了解最后做出来是个什么东西:

     

     

     

    再奉上两个波形显示控件的演示视频(两个视频内容差不多的呵呵):

        

     

     

     

    摘    要

    计算机技术的飞速发展使得其在自动化系统中的应用日益增强。大量监控、图像数据显示软件活跃在自动化工业及自动化教学领域。同时,软件系统的日益复杂化使得模块化开发变得尤为重要。本课题所设计的基于C#的波形显示控件就可在微软.NET平台下进行代码功能重用,达到模块化开发和快速开发的目的,使得程序员能够集中精力设计软件的具体业务流程,而不必担心波形呈现的问题。

    本文先介绍了.NET平台下用户控件开发的基本方法,以及用C#描述的GDI+图形开发技术,然后提出一种基于C#的波形显示控件的设计思路,并对波形坐标值转换、坐标标尺、工具栏、局部放大等具体的设计细节进行详细解析。

    本课题设计的波形显示控件实现了同时显示多条数据曲线、局部放大查看、波形显示自动调整最佳坐标范围、动态显示波形等功能。创新之处在于设计了一种方法,使得波形显示控件的坐标轴的起点值和终点值能够以浮点数显示,并自动根据当前波形显示控件的大小,描绘出符合用户视觉的坐标标尺。

    最后,还设计了一个波形显示控件的演示程序,用于介绍该控件的使用方法以及功能测试,并提出了该波形显示控件可改进的地方。

     

    关键词:波形显示控件;C#;GDI+;动态波形

     

    目  录

    (注意这里是采用锚链接,订阅的朋友可能访问会失效的,例如QQ邮箱中的订阅= = 还是访问原文吧)

    1 绪论

      1.1 课题背景

      1.2 波形显示控件实现的功能

    2 主要开发技术介绍

      2.1 .NET用户控件介绍

      2.2 GDI+技术介绍

    3 波形显示控件整体设计

      3.1 数据存储结构的设计

      3.2 控件界面模块的设计

      3.3 控件工作流程的设计

    4 波形显示控件各细节的实现

      4.1 坐标值和标尺的实现

        4.1.1 坐标相关的成员变量

        4.1.2 坐标标定权值的概念

        4.1.3 坐标标尺的绘制

        4.1.4 子标尺线的选择性显示

      4.2 数据点的描绘

        4.2.1 数据值转换为坐标值

        4.2.2 溢出坐标范围的数据点的处理

        4.2.3 遍历所有数据线并绘制出

      4.3 波形显示区域网格的实现

        4.3.1 网格相关的成员变量

        4.3.2 网格的绘制

      4.4 工具栏按钮的实现

        4.4.1 工具栏按钮相互关系

        4.4.2 工具栏提示标签的实现

      4.5 波形放大功能的实现

        4.5.1 局部放大选择框的实现

        4.5.2 放大选择框的鼠标操作

        4.5.3 放大选择框的按钮操作

        4.5.4 更新数据显示范围为放大的范围

      4.6 坐标自动调整及恢复默认坐标的实现

        4.6.1 坐标自动调整功能

        4.6.2 恢复默认坐标范围功能

      4.7 波形显示控件接口的实现

        4.7.1 控件基本属性

        4.7.2 控件外观样式

        4.7.3 控件绘图接口

      4.8 波形显示控件其他细节的处理

        4.8.1 坐标值产生遮盖时的处理

        4.8.2 波形显示控件大小改变时的处理

        4.8.3 按钮点击时进行禁用操作

        4.8.4 右键菜单的显示

        4.8.5 XML注释以及智能提示

    5 波形显示控件功能的演示和使用

      5.1 波形显示控件演示程序的设计

      5.2 波形显示控件功能的演示

        5.2.1 外观样式的更改

        5.2.2 波形显示演示

        5.2.3 波形显示控件在实际项目中的使用

    6 课题总结

    参考文献

     


    1  绪论

    1.1  课题背景

    波形显示控件广泛见于监控测量,图像数据显示等自动化相关软件中,更是组态软件必不可少的一部分。例如美国国家仪器有限公司(National Instruments)的NI Measurement Studio集成式套件以及LabView图形化程序开发环境等,都包含技术成熟的波形显示控件,功能丰富且强大。

    目前购买成熟的自动控制相关的第三方控件库往往需要支付较高的费用,且大多数项目只用到些许专业性控件,例如一个喷管实验平台软件,图形用户界面只需要波形显示控件、U型差计控件和压力表控件,因此不适合科研机构以及中小型软件开发公司。所以掌握简单的控件开发技术,并开发属于自己团队或公司的控件库,从而降低软件开发成本,显得十分必要。

    微软的.NET解决方案依据其对已有代码的互操作性、简化部署、分布式、高效开发等诸多优点,完全胜任自动化系统软件的开发。C#是微软为.NET平台开发的一门语言,通过.NET平台可以轻松使用GDI+技术开发可重用的用户图形界面控件。GDI+是目前在Windows窗体应用程序中以编程方式呈现图形的唯一方法,它使程序设计者可以创建图形、绘制文本以及将图形图像作为对象操作,旨在提供较好的性能并且易于使用。

    波形显示控件因为涉及到坐标系、数据显示方式、精确度、实时性等因素,存在一定的开发难度。本课题意在使用微软.NET平台下的C#语言,提供一种坐标计算方法,解决自动调整最佳坐标范围,以符合用户视觉的方式显示坐标标尺,并通过GDI+技术显示波形数据,具有一定的实际开发参考价值。开发完成后的波形显示控件,可以快速嵌入到.NET平台下的软件工程中,开发者只需简单的操作,就可以使用该控件友好地显示波形数据,从而达到快速开发的目的。

    回到目录

    1.2  波形显示控件实现的功能

    本课题所设计的波形显示控件,主要实现以下功能:

    (1)    多条波形数据的显示。

    该波形显示控件能够同时显示多条波形数据,用户能够控制每条波形数据的显示颜色、线宽、线帽、以及线转折的样式。并且提供了三种波形数据显示的方式:连续数据线、离散点、条形图。

    (2)    友好坐标标尺的显示。

    该波形显示控件能够根据当前显示数据的坐标范围,友好地显示坐标标尺。例如X轴坐标起始值为34.2,结束坐标值为100.7,则控件不是简单得将坐标10等分并显示并不友好的坐标值,而是通过计算当前波形显示控件的大小,显示40、50……这样的友好的坐标值,并判断是否需要继续在40到50的坐标值之间显示更小分度的坐标值。

    (3)    波形显示区域网格的显示。

    该波形显示控件可以显示同坐标标尺的坐标线相对应的网格,使得用户能够更直观地观察波形数据。

    (4)    波形的局部放大。

    该波形显示控件提供了波形局部放大的功能。并根据实际使用和测试,控制了波形放大的精度,以免产生数据溢出的问题。

    (5)    坐标自动调整。

    该波形显示控件能够根据当前要显示的波形数据的值,自动选择最佳的坐标范围,来直观地在控件的波形显示区域显示完整的波形曲线。

    (6)    外观颜色方案的修改。

    该波形显示控件能够修改外观样式,诸如背景色、网格颜色、坐标线颜色、坐标值颜色等都可以进行调整,以使控件外观能够符合软件整体风格。

    (7)    其他细节。

    该波形显示控件还设计了一个工具栏,可以方面地使用网格显示、局部放大、坐标自动调整、恢复默认坐标功能。另外还设计右键菜单,能够显示当前鼠标位置的具体坐标值,以及工具栏按钮的快捷按钮。

    回到目录

    2  主要开发技术介绍

    2.1  .NET用户控件介绍

    在微软.NET平台下,可以设计出在应用程序内部或应用程序之间提供一致性行为和用户界面的复合控件,即用户控件。用户控件可以是某个应用程序的本地控件,也可以编译成DLL供多个应用程序使用。

    用户控件极大限度的帮助程序员进行代码重用和快速开发。通常用户控件通过继承UserControl基类,并组合微软提供的基础控件,如Button控件、PictureBox控件、Label控件等,然后进行功能的扩充和组合,从而创建出特定功能的用户控件。

    在Visual Studio 2005下使用C#开发.NET用户控件,可以通过新建Windows控件库来实现。创建成功后软件会自动从UserControl基类继承一个类,并允许通过设计视图添加所需要的已有控件。

     

    图 2‑1  设计用户控件界面

     图 2‑1  设计用户控件界面

    设计好大致的界面后,就可以着手设计具体的代码,用户控件通常通过对消息处理函数的编写,来实现特定的功能,并将控件中的各个模块联系起来。用户控件还需要设计出公开的接口属性和方法给控件的使用者,这样控件的使用者就能够调用公开的属性和方法,来实现对控件的操作和控制。另外,在编写控件的时候对各个属性和方法编写XML注释,并在生成控件的时候输出XML文档文件,这样控件使用者在使用该控件的时候,能够享受Visual Studio智能提示带来的便利。

     

    编译运行后可以检查基本的控件效果:

     

    图 2‑2  用户控件的调试运行

     

    最后可以通过项目属性设置程序集信息。

     

    图 2‑3  设置程序集信息

     

    这样,一个用户控件就设计完成了。

    用户控件自身不能独立作为程序运行,需要嵌入到特定的软件中。可以通过选择工具箱,添加新创建的.NET Framework组件,添加到工具箱中。其用法同微软提供的基础控件一样,可以通过拖拽的方式进行使用。

    回到目录

    2.2  GDI+技术介绍

    GDI+是.NET Framework类库,用于进行图形编程。它是一种基于GDI的技术,GDI即Windows Graphical Device Interface,是Windows API(应用程序编程接口)中处理图形的部分。

    GDI+是目前在Windows窗口应用程序中以编程方式呈现图形的唯一方法,它使程序设计者可以创建图形、绘制文本以及将图形图像作为对象操作,旨在提供较好的性能并且易于使用。

    GDI+技术在Windows应用程序中得到了广泛的应用,使得Windows图形图像编程变得格外得容易。目前Windows平台下的大量应用软件的图形界面通过GDI+技术实现。利用GDI+技术可以方便地在屏幕、打印机或者其他输出设备上输出图形、文本等内容,程序员无需关心硬件设备和设备驱动,就可以编写出设备无关的应用程序。一些新兴的信息化软件通过GDI+技术能实现动态交互的高级效果,比如可视化电子地图。

    在使用GDI+绘图之前,需要获得绘图对象Graphics,通常在编写控件的Paint事件时,Graphics对象可通过PaintEventArgs参数获得。所有的绘制过程都是面向对象的,例如实例化1像素的实线黑色画笔并绘制线条,可用如下的方式创建:

    Graphics Grap = e.Graphics;
    Pen p
    = new Pen(Color.Black);
    Grap.DrawLine(p,
    0, 0, 100, 100);
    p.Dispose();

    若填充一个区域的颜色,则代码样式如下所示:

    SolidBrush b = new SolidBrush(Color.Red);

    Grap.FillRectangle(b,
    0,0,10,10);

    b.Dispose();

    其直观的操作方式使得程序员能快速绘制椭圆,椭圆弧,矩形,贝塞尔曲线,路径等。

    通过GDI+技术创建自定义控件能实现各种功能。只需要在建立自定义控件后,编写响应Paint事件的代码,通过GDI+技术绘制必须的图形,就可以控制自定义控件的外观。本课题设计的波形显示控件,大量得运用了GDI+技术进行绘图操作,使得控件能够呈现出出色的界面效果。

    回到目录

    3  波形显示控件整体设计

    3.1  数据存储结构的设计

    本课题设计的波形显示控件主要用于显示数据点集合。数据点集合具有大小不确定性,因此可以使用.NET提供的泛型支持,其主要的优点是性能,因此要显示的数据集合可以使用泛型集合中的List<T>类存储,List<T>类可以动态增大和减少其容量。同时考虑到波形显示控件需能够同时显示多条曲线,且数据点集合根据X轴的值和Y轴的值分别创建List<float>。

    经过上面分析,得出波形显示控件内部需要创建两个List<List<float>>对象,一个用于存储要显示的数据点集合的X轴值的引用,另一个用于存储要显示的数据点集合的Y轴值的引用。另外,还需要创建List<color>、List<int>、List<LineJoin>、List<LineCap>、List<DrawStyle>分别来存储每条要显示的数据点集合的颜色、线条宽度、连接点样式、起始线帽、样式。其中DrawStyle为自定义枚举,用于标识画图样式:线条、点或者条形图。具体代码设计如下所示:

    public enum DrawStyle{ Line,dot,bar }

    private List<List<float>> _listX = new List<List<float>>(); //X轴数据集

    private List<List<float>> _listY = new List<List<float>>(); //Y轴数据集

    private List<Color> _listColor = new List<Color>(); //线条颜色

    private List<int> _listWidth = new List<int>(); //线条宽度

    private List<LineJoin> _listLineJoin = new List<LineJoin>(); //连接点

    private List<LineCap> _listLineCap = new List<LineCap>(); //起始线帽

    private List<DrawStyle> _listDrawStyle = new List<DrawStyle>(); //样式

    由上面可知,波形显示控件实际上本身是不存储实际的数据值的,而相当于存储了要显示的数据的“引用”,即实现的是一个无源控件,这样有利于数据处理层和数据呈现层的分离,使软件更趋向于模块化。另一方面,为实现多波形显示带来了效率:只需引用传递波形显示控件要显示的数据,而无需整体地复制所有的显示数据给波形显示控件。

    回到目录

    3.2  控件界面模块的设计

    控件的界面可以通过使用微软提供的基础控件进行布局。

    首先使用5个pictureBox控件分别表示底部的X轴坐标区域、左侧的Y轴坐标区域、顶部标题栏区域、右侧工具栏区域、以及中间的波形显示区域。除中间波形显示区域的pictureBox控件外,其余4个pictureBox控件大小有所限制,这样有助于坐标显示的计算。具体参数如下表所示:

    表格 3‑1   控件界面5大模块

    区域

    控件类型

    控件名称

    控件大小

    底部X轴坐标区域

    PictureBox

    pictureBoxBottom

    高度固定45像素

    左侧Y轴坐标区域

    PictureBox

    pictureBoxLeft

    宽度固定50像素

    顶部标题栏区域

    PictureBox

    pictureBoxTop

    高度固定30像素

    右侧工具栏区域

    PictureBox

    pictureBoxRight

    宽度固定50像素

    中间波形显示区域

    PictureBox

    pictureBoxGraph

    不设置固定值

     

    右侧工具栏区域中,需要更多控件来标识工具栏,参数如下表所示: 

    表格 3‑2  工具栏模块

    作用

    控件类型

    控件名称

    控件大小

    底部背景

    Panel

    panelControlItem

    36,178

    内部滑动背景

    Panel

    panelItemsIN

    34,178

    网格显示按钮

    Button

    buttonLinesShowXY

    32,32

    放大选取框功能按钮

    Button

    buttonBigModeXY

    32,32

    坐标自动调整按钮

    Button

    buttonAutoModeXY

    32,32

    默认坐标范围按钮

    Button

    buttonReXY

    32,32

    工具栏上移按钮

    Button

    buttonControlItemUP

    36,10

    工具栏下移按钮

    Button

    buttonItemsDown

    36,10

    工具栏提示标签

    Panel

    labelItemShuoMing

    100,32

     

    其中的内部滑动背景Panel、工具栏上移按钮和工具栏下移按钮是为今后功能扩充的时候预留的。当工具栏的工具按钮过多的时候,可以通过上移按钮和下移按钮进行工具栏中项目的滚动。本课题实际设计过程中,上移按钮和下移按钮是处于禁用状态。另外,工具栏提示标签初始为隐藏状态,只有在鼠标经过工具栏按钮的时候,工具栏提示标签则移动到指定位置处并显示相应的提示文字。

    在实际使用过程中,还存在一个波形局部放大的功能,可以通过一个半透明的PictureBox控件实现,另外还需要两个按钮:放大和取消。参数如下表所示:

    表格 3‑3  波形局部放大模块

    作用

    控件类型

    控件名称

    控件大小

    半透明的放大框

    PictureBox

    pictureBoxBigXY

    根据实际操作

    两个按钮的容器

    Panel

    panelBigXY

    83,32

    放大按钮

    Button

    buttonBigXYBig

    40,32

    取消按钮

    Button

    buttonBigXYQuit

    40,32

     

    具体设计结果如下图所示: 

    图 3‑1  控件界面模块的设计

     

     

    波形显示区域还提供了右键菜单的功能,具体参数如下表: 

    表格 3‑4右键菜单模块

    作用

    控件类型

    控件名称

    标识菜单

    ContextMenuStrip

    MenuRightClick

    当前位置X坐标值

    ToolStripTextBox

    ToolStripTextBoxX

    当前位置Y坐标值

    ToolStripTextBox

    ToolStripTextBoxY

    网格显示

    ToolStripMenuItem

    网格显示ToolStripMenuItem

    放大选取框功能

    ToolStripMenuItem

    放大选取框功能ToolStripMenuItem

    坐标自动调整

    ToolStripMenuItem

    坐标自动调整ToolStripMenuItem

    默认坐标范围

    ToolStripMenuItem

    默认坐标范围ToolStripMenuItem

    回到目录

    3.3  控件工作流程的设计

    波形显示控件设置了两个影响显示方式的标记:标识当前是否处于放大查看模式,以及标识当前坐标是否自动调整以适合窗口大小。作为波形显示控件的私有成员变量,如下所示:

    private bool _isBigModeXY = false; //是否处于放大查看模式

    private bool _isAutoModeXY = true; //是否自动调整以适合窗口大小

    若当前处于放大模式,则波形在动态显示的时候,并不自动改变X轴和Y轴的坐标范围(即使有数据点越出波形显示控件的显示范围),只有在放大选取框进行局部放大的时候改变X轴和Y轴的坐标范围。若当前非放大模式,且为自动调整坐标模式,则遍历要显示的数据值,确定要显示的最大坐标范围,然后修改X轴和Y轴的坐标范围。整个波形显示控件的显示方式判断和实现过程,设计为在中间波形显示区域pictureBoxGraph的OnPaint消息中。

    具体波形显示的工作流程如下所示:

     

    图 3‑2  控件工作流程

     

     

     

    4  波形显示控件各细节的实现

    4.1  坐标值和标尺的实现

    4.1.1  坐标相关的成员变量

    因为控件存在局部放大的功能,所以局部放大后的坐标轴起始值和结束值通常会是浮点数。仅仅根据坐标轴两点的浮点数值难以描绘出符合用户视觉的坐标线和坐标值。因此引入了坐标标定值的概念,得到下列私有成员变量:

    private float _fXBegin; //当前显示波形的X轴起始坐标值

    private float _fXEnd; //当前显示波形的X轴结束坐标值

    private float _fYBegin; //当前显示波形的Y轴起始坐标值

    private float _fYEnd; //当前显示波形的Y轴结束坐标值

    private float _fXBeginGO; //当前显示波形的X轴坐标标定起始值

    private float _fXEndGO; //当前显示波形的X轴坐标标定结束值

    private float _fYBeginGO; //当前显示波形的Y轴坐标标定起始值

    private float _fYEndGO; //当前显示波形的Y轴坐标标定结束值

    具体的意义如下图所示:

     

    图 4‑1  坐标相关成员变量的意义

     

    由上图可知,_fXBegin和_fXEnd代表的即为实际的坐标起始值和结束值(如上图中的起点值0和终点值60),而_fXBeginGo和_fXEndGo在用户使用波形显示控件的时候并不会显示出来,仅仅用于内部坐标标尺的计算,见下图:

     

    图 4‑2  _fXBeginGo和_fXEndGo的意义

     

    其具体表示的值通常在波形显示控件表示范围的外侧,上图中_fXBegin的值为21.67,而_fXBeginGo的值为10,_fXEnd的值为52.96,而_fXEndGo的值为60。这样设计坐标就能够根据_fXBeginGo和_fXEndGo设计出符合用户视觉的坐标线和坐标值,例如上图中显示的坐标值30、40、50,并不是简单地将_fXBegin和_fXEnd等分得到的。

    回到目录

    4.1.2  坐标标定权值的概念

    在确定了双坐标模式后(坐标值和坐标标定值)。用坐标值来描述实际的坐标轴的端点坐标,用坐标标定值来描述整个坐标标尺的坐标线和坐标轴上的子坐标。这样就需要保证坐标标定值要为简单的数据,例如-10、30、0.05等,即保证该浮点值中只有一位是非零的。于是引入了坐标标定权值的概念,定义如下:

    private float _fXQuanBeginGO; //当前显示波形的X轴坐标标定起始权值

    private float _fXQuanEndGO; //当前显示波形的X轴坐标标定结束权值

    private float _fYQuanBeginGO; //当前显示波形的Y轴坐标标定起始权值

    private float _fYQuanEndGO; //当前显示波形的Y轴坐标标定结束权值

    坐标标定权值表示的是一个浮点数最高非零位对应的权,例如34的坐标标定权值为10,0.036的坐标标定权值为0.01,0的坐标标定权值设定为1。坐标轴刻度线和刻度值通过坐标标定值来实现。

    因此,可以设计一个函数,来计算一个浮点数的坐标标定权值:

    private float _getQuan(float m);

    以X轴举例,_fXBegin为21.67则计算得到的_fXQuanBeginGO为10,_fXQuanEndGO为52.96则计算得到的权值为10。之后就可以通过权值来修改_fXBeginGo和_fXEndGo,即最后得到的_fXBeginGo为10,_fXEndGo为60。因此,在21.67到52.96范围内描绘出的子坐标值为30、40、50。同样的,如果有需要的话,可以方便得将30到40之间的坐标标尺继续分割下去。

    回到目录

    4.1.3  坐标标尺的绘制

    在绘制坐标标尺前,先判断起始坐标权值和结束坐标权值哪个大,并从权值大的方向往权值小的方向绘制标尺。计算出当前权值下可分多少段坐标,而后转换为实际要描绘的像素位置(在pictureBoxBottom和pictureBoxLeft中)。

    if (_fXQuanBeginGO <= _fXQuanEndGO) //X轴从右往左画

    {
    //……

    linesQuan
    = _fXQuanEndGO; //获得两权的大值

    linesNum
    = (_fXEndGO - _fXBeginGO) / linesQuan; //可以分成的线段

    pxwidth
    = //所要画坐标的像素范围

    (
    float)(width - 100) / (_fXBegin - _fXEnd) * (_fXBeginGO - _fXEndGO);

    pxLine
    = pxwidth / linesNum; //每段坐标线间隔

    pxGO
    = //所要画坐标的起点像素位置

    (_fXEndGO
    - _fXBegin) / (_fXEnd - _fXBegin) * (width - 100) + 50;

    //……

    回到目录

    4.1.4  子标尺线的选择性显示

    根据每段坐标线间隔,可以设计出符合用户视觉的子标尺线,如下图所示:

     

    图 4‑3子标尺线的选择性显示A

     

    图 4‑4子标尺线的选择性显示B

     

    当波形显示控件被拉伸到足够大的时候,子标尺线能够选择性的显示。具体设计可以通过使用坐标标尺绘制时定义的每段坐标线间隔pxLine来实现。本课题的坐标设计为可以显示三层坐标线,两层坐标值。

    当pxLine小于等于250时候,画第一层坐标,显示坐标值;

    画第二层坐标,第一层坐标的基础上5等分,前提是间距大于10px,若间距大于50px则显示坐标值。即当pxLine大于250,则将pxLine五等分,绘制第二层坐标线以及坐标值,当pxLine只大于50,则将pxLine五等分,绘制第二层坐标线。

    继续判断若此时pxLine大于50,则将pxLine五等分,绘制第三层坐标线,若pxLine只大于20,则将pxLine二等分,并绘制第三层坐标线。

    if (pxLine <= 250)

    { currentI
    = (int)linesNum + 1;

    showTextT
    = (decimal)_fXEndGO;

    currentDraw
    = pxGO;

    for (int i = 0; i < currentI; i++)

    {
    if (currentDraw > 50 && currentDraw < width - 50)

    { Grap.DrawLine(pe, currentDraw,
    0, currentDraw, 6); //画坐标线

    Grap.DrawString
    //画坐标值

    (showTextT.ToString(), fo, brushString, currentDraw,
    6, format);

    }

    showTextT
    -= (decimal)linesQuan; //更新要画的坐标值

    currentDraw
    -= pxLine; //更新坐标线和坐标值的位置

    }

    }

    //……

    回到目录

    4.2  数据点的描绘

    4.2.1  数据值转换为坐标值

    在数据存储结构设计的时候,通过两个List<List<float>>获得的是要显示数据的数据值,而不是最后描绘到波形显示控件上的具体坐标值,因此需要从数据值到坐标值的转换。并将转换后得到的坐标值存储到成员变量中:

    private List<PointF> _listDrawPoints = new List<PointF>();

    默认情况下,GDI+是以像素单位来绘图的,初始情况下从控件的左上角沿X轴向右增长,沿Y轴向下增长,并且左上角第一个像素的坐标为(0,0)。为了计算方便,将坐标系变换为以左下角为零点,从左下角沿X轴向右增长,沿Y轴向上增长。然后设计一个函数,遍历要画的数据集合,并转换为坐标值:

    private bool _changeToDrawPoints(

    int index, //要遍历的数据集合的编号

    ref List<PointF> listDrawPoints, //转后后的坐标集合

    int width, //画布像素宽度

    int height, //画布像素高度

    );

     

    同时定义了一个私有成员变量,表示坐标精确度:

    private float _fAccuracy = 0.05f;

    若坐标起始和结束值之差小于精度范围,则函数返回false,这样防止出现数据转换的过程中出现数据溢出:

    if ((_fXEnd - _fXBegin) < _fAccuracy || (_fYEnd - _fYBegin) < _fAccuracy)

    return false;

    在遍历数据的时候,出现非数字值则跳过:

    if (float.IsNaN(_listX[index][i]) || float.IsNaN(_listY[index][i]))

    continue;

    数据值根据当前波形显示控件大小和坐标范围转换为坐标值:

    currentPointF.X =

    (_listX[index][i]
    - _fXBegin) * (width - 1) / (_fXEnd - _fXBegin);

    currentPointF.Y
    =

    (_listY[index][i]
    - _fYBegin) * (height - 1) / (_fYEnd - _fYBegin);

    listDrawPoints.Add(currentPointF);

    回到目录 

    4.2.2  溢出坐标范围的数据点的处理

    当有要绘制的数据值超出的波形显示控件当前坐标的表示范围,若要实现自动调整坐标范围的功能,首先要实现坐标端点的自动改变。因为本课题设计的坐标为双坐标模式,因此可以添加一个函数来实现,根据溢出坐标范围的浮点数,改变X轴的坐标标定权值和坐标标定值:

    private void _changXBegionOrEndGO(

    float m, //溢出坐标范围的浮点数

    bool isL //是否从左边溢出

    );

    同样的还有Y轴对应的函数:

    private void _changYBegionOrEndGO(float m, bool isL);

    函数内先通过_getQuan函数获得溢出点的权,并根据该权值修改对应坐标轴的起点坐标权值和结束坐标权值,同时控制权差在10倍以内,然后根据新的权值修改坐标的标定值。具体设计如下:

    float quan = _getQuan(m);

    if(isL)

    {

    if (quan < _fXQuanEndGO)

    _fXQuanBeginGO
    = _fXQuanEndGO / 10f;

    else if (quan > _fXQuanEndGO)

    { _fXQuanBeginGO
    = quan;

    _fXQuanEndGO
    = _fXQuanBeginGO / 10f;

    }
    else _fXQuanBeginGO = _fXQuanEndGO;

    if (m <= _fXQuanBeginGO && m >= -_fXQuanBeginGO)

    _fXBeginGO
    = -_fXQuanBeginGO;

    else

    _fXBeginGO
    = ((int)(m / _fXQuanBeginGO) - 1) * _fXQuanBeginGO;

    }

    else ……

    实际使用过程中,在pictureBoxGraph的OnPaint消息响应函数中在判断绘图模式为放大模式或坐标自动调整模式的时候,可以调用该函数以实现相应的功能。

    回到目录

    4.2.3  遍历所有数据线并绘制出

    绘制数据线的工作在pictureBoxGraph的OnPaint消息中完成。在该函数根据绘图模式调整完坐标范围并更新pictureBoxBottom和pictureBoxLeft的坐标标尺的显示后,开始遍历所有要显示的数据并绘制出。

    每绘制List<List<float>>中的一条数据集合,都先调用原先设计好的数据值转坐标值函数_changeToDrawPoints,若操作成功,则获取当前要绘制的数据集合的颜色、线宽、连接点样式、起始线帽,并加载到当前画笔中。

    for (int i = 0; i < _listX.Count; i++)

    { _listDrawPoints.Clear();

    if (!_changeToDrawPoints(i, ref _listDrawPoints, width, height))

    continue;

    pe.Color
    = _listColor[i]; //装载颜色

    pe.Width
    = _listWidth[i]; //装载宽度

    pe.LineJoin
    = _listLineJoin[i]; //装载连接点

    pe.StartCap
    = _listLineCap[i]; //装载起始线帽

    然后通过判断绘图样式(线、点、条形图),绘制出图形。注意在绘制线条的时候,设置连接点指定成斜角的连接,这样可以防止线宽在大于1的情况下导致的转折点不精确的问题:

    if (_listDrawStyle[i] == DrawStyle.Line) //绘制线

    { f (_listDrawPoints.Count
    == 1) continue;

    pe.LineJoin
    = LineJoin.Bevel;

    Grap.DrawLines(pe, _listDrawPoints.ToArray());

    }

    由上面代码可知,实际使用控件时若绘图样式设置为线,则传入的线条连接点参数是不会被使用的。绘制点和条形图如下所示:

    else if (_listDrawStyle[i] == DrawStyle.dot) //绘制方形点

    {
    foreach (PointF points in _listDrawPoints)

    { Grap.DrawRectangle(pe, points.X, points.Y,
    1, 1); }

    }

    else

    {
    foreach (PointF points in _listDrawPoints) //绘制条形线

    { Grap.DrawLine(pe, points.X, points.Y, points.X,
    0); }

    }

    回到目录

    4.3  波形显示区域网格的实现

    4.3.1  网格相关的成员变量

    网格的显示是同显示的坐标标尺的标尺线相对应的,因此在绘制坐标标尺的同时,可以保存绘制标尺的状态,然后在pictureBoxGraph中绘制数据点之前,将网格绘制到pictureBoxGraph中。因此需要的成员变量如下:

    private bool _bXLinesLBegin; //X轴网格线是否从左开始画

    private bool _bYLinesLBegin; //Y轴网格线是否从下开始画

    private float _fXpxGO; //所要画X轴坐标的起点像素位置

    private float _fYpxGO; //所要画Y轴坐标的起点像素位置

    private float _fXLinesShowFirst = 0; //X轴第一层网格线间隔

    private float _fXLinesShowSecond = 0; //X轴第二层网格线间隔

    private float _fXLinesShowThird = 0; //X轴第三层网格线间隔

    private float _fYLinesShowFirst = 0; //Y轴第一层网格线间隔

    private float _fYLinesShowSecond = 0; //Y轴第二层网格线间隔

    private float _fYLinesShowThird = 0; //Y轴第三层网格线间隔

    当网格线间隔为0的时候,则不画出该层的网格线。为了增强用户体验,将各层的网格线使用不同的透明度绘制出:

    pe.Color = Color.FromArgb(_iLineShowColorAlpha, _iLineShowColor);

    pe.Color
    = Color.FromArgb(_iLineShowColorAlpha / 2, _iLineShowColor);

    pe.Color
    = Color.FromArgb(_iLineShowColorAlpha / 3, _iLineShowColor);

    图 4‑5  网格显示效果

    回到目录

    4.3.2  网格的绘制

    在pictureBoxGraph的OnPaint更新pictureBoxLeft和pictureBoxBottom后,开始绘制网格。绘制前判断当然用户是否选择了显示网格,通过私有成员变量_isLinesShowXY判断,该变量能够通过工具栏按钮和右键菜单改变。

    网格线采用1像素的宽度绘制,且从第三层网格线开始绘制。

    if (_isLinesShowXY)

    { Grap.SmoothingMode
    = SmoothingMode.None; //保证网格线的清晰

    pe.Width
    = 1;

    float i = _fXpxGO; //临时,计数

    pe.Color
    = Color.FromArgb(_iLineShowColorAlpha / 3, _iLineShowColor);

    if (_fXLinesShowThird != 0) //画第三层网格

    {
    if (_bXLinesLBegin)

    {
    while (i < width)

    { Grap.DrawLine(pe, i,
    0, i, height);

    i
    = i + _fXLinesShowThird; } }

    else

    {
    while (i > 0)

    { Grap.DrawLine(pe, i,
    0, i, height);

    i
    = i - _fXLinesShowThird; } }

    }

    ……

    两个私有成员变量iLineShowColorAlpha和iLineShowColor标识网格的透明度和颜色,并通过属性的方式作为接口公开给使用者:

    public int m_iLineShowColorAlpha //网格线的透明度

    {
    set { _iLineShowColorAlpha = value; }

    get { return _iLineShowColorAlpha; } }

    public Color m_iLineShowColor //网格线的颜色

    {
    set { _iLineShowColor = value; }

    get { return _iLineShowColor; } }

    图 4‑6  设置为红色的网格

    回到目录

    4.4  工具栏按钮的实现

    4.4.1  工具栏按钮相互关系

    本课题设计的工具栏按钮包括网格显示按钮、放大选取框功能按钮、坐标自动调整按钮、默认坐标范围按钮。

    显示网格按钮同其他三个按钮不存在功能上的冲突,因此可以独立考虑。

    放大选取框功能按钮默认处于未开启状态,若开启放大选取框功能,并成功的进行了局部放大操作,则自动关闭坐标自动调整功能。

    坐标自动调整按钮默认处于开启状态,若开启坐标自动调整功能,则自动关闭放大选取框功能。

    默认坐标范围按钮默认处于未开启状态,当用户点击默认坐标范围按钮后,自动将坐标范围调整为波形显示控件初始的坐标范围,并关闭坐标自动调整功能。

    回到目录

    4.4.2  工具栏提示标签的实现

    工具栏提示标签labelItemShuoMing默认情况下是处于隐藏状态的,只有当用户鼠标经过某一按钮的时候,按钮的MouseEnter消息被调用,并修改提示标签的位置和标签的内容,并设置Visible为true:

    private void buttonLinesShowXY_MouseEnter(object sender, EventArgs e)

    { Point po
    = new Point();

    po.X
    = panelControlItem.Location.X - 100;

    po.Y
    = panelControlItem.Location.Y + buttonLinesShowXY.Location.Y;

    labelItemShuoMing.Location
    = po; //更新标签说明坐标

    labelItemShuoMing.Text
    = "网格显示"; //更新标签说明文字

    labelItemShuoMing.Visible
    = true; //显示标签说明

    }

    并在鼠标离开按钮的时候重新设置Visible为false。

    具体效果如下图所示:

     

    图 4‑7  工具栏提示标签 

    回到目录

    4.5  波形放大功能的实现

    4.5.1  局部放大选择框的实现

    局部放大选取框通过一个半透明的pictureBox控件,作为选取框的背景,命名为pictureBoxBigXY并在选取框的右下角放置一个Label,容纳放大和取消按钮,两个按钮的名称分别为buttonBigXYBig和buttonBigXYQuit。最后运行的实际效果如下图所示:

     

    图 4‑8  局部放大选择框

     

    用户在点击放大按钮后,实现的效果如下:

     

    图 4‑9  点击放大按钮后的效果

     

     

     为了控制pictureBoxBigXY的显示,需要定义五个私有成员变量:

    private Point _pictureBoxBigXY_L; //存放波形放大方框的起点坐标

    private Point _pictureBoxBigXY_R; //存放鼠标移动时的坐标

    private Point _pictureBoxBigXY_M; //存放最后调整后波形放大框的位置坐标

    private float _labelXYNumX; //存放坐标显示Label的X值

    private float _labelXYNumY; //存放坐标显示Label的Y值

    需要响应的消息如下表所示:

    表格 4‑1局部放大响应的消息

    消息所属

    消息类型

    作用

    pictureBoxGraph

    鼠标按下

    设置pictureBoxBigXY的父容器并更新其位置

    pictureBoxGraph

    鼠标移动

    更新pictureBoxBigXY的大小并显示

    pictureBoxGraph

    鼠标抬起

    判断并显示放大和取消两个按钮

    buttonBigXYBig

    单击

    根据当前pictureBoxBigXY范围进行放大操作

    buttonBigXYQuit

    单击

    隐藏pictureBoxBigXY

    回到目录

    4.5.2  放大选择框的鼠标操作

    在pictureBoxGraph中按下鼠标左键,则根据_isShowBigSmallModeXY标记判断是否进行放大选择框的初始化操作。修改鼠标的光标为十字光标,若先前已经显示过放大选择框,则设置为隐藏,并设置pictureBoxGraph作为buttonBigXYBig的父容器,这样方便坐标到数据值的转换:

    private void pictureBoxGraph_MouseDown(object sender, MouseEventArgs e)

    {
    if (_isShowBigSmallModeXY && e.Button == MouseButtons.Left)

    { pictureBoxGraph.Cursor
    = Cursors.Cross; //十字光标

    pictureBoxBigXY.Visible
    = false; //隐藏波形放大框

    panelBigXY.Visible
    = false; //隐藏隐藏波形放大操作框

    pictureBoxBigXY.Parent
    = pictureBoxGraph; //父容器

    panelBigXY.Parent
    = pictureBoxBigXY; //父容器

    _pictureBoxBigXY_L.X
    = e.Location.X;

    _pictureBoxBigXY_L.Y
    = e.Location.Y;

    pictureBoxBigXY.Location
    = _pictureBoxBigXY_L; //更新位置

    }

    ……

    }


    左键按下后用户通过移动鼠标来选取需要放大的区域。因此必须在鼠标移动过程中不断获得当前鼠标的位置,并根据鼠标按下的位置和当前鼠标的位置,描绘出最后放大选取框的位置和大小。这里需要考虑到用户操作鼠标的方向可能是向右下角拖动,也可能向左上角拖动,因此鼠标按下时获得的坐标,并非完全代表pictureBoxBigXY的位置,需要通过重新计算获得。

    这里还需要考虑一种情况:当用户按下鼠标左键并拖动鼠标到控件外边的时候,就需要保证pictureBoxBigXY始终显示在pictureBoxGraph中:

     

    图 4‑10  放大选择框无法继续往左下角放大

     

    if (e.Location.X > pictureBoxGraph.Width - 10)

    { _pictureBoxBigXY_R.X
    = pictureBoxGraph.Width - 10; }

    else if (e.Location.X < 10) { _pictureBoxBigXY_R.X = 10; }

    else { _pictureBoxBigXY_R.X = e.Location.X; }

    上面演示的代码是防止横坐标越界,同样的,纵坐标也要进行验证。之后通过判断设置pictureBoxBigXY新的位置:

    _pictureBoxBigXY_M.X = (_pictureBoxBigXY_L.X < _pictureBoxBigXY_R.X) ? _pictureBoxBigXY_L.X : _pictureBoxBigXY_R.X;

    _pictureBoxBigXY_M.Y
    = (_pictureBoxBigXY_L.Y < _pictureBoxBigXY_R.Y) ? _pictureBoxBigXY_L.Y : _pictureBoxBigXY_R.Y;

    pictureBoxBigXY.Location
    = _pictureBoxBigXY_M;

    pictureBoxBigXY的大小则通过调用Math.Abs计算得到。

    鼠标抬起的时候需判断当前的波形放大选择框是否足够大小显示放大和取消两个按钮,若不够显示则不显示,反之则调整位置并显示。

     

    图 4‑11  放大选取框不够显示放大按钮的情况

     

    回到目录

    4.5.3  放大选择框的按钮操作

    放大选择框有放大和取消两个按钮。其中放大按钮的单击事件中,转换pictureBoxBigXY的四个角的坐标值为实际值,并调用Refresh更新显示。

    函数中需要设置放大的范围,防止导致数据溢出的错误:

    if (_fXEnd - _fXBegin < 1.0f || _fYEnd - _fYBegin < 1.0f){ return; }

    设计一个函数,将波形显示中矩形区域的坐标转换为数据值,这里获得的坐标值是以左上角为原点的,而要转换到的数据值是从左下角向右X轴正向增长,向上Y轴正向增长,所以转换的时候需要特别注意,并且转换的过程中需要用临时变量来保存转换后的值,防止先转换完成的坐标值对下一个转换产生影响:

    private void _changeXYPointsToNum(float xB, float xE, float yB, float yE,

    ref float outxB, ref float outxE, ref float outyB, ref float outyE)

    {
    float currentB, currentE;

    currentB
    =xB/(pictureBoxGraph.Width-1)*(_fXEnd-_fXBegin) +_fXBegin;

    currentE
    =xE/(pictureBoxGraph.Width - 1)*(_fXEnd-_fXBegin)+_fXBegin;

    outxB
    = currentB; outxE = currentE;

    currentB
    =_fYEnd-yB/(pictureBoxGraph.Height-1)*(_fYEnd-_fYBegin);

    currentE
    =_fYEnd-yE/(pictureBoxGraph.Height-1)*(_fYEnd-_fYBegin);

    outyE
    = currentB; outyB = currentE;

    }

    在调用该函数的时候传入的参数即为_fXBegin、_fXEnd、_fYBegin、_fYEnd。即通过调用该函数,可以改变X轴和Y轴的坐标值,在pictureBoxGraph的OnPaint消息函数中,会根据上面的四个值改变坐标的标定值,从而正确的实现放大效果。

    回到目录

    4.5.4  更新数据显示范围为放大的范围

    放大模式下坐标不自动调整,使用当前坐标范围修改标定权值和标定坐标范围,在pictureBoxGraph的OnPaint消息函数中:

    _fXQuanBeginGO = _getQuan(_fXBegin);_fXQuanEndGO = _getQuan(_fXEnd);

    _fYQuanBeginGO
    = _getQuan(_fYBegin);_fYQuanEndGO = _getQuan(_fYEnd);

    _changXBegionOrEndGO(_fXBegin,
    true);

    _changXBegionOrEndGO(_fXEnd,
    false);

    _changYBegionOrEndGO(_fYBegin,
    true);

    _changYBegionOrEndGO(_fYEnd,
    false);

    回到目录

    4.6  坐标自动调整及恢复默认坐标的实现

    4.6.1  坐标自动调整功能

    在工具栏按钮buttonAutoModeXY的单击事件中,重新初始化坐标值和坐标标定值,使用事先保存好的默认的坐标范围:

    private float _fXBeginSYS = 0f; //X轴起始坐标值

    private float _fXEndSYS = 60f; //X轴结束坐标值

    private float _fYBeginSYS = 0f; //Y轴起始坐标值

    private float _fYEndSYS = 1f; //Y轴结束坐标值

    同时,需要标记_isBigModeXY为false。另外需要注意的是,之前的局部放大操作若达到放大的极限(横坐标首尾之差小于1.0或纵坐标首尾之差小于1.0),则会禁用放大按钮。因此需要在buttonAutoModeXY的单击事件中重新设置buttonBigXYBig的Enabled属性为true。

    上面的步骤实现了先恢复默认坐标的功能,然后再在pictureBoxGraph的OnPaint事件中,通过遍历当前要绘制的数据,调用_changXBegionOrEndGO完成坐标标定值和坐标标定权值的更新。之后刷新pictureBoxLeft和pictureBoxBottom更新坐标标尺的显示,即实现了坐标自动调整的功能。

    回到目录

    4.6.2  恢复默认坐标范围功能

    恢复默认坐标范围实际上少了坐标自动调整在pictureBoxGraph中的操作。即直接更新坐标值和坐标标定值、以及坐标标定权值:

    _fXBegin = _fXBeginGO = _fXBeginSYS;

    _fYBegin
    = _fYBeginGO = _fYBeginSYS;

    _fXEnd
    = _fXEndGO = _fXEndSYS; _fYEnd = _fYEndGO = _fYEndSYS;

    _fXQuanBeginGO
    = _getQuan(_fXBeginGO);

    _fXQuanEndGO
    = _getQuan(_fXEndGO);

    _fYQuanBeginGO
    = _getQuan(_fYBeginGO);

    _fYQuanEndGO
    = _getQuan(_fYEndGO);

    pictureBoxGraph.Refresh();
    //刷新界面

    panelItemsIN.Refresh();
    //刷新按钮显示

    回到目录

    4.7  波形显示控件接口的实现

    4.7.1  控件基本属性

    控件的标题、X轴名称、Y轴名称、以及坐标的初始值通过属性的方式公开给用户:

    表格 4‑2  控件基本属性

    名称

    数据类型

    作用

    m_SyStitle

    string

    波形显示控件标题

    m_SySnameX

    string

    X轴名称

    m_SySnameY

    string

    Y轴名称

    m_fXBeginSYS

    float

    初始X轴起始坐标

    m_fXEndSYS

    float

    初始X轴结束坐标

    m_fYBeginSYS

    float

    初始Y轴起始坐标

    m_fYEndSYS

    float

    初始Y轴结束坐标

     

    在控件内部,控件的标题是在pictureBoxTop的OnPaint中绘制出的:

    private void pictureBoxTop_Paint(object sender, PaintEventArgs e)

    { ……

    brush.Color
    = _titleBorderColor;

    Grap.DrawString(_SyStitle, foTitle, brush, pictureBoxTop.Width
    * _titlePosition+1, height+1, format);

    Grap.DrawString(_SyStitle, foTitle, brush, pictureBoxTop.Width
    * _titlePosition-1, height-1, format);

    brush.Color
    = _titleColor;

    Grap.DrawString(_SyStitle, foTitle, brush, pictureBoxTop.Width
    * _titlePosition, height, format);

    ……

    }

    可得实际上控件的标题包括两层,分别通过_titleBorderColor和_titleColor绘制出,并且控件的通过_titlePosition控制其在水平方向上绘制的位置。同样的,X轴的标签在pictureBoxBottom的OnPaint中绘制出,Y轴标签则是在pictureBoxTop的OnPaint中绘制出。

    回到目录

    4.7.2  控件外观样式

    控件的外观样式一共涉及到21个属性,具体如下标所示:

    表格 4‑3  控件外观样式

    名称

    作用

    名称

    作用

    m_titleSize

    控件标题字体大小

    m_GraphBackColor

    波形显示区域背景色

    m_titlePosition

    控件标题位置

    m_ControlItemBackColor

    工具栏背景色

    m_titleColor

    控件标题颜色

    m_ControlButtonBackColor

    工具栏按钮背景颜色

    m_titleBorderColor

    控件标题描边颜色

    m_ControlButtonForeColorL

    工具栏按钮前景选中颜色

    m_backColorL

    背景色渐进起始颜色

    m_ControlButtonForeColorH

    工具栏按钮前景未选中颜色

    m_backColorH

    背景色渐进终止颜色

    m_DirectionBackColor

    标签说明框背景颜色

    m_coordinateLineColor

    坐标线颜色

    m_DirectionForeColor

    标签说明框文字颜色

    m_coordinateStringColor

    坐标值颜色

    m_BigXYBackColor

    放大选取框背景颜色

    m_coordinateStringTitleColor

    坐标标题颜色

    m_BigXYButtonBackColor

    放大选取框按钮背景颜色

    m_iLineShowColorAlpha

    网格线的透明度

    m_BigXYButtonForeColor

    放大选取框按钮文字颜色

    m_iLineShowColor

    网格线的颜色

     

     

     m_titleSize为int类型、m_titlePosition为float类型、m_iLineShowColorAlpha为ing类型,其他的外观样式属性都为Color类型。其中某些属性是对应了多个私有成员变量的,这样可以统一的进行颜色的更新:

    public Color m_ControlItemBackColor

    {
    set

    { ControlItemBackColor
    = value;

    panelControlItem.BackColor
    = ControlItemBackColor;

    buttonItemsDown.ForeColor
    = ControlItemBackColor;

    buttonControlItemUP.ForeColor
    = ControlItemBackColor;

    }

    get{ return ControlItemBackColor; }

    }

    回到目录

    4.7.3  控件绘图接口

    本课题设计的波形显示控件主要提供了五个函数供使用者调用。用来控制波形显示控件的绘图操作。

    函数f_ClearAllPix用于清空所有加载的波形数据,具体设计如下:

    public void f_ClearAllPix()

    { _listX.Clear(); _listY.Clear(); _listColor.Clear(); _listWidth.Clear();

    _listLineJoin.Clear(); _listLineCap.Clear(); _listDrawStyle.Clear();

    pictureBoxGraph.Refresh();
    //更新

    }

     

    函数f_reXY用于重新初始化X轴和Y轴坐标,内部通过调用工具栏按钮的恢复默认坐标范围按钮和设置自动调整坐标按钮来实现,具体设计如下:

    public void f_reXY()

    { buttonReXY_Click(
    null, null);

    buttonAutoModeXY_Click(
    null, null);

    }

     

    函数f_Refresh用来更新显示,实际上再每次需要重新绘图的时候,只需要更新pictureBoxGraph即可,因为pictureBoxGraph的OnPaint函数中会调用pictureBoxBottom和pictureBoxLeft的更新显示,因此设计如下:

    public void f_Refresh()

    { pictureBoxGraph.Refresh(); }

     

    函数f_LoadOnePix用于清空原有数据并加载一条波形数据:

    public void f_LoadOnePix(ref List<float> listX, ref List<float> listY, Color listColor, int listWidth, LineJoin listLineJoin, LineCap listLineCap,DrawStyle listDrawStyle)

    { f_ClearAllPix();
    //重新初始化

    _listX.Add(listX); _listY.Add(listY);

    _listColor.Add(listColor); _listWidth.Add(listWidth);

    _listLineJoin.Add(listLineJoin); _listLineCap.Add(listLineCap);

    _listDrawStyle.Add(listDrawStyle);

    }

    函数f_AddPix则是在原有波形上添加一条波形数据,其实现的过程中少了清空原有波形数据这一步,因此数据是在原有数据的基础上继续添加上去的。

    回到目录

    4.8  波形显示控件其他细节的处理

    4.8.1  坐标值产生遮盖时的处理

    在坐标标尺的调整过程中,会出现子坐标同两端的坐标重叠的现象,因此为了能够更友好的显示重叠部分的坐标,可以在绘制坐标轴两端坐标的时候,先填充一个背景颜色,用户遮盖可能和两端坐标重叠的子坐标:

    Grap.FillRectangle(brush, 28, 8, 46, 16); //坐标背景色,用于遮盖

    Grap.FillRectangle(brush, width
    - 63, 8, 50, 16); //坐标背景色,用于遮盖

    Grap.DrawLine(pe,
    50, 0, 50, 10); //X轴起始坐标线条

    Grap.DrawString(
    string.Format("{0}", Math.Round(_fXBegin, _iAccuracy)), fo, brushString, 51, 10, format); //X轴起始坐标值

    ……

    注意上面通过_iAccuracy来控制两端坐标值能够显示的小数点位数,防止浮点数显示过多小数位数出现的重叠问题,具体定义如下:

    private int _iAccuracy = 2; //坐标显示最多小数位数

    最后实现的效果如下:

     

    图 4‑12  坐标遮盖的问题

     

    上图红色方框部分,X轴的末尾坐标值1431.46和子坐标值1400重叠,通过遮盖子坐标,能够使用户更有效地观察坐标值,同样的,Y轴的两端坐标和子坐标的显示也做类似的处理。

    回到目录

    4.8.2  波形显示控件大小改变时的处理

    实际使用中,若用户打开了放大局部放大功能,并在波形显示区域拖出了一个矩形,若此时用户在未点击放大和取消按钮之前,改变了波形显示控件的大小(或者说是使用该控件的软件界面的大小),就会导致之后的实际放大区域和用户期望的不相符合,因此,需要在控件大小改变时隐藏放大选取框:

    private void ZGraph_Resize(object sender, EventArgs e)

    { pictureBoxBigXY.Visible
    = false; //隐藏放大选择框

    panelBigXY.Visible
    = false; //隐藏放大取消按钮

    _isShowBigSmallModeXY
    = false; //标记为隐藏

    ……

    回到目录

    4.8.3  按钮点击时进行禁用操作

    防止按钮再处理的过程中被再次点击,因此在按钮处理函数中进行按钮的禁用操作,另外重新设置按钮的焦点:

    private void buttonBigModeXY_Click(object sender, EventArgs e)

    { buttonBigModeXY.Enabled
    = false; //禁用按钮

    buttonBigModeXY.Parent.Focus();
    //取消焦点

    ……

    buttonBigModeXY.Enabled
    = true; //启用按钮

    ……

    回到目录

    4.8.4  右键菜单的显示

    在使用过程中,用户能通过右键菜单实现工具栏中提供的功能。同时,右键菜单中还显示当然鼠标位置的数据值,在pictureBoxGraph的右键按下时获取:

    if (e.Button == MouseButtons.Right)

    { _changeXYPointsToNum(e.Location.X, e.Location.Y,
    ref _labelXYNumX, ref _labelXYNumY);

    toolStripTextBoxX.Text
    = //显示当前点的横坐标值

    string.Format(" X:{0}", Math.Round(_labelXYNumX, _iAccuracy + 2));

    toolStripTextBoxY.Text
    = //显示当前点的纵坐标值

    string.Format(" Y:{0}", Math.Round(_labelXYNumY, _iAccuracy + 2));

    }

     

    其中的_changeXYPointsToNum函数将波形显示中一个点的坐标转换为数据值,具体实现如下:

    private void _changeXYPointsToNum(float x,float y,ref float outX,ref float outY)

    { outX
    = x / (pictureBoxGraph.Width - 1) * (_fXEnd - _fXBegin) + _fXBegin;

    outY
    = _fYEnd - y / (pictureBoxGraph.Height - 1) * (_fYEnd - _fYBegin);}

     

    右键菜单的效果如下图:

     

    图 4‑13  右键菜单

    回到目录

    4.8.5  XML注释以及智能提示

    Visual Studio中能够为代码生成XML注释,并能利用该注释产生智能提示的功能,这样能够方便开发人员以及控件的使用者快速获得函数以及属性的信息。

     

    图 4‑14  XML风格的注释

     

    拥有XML风格注释的函数或属性,在使用的时候能够产生智能提示的效果:

     

    图 4‑15  智能提示

     

    对控件中需要公开的属性和方法都加上XML风格的注释后,要想控件在提供给控件使用者时,任然能产生智能提示的话,需要将XML文档到处,并在使用最终生成的DLL控件时,将该导出的XML文档放置在同一目录下,这样就能实现智能提示的功能了。具体需要在项目属性的生成选项卡中设置:

     

    图 4‑16  XML文档输出

     

    这样使用者就能够方便快捷地得知该控件的方法和属性的含义。

    回到目录

    5  波形显示控件功能的演示和使用

    5.1  波形显示控件演示程序的设计

    为了配合波形显示控件,本课题还设计了一个波形显示控件的演示程序。设计最终界面如下图所示:

     

    图 5‑1  波形显示控件演示程序

     

    其中右侧一栏主要是对波形显示控件外观样式的控制。可以改变某一属性的参数,也可以点击下方的默认样式、样式1和样式2。其中样式1和样式2是在演示程序内部通过调用波形显示控件的各个接口属性来做相应的改变的。默认样式则是在演示控件初始化之后,将此时控件的各个属性保存在成员变量中,之后可以通过点击该按钮从新将成员变量中的参数值赋值给波形显示控件对应的属性。

    左下方提供了简单的数据显示模拟和基本属性更改的操作。该演示程序主要模拟了多条曲线的绘制,以及模拟自动化检测软件中串口采样的过程,即实现波形的动态显示,随机点的显示实现过程同串口采样模拟类似。

    回到目录

    5.2  波形显示控件功能的演示

    5.2.1  外观样式的更改

    用户可以通过对右边属性值的更改改变波形显示控件的外观。通过点击对应的属性的彩色框,可以更改颜色:

     

    图 5‑2  改变控件的标题颜色

     

     

    用户也可以点击下发的样式1和样式2,其在按钮的单击消息函数中修改了波形显示控件的样式:

     

    图 5‑3  演示程序样式1

     

      

    图 5‑4  演示程序样式2

    用户可以根据自己喜欢的颜色,逐一设置符合软件整体风格的样式。

    回到目录

    5.2.2  波形显示演示

    (1)    绘制多条曲线

    演示程序内部定义了8个List<float>,即可以表示4条不同的数据集合,从x1、y1命名到x4、y4。可通过修改该4条数据集合的数据实现不同的演示效果。

    点击左下角的-300~num画四条数据按钮,可以在控件中绘制演示程序内设置的数据曲线,可以通过更改测试数据值num来测试波形显示控件的显示效果。其具体内部实现通过遍历-300~num,一次添加数据值:

    x1.Clear(); y1.Clear(); x2.Clear(); y2.Clear();

    x3.Clear(); y3.Clear(); x4.Clear(); y4.Clear();

    for (int i = -300; i < num; i++) //这里省略num小于-300的情况

    { x1.Add(i); y1.Add(i
    % 1000);

    x2.Add(i); y2.Add((
    float)Math.Sin(i / 100f) * 200);

    x3.Add(i); y3.Add(
    0);

    x4.Add(i); y4.Add((
    float)Math.Sin(i / 100) * 200);

    }

     然后调用波形显示控件的绘图函数绘制出:

    zGraphTest.f_reXY(); //恢复默认坐标范围

    zGraphTest.ff_LoadOnePix(
    ref x1, ref y1, Color.Red, 2);

    zGraphTest.f_AddPix(
    ref x2, ref y2, Color.Blue, 4);

    zGraphTest.f_AddPix(
    ref x3, ref y3, Color.FromArgb(0, 128, 192), 2);

    zGraphTest.f_AddPix(
    ref x4, ref y4, Color.Yellow, 4);

    zGraphTest.f_Refresh();
    //更新并显示

     注意在调用绘图函数绘制相应的曲线后,波形并不会马上显示出来,因此在4条曲线都添加完毕后,调用波形显示控件的f_Refresh更新显示。显示效果如下图所示:

     

    图 5‑5  波形显示演示绘制多条曲线(num为1580)

     

     

    图 5‑6  波形显示控件演示绘制多条曲线(num为-10000)

     

     

    图 5‑7  波形显示控件绘制多条曲线(num为1580时局部放大的效果)

      

    (2)    绘图样式的选择

    控件还提供了绘制样式的选择:点、线、矩形条。演示程序实现如下:

    for (int i = 0; i < 18000; i += 1000)

    { x1.Add(i); y1.Add(i
    /4f);

    x2.Add(i); y2.Add(i
    /4f);

    x3.Add(i); y3.Add(i
    / 8f);

    }

    zGraphTest.f_LoadOnePix(
    ref x1, ref y1, Color.Red, 3); //绘制线

    zGraphTest.f_AddPix(
    ref x2, ref y2, Color.Yellow, 5, LineJoin.Round,

    LineCap.Flat, ZhengJuyin.UI.ZGraph.DrawStyle.dot);
    //绘制点

    zGraphTest.f_AddPix(
    ref x3, ref y3, Color.FromArgb(0,128,192), 12,

    LineJoin.MiterClipped, LineCap.NoAnchor,

    ZhengJuyin.UI.ZGraph.DrawStyle.bar);
    //绘制矩形条

     

    绘图演示演示程序显示如下效果:

     

    图 5‑8  波形显示控件绘制样式演示

     

     

    图 5‑9  波形显示控件绘制样式演示(局部放大的效果) 

    绘制线条的宽度都是像素为单位的,所以绘制的矩形条,即使进行了局部放大操作,矩形条的宽度任然是原先的宽度显示,可观察上图的局部放大效果。

      

    (3)    模拟串口采样

    波形显示控件在实际使用过程中,通常用户显示外界动态的波形数据,而在自动化方面,串口通讯尤为常见。演示程序内部通过开启一个Timer控件,按照特定的周期更新波形显示的数据,同时只需要刷新波形显示控件即可得到新的波形。串口采样按钮的单击事件只是简单得添加空数据的引用:

    zGraphTest.f_LoadOnePix(ref x1, ref y1, Color.Red, 2);

    zGraphTest.f_AddPix(
    ref x2, ref y2, Color.Blue, 3);

    zGraphTest.f_AddPix(
    ref x3, ref y3, Color.FromArgb(0, 128, 192), 2);

    zGraphTest.f_AddPix(
    ref x4, ref y4, Color.Yellow, 3);

    f_timerDrawStart();
    //开启Timer控件

    Timer控件的周期函数实现如下: 

    private int timerDrawI = 0;

    private void timerDraw_Tick(object sender, EventArgs e)

    { x1.Add(timerDrawI); y1.Add(timerDrawI
    % 100);

    x2.Add(timerDrawI); y2.Add((
    float)Math.Sin(timerDrawI / 10f) * 200);

    x3.Add(timerDrawI); y3.Add(
    50);

    x4.Add(timerDrawI); y4.Add((
    float)Math.Sin(timerDrawI / 10) * 200);

    timerDrawI
    ++;

    zGraphTest.f_Refresh();

    ……

    }

     

    模拟串口通讯最后实现的效果如下:

     

    图 5‑10  模拟串口通讯的显示

     

     

    图 5‑11  模拟串口通讯的显示(一段时间后)

    注意到在自动坐标模式下,波形显示的范围能够根据当前显示数据的范围自动调整,这样观察者能够观察数据的整体显示效果。

      

    (4)    模拟随机点的显示

    该演示程序模拟随即点的显示思路同模拟串口通讯,也是通过Timer实现的,只是数据是通过产生随机值获得的:

    Random rand = new Random();

    private void timerRandom_Tick(object sender, EventArgs e)

    { x1.Add(rand.Next(
    60)); //添加随机值

    y1.Add((
    float)rand.NextDouble()); //添加随机值

    zGraphTest.f_Refresh();

    ……

    }

     

    产生的效果如下:

     

    图 5‑12  模拟随机点的显示

     

     

    图 5‑13  模拟随机点的显示(一段时间后) 

    上面为该波形显示控件演示程序提供的演示内容,以及简单的使用方法。实际在使用过程中,因为Timer的时间间隔并不是精确的(收到消息队列的影响),通常通过多线程采样,将数据处理后更新给波形显示控件,之后显示出波形。

    回到目录

    5.2.3  波形显示控件在实际项目中的使用

    在实际使用过程中,设计者通过Visual Studio的工具箱,添加选项卡功能,将控件添加到工具箱中,之后通过拖拽的方式即可在设计视图添加该波形显示控件。

     

    图 5‑14  波形显示控件的添加

     

     

    下图为波形显示控件在喷管实验平台软件中的应用,经测试,完全能够满足需求:

     

    图 5‑15  波形显示控件的实际应用

     

    波形显示控件在数据采集过程中作为数据显示的主要窗口,另外在历史数据查询中可以用来显示历史实验数据,根据需求显示多条实验数据并进行直观的比较。

    回到目录

    6  课题总结

    本课题设计的波形显示控件通过双坐标模式,成功的实现了友好坐标标尺的显示,以及波形的动态范围自动调整。另外提供的显示网格功能、局部放大功能、以及波形显示控件的整体UI效果,都较为出色。并同时设计了波形显示控件演示程序,介绍控件的使用方法并观察显示效果。

    在波形显示的设计上,采用的并不是将数据点绘制在内存位图上,然后通过映射位图的方式实现显示,而是直接通过坐标换算来实现显示和局部放大。因为显示的数据点集合存在较强的相互位置关系,若之前通过内存图像的方式存储,则不能保证数据量的大小,比如数据点集合遍历后的X轴范围为0~210,则内存中就要创建宽度为至少210像素的图像,否则会导致局部放大查看后数据显示丢失,且容易产生因为一个孤立的较远的点而浪费大量的内存空间的情况。波形显示控件在设计的初期,使用的便是pictureBox控件,其本身提供的缓冲后显示的效果能够使控件显示过程更为流畅。

    波形显示控件在进行坐标转换时,数据溢出的处理显得尤为重要,因此限制了波形显示控件局部放大的范围,防止放大后的内部数据转换出现数据溢出。同时,坐标值转数据值和数据值转坐标值,都需要考虑到GDI+默认坐标系的问题。

    在控件测试的过程中,修改了不少遗漏的细节问题,例如放大选取框拖到控件外的情况,以及在点击放大按钮前修改软件大小,会导致放大的范围并非用户需要的范围。在设计控件接口的时候,将控件的颜色方案作为属性公开给用户,方便用户配置符合软件风格的显示方案。

    最后,控件任然存在不足和需要改进的地方:

    (1)本课题设计的波形显示控件并未提供平移波形的功能,实际上可利用设计局部放大功能的思路,实现波形拖拽移动的效果。

    (2)局部放大功能是通过使用一个半透明的pictureBox实现的,这样在数据量较大的时候产生残影的效果,可以通过直接异或显示区域的颜色来改进。

    (3)波形的显示过程中并为设置刷新时的裁剪区域,这样每次数据更新都会刷新整个波形显示区域,可以通过设置裁剪区域来提高绘图的效率。

    (4)在显示标尺坐标值的时候,为防止浮点数加法过程中产生的显示值出错,采用了decimal数据类型,牺牲了绘图效率。

    回到目录

    参考文献

    [1] 闫宇晗,常鑫.在C#中用GDI+实现图形动态显示[J].计算机技术与发展,2006,16(12):118.

    [2] 高宏亮,王淑娟,翟国富,陈功军.采用Visual C++实现的函数波形显示控件[J].电测与仪表,2006,43(12):62-65.

    [3] 张文,秦开宇,李志强. VC环境下多波形显示ActiveX控件开发[J].中国测试,2009,35(2):34-36.

    [4] 陈本峰,苏琦. Windows GDI+的研究与应用[J].计算机应用研究,2003,20(3):56-59.

    [5] Archer T.C#技术内幕[M].侯晓霞,柴洪辉译.北京:清华大学出版社,2002.

    [6] Nagel C,Evjen B.C#高级编程[M].李敏波译.第4版.北京:清华大学出版社,2006.

    [7] Sells C,Weinhardt M.Windows Forms 2.0程序设计[M].汪泳译.北京:电子工业出版社,2008.

    [8] SerBan I.GDI+ Custom Controls with Visual C# 2005[M].UK:Packt Publishing Ltd,2006.

    [9] MacDonald M.Pro .NET 2.0 Windows Forms and Custom Controls in C#[M].Apress,2005:211-262.

    [10] Troelsen A.Pro C# with .NET 3.0[M].Apress,2007:649-698.

    [11] hite E.GDI+程序设计[M].杨浩,张哲峰译.北京:清华大学出版社,2002.

    展开全文
  • 一种解决方法是,通过对电机本身气隙齿槽、定子绕组的优化设计,使反电动势波形尽可能接近理想波形,从而减小电磁转矩脉动。例如,对表面粘贴式磁钢结构的电机,常采用径向充磁而使气隙磁密更接近方波。又如,为了...
  • 其中波形弹簧回复力不足是关键因素。对此提出了解决措施,即取消现有活塞与缸体间的弹簧拉杆,重新设计了波形弹簧,活塞与缸体内外径密封也使用了专用密封。通过研究波形弹簧的设计计算方法,改善了波形弹簧的性能,...
  • 借助动力学分析软件ANSYS/LS-DYNA,运用光滑粒子流体动力学(SPH)方法,对爆炸复合界面波形参数变化的影响因素进行了二维数值模拟。模拟结果再现了爆炸复合生产中的界面波和射流现象。研究结果表明,爆炸复合过程中界面...
  • 在煤层气勘探开发中,陷落柱是制约煤层气勘探成效的重要因素之一,因此,有效识别陷落柱对提高煤层气勘探成效具有重要意义。以往识别方法都是基于三维地震数据利用陷落柱这一构造引起的地震反射同相轴的非连续性进行...
  • 采集仪器通常使用的是示波器和逻辑分析仪,而信号源在系统中则扮演了激励源的角色,波形发生器就是种类众多的信号源的一种,在电子测试测量领域应用广泛。信号源何时诞生?经历了怎样的发展历程?信号源是一种古老的...
  • 波形发生电路

    千次阅读 2013-10-23 16:34:56
    另外,放大电路的放大倍数因受环境温度及元件老化等因素影响,也要发生波动。以上情况都将直接影响振荡电路输出波形的质量,因此,通常都在放大电路中引入负反馈以改善振荡波形。在图8.2.1所示的RC串并联网络振荡...
  • pwn波形和占空比

    千次阅读 2016-09-20 20:16:01
    PWM就是脉冲宽度调制,也就是占空比可变的脉冲波形. 脉冲宽度调制是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是...
  • 以CVCF逆变器为核心的UPS得到了广泛的应用,对其输出波形主要的技术要求包括低的稳态总谐波畸变率(THD)和快速的动态响应,由于非线性负载、PWM调制过程中的死区和逆变器系统本身的弱阻尼性等因素影响,采用一般...
  • 影响PCB特性阻抗的因素有哪些?

    千次阅读 2020-05-18 14:56:10
    ​一般来说,影响PCB特性阻抗的因素:介质厚度H、铜的厚度T、走线的宽度W、走线的间距、叠层选取的材质的介电常数Er、阻焊的厚度。 一般来说,介质厚度、线距越大阻抗值越大;介电常数、铜厚、线宽、阻焊厚度越大...
  • 谐振接地系统发生单相接地故障时,各线路暂态零序电流波形具有非线性非...对噪声干扰、两点接地、电弧故障、采样不同步等情况的仿真结果表明,所提故障选线方法不受工程应用中可能存在的影响因素影响,实现可靠选线。
  • CO2气体保护焊中影响飞溅和焊缝成形的直接因素是焊接电流。文章通过电流波形发生器产生符合提高焊接质量的短路、燃弧阶段的电流波形,并设计了相应的模糊PI控制器,构成CO2焊接逆变电源的模糊PI电流波形控制系统,以...
  • Python音频处理(一)——信号,波形与频谱

    万次阅读 热门讨论 2020-03-06 19:35:41
    本文目录前言波形频谱Spectrum波形对象信号对象 前言 音频处理属于大学课程《多媒体技术》,什么采样率,频谱等理论知识,小编这里会慢慢的根据实际的代码进行讲解,不会一笼统的纯理论知识一大堆摆上来,毕竟学习...
  • 影响织物缩率的因素又有哪些? 纱线在过程中产生了屈曲,故其在织物中所占的长度或宽度就必定小于它原有的伸直长度,反应这两者之间差异程度的百分率就是织造缩率,简称织缩率或织缩。分别以经纱织缩率和纬纱织缩率...
  • 综合考虑地物反射率、发射波形和激光断面阵列(LPA)这3个因素对回波仿真结果的影响, 并进行对比实验, 探讨了最优的模拟仿真方法。实验中选择某研究区, 以冰、云和陆地高程卫星(ICESat)/地球科学激光测高系统(GLAS)...
  • 文章目录一、打开工程二、 质量度分析三、 问题分析1、眼图分析:幅值低、边沿台阶2、波形分析:幅值低、边沿台阶四、解决“台阶”解决1、边沿台阶的源头2、消除边沿台阶1)减少分支长度2)长分支上加适当电阻3)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,966
精华内容 3,186
关键字:

影响波形的因素