OPENOFDM仿真:将FFT输入输出保存为文件

66 篇文章 23 订阅
58 篇文章 27 订阅
本文详细介绍了如何在OpenOFDM的sync_long.v文件中实现FFT模块的输入输出文件记录,通过动态修改文件名后缀和计数器生成,确保数据对应性。作者展示了如何使用ASCII字符转换、文件操作以及计数器控制文件生成过程。
摘要由CSDN通过智能技术生成

在openofdm的sync_long.v文件里面有FFT 模块,实现时域向频域的转换。每次给FFT模块输入16位(IQ各位1位)64组复数,得到IQ各为23位的64组复数。我们这里写点代码,将FFT模块的每此64组输入和64组输出记录下来保存在单独命名的文件并实现驶入输出的对应。 

首先我们要实现文件名的可以动态生成。这里思路是修改文件名称的后2个字节。

1,动态生成文件名
reg [40*8-1:0] lw_fft_in_name = "./sim_out/lw/lw_fft_inXX" ; 
定义了一个包含了路径的文件名,后面两字节XX我们通过可以通过修改寄存器lw_fft_in_name的[15:0]寄存器位来修改。比如要将XX替换为01则


reg [40*8-1:0] lw_fft_out_name = "./sim_out/lw/lw_fft_outXX" ; 
lw_fft_out_name[7:0] <=  "1";
lw_fft_out_name[15:8] <= "0" ;

我们写一个二进制转换成ASCII字符的fuction,如下:

function [7:0]bin2char ;
input [3:0] b ;
begin
case(b)
0,1,2,3,4,5,6,7,8,9:bin2char = b + "0" ;
'ha,'hb,'hc,'hd,'he,'hf : bin2char = b + "a" -10  ; 
default bin2char = "x"  ;
endcase end 
endfunction 

这样就可以实现动态生成文件名称了。

integer lw_log_fft_in  ;
reg [40*8-1:0] lw_fft_in_name = "./sim_out/lw/lw_fft_inXX" ; 

always @ (posedge clock)begin 
lw_fft_in_name[7:0] <= bin2char ( ci[3:0] );
lw_fft_in_name[15:8] <= bin2char ( ci[7:4] );
if (start_of_a_fft)lw_log_fft_in <= $fopen (lw_fft_in_name,"w");
end 

2,设置计数寄存器

我们设置一个计数器参与文件名的生成。比较简单我直接列代码

reg [7:0] ci= 0,co  = 0 ;
reg fft_start_delayedr;

always @(posedge clock) fft_start_delayedr<=fft_start_delayed;
wire start_of_a_fft  =  {fft_start_delayedr,fft_start_delayed }==2'b01;
always @ (posedge  clock) if (reset)ci<=0; else if (start_of_a_fft) ci<=ci+1;

integer lw_log_fft_in  ;
reg [40*8-1:0] lw_fft_in_name = "./sim_out/lw/lw_fft_inXX" ; 

always @ (posedge clock)begin 
lw_fft_in_name[7:0] <= bin2char ( ci[3:0] );
lw_fft_in_name[15:8] <= bin2char ( ci[7:4] );
if (start_of_a_fft)lw_log_fft_in <= $fopen (lw_fft_in_name,"w");
end 
always @ (posedge clock )if (fft_in_cnt!=0)begin   
$fwrite(  lw_log_fft_in  ,"%04x,%04x\n" ,$signed (fft_in_re[15:0] ),$signed (fft_in_im[15:0])); 
//$fwrite(  lw_log_fft_in  ,"%d,%d\n" ,fft_in_re[15:0] ,fft_in_im[15:0]); 
$fflush(lw_log_fft_in); 
end

这里加了上升边沿检测,在start上升边沿来到,就是将计数器ci加1,同时将之前ci的计数参与输出文件的命名。另外由于fft接口时序中只有一个起始信号start,之后的64个周期一直有数据输入,我们设置了fft_in_cnt来表明正在对fft进行数据输入。

修改后的sync_long.v代码如下:

module sync_long (
    input clock,
    input reset,
    input enable,

    input set_stb,
    input [7:0] set_addr,
    input [31:0] set_data,

    input [31:0] sample_in,
    input sample_in_strobe,
    input signed [31:0] phase_offset,
    input short_gi,

    output [`ROTATE_LUT_LEN_SHIFT-1:0] rot_addr,
    input [31:0] rot_data,

    output [31:0] metric,
    output metric_stb,
    output reg long_preamble_detected,

    output reg [31:0] sample_out,
    output reg sample_out_strobe,

    output reg [2:0] state
);

`include "common_params.v"

function [7:0]bin2char ;
input [3:0] b ;
begin
case(b)
0,1,2,3,4,5,6,7,8,9:bin2char = b + "0" ;
'ha,'hb,'hc,'hd,'he,'hf : bin2char = b + "a" -10  ; 
default bin2char = "x"  ;
endcase end 
endfunction 


localparam IN_BUF_LEN_SHIFT = 8;

localparam NUM_STS_TAIL = 32;

reg [15:0] in_offset;
reg [IN_BUF_LEN_SHIFT-1:0] in_waddr;
reg [IN_BUF_LEN_SHIFT-1:0] in_raddr;
wire [IN_BUF_LEN_SHIFT-1:0] gi_skip = short_gi? 9: 17;
reg signed [31:0] num_input_produced;
reg signed [31:0] num_input_consumed;
reg signed [31:0] num_input_avail;

reg [2:0] mult_stage;
reg [1:0] sum_stage;
reg  mult_strobe;

wire signed [31:0] stage_sum_i;
wire signed [31:0] stage_sum_q;

wire stage_sum_stb;

reg signed [31:0] sum_i;
reg signed [31:0] sum_q;
reg sum_stb;

reg signed [31:0] phase_correction;
reg signed [31:0] next_phase_correction;


complex_to_mag #(.DATA_WIDTH(32)) sum_mag_inst (
    .clock(clock),
    .enable(enable),
    .reset(reset),

    .i(sum_i),
    .q(sum_q),
    .input_strobe(sum_stb),

    .mag(metric),
    .mag_stb(metric_stb)
);

reg [31:0] metric_max1;
reg [(IN_BUF_LEN_SHIFT-1):0] addr1;
reg [31:0] metric_max2;
reg [(IN_BUF_LEN_SHIFT-1):0] addr2;
reg [15:0] gap;

reg [31:0] cross_corr_buf[0:15];

reg [31:0] stage_X0;
reg [31:0] stage_X1;
reg [31:0] stage_X2;
reg [31:0] stage_X3;

reg [31:0] stage_Y0;
reg [31:0] stage_Y1;
reg [31:0] stage_Y2;
reg [31:0] stage_Y3;

stage_mult stage_mult_inst (
    .clock(clock),
    .enable(enable),
    .reset(reset),

    .X0(stage_X0[31:16]),
    .X1(stage_X0[15:0]),
    .X2(stage_X1[31:16]),
    .X3(stage_X1[15:0]),
    .X4(stage_X2[31:16]),
    .X5(stage_X2[15:0]),
    .X6(stage_X3[31:16]),
    .X7(stage_X3[15:0]),

    .Y0(stage_Y0[31:16]),
    .Y1(stage_Y0[15:0]),
    .Y2(stage_Y1[31:16]),
    .Y3(stage_Y1[15:0]),
    .Y4(stage_Y2[31:16]),
    .Y5(stage_Y2[15:0]),
    .Y6(stage_Y3[31:16]),
    .Y7(stage_Y3[15:0]),

    .input_strobe(mult_strobe),

    .sum({stage_sum_i, stage_sum_q}),
    .output_strobe(stage_sum_stb)
);

localparam S_SKIPPING = 0;
localparam S_WAIT_FOR_FIRST_PEAK = 1;
localparam S_WAIT_FOR_SECOND_PEAK = 2;
localparam S_IDLE = 3;
localparam S_FFT = 4;

reg fft_start;
wire fft_start_delayed;
wire fft_in_stb;
reg fft_loading;
wire signed [15:0] fft_in_re;
wire signed [15:0] fft_in_im;
wire [22:0] fft_out_re;
wire [22:0] fft_out_im;
wire fft_ready;
wire fft_done;
wire fft_busy;
wire fft_valid;

wire [31:0] fft_out = {fft_out_re[22:7], fft_out_im[22:7]};

wire signed [15:0] raw_i;
wire signed [15:0] raw_q;
reg raw_stb;

ram_2port  #(.DWIDTH(32), .AWIDTH(IN_BUF_LEN_SHIFT)) in_buf (
    .clka(clock),
    .ena(1),
    .wea(sample_in_strobe),
    .addra(in_waddr),
    .dia(sample_in),
    .doa(),
    .clkb(clock),
    .enb(fft_start | fft_loading),
    .web(1'b0),
    .addrb(in_raddr),
    .dib(32'hFFFF),
    .dob({raw_i, raw_q})
);

rotate rotate_inst (
    .clock(clock),
    .enable(enable),
    .reset(reset),

    .in_i(raw_i),
    .in_q(raw_q),
    .phase(phase_correction),
    .input_strobe(raw_stb),

    .rot_addr(rot_addr),
    .rot_data(rot_data),
    
    .out_i(fft_in_re),
    .out_q(fft_in_im),
    .output_strobe(fft_in_stb)
);

delayT #(.DATA_WIDTH(1), .DELAY(9)) fft_delay_inst (
    .clock(clock),
    .reset(reset),

    .data_in(fft_start),
    .data_out(fft_start_delayed)
);


xfft_v7_1 dft_inst (
    .clk(clock),
    .fwd_inv(1),
    .start(fft_start_delayed),
    .fwd_inv_we(1),

    .xn_re(fft_in_re),
    .xn_im(fft_in_im),
    .xk_re(fft_out_re),
    .xk_im(fft_out_im),
    .rfd(fft_ready),
    .done(fft_done),
    .busy(fft_busy),
    .dv(fft_valid)
);

 


integer fft_out_file ;

reg [7:0] lw_dump_state ;


reg [7:0] ci= 0,co  = 0 ;
reg fft_start_delayedr;

always @(posedge clock) fft_start_delayedr<=fft_start_delayed;
wire start_of_a_fft  =  {fft_start_delayedr,fft_start_delayed }==2'b01;
always @ (posedge  clock) if (reset)ci<=0; else if (start_of_a_fft) ci<=ci+1;

integer lw_log_fft_in  ;
reg [40*8-1:0] lw_fft_in_name = "./sim_out/lw/lw_fft_inXX" ; 

always @ (posedge clock)begin 
lw_fft_in_name[7:0] <= bin2char ( ci[3:0] );
lw_fft_in_name[15:8] <= bin2char ( ci[7:4] );
if (start_of_a_fft)lw_log_fft_in <= $fopen (lw_fft_in_name,"w");
end 
always @ (posedge clock )if (fft_in_cnt!=0)begin   
$fwrite(  lw_log_fft_in  ,"%04x,%04x\n" ,$signed (fft_in_re[15:0] ),$signed (fft_in_im[15:0])); 
//$fwrite(  lw_log_fft_in  ,"%d,%d\n" ,fft_in_re[15:0] ,fft_in_im[15:0]); 
$fflush(lw_log_fft_in); 
end


integer lw_log_fft_out  ;reg fft_validr ;
always@(posedge clock) fft_validr<=fft_valid ;
wire fft_end = {fft_validr,fft_valid} == 2'b10 ;

reg [70*8-1:0] fn ;
always @ (posedge  clock)if (reset)co<=0;else if (fft_end)co<=co+1;

/*
always @ (posedge clock )
if (fft_in_cnt!=0)
begin   $fwrite(  lw_log_fft_in  ,"%04x,%04x\n" ,fft_in_re[15:0] ,fft_in_im[15:0]); 
$fflush(lw_log_fft_in); 
end
*/ 

 
reg [40*8-1:0] lw_fft_out_name = "./sim_out/lw/lw_fft_outXX" ; 

always @ (posedge clock)begin 
lw_fft_out_name[7:0] <= bin2char ( co[3:0] );
lw_fft_out_name[15:8] <= bin2char ( co[7:4] );
if (fft_end)lw_log_fft_out <= $fopen (lw_fft_out_name,"w");
end 
  

reg [7:0] fft_in_cnt;

always @ (posedge clock )if (fft_start_delayed) fft_in_cnt <= 1; 
else if (fft_in_cnt!=0) fft_in_cnt<= (fft_in_cnt==64) ? 0: fft_in_cnt +  1; 

always @ (posedge clock )if (fft_in_cnt!=0)begin   
$fwrite(  lw_log_fft_in  ,"%04x,%04x\n" ,$signed (fft_in_re[15:0] ),$signed (fft_in_im[15:0])); 
//$fwrite(  lw_log_fft_in  ,"%d,%d\n" ,fft_in_re[15:0] ,fft_in_im[15:0]); 
$fflush(lw_log_fft_in); 
end

 
always @ (posedge clock )if (fft_valid)begin   
//$fwrite(  lw_log_fft_out ,"%04x,%04x\n" ,fft_out_re[22:7] ,fft_out_im[22:7]);
$fwrite(  lw_log_fft_out ,"%d,%d\n" ,$signed (fft_out_re ) ,$signed (fft_out_im) );
//$fwrite(  lw_log_fft_out ,"%d,%d\n" ,fft_out_re[22:7] ,fft_out_im[22:7]); 
$fflush(lw_log_fft_out); 
end 

reg [15:0] num_sample;
reg [15:0] num_ofdm_symbol;

integer i;
integer j;
always @(posedge clock) begin
    if (reset) begin
        for (j = 0; j < 16; j= j+1) begin
            cross_corr_buf[j] <= 0;
        end
        do_clear();
        state <= S_SKIPPING;
    end else if (enable) begin
        if (sample_in_strobe && state != S_SKIPPING) begin
            in_waddr <= in_waddr + 1;
            num_input_produced <= num_input_produced + 1;
        end
        num_input_avail <= num_input_produced - num_input_consumed;

        case(state)
            S_SKIPPING: begin
                // skip the tail of  short preamble
                if (num_sample >= NUM_STS_TAIL) begin
                    num_sample <= 0;
                    state <= S_WAIT_FOR_FIRST_PEAK;
                end else if (sample_in_strobe) begin
                    num_sample <= num_sample + 1;
                end
            end

            S_WAIT_FOR_FIRST_PEAK: begin
                do_mult();

                if (metric_stb && (metric > metric_max1)) begin
                    metric_max1 <= metric;
                    addr1 <= in_raddr - 1;
                end

                if (num_sample >= 64) begin
                    num_sample <= 0;
                    addr2 <= 0;
                    state <= S_WAIT_FOR_SECOND_PEAK;
                end else if (metric_stb) begin
                    num_sample <= num_sample + 1;
                end

            end

            S_WAIT_FOR_SECOND_PEAK: begin
                do_mult();

                if (metric_stb && (metric > metric_max2)) begin
                    metric_max2 <= metric;
                    addr2 <= in_raddr - 1;
                end
                gap <= addr2 - addr1;

                if (num_sample >= 64) begin
                    `ifdef DEBUG_PRINT
                        $display("PEAK GAP: %d (%d - %d)", gap, addr2, addr1);
                        $display("PHASE OFFSET: %d", phase_offset);
                    `endif
                    if (gap > 62 && gap < 66) begin
                        long_preamble_detected <= 1;
                        num_sample <= 0;
                        mult_strobe <= 0;
                        sum_stb <= 0;
                        // offset it by the length of cross correlation buffer
                        // size
                        in_raddr <= addr1 - 16;
                        num_input_consumed <= addr1 - 16;
                        in_offset <= 0;
                        num_ofdm_symbol <= 0;
                        phase_correction <= 0;
                        next_phase_correction <= phase_offset;
                        state <= S_FFT;
                    end else begin
                        state <= S_IDLE;
                    end
                end else if (metric_stb) begin
                    num_sample <= num_sample + 1;
                end
            end

            S_FFT: begin
                if (long_preamble_detected) begin
                    `ifdef DEBUG_PRINT
                        $display("Long preamble detected");
                    `endif
                    long_preamble_detected <= 0;
                end

                if (~fft_loading && num_input_avail > 64) begin
                    fft_start <= 1;
                    in_offset <= 0;
                end

                if (fft_start) begin
                    fft_start <= 0;
                    fft_loading <= 1;
                end

                raw_stb <= fft_start | fft_loading;
                if (raw_stb) begin
                    if (phase_offset > 0) begin
                        if (next_phase_correction > PI) begin
                            phase_correction <= next_phase_correction - DOUBLE_PI;
                            next_phase_correction <= next_phase_correction + phase_offset - DOUBLE_PI;
                        end else begin
                            phase_correction <= next_phase_correction;
                            next_phase_correction <= next_phase_correction + phase_offset;
                        end
                    end else begin
                        if (next_phase_correction < -PI) begin
                            phase_correction <= next_phase_correction + DOUBLE_PI;
                            phase_correction <= next_phase_correction + DOUBLE_PI + phase_offset;
                        end else begin
                            phase_correction <= next_phase_correction;
                            phase_correction <= next_phase_correction + phase_offset;
                        end
                    end
                end

                if (fft_start | fft_loading) begin
                    in_offset <= in_offset + 1;

                    if (in_offset == 63) begin
                        fft_loading <= 0;
                        num_ofdm_symbol <= num_ofdm_symbol + 1;
                        if (num_ofdm_symbol > 0) begin
                            // skip the Guard Interval for data symbols
                            in_raddr <= in_raddr + gi_skip;
                            num_input_consumed <= num_input_consumed + gi_skip;
                        end else begin
                            in_raddr <= in_raddr + 1;
                            num_input_consumed <= num_input_consumed + 1;
                        end
                    end else begin
                        in_raddr <= in_raddr + 1;
                        num_input_consumed <= num_input_consumed + 1;
                    end
                end

                sample_out_strobe <= fft_valid;
                sample_out <= fft_out;
            end

            S_IDLE: begin
            end

            default: begin
                state <= S_WAIT_FOR_FIRST_PEAK;
            end
        endcase
    end else begin
        sample_out_strobe <= 0;
    end
end

integer do_mult_i;
task do_mult; begin
    // cross correlation of the first 16 samples of LTS
    if (sample_in_strobe) begin
        cross_corr_buf[15] <= sample_in;
        for (do_mult_i = 0; do_mult_i < 15; do_mult_i = do_mult_i+1) begin
            cross_corr_buf[do_mult_i] <= cross_corr_buf[do_mult_i+1];
        end

        sum_stage <= 0;
        sum_i <= 0;
        sum_q <= 0;
        sum_stb <= 0;

        stage_X0 <= cross_corr_buf[1];
        stage_X1 <= cross_corr_buf[2];
        stage_X2 <= cross_corr_buf[3];
        stage_X3 <= cross_corr_buf[4];

        stage_Y0[31:16] <= 156;
        stage_Y0[15:0] <= 0;
        stage_Y1[31:16] <= -5;
        stage_Y1[15:0] <= 120;
        stage_Y2[31:16] <= 40;
        stage_Y2[15:0] <= 111;
        stage_Y3[31:16] <= 97;
        stage_Y3[15:0] <= -83;

        mult_strobe <= 1;
        mult_stage <= 1;
    end

    if (mult_stage == 1) begin
        stage_X0 <= cross_corr_buf[4];
        stage_X1 <= cross_corr_buf[5];
        stage_X2 <= cross_corr_buf[6];
        stage_X3 <= cross_corr_buf[7];

        stage_Y0[31:16] <= 21;
        stage_Y0[15:0] <= -28;
        stage_Y1[31:16] <= 60;
        stage_Y1[15:0] <= 88;
        stage_Y2[31:16] <= -115;
        stage_Y2[15:0] <= 55;
        stage_Y3[31:16] <= -38;
        stage_Y3[15:0] <= 106;

        mult_stage <= 2;
    end else if (mult_stage == 2) begin
        stage_X0 <= cross_corr_buf[8];
        stage_X1 <= cross_corr_buf[9];
        stage_X2 <= cross_corr_buf[10];
        stage_X3 <= cross_corr_buf[11];

        stage_Y0[31:16] <= 98;
        stage_Y0[15:0] <= 26;
        stage_Y1[31:16] <= 53;
        stage_Y1[15:0] <= -4;
        stage_Y2[31:16] <= 1;
        stage_Y2[15:0] <= 115;
        stage_Y3[31:16] <= -137;
        stage_Y3[15:0] <= 47;

        mult_stage <= 3;
    end else if (mult_stage == 3) begin
        stage_X0 <= cross_corr_buf[12];
        stage_X1 <= cross_corr_buf[13];
        stage_X2 <= cross_corr_buf[14];
        stage_X3 <= cross_corr_buf[15];

        stage_Y0[31:16] <= 24;
        stage_Y0[15:0] <= 59;
        stage_Y1[31:16] <= 59;
        stage_Y1[15:0] <= 15;
        stage_Y2[31:16] <= -22;
        stage_Y2[15:0] <= -161;
        stage_Y3[31:16] <= 119;
        stage_Y3[15:0] <= 4;

        mult_stage <= 4;
    end else if (mult_stage == 4) begin
        mult_stage <= 0;
        mult_strobe <= 0;
        in_raddr <= in_raddr + 1;
        num_input_consumed <= num_input_consumed + 1;
    end

    if (stage_sum_stb) begin
        sum_stage <= sum_stage + 1;
        sum_i <= sum_i + stage_sum_i;
        sum_q <= sum_q + stage_sum_q;
        if (sum_stage == 3) begin
            sum_stb <= 1;
        end
    end else begin
        sum_stb <= 0;
        sum_i <= 0;
        sum_q <= 0;
    end
end
endtask

task do_clear; begin
    gap <= 0;

    in_waddr <= 0;
    in_raddr <= 0;
    in_offset <= 0;
    num_input_produced <= 0;
    num_input_consumed <= 0;
    num_input_avail <= 0;

    phase_correction <= 0;
    next_phase_correction <= 0;

    raw_stb <= 0;

    sum_i <= 0;
    sum_q <= 0;
    sum_stb <= 0;
    sum_stage <= 0;
    mult_strobe <= 0;

    metric_max1 <= 0;
    addr1 <= 0;
    metric_max2 <= 0;
    addr2 <= 0;

    mult_stage <= 0;

    long_preamble_detected <= 0;
    num_sample <= 0;
    num_ofdm_symbol <= 0;

    fft_start <= 0;
    fft_loading <= 0;

    sample_out_strobe <= 0;
    sample_out <= 0;

    stage_X0 <= 0;
    stage_X1 <= 0;
    stage_X2 <= 0;
    stage_X3 <= 0;

    stage_Y0 <= 0;
    stage_Y1 <= 0;
    stage_Y2 <= 0;
    stage_Y3 <= 0;
end
endtask

endmodule

运行后在sim_ou/lw目录生成了我们想要的文件:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值