由序列檢測啟發:資料流滑動視窗操作

jerry_cat發表於2021-08-27

  通訊中我們常用序列檢測器用來檢測通訊幀的同步幀頭,以此達到同步的目的。序列檢測就是對於不斷輸入的二進位制資料流中檢測出特定序列的二進位制資料流。

比如在10101100100101中檢測110010。這種一般採用移位暫存器來實現,可以自行百度:移位暫存器實現序列檢測。

  關鍵字:滑動視窗法;verilog;FPGA;均值濾波

  然而這篇博文想傳播的思想是:我們能不能直接移位檢測取樣後的資料流呢?  比如取樣8bit din:8‘d55,8'd111,8'd40,8'd122,8'd100,8'd30,8'd120,我們想檢測出8'd111,8'd40,8'd122,8'd100。

這樣做能對資料進行均值濾波,這種思想還可以用來做擴頻接收中的匹配濾波捕獲,本文就拿均值濾波來舉例吧。

  假設我們要在取樣到的資料流進行均值濾波,資料流輸入為12bit,一幀有65個資料,視窗大小為5,對輸入資料採用1/4均值。

程式碼如下:

module data_capture
(
    input clk,rstn,
    
    input in_vld,
    input[11:0] din,
    
    output reg out_vld,
    output reg[31:0] dout
);
parameter AVE_DATA_NUM = 3'd5;
/////////////////////Shift register///////////////////////////
reg [11:0] data_reg [AVE_DATA_NUM-1:0];
reg [3:0]temp_i;

always @ (posedge clk)
begin
    if(rstn || !in_vld)
        for (temp_i=0; temp_i<AVE_DATA_NUM; temp_i=temp_i+1)
            data_reg[temp_i] <= 'd0;
    else
    begin
        data_reg[0] <= din;
        for (temp_i=0; temp_i<AVE_DATA_NUM-1; temp_i=temp_i+1)
            data_reg[temp_i+1] <= data_reg[temp_i];
    end
end

/////////////////////sum//////////////////////////////
reg [31:0] sum;

always @ (posedge clk )
begin
    if (rstn || !in_vld)
        sum <= 'd0;
    else
        sum <= sum + din - data_reg[AVE_DATA_NUM-1]; //Replace the oldest data with the latest input data
end

////////////////////cnt////////////////////////////
reg[8:0] cnt;

always @(posedge clk)
begin
    if (rstn || !in_vld)
        cnt <= 'd0;
    else if(cnt == 9'd64)
        cnt <= 0;
    else
        cnt <= cnt + 1'b1;
        
end

///////////////////dout////////////////////////////
always @(posedge clk)
begin
    if (rstn || !in_vld) begin
        dout <= 11'd0;
        out_vld <= 1'd0;
    end
    else if(cnt > 9'd4) begin
        out_vld <= 1'b1;
        dout <= sum>>2; //sum/4。
    end
    else begin
        out_vld <= 1'b0;
        dout    <= 0;
    end
end    


endmodule

一幀64個12bit,因為視窗大小為5,只有當第5個資料到來時才開始取均值,同時拉高out_vld。

testbeach如下:

`timescale 1ns/1ns

module capture_tb();

reg clk,rstn;
reg in_vld;
reg[11:0] din;

wire out_vld;
wire[31:0] dout;


initial begin
    clk = 1;
    rstn = 1;
    in_vld = 0;
    #200
        rstn = 0;
        in_vld = 1;
    #10000
    $stop();
end

always #10 clk = ~clk;

always #20 din = {$random}%100;

data_capture tb(
    .clk(clk),.rstn(rstn),
    
    .in_vld(in_vld),
    .din(din),
    
    .out_vld(out_vld),
    .dout(dout)
);

endmodule

模擬圖如下所示:

第一個dout為in_vld拉高之後的29,18,97,29,12的1/4均值;

第二個dout為in_vld拉高後第二個clk開始取樣得到的資料18,97,29,12,89的均值,新來的89把最老的29給頂走了。

其實計算有些是有小數的,但是FPGA就這樣,小數都想下取整了。

 

相關文章