基于FPGA和MCU的超声流量测量互相关算法实现

基于FPGA和MCU的互相关算法实现–超声流量测量

  • 1 引言
  • 2 摘要
  • 3 FPGA方案设计
  • 3.1 为什么需要FPGA
  • 3.2 FPGA数据采集模块框图
  • 3.3 Interface接口设计
  • 3.4 ADC接口模块设计
  • 3.5 Reg control模块
  • 3.6 PWM产生模块
  • 3.7 控制模块
  • 4 MCU互相关算法设计
  • 4.1 通信接口
  • 4.2 互相关算法模块
  • 4.2.1 数据采集模块
  • 4.2.2 互相关计算
  • 5 仿真验证
  • 5.1 FPGA部分仿真
  • 5.2 MCU部分仿真
  • 6 总结
  • 1 引言

    超声流量计是一种工业上应用于液体,气体的非接触式测量仪器,具有测量精度高,安装方便的特点,目前是工业上主流的测量仪器。
    在市政行业的原水、自来水、中水、污水的计量中,超声流量计具有大量程比、无压损的特点,在保证测量准确度的同时提高了管网的输水效率;
    在水利水电行业的输水管道、渠道、泵站、电站的流量计量中,超声流量计具有大口径、现场安装、在线标定的特点,使准确测量成为可能。同时通过对水泵、水轮机单泵、单机的计量来实现设备优化、经济运行的目的;
    在工业冷却循环水的计量中,超声流量计实现了在线不断流带压安装和在线标定;

    2 摘要

    本文详细论述了超声流量计中的互相关算法基于FPGA和MCU的实现方案,以及设计原理。系统模块的组成包括ADC数据处理模块,与MCU通信接口模块,寄存器控制模块,PWM发波模块。MCU向FPGA配置运行参数,并启动测量。然后FPGA开始发波,测量回波信号,正反向各一次,并将测量到的回波信号存到ram,发送中断信号给MCU,然后MCU响应中断后读取FPGAram中的数据,并进行互相关计算。该系统具有测量精度高的特点,另外互相关算法也做了深度定制优化,大大提高了运算速度。

    3 FPGA方案设计

    3.1 为什么需要FPGA

    FPGA主要负责数据的采集与超声波的发送部分。为什么要用FPGA,单片机为什么做了不呢?下面我们来详细分析一下:
    首先我们目的是要测量液体在管中的流量,根据超声时差测量法可知,只要测出超声波正向和反向传播的时间或者时间差,就可以简介推算出液体的流量。那么我们主要问题就是解决如何测量出正反向传播时间或者时间差。这个时间差是ns甚至ps级别的,50MHz的ADC 10倍插值,精度才可达到2ns,一般单片机很难挂载50MHz的ADC。
    另外一点单片机很难完成的任务是自发出PWM波(t0)后到采集第一个数据的时间点(t1), t1-t0这个时间差精度必须得保证ps级别。然而这对单片机来说是一项非常艰巨的任务。
    以上两点在单片机上很难实现的,而在FPGA上很轻松就能实现。

    3.2 FPGA数据采集模块框图

    FPGA总体框图

    3.3 Interface接口设计

    该模块主要工作是负责FPGA与MCU的通信,通信数据位宽为MCU RX 8bit,MCU TX 1bit。通信分为接收端和发送端,接收端采用SPI协议,发送端采用8bit并行端口,并行端口具有很大的传输带宽,主要是为了应对数据打量传输而设计的。
    Interface接口模块将MCU读写的时序转换为对寄存器模块的读写控制操作,来完成MCU对寄存器控制和ADC ram内的数据读取操作。具体操作时序如下:
    写操作

    上图是一个MCU写数据的操作,通过内部逻辑转换后,转化成对寄存器模块的写操作,如下图所示

    读操作

    上图是一个MCU读数据的操作,读取的16bit数据通过总线两次传输,每次传输8bit。通过内部逻辑转换后,转化成对寄存器模块的读操作,如下图所示

    3.4 ADC接口模块设计

    ADC接口模块主要是生成系统时钟的4分频时钟,用以采样ADC的数据。数据位宽为10bit,时钟下降沿采样数据,数据格式是10bit有符号二进制整数。
    在系统给叔采样窗口信号window后,模块在这个窗口内进行ADC数据采样,进来的数据存入RAM里面。模块内部有两个256深度的ram,跟据输入信号DIR来判断存入哪一个ram。Ram数据存满后等待reg control模块来读取。
    以下是此模块的读时序:

    3.5 Reg control模块

    寄存器控制模块负责接收MCU的读写指令,改变相应的寄存器的值。通过此方式可以间接配置各个模块的功能参数,比如window宽度,采样开始,查询中断,读ram数据等等操作。寄存器接口时序上面已经给出,这里就不再重复阐述了。

    3.6 PWM产生模块

    PWM产生模块主要负责根据MCU传过来的参数来产生PWM波形,经过外部放大驱动超声模块,产生超声波。
    该模块的输入参数有占空比,周期。输出是一对互补的pwm信号,持续3个周期,该模块设计非常简单,基本核心就是使用一个计数器,计都指定的数值改变输出极性。
    具体输出波形如下:

    3.7 控制模块

    控制模块完成系统的核心运转逻辑,pwm发波控制,驱动器电源的使能控制,输出切换器的控制,正反向控制。
    MCU只需要发出一个start指令,该模块就会运行一次,完成正反向发波与采集,电源使能控制。模块内部实际运行是用状态机实现的:

    状态介绍:
    IDLE:空闲
    SW:方向切换,控制正反向发波。
    WAIT:等待计数,为了等待切换完成。
    PWM:PWM发波请求。
    ADC: 进行ADC采集,主要是根据采集窗口的时隙来采集反射波在ADC上的数据。
    PWR:电源控制,此阶段关闭一段时间电源。

    模块开始处于idle状态,MCU控制start信号,开始运行,进入下一个状态切换开关,用来改变正反向发波,然后进入wait状态等待切换完成,计数完成后进入PWM发波状态,请求发波。待发波后开始等待ADC采集,当ADC采集完成后会返回reflect信号,根据这个信号可以判断何时进入PWR状态。在PWR状态时候关闭驱动电源一段时间。然后进入end状态,在此时需要判断方向,如果DIR=1则表示正反向都已经完成,则回到IDLE,否则再次进入SW状态,重复以上步骤。

      case (r_state)
            S_IDLE  :
                if(start_pulse==1'b1)
                    r_nxtstate = S_SW;
                else
                    r_nxtstate = S_IDLE;
            S_SW    :
                r_nxtstate = S_WAIT;//8 cycle
            S_WAIT  :
                if(wait_cnt[4:0]==5'b11110)//15us
                    r_nxtstate = S_PWM;  
                else  
                    r_nxtstate = S_WAIT;  
            S_PWM   :
                r_nxtstate = S_ADC;
            S_ADC   :
                if(reflected==1'b1 )
                    r_nxtstate = S_LOOP; 
                else if(start_pulse==1'b1)
                    r_nxtstate = S_SW; 
                else 
                    r_nxtstate = S_ADC; 
           
                    r_nxtstate = S_PWR;
            S_LOOP  :if(loop_cnt == C_CYCLES)
                        r_nxtstate = S_PWR ;     
                    else if(window==1'b0)
                        r_nxtstate = S_PWM;  
                    else 
                        r_nxtstate = S_LOOP; 
     		S_PWR   :
                if(wait_cnt == 9'd460)
                    r_nxtstate = S_END; 
                else  
     		S_END   :
                    if(dir==1'b1)
                        r_nxtstate = S_IDLE; 
                    else 
                        r_nxtstate = S_SW;
    		default: begin
                r_nxtstate = S_IDLE;
            end
          endcase
    
        
    
    

    4 MCU互相关算法设计

    在MCU设计中,主要完成以下功能:
     与FPGA进行通信,设计通信接口
     看门狗设计
     EEPROM存储功能设计
     点阵屏驱动显示
     按键功能设计
     互相关算法模块

    4.1 通信接口

    该功能模块主要是用GPIO模拟出SPI的写时序和并行接口读时序,来完成与FPGA的通信。来完成对FPGA的寄存器设计与数据的读取。
    SPI时序图在上文中已有提及,以下是读写代码部分:

    接口通讯 写
    	FP_WE(0);
    	delay_us(2);
    	for(i=8;i>0;i--){
    		FP_RS(0);
    		delay_us(5);
    		if( (addr_temp>>(i-1)) &0x01 ) FP_OE(1);
    		else FP_OE(0);
    		FP_RS(1);
    		delay_us(5);
    	}
    
    	for(i=16;i>0;i--){
    		FP_RS(0);
    		delay_us(5);
    		if( (wdata>>(i-1)) &0x01 ) FP_OE(1);
    		else FP_OE(0);
    		FP_RS(1);
    		delay_us(5);
    	}
    	FP_RS(0);
    	delay_us(5);
    	FP_WE(1);
    	delay_us(10);
    
    
    接口通讯 读
    
    FP_WE(1);
    	delay_us(2);
    	FP_RS(0);
    	delay_us(5);
    	FP_RS(1);
    	delay_us(5);
    	while(FP_ACK==0);
    	FP_RS(0);
    	delay_us(5);
    	RESULT= 0x0000|FP_D0_i|(FP_D1_i<<1)|(FP_D2_i<<2)|(FP_D3_i<<3)|(FP_D4_i<<4)|(FP_D5_i<<5)|(FP_D6_i<<6)|(FP_D7_i<<7);
    	delay_us(5);
    	RESULT=RESULT<<8;
    
    	FP_RS(1);
    	delay_us(5);
    	while(FP_ACK==0);
    	FP_RS(0);
    	delay_us(5);
    	RESULT= RESULT|FP_D0_i|(FP_D1_i<<1)|(FP_D2_i<<2)|(FP_D3_i<<3)|(FP_D4_i<<4)|(FP_D5_i<<5)|(FP_D6_i<<6)|(FP_D7_i<<7);
    	delay_us(5);
    	return RESULT;
    
    

    4.2 互相关算法模块

    该算法模块主要是对正反向采集的波形进行互相关计算,来计算出两组波形的Δt延迟。

    4.2.1 数据采集模块

    采集模块在主程序中一直运行,

    程序中主要检测busy信号,以此判断模块是否正在忙于互相关运算。
    另外还有smpl_rdy状态,这个是指示FPGA侧数据采集完毕的标志。此标志在MCU中断中设置为1,数据采集完成后设计为0。

    4.2.2 互相关计算

    互相关计算原理
    公式:

    由此可见,互相关计算其实就是计算两个函数在0-tc时间内的乘积的积分。最后判断在t=?时候C(t)有最大值。由于我们的使用环境比较特别,在Cmax的时候t一般不会太大,所以我们在t=0-100内计算出C(t)。
    本设计中互相关计算模块主要利用互相关算法,来对输入的两组数据进行插值滤波,相乘累加运算,求得最大相关的点位(C(t)最大时t的值)。FPGA端采集的数据是240个,在算法中经过10倍插值,最终数据是2400个,如此下来,精度就扩大了10倍,假设FPGA端ADC的时钟是50MHz,那么经过10倍插值后精度就是2nS。由此可以算出在10cm的管径中测水的流量,精度可以达到0.01m/s,测量范围1m/s。
    软件设计流程如下:

    5 仿真验证

    5.1 FPGA部分仿真

    测试程序里面需要模拟ADC芯片的动作,产生假数据,让FPGA采集,然后再模拟MCU的动作从FPGA的ram读取数据,检查是否一致。
    测试代码如下:

    //sensor test
    $display("sensor test start");
    
    fpga_write(8'h06,16'h1);//start pwm
    wait(irq_ram);//wait for ram adc sample done
    fpga_write(8'h06,16'h2);//clear rdy flag
    
    #1000;
    fpga_write(8'h2f,16'h0);//关闭读ram1
    #1000
    fpga_write(8'h2e,16'h1);//使能读ram0
        for (i=0; i<240; i=i+1) begin
            addr_temp=8'h2d;
            fpga_read(addr_temp,ram0[i]);//read ram data
            //fpga_setaddr(8'h2d);
            //fpga_cont_rd(ram0[i]);
            @(posedge clk) #1
            #500;
    
            $display("addr : %d ; data is %x",i,ram0[i]);
        end
    #1000;
    fpga_write(8'h2e,16'h0);//关闭读ram0
    #1000
    fpga_write(8'h2f,16'h1);//使能读ram1
        for (i=0; i<240; i=i+1) begin
            addr_temp=8'h2d;
            fpga_read(addr_temp,ram1[i]);//read ram data
            //fpga_setaddr(8'h2d);
            //fpga_cont_rd(ram0[i]);
            @(posedge clk) #1
            #500;
    
            $display("addr : %d ; data is %x",i,ram1[i]);
        end
    fpga_write(8'h2f,16'h0);//关闭读ram1
    $stop;
    end
    
    
    

    仿真结果:

    从结果上来看,读出来的数据跟预设的数据是一致的,证明逻辑是没有问题的。

    5.2 MCU部分仿真

    在MCU软件部分,只针对互相关算法进行仿真,两组采样数据预先设置初值,然后代入算法模块进行计算,检查计算结果是否与预期的一致。另外需要注意的是测试程序插值采用5倍插值。
    初值设置:将da_buff初始化为0,0,0,0,0,5到119,118,117,…0,0,0,0一个先递增再递减的向量数据,将db_buff初始化为da_buff右移一个数据的向量。
    测试主程序如下:

    for (i = 0; i < 240; i++) {
    		if ((i > 4) && (i < 236)) {
    			if (i < 120)
    				da_buff[i] = i;
    			else
    				da_buff[i] = 239 - i;
    		}
    		else
    			da_buff[i] = 0;
    	}
    	db_buff[0] = 0;
    	for (i = 1; i < 240; i++) {
    		if ((i > 5) && (i < 237)) {
    			if ((i+1) < 120)
    				db_buff[i] = i-1;
    			else
    				db_buff[i] = 239 - i+1;
    		}
    		else
    			db_buff[i] = 0;
    	}
    	while(1){
    	offset = hxg1(da_buff, db_buff);
    
    	printf("offset is: %d",offset);
    
    

    在print处设置断点,运行仿真:

    从结果上看,offset为5,与预期的结果相符合。

    6 总结

    本设计采用FPGA和MCU的方案,充分发挥FPGA的优势,利用FPGA采集两组相关数据。MCU部分解决的最大的问题就是如何提升采样精度,该设计中没有复杂的fft,和fft逆变换,大大节省了CPU的资源开销,提高了系统的稳定性和运行速率。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于FPGA和MCU的超声流量测量互相关算法实现

    发表评论