1、 机械振动测量实验一、实验目的1、熟悉并掌握MATLAB的基本操作以及调试器的使用方法2、理解图形句柄的含义,熟悉MATLAB界面设计的常用函数和设计方法3、 熟悉Simulink的使用,理解一些常用模块的功能和含义,并熟悉通过Simulink进行动态系统建模和仿真的流程,特别是子系统的创建与封装4、进行数据采集程序的设计,能够将通过采集卡采集到的数据显示到界面中5、掌握用MATLAB对机械振动信号进行信号频谱分析的方法,初步了解简单滤波器的设计。二、实验原理和设计思路该自主实验的硬件平台是转子实验台,设置合适的通道数,即可通过采集卡对转子的机械振动信号进行采集。Simulink是MATLAB
2、的重要软件包,是一种用来实现计算机仿真的软件工具,用于对动态系统建模和仿真,它采用系统模块直观地描述系统典型环节,方便建立系统模型。它是MATLAB 的一个附加组件,可用于实现各种动态系统(包括连续系统、离散系统和混合系统)的建模、分析和仿真。由Simulink建立动态仿真模型,即可获得采集到的振动信号。为了使采集到的振动信号以及信号处理结果能够更好地呈现出来,需要搭建图形交互界面。MATLAB提供了丰富的绘图功能,在MATLAB中,图形对象的名字叫做句柄,它是图形对象的标识代码(唯一的身份),标识代码含有图形对象的各种必要的属性信息。其中,根屏幕的句柄为0,图形窗口的句柄为正整数,其它对象的
3、句柄为对应的双精度浮点数。可以通过这个“句柄”,得到或者修改图形对象的属性。同时,MATLAB还提供了很多图形对象属性函数,能够很方便地对一些图形或控件进行属性设置。具体设计思路如下:我们设计的这个“机械振动测量”软件平台主要包括四个模块,即Simulink动态仿真模块、数据采集模块、图形界面绘制模块、信号处理模块。1、Simulink动态仿真模块该模块为shilei1.mdl文件。通过S-Function,用户可以将自己的模块加入Simulink模型中,从而可以实现用户自定义的算法或者与硬件设备交互等。在该模块中,能够设置采样频率等相关参数,从而获得不同采样频率下的机械振动信号。2、数据采集
4、模块该模块为shilei.cpp文件,功能是实现采集卡的数据信号采集。因为我们所使用的转子实验平台中,振动加速度信号是从通道1中采集,所以在对应采集函数中要将通道设置为通道1。然后通过采集卡初始化函数ADCardInit()、采集函数DAQ1()、读取采样数据函数ReadDaq()等,实现机械振动信号的采集。3、图形界面绘制模块该模块主要是在jixiezhendong.m文件中实现,能够将采集到的机械振动信号绘制到图形界面中,同时能够提供人机交互的一些控件,方便用户进行机械振动测量的相关操作,并获取频谱分析图、振动频率和振动加速度等相关信息。4、信号处理模块该模块主要包括getdata.m,c
5、allradio1.m,callradio2.m三个M文件。由于采集到的机械振动信号中混杂有噪声信号,要想得到准确的振动信号和振动参数,需要通过滤波来滤掉高频的噪声信号,只留下低频的机械振动信号,所以首先需要进行滤波器的设计。其次,关于机械振动测量有两个重要参数,即振动频率和振动加速度。其中,振动频率为幅值最大的波对应的频率,振动加速度为最大幅值电压通过一个转换得到的加速度。所以,在频谱分析的基础上,通过数据处理即可得到振动频率和振动加速度这两个参数。三、设计过程1、复习MATLAB的一些基本指令和操作。比如数值数组及其运算、控制流、M文件等,同时还有MATLAB调试器的相关操作使用,以及MA
6、TLAB的图形绘制操作。2、“机械振动测量”界面的设计。参照DRVI快速可重组虚拟仪器实验平台中的转子实验台加速度传感器振动测量实验的测量界面,如上图所示,了解机械振动测量所需要得到的数据和结果。然后结合老师课堂讲解和实验指导书中关于界面设计的内容,进行“机械振动测量”界面的设计。3、数据采集程序设计。参考实验指导书中数据采集的步骤介绍,进行数据采集程序的设计,同时还有Simulink仿真模块的搭建。从而,实现通过采集卡对转子振动信号的采集,同时能够使振动信号在设计的界面中显示出来。4、机械振动信号的数据处理。获得机械振动信号后,就要对信号进行处理,主要包括频谱分析、低通滤波、参数计算等部分。
7、通过低通滤波滤掉高频的噪声信号,通过参数计算获得振动频率和振动加速度两个机械振动参数。四、Simulink模型下图为本系统的Simulink模型(shilei1.mdl)其中,Constant模块表示的是采样频率,通过修改该常数的值,即可设置不同的采样频率。To Workspace模块的功能是把输出的数据写入工作空间,以便于getdata.m文件对输出信号进行读取,并绘制到界面中。Scope模块的功能是将输出的信号实时显示出来。五、代码及注释1、C+代码及注释shilei.cpp文件的主要功能包括Simulink模型的输入输出通道的设置,以及采集卡的初始化、开启、更新以及退出等功能,可以生成动
8、态链接库,是能够实现对通道信号进行采集的重要文件。以下是shilei.cpp文件的代码及注释/* * sfuntmpl_basic.c: Basic C template for a level 2 S-function. * * - * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | * - * * Copyright 1990-2002 The MathWorks, Inc. * $Revision: 1.27 $ */* * You must specify the S_FUNCTIO
9、N_NAME as the name of your S-function * (i.e. replace sfuntmpl_basic with the name of your S-function). */#define S_FUNCTION_NAME shilei /将S_FUNCTION名字改成和文件名一样,即shilei#define S_FUNCTION_LEVEL 2/* * Need to include simstruc.h for the definition of the SimStruct and * its associated macro definitions.
10、 */#include simstruc.h /添加头文件#include abc.h/* 定义全局变量 */double buffer5000; /定义一个通道的数据缓存bufferdouble buffer15000; /定义另一个通道的数据缓存bufferint pnum; /定义读取指针数char ch8; /定义表示8个通道的二进制字符数组/* Error handling * - * * You should use the following technique to report errors encountered within * an S-function: * * ss
11、SetErrorStatus(S,Error encountered due to .); * return; * * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. * It cannot be a local variable. For example the following will cause * unpredictable errors: * * mdlOutputs() * * char msg256; ILLEGAL: to fix use static char msg256
12、; * sprintf(msg,Error due to %s, string); * ssSetErrorStatus(S,msg); * return; * * * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. */*=* * S-function methods * *=*/* Function: mdlInitializeSizes = * Abstract: * The sizes information is used by Simulink to determine the S-function * bl
13、ocks characteristics (number of inputs, outputs, states, etc.). */* mdlInitializeSizes函数用于获取输入端口和输出端口的数量、端口宽度,以及* S-function所需的任何其它对象(诸如状态数量)等有关信息。*/static void mdlInitializeSizes(SimStruct *S) /* See sfuntmpl_doc.c for more details on the macros below */ ssSetNumSFcnParams(S, 0); /* Number of expec
14、ted parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S) /* Return if number of expected != number of actual parameters */ return; ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0);/设置3个输入通道/* void ssSetNumInputPorts(SimStruct *S, int_T nInputPorts),该函数的第一* 参数为模块的一个数据结构,第二个参数nInputPor
15、ts指定模块有几个输入接口。*/if (!ssSetNumInputPorts(S, 3) return;/* void ssSetInputPortWidth(SimStruct *S, int_T port, int_T width),该函数* 的第一个参数为模块的一个数据结构,第二个参数为接口编号,第三个参数指定第* 二个参数所指定接口的数据宽度。*/ ssSetInputPortWidth(S, 0, 1); ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ ssSetInputPo
16、rtWidth(S, 1, 1); ssSetInputPortRequiredContiguous(S, 1, true); /*direct input signal access*/ ssSetInputPortWidth(S, 2, 1); ssSetInputPortRequiredContiguous(S, 2, true); /*direct input signal access*/ /* * Set direct feedthrough flag (1=yes, 0=no). * A port has direct feedthrough if the input is us
17、ed in either * the mdlOutputs or mdlGetTimeOfNextVarHit functions. * See matlabroot/simulink/src/sfuntmpl_directfeed.txt. */ /* void ssSetInputPortDirectFeedThrough(SimStruct *S, int_T port, int_T * dirFeed),该函数的第一个参数为模块的一个数据结构,第二个参数为接口编号,* 第三个参数为用于指定接口的输入数据是否能在mdlOutputs或者* mdlGetTimeOfNextVarHit中调
18、用,0表示不能调用,1表示能调用。*/ ssSetInputPortDirectFeedThrough(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 1, 1); ssSetInputPortDirectFeedThrough(S, 2, 1); /设置2个输出通道 if (!ssSetNumOutputPorts(S, 2) return; ssSetOutputPortWidth(S, 0, 1); ssSetOutputPortWidth(S, 1, 1); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S,
19、 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0);/* Function: mdlInitializeSampleTimes = * Abstract: * This function is used to specify the sample time(s) for your * S-function. You must register the same number of sample times as *
20、specified in ssSetNumSampleTimes. */设置S-function 的采样时间static void mdlInitializeSampleTimes(SimStruct *S) ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0);#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */#if defined(MDL_INITIALIZE_CONDITIONS) /* Func
21、tion: mdlInitializeConditions = * Abstract: * In this function, you should initialize the continuous and discrete * states for your S-function block. The initial states are placed * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). * You can also perform any other initialization act
22、ivities that your * S-function may require. Note, this routine will be called at the * start of simulation and if it is present in an enabled subsystem * configured to reset states, it will be call when the enabled subsystem * restarts execution to reset the states. */ static void mdlInitializeCondi
23、tions(SimStruct *S) #endif /* MDL_INITIALIZE_CONDITIONS */#define MDL_START /* Change to #undef to remove function */#if defined(MDL_START) /* Function: mdlStart = * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is th
24、e place * to do it. */* 采集卡初始化及开启数据采集 */ static void mdlStart(SimStruct *S) const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); double fs=u0; /将Simulink仿真模型中的第一个常数值赋给采样频率fs/采集卡初始化/ ADCardInit() 是采集卡DLL函数,作用是初始化采集卡。如果初始化成功则返/ 回1,用于判断是否连上采集卡。 if(ADCardInit()!=1) ssSetErrorStatus(S, Cant find
25、the DAQCard!); / DAQ1(ch, Fs, len, buffer) 是采集卡DLL单通道采集函数,作用是启动采集卡/ 进行单通道数据采集。参数1为采样通道,是以8为二进制数表示各个通道是否/ 开启。参数2为采样频率,参数3为采样点个数,参数4为数据缓存数组。 DAQ1(0x1,fs,1024*4,buffer); /开启采集:对通道1采集数据 pnum=0; /初始化指针位置 #endif /* MDL_START */* Function: mdlOutputs = * Abstract: * In this function, you compute the output
26、s of your S-function * block. Generally outputs are placed in the output vector, ssGetY(S). */* 读取buffer 数据和输出数据 */static void mdlOutputs(SimStruct *S, int_T tid)int length=1024*4; /读取的buffer 的长度/ ReadDaq() 的作用是读取下位机buf 里的采样数据。其中,参数1为通道号,参数/ 2为buffer 长度,参数3为保存的buffer 指针。 ReadDaq(1,length,buffer); /从
27、采集卡读取buffer/ const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); /获取输出指针/ y0 = u0; if(pnum=length) pnum=0; /判断指针是否已满 *y=bufferpnum; /输出第pnum 个点的值 pnum+; /指针加1#define MDL_UPDATE /* Change to #undef to remove function */#if defined(MDL_UPDATE) /* Fu
28、nction: mdlUpdate = * Abstract: * This function is called once for every major integration time step. * Discrete states are typically updated here, but this function is useful * for performing any tasks that should only take place once per * integration step. */ static void mdlUpdate(SimStruct *S, i
29、nt_T tid) #endif /* MDL_UPDATE */#define MDL_DERIVATIVES /* Change to #undef to remove function */#if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives = * Abstract: * In this function, you compute the S-function blocks derivatives. * The derivatives are placed in the derivative vector, ssGetdX(S
30、). */ static void mdlDerivatives(SimStruct *S) #endif /* MDL_DERIVATIVES */* Function: mdlTerminate = * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was * allocated in mdlStart, this is the place to free
31、it. */* 退出采集卡 */static void mdlTerminate(SimStruct *S) ADCardQuit(); /采集卡的DLL函数,作用是退出采集卡/*=* * See sfuntmpl_doc.c for the optional S-function methods * *=*/*=* * Required S-function trailer * *=*/#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */#include simulink.c /* MEX-file i
32、nterface mechanism */#else#include cg_sfun.h /* Code generation registration function */#endif2、M代码及注释我们设计的“机械振动测量”界面共包括四个M文件,分别是jixiezhendong.m, getdata.m, callradio1.m, callradio2.m。(1)jixiezhendong.m 文件代码及注释该文件的主要功能是生成“机械振动测量”的界面,包括两个轴对象、两个按钮控件、两个无线电选择控件、两个编辑框控件以及一些静态文本框等,通过对这些对象的定义和属性的设置,能够生成“机械
33、振动测量”的界面,如下图所示。同时,该文件中还包括控件的一些回调属性的定义。比如点击“开始”按钮开启定时器开始计时,并运行getdata.m文件;点击“停止”按钮停止计时;选择“原始信号”或“低通滤波”可分别开启定时器,并运行callradio1.m或callradio2.m文件。以下是jixiezhendong.m文件的代码及注释clf reset; %清除图像窗口当前图像,重置所有对象设置set (gcf,menubar,none); %去掉窗口中的菜单栏set(gcf,unit,normalized,position,0.05,0.2,0.62,0.75); %设置窗口在屏幕中的显示位置
34、和窗口大小set(gcf,defaultuicontrolunits,normalized); %设置用户缺省控件单位属性值set(gcf,defaultuicontrolfontname,楷体); %设置用户缺省控件字体set(gcf,defaultuicontrolfontsize,13); %设置用户缺省控件字体大小set(gcf,NumberTitle,off,Name,机械振动测量); %设置图形窗口的名称h_axes1=axes(position,0.1,0.53,0.56,0.3); %定义轴位框位置axis(0 0.094 -1000 1000); %设置坐标轴的范围title
35、(传感器输出波形); %坐标轴命名xlabel(时间(s); %定义x轴的标签名ylabel(电压(mv)); %定义y轴的标签名h_axes2=axes(position,0.1,0.1,0.56,0.3); %定义轴位框的位置title(频谱分析图谱); %坐标轴命名xlabel(频率(Hz)); %定义x轴的标签名ylabel(电压(mv)); %定义y轴的标签名hpush1=uicontrol(gcf,style,push,. %创建“开始”按钮 position,0.83,0.8,0.1,0.05,. %按钮的位置 string,开始,. %按钮的文字标识fontweight,bol
36、d); %按钮字体为加粗hpush2=uicontrol(gcf,style,push,position,0.83,0.73,0.1,0.05,string,停止,fontweight,bold); %创建“停止”按钮hr1=uicontrol(gcf,style,radio,position,0.82,0.48,0.12,0.05,string,原始信号,fontweight,bold); %创建“原始信号”单选按钮hr2=uicontrol(gcf,style,radio,position,0.82,0.44,0.12,0.05,string,低通滤波,fontweight,bold);
37、%创建“低通滤波”单选按钮hedit1=uicontrol(gcf,style,edit,position,0.83,0.17,0.1,0.05,fontweight,bold); %创建“振动频率”编辑框hedit2=uicontrol(gcf,style,edit,position,0.83,0.1,0.1,0.05,fontweight,bold); %创建“振动加速度”编辑框 htext1=uicontrol(gcf,style,text,position,0.3,0.92,0.4,0.07,fontname,隶书,fontsize,32,string,机械振动测量); %创建“机械振
38、动测量”静态文本框htext2=uicontrol(gcf,style,text,position,0.72,0.17,0.11,0.048,string,振动频率=,fontweight,bold); %创建“振动频率=”静态文本框htext3=uicontrol(gcf,style,text,position,0.69,0.1,0.14,0.048,string,振动加速度=,fontweight,bold); %创建“振动加速度=”静态文本框htext4=uicontrol(gcf,style,text,position,0.93,0.17,0.035,0.048,string,Hz,f
39、ontweight,bold); %创建“Hz”静态文本框htext5=uicontrol(gcf,style,text,position,0.93,0.1,0.068,0.048,string,mm/s2,fontweight,bold); %创建“mm/s2”静态文本框%在“开始”按钮中设置回调属性set(hpush1,callback,. set_param(shilei1,SimulationCommand,start),. %让shilei1.mdl文件运行 t=timer(TimerFcn,getdata,Period,1,ExecutionMode,fixedSpacing,TasksToExecute,inf),. %设置定时器,运行getdata.m文件 pause(2);start(t);,. %暂停2秒并启动定时器 );%在“停止”按钮中设置回调属性set(hpush2,callback,stop(t);set_param(shilei1,Simulation