LVPE correction before estimation

- Add state in equalizer and rename others
- Add new dumper files in testbench to check with MATLAB
This commit is contained in:
thavinga 2023-01-09 15:45:05 +01:00
parent b0df85040f
commit 95e93cadfd
2 changed files with 161 additions and 56 deletions

View File

@ -88,6 +88,10 @@ integer phase_offset_pilot_sum_fd;
integer phase_offset_phase_out_fd;
integer cpe_fd;
integer lvpe_fd;
integer sxy_fd;
integer prev_peg_fd;
integer peg_sym_scale_fd;
integer peg_pilot_scale_fd;
integer rot_in_fd;
integer rot_out_fd;
integer equalizer_prod_fd;
@ -163,6 +167,10 @@ always @(posedge clock) begin
phase_offset_phase_out_fd = $fopen("./phase_offset_phase_out.txt", "w");
cpe_fd = $fopen("./cpe.txt", "w");
lvpe_fd = $fopen("./lvpe.txt", "w");
sxy_fd = $fopen("./sxy.txt", "w");
prev_peg_fd = $fopen("./prev_peg.txt", "w");
peg_sym_scale_fd = $fopen("./peg_sym_scale.txt", "w");
peg_pilot_scale_fd = $fopen("./peg_pilot_scale.txt", "w");
rot_in_fd = $fopen("./rot_in.txt", "w");
rot_out_fd = $fopen("./rot_out.txt", "w");
equalizer_prod_fd = $fopen("./equalizer_prod.txt", "w");
@ -285,6 +293,10 @@ always @(posedge clock) begin
$fclose(phase_offset_phase_out_fd);
$fclose(cpe_fd);
$fclose(lvpe_fd);
$fclose(sxy_fd);
$fclose(prev_peg_fd);
$fclose(peg_sym_scale_fd);
$fclose(peg_pilot_scale_fd);
$fclose(rot_in_fd);
$fclose(rot_out_fd);
$fclose(equalizer_prod_fd);
@ -430,25 +442,25 @@ always @(posedge clock) begin
$fflush(sync_long_out_fd);
end
// equalizer
if ((dot11_inst.equalizer_inst.num_ofdm_sym == 1 || (dot11_inst.equalizer_inst.pkt_ht==1 && dot11_inst.equalizer_inst.num_ofdm_sym==5)) && dot11_inst.equalizer_inst.state == dot11_inst.equalizer_inst.S_CALC_FREQ_OFFSET && dot11_inst.equalizer_inst.sample_in_strobe_dly == 1 && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset) begin
if ((dot11_inst.equalizer_inst.num_ofdm_sym == 1 || (dot11_inst.equalizer_inst.pkt_ht==1 && dot11_inst.equalizer_inst.num_ofdm_sym==5)) && dot11_inst.equalizer_inst.state == dot11_inst.equalizer_inst.S_CPE_ESTIMATE && dot11_inst.equalizer_inst.sample_in_strobe_dly == 1 && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset) begin
$fwrite(new_lts_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.lts_i_out, dot11_inst.equalizer_inst.lts_q_out);
$fflush(new_lts_fd);
end
if (dot11_inst.equalizer_inst.pilot_in_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.pilot_in_stb && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_CPE_ESTIMATE && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(phase_offset_pilot_input_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.input_i, dot11_inst.equalizer_inst.input_q);
$fflush(phase_offset_pilot_input_fd);
$fwrite(phase_offset_lts_input_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.lts_i_out, dot11_inst.equalizer_inst.lts_q_out);
$fflush(phase_offset_lts_input_fd);
end
if (dot11_inst.equalizer_inst.pilot_out_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.pilot_out_stb && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_CPE_ESTIMATE && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(phase_offset_pilot_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.pilot_i, dot11_inst.equalizer_inst.pilot_q);
$fflush(phase_offset_pilot_fd);
end
if (dot11_inst.equalizer_inst.phase_in_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.phase_in_stb && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_PILOT_PE_CORRECTION && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(phase_offset_pilot_sum_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.pilot_sum_i, dot11_inst.equalizer_inst.pilot_sum_q);
$fflush(phase_offset_pilot_sum_fd);
end
if (dot11_inst.equalizer_inst.phase_out_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.phase_out_stb && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_PILOT_PE_CORRECTION && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(phase_offset_phase_out_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.phase_out));
$fflush(phase_offset_phase_out_fd);
end
@ -460,13 +472,29 @@ always @(posedge clock) begin
$fwrite(lvpe_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.lvpe));
$fflush(lvpe_fd);
end
if (dot11_inst.equalizer_inst.rot_in_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.lvpe_out_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(sxy_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.Sxy));
$fflush(sxy_fd);
end
if (dot11_inst.equalizer_inst.num_output == dot11_inst.equalizer_inst.num_data_carrier && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_ALL_SC_PE_CORRECTION && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(prev_peg_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.prev_peg_reg));
$fflush(prev_peg_fd);
end
if (dot11_inst.equalizer_inst.lvpe_out_stb && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(peg_sym_scale_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.peg_sym_scale));
$fflush(peg_sym_scale_fd);
end
if (dot11_inst.equalizer_inst.pilot_count1 < 4 && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_PILOT_PE_CORRECTION && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(peg_pilot_scale_fd, "%d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.peg_pilot_scale));
$fflush(peg_pilot_scale_fd);
end
if (dot11_inst.equalizer_inst.rot_in_stb && dot11_inst.equalizer_inst.enable && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_ALL_SC_PE_CORRECTION && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
$fwrite(rot_in_fd, "%d %d %d %d\n", iq_count, $signed(dot11_inst.equalizer_inst.buf_i_out), $signed(dot11_inst.equalizer_inst.buf_q_out), $signed(dot11_inst.equalizer_inst.sym_phase));
$fflush(rot_in_fd);
end
if (dot11_inst.equalizer_inst.rot_out_stb && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_ADJUST_FREQ_and_SAMPL_OFFSET && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
if (dot11_inst.equalizer_inst.rot_out_stb && dot11_inst.equalizer_inst.state==dot11_inst.equalizer_inst.S_ALL_SC_PE_CORRECTION && dot11_inst.equalizer_inst.enable && ~dot11_inst.equalizer_inst.reset && dot11_inst.demod_is_ongoing) begin
// when enable is 0, it locked equalizer all internal variables till the next reset/enable, some large delayed signal, such as rot out, logged with some garbage
// limite the log to dot11_inst.equalizer_inst.S_ADJUST_FREQ_and_SAMPL_OFFSET state
// limite the log to dot11_inst.equalizer_inst.S_ALL_SC_PE_CORRECTION state
$fwrite(rot_out_fd, "%d %d %d\n", iq_count, dot11_inst.equalizer_inst.rot_i, dot11_inst.equalizer_inst.rot_q);
$fflush(rot_out_fd);
end

View File

@ -82,11 +82,31 @@ reg [63:0] ht_lts_ref;
reg [63:0] subcarrier_mask;
reg [63:0] data_subcarrier_mask;
reg [63:0] pilot_mask;
reg [5:0] pilot_loc[3:0];
reg signed [5:0] pilot_idx[3:0];
localparam pilot_loc1 = 7;
localparam pilot_loc2 = 21;
localparam pilot_loc3 = 43;
localparam pilot_loc4 = 57;
localparam signed pilot_idx1 = 8;
localparam signed pilot_idx2 = 22;
localparam signed pilot_idx3 = -20;
localparam signed pilot_idx4 = -6;
initial begin
pilot_loc[0] = pilot_loc1;
pilot_idx[0] = pilot_idx1;
pilot_loc[1] = pilot_loc2;
pilot_idx[1] = pilot_idx2;
pilot_loc[2] = pilot_loc3;
pilot_idx[2] = pilot_idx3;
pilot_loc[3] = pilot_loc4;
pilot_idx[3] = pilot_idx4;
end
reg [126:0] polarity;
reg [3:0] ht_polarity;
reg [3:0] current_polarity;
reg [3:0] pilot_count1, pilot_count2;
reg [3:0] pilot_count1, pilot_count2, pilot_count3;
reg signed [15:0] input_i;
reg signed [15:0] input_q;
@ -125,8 +145,6 @@ reg signed [31:0] pilot_sum_q;
assign phase_in_i = pilot_i_reg;
assign phase_in_q = pilot_q_reg;
reg sum_phase;
//reg signed [15:0] pilot_phase_err;
reg signed [16:0] pilot_phase_err; // 15 --> 16 = 15 + 1, extended from cpe
reg signed [15:0] cpe; // common phase error due to RFO
@ -135,14 +153,15 @@ reg signed [23:0] Sxy; // 15-->23. to avoid overflow: pilot_phase_err 16 + 5 + 2
localparam Sx2 = 980;
// linear varying phase error (LVPE) parameters
reg signed [7:0] sym_idx;
reg signed [7:0] sym_idx, sym_idx2;
reg lvpe_in_stb;
wire lvpe_out_stb;
wire signed [31:0] lvpe_dividend, lvpe;
wire signed [31:0] lvpe_dividend, lvpe, peg_sym_scale;
wire signed [23:0] lvpe_divisor;
assign lvpe_dividend = (sym_idx <= 33 ? sym_idx*Sxy : (sym_idx-64)*Sxy);
assign lvpe_divisor = Sx2;
reg signed [31:0] prev_peg, prev_peg_reg, peg_pilot_scale;
assign peg_sym_scale = (sym_idx2 <= 33 ? sym_idx2*prev_peg : (sym_idx2-64)*prev_peg);
//reg signed [15:0] phase_err;
reg signed [17:0] phase_err; // 15-->16: phase_err <= cpe + lvpe[17:0]; 16 + 1 = 17 for sym_phase
@ -181,11 +200,11 @@ reg signed [18:0] lts_sum_q;
reg [2:0] lts_mv_avg_len;
reg lts_div_in_stb;
wire [31:0] dividend_i = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? (lts_sum_i[18] == 0 ? {13'h0,lts_sum_i} : {13'h1FFF,lts_sum_i}) : (state == S_ADJUST_FREQ_and_SAMPL_OFFSET ? prod_i_scaled : 0);
wire [31:0] dividend_q = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? (lts_sum_q[18] == 0 ? {13'h0,lts_sum_q} : {13'h1FFF,lts_sum_q}) : (state == S_ADJUST_FREQ_and_SAMPL_OFFSET ? prod_q_scaled : 0);
wire [23:0] divisor_i = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? {21'b0,lts_mv_avg_len} : (state == S_ADJUST_FREQ_and_SAMPL_OFFSET ? mag_sq[23:0] : 1);
wire [23:0] divisor_q = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? {21'b0,lts_mv_avg_len} : (state == S_ADJUST_FREQ_and_SAMPL_OFFSET ? mag_sq[23:0] : 1);
wire div_in_stb = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? lts_div_in_stb : (state == S_ADJUST_FREQ_and_SAMPL_OFFSET ? prod_out_strobe : 0);
wire [31:0] dividend_i = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? (lts_sum_i[18] == 0 ? {13'h0,lts_sum_i} : {13'h1FFF,lts_sum_i}) : (state == S_ALL_SC_PE_CORRECTION ? prod_i_scaled : 0);
wire [31:0] dividend_q = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? (lts_sum_q[18] == 0 ? {13'h0,lts_sum_q} : {13'h1FFF,lts_sum_q}) : (state == S_ALL_SC_PE_CORRECTION ? prod_q_scaled : 0);
wire [23:0] divisor_i = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? {21'b0,lts_mv_avg_len} : (state == S_ALL_SC_PE_CORRECTION ? mag_sq[23:0] : 1);
wire [23:0] divisor_q = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? {21'b0,lts_mv_avg_len} : (state == S_ALL_SC_PE_CORRECTION ? mag_sq[23:0] : 1);
wire div_in_stb = (state == S_SMOOTH_CH_DC || state == S_SMOOTH_CH_LTS) ? lts_div_in_stb : (state == S_ALL_SC_PE_CORRECTION ? prod_out_strobe : 0);
reg [15:0] num_output;
@ -206,7 +225,7 @@ wire prod_out_strobe;
// for side channel
reg sample_in_strobe_dly;
assign csi = {lts_i_out, lts_q_out};
assign csi_valid = ( (num_ofdm_sym == 1 || (pkt_ht==1 && num_ofdm_sym==5)) && state == S_CALC_FREQ_OFFSET && sample_in_strobe_dly == 1 && enable && (~reset) );
assign csi_valid = ( (num_ofdm_sym == 1 || (pkt_ht==1 && num_ofdm_sym==5)) && state == S_CPE_ESTIMATE && sample_in_strobe_dly == 1 && enable && (~reset) );
always @(posedge clock) begin
if (reset) begin
@ -376,10 +395,11 @@ localparam S_SECOND_LTS = 1;
localparam S_SMOOTH_CH_DC = 2;
localparam S_SMOOTH_CH_LTS = 3;
localparam S_GET_POLARITY = 4;
localparam S_CALC_FREQ_OFFSET = 5;
localparam S_CALC_SAMPL_OFFSET = 6;
localparam S_ADJUST_FREQ_and_SAMPL_OFFSET = 7;
localparam S_HT_LTS = 8;
localparam S_CPE_ESTIMATE = 5;
localparam S_PILOT_PE_CORRECTION = 6;
localparam S_LVPE_ESTIMATE = 7;
localparam S_ALL_SC_PE_CORRECTION = 8;
localparam S_HT_LTS = 9;
always @(posedge clock) begin
if (reset|reset_internal) begin
@ -408,10 +428,12 @@ always @(posedge clock) begin
current_polarity <= 0;
pilot_count1 <= 0;
pilot_count2 <= 0;
pilot_count3 <= 0;
in_waddr <= 0;
in_raddr <= 0;
sym_idx <= 0;
sym_idx2 <= 0;
lts_reg1_i <= 0; lts_reg2_i <= 0; lts_reg3_i <= 0; lts_reg4_i <= 0; lts_reg5_i <= 0;
lts_reg1_q <= 0; lts_reg2_q <= 0; lts_reg3_q <= 0; lts_reg4_q <= 0; lts_reg5_q <= 0;
@ -432,7 +454,9 @@ always @(posedge clock) begin
pilot_i_reg <= 0;
pilot_q_reg <= 0;
pilot_iq_phase[0] <= 0; pilot_iq_phase[1] <= 0; pilot_iq_phase[2] <= 0; pilot_iq_phase[3] <= 0;
sum_phase <= 0;
prev_peg <= 0;
prev_peg_reg <= 0;
peg_pilot_scale <= 0;
prod_in_strobe <= 0;
@ -606,10 +630,10 @@ always @(posedge clock) begin
input_q <= 0;
lts_raddr <= 0;
num_ofdm_sym <= num_ofdm_sym + 1;
state <= S_CALC_FREQ_OFFSET;
state <= S_CPE_ESTIMATE;
end
S_CALC_FREQ_OFFSET: begin
S_CPE_ESTIMATE: begin
if (~ht & ht_next) begin
ht <= 1;
num_data_carrier <= 52;
@ -631,10 +655,8 @@ always @(posedge clock) begin
pilot_mask <= {pilot_mask[0], pilot_mask[63:1]};
if (pilot_mask[0]) begin
pilot_count1 <= pilot_count1 + 1;
current_polarity <= {current_polarity[0],
current_polarity[3:1]};
// obtain the conjugate of current pilot sub carrier
if (current_polarity[0] == 0) begin
if (current_polarity[pilot_count1] == 0) begin
input_i <= sample_in[31:16];
input_q <= ~sample_in[15:0] + 1;
end else begin
@ -652,43 +674,92 @@ always @(posedge clock) begin
if (pilot_out_stb) begin
pilot_sum_i <= pilot_sum_i + pilot_i;
pilot_sum_q <= pilot_sum_q + pilot_q;
pilot_i_reg <= pilot_i;
pilot_q_reg <= pilot_q;
phase_in_stb <= 1;
end else if (pilot_count2 == 4 && sum_phase == 0) begin
pilot_count2 <= pilot_count2 + 1;
end else if (pilot_count2 == 4) begin
pilot_i_reg <= pilot_sum_i;
pilot_q_reg <= pilot_sum_q;
phase_in_stb <= 1;
sum_phase <= 1;
pilot_count2 <= 0;
end else begin
phase_in_stb <= 0;
end
if (phase_out_stb && pilot_count2 < 4) begin
pilot_count2 <= pilot_count2 + 1;
pilot_iq_phase[pilot_count2] <= phase_out;
`ifdef DEBUG_PRINT
$display("[PILOT OFFSET] %d", phase_out);
`endif
end else if (phase_out_stb && pilot_count2 == 4) begin
if (phase_out_stb) begin
cpe <= phase_out;
pilot_count1 <= 0;
pilot_count1 <= 0;
pilot_count2 <= 0;
pilot_count3 <= 0;
Sxy <= 0;
state <= S_CALC_SAMPL_OFFSET;
sum_phase <= 0;
in_raddr <= pilot_loc[0][5:0]; // sample in location, compensate for RAM read delay
lts_raddr <= pilot_loc[0][5:0]; // LTS location, compensate for RAM read delay
peg_pilot_scale <= pilot_idx[0]*prev_peg;
state <= S_PILOT_PE_CORRECTION;
end
end
S_CALC_SAMPL_OFFSET: begin
S_PILOT_PE_CORRECTION: begin
// rotate pilots with accumulated PEG up to previous symbol
if (pilot_count1 < 4) begin
if (pilot_count1 < 3) begin
in_raddr <= pilot_loc[pilot_count1+1][5:0];
peg_pilot_scale <= (pilot_idx[pilot_count1+1])*prev_peg;
rot_in_stb <= 1;
end
phase_err <= {cpe[15], cpe[15], cpe[15:0]} + peg_pilot_scale[17:0];
pilot_count1 <= pilot_count1 + 1;
end else begin
rot_in_stb <= 0;
end
if (rot_out_stb && pilot_count2 < 4) begin
if (pilot_count2 < 3) begin
lts_raddr <= pilot_loc[pilot_count2+1][5:0];
end
// obtain the conjugate of current pilot sub carrier
if (current_polarity[pilot_count2] == 0) begin
input_i <= rot_i;
input_q <= -rot_q;
end else begin
input_i <= -rot_i;
input_q <= rot_q;
end
pilot_in_stb <= 1; // start complex mult. with LTS pilot
pilot_count2 <= pilot_count2 + 1;
end else begin
pilot_in_stb <= 0;
end
if (pilot_out_stb) begin
pilot_i_reg <= pilot_i;
pilot_q_reg <= pilot_q;
phase_in_stb <= 1;
end else begin
phase_in_stb <= 0;
end
if (phase_out_stb && pilot_count3 < 4) begin
pilot_count3 <= pilot_count3 + 1;
pilot_iq_phase[pilot_count3] <= phase_out;
end
if (pilot_count3 == 4) begin
phase_in_stb <= 0;
pilot_count1 <= 0;
pilot_count2 <= 0;
pilot_count3 <= 0;
state <= S_LVPE_ESTIMATE;
end
end
S_LVPE_ESTIMATE: begin
if (pilot_count1 < 4) begin
// sampling rate offset (SFO) is calculated as pilot phase error
if(pilot_iq_phase[pilot_count1] < cpe - 1608) begin
pilot_phase_err <= pilot_iq_phase[pilot_count1] - cpe + 3217;
end else if(pilot_iq_phase[pilot_count1] > cpe + 1608) begin
pilot_phase_err <= pilot_iq_phase[pilot_count1] - cpe - 3217;
if(pilot_iq_phase[pilot_count1] < -1608) begin
pilot_phase_err <= pilot_iq_phase[pilot_count1] + 3217;
end else if(pilot_iq_phase[pilot_count1] > 1608) begin
pilot_phase_err <= pilot_iq_phase[pilot_count1] - 3217;
end else begin
pilot_phase_err <= pilot_iq_phase[pilot_count1] - cpe;
pilot_phase_err <= pilot_iq_phase[pilot_count1];
end
pilot_count1 <= pilot_count1 + 1;
@ -703,20 +774,21 @@ always @(posedge clock) begin
end else if(pilot_count1 == 4) begin
Sxy <= Sxy + -7*pilot_phase_err;
in_raddr <= 0;
in_raddr <= 0;
sym_idx <= 0;
sym_idx2 <= 1;
lvpe_in_stb <= 0;
// compensate for RAM read delay
lts_raddr <= 1;
rot_in_stb <= 0;
num_output <= 0;
state <= S_ADJUST_FREQ_and_SAMPL_OFFSET;
state <= S_ALL_SC_PE_CORRECTION;
end
// Sx² = (x-)*(x-) = x² = (7² + 21² + (-21)² + (-7)²) = 980
// phase error gradient (PEG) = Sxy/Sx²
end
S_ADJUST_FREQ_and_SAMPL_OFFSET: begin
S_ALL_SC_PE_CORRECTION: begin
if (sym_idx < 64) begin
sym_idx <= sym_idx + 1;
lvpe_in_stb <= 1;
@ -726,10 +798,14 @@ always @(posedge clock) begin
// first rotate, then normalize by avg LTS
if (lvpe_out_stb) begin
// phase_err <= cpe + lvpe[15:0];
phase_err <= {cpe[15], cpe[15], cpe[15:0]} + lvpe[17:0];
sym_idx2 <= sym_idx2 + 1;
phase_err <= {cpe[15], cpe[15], cpe[15:0]} + lvpe[17:0] + peg_sym_scale[17:0];
rot_in_stb <= 1;
in_raddr <= in_raddr + 1;
if (sym_idx2 == 32) begin
// lvpe output is 32*PEG due to sym_idx
prev_peg_reg <= prev_peg_reg + (lvpe >>> 5);
end
end else begin
rot_in_stb <= 0;
end
@ -754,6 +830,7 @@ always @(posedge clock) begin
end
if (num_output == num_data_carrier) begin
prev_peg <= prev_peg_reg;
state <= S_GET_POLARITY;
end
end