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

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的资源开销,提高了系统的稳定性和运行速率。

  • 30
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小精灵_2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值