Skip to content

Commit

Permalink
Optional cfo cor (#30)
Browse files Browse the repository at this point in the history
make cfo correction optional
  • Loading branch information
catkira committed Jul 18, 2023
1 parent eb6b40e commit 93078bb
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 138 deletions.
124 changes: 70 additions & 54 deletions hdl/PSS_detector.sv
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module PSS_detector
parameter INITIAL_DETECTION_SHIFT = 3,
parameter INITIAL_CFO_MODE = 0,
parameter CIC_RATE = 2,
parameter HAS_CFO_CALC = 1,

localparam SAMPLE_RATE = 1920000,
localparam AXI_ADDRESS_WIDTH = 11
Expand Down Expand Up @@ -393,73 +394,85 @@ reg CFO_calc_valid_in;
reg CFO_calc_valid_out;
reg signed [CFO_DW - 1 : 0] CFO_angle;
reg signed [DDS_DW - 1 : 0] CFO_DDS_inc;
CFO_calc #(
.C_DW(C_DW),
.CFO_DW(CFO_DW),
.DDS_DW(DDS_DW)
)
CFO_calc_i(
.clk_i(clk_i),
.reset_ni(reset_int_n),
.C0_i(C0_in),
.C1_i(C1_in),
.valid_i(CFO_calc_valid_in),
if (HAS_CFO_CALC) begin
CFO_calc #(
.C_DW(C_DW),
.CFO_DW(CFO_DW),
.DDS_DW(DDS_DW)
)
CFO_calc_i(
.clk_i(clk_i),
.reset_ni(reset_int_n),
.C0_i(C0_in),
.C1_i(C1_in),
.valid_i(CFO_calc_valid_in),

.CFO_angle_o(CFO_angle),
.CFO_DDS_inc_o(CFO_DDS_inc),
.valid_o(CFO_calc_valid_out)
);
.CFO_angle_o(CFO_angle),
.CFO_DDS_inc_o(CFO_DDS_inc),
.valid_o(CFO_calc_valid_out)
);
end else begin
always_comb begin
CFO_calc_valid_out <= '0;
CFO_DDS_inc <= '0;
CFO_angle <= '0;
end
end

localparam [1 : 0] SEARCH = 0;
localparam [1 : 0] FIND = 1;
localparam [1 : 0] PAUSE = 2;
reg N_id_2_valid;

reg [1 : 0] CFO_state;
localparam [1 : 0] WAIT_FOR_PEAK = 0;
localparam [1 : 0] DISABLE_CFO_IN = 1;
localparam [1 : 0] WAIT_FOR_CFO = 2;

//-------------------------------------------------------------------------------
// FSM to control CFO_calc
// it is not sensitive to new incoming peaks while it waits for CFO_calc to finish
// this can cause a peak to be ignored if it follows close after another peak
//
// TODO: signal a valid N_id_2 only of the calculated CFO is below a certain threshold,
// i.e. +- 100 Hz, if it is above, wait for next SSB with corrected CFO
always @(posedge clk_i) begin
if (!reset_int_n) begin
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_valid_o <= '0;
end else begin
case (CFO_state)
WAIT_FOR_PEAK : begin
CFO_valid_o <= '0;
if (N_id_2_valid) begin
C0_in <= C0_f[N_id_2_o];
C1_in <= C1_f[N_id_2_o];
CFO_calc_valid_in <= 1;
CFO_state <= DISABLE_CFO_IN;
if (HAS_CFO_CALC) begin
reg [1 : 0] CFO_state;
localparam [1 : 0] WAIT_FOR_PEAK = 0;
localparam [1 : 0] DISABLE_CFO_IN = 1;
localparam [1 : 0] WAIT_FOR_CFO = 2;
always @(posedge clk_i) begin
if (!reset_int_n) begin
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_valid_o <= '0;
end else begin
case (CFO_state)
WAIT_FOR_PEAK : begin
CFO_valid_o <= '0;
if (N_id_2_valid) begin
C0_in <= C0_f[N_id_2_o];
C1_in <= C1_f[N_id_2_o];
CFO_calc_valid_in <= 1;
CFO_state <= DISABLE_CFO_IN;
end
end
end
DISABLE_CFO_IN : begin
CFO_calc_valid_in <= '0;
CFO_state <= WAIT_FOR_CFO;
end
WAIT_FOR_CFO : begin
if (CFO_calc_valid_out) begin
$display("PSS_detector: detected CFO angle is %f deg", $itor(CFO_angle) / $itor((2**(CFO_DW - 1) - 1)) * $itor(180));
$display("PSS_detector: detected CFO frequency is %f Hz", $itor(CFO_angle) * SAMPLE_RATE / 64 / (2**(CFO_DW - 1) - 1));
$display("PSS detector: detected CFO DDS_inc is %d", CFO_DDS_inc);
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= cfo_mode == CFO_MODE_AUTO ? CFO_angle : '0;
CFO_DDS_inc_o <= cfo_mode == CFO_MODE_AUTO ? CFO_DDS_inc : '0;
CFO_valid_o <= 1 && (cfo_mode == CFO_MODE_AUTO);
DISABLE_CFO_IN : begin
CFO_calc_valid_in <= '0;
CFO_state <= WAIT_FOR_CFO;
end
end
endcase
WAIT_FOR_CFO : begin
if (CFO_calc_valid_out) begin
$display("PSS_detector: detected CFO angle is %f deg", $itor(CFO_angle) / $itor((2**(CFO_DW - 1) - 1)) * $itor(180));
$display("PSS_detector: detected CFO frequency is %f Hz", $itor(CFO_angle) * SAMPLE_RATE / 64 / (2**(CFO_DW - 1) - 1));
$display("PSS detector: detected CFO DDS_inc is %d", CFO_DDS_inc);
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= cfo_mode == CFO_MODE_AUTO ? CFO_angle : '0;
CFO_DDS_inc_o <= cfo_mode == CFO_MODE_AUTO ? CFO_DDS_inc : '0;
CFO_valid_o <= 1 && (cfo_mode == CFO_MODE_AUTO);
end
end
endcase
end
end
end else begin
always_comb begin
CFO_valid_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_angle_o <= '0;
end
end

Expand All @@ -473,6 +486,9 @@ end
//
// If USE_MODE is 0, the FSM is permanently in SEARCH mode
wire [1 : 0] mode_select;
localparam [1 : 0] SEARCH = 0;
localparam [1 : 0] FIND = 1;
localparam [1 : 0] PAUSE = 2;
assign mode_select = USE_MODE ? mode_i : SEARCH;
reg [1 : 0] N_id_2;

Expand Down
159 changes: 85 additions & 74 deletions hdl/receiver.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module receiver
parameter VARIABLE_NOISE_LIMIT = 1,
parameter INITIAL_DETECTION_SHIFT = 4,
parameter INITIAL_CFO_MODE = 0,
parameter HAS_CFO_COR = 1,

localparam BLK_EXP_LEN = 8,
localparam FFT_LEN = 2 ** NFFT,
Expand Down Expand Up @@ -336,84 +337,93 @@ sample_id_cdc_i(
.m_axis_out_tempty()
);

reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc, CFO_DDS_inc_f;
reg CFO_valid;
wire [DDS_OUT_DW - 1 : 0] DDS_out;
wire DDS_out_valid;
reg [DDS_PHASE_DW - 1 : 0] DDS_phase;
reg DDS_phase_valid;

always @(posedge clk_i) begin
if (!reset_ni) begin
DDS_phase <= '0;
DDS_phase_valid <= '0;
CFO_DDS_inc_f <= '0;
end
else begin
DDS_phase_valid <= 1;
if (CFO_mode == 0) begin
if (CFO_valid) begin
// CFO_DDS_inc_f <= '0; // deactive CFO correction for debugging
CFO_DDS_inc_f <= CFO_DDS_inc_f - CFO_DDS_inc; // incoming CFO_DDS_inc are relative to last one !
end
if(FIFO_out_tvalid) begin
DDS_phase <= DDS_phase + CFO_DDS_inc_f;
end
end else begin
// manual CFO mode
CFO_DDS_inc_f <= '0;
reg CFO_valid;
reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc;
if (HAS_CFO_COR) begin
reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc_f;
wire [DDS_OUT_DW - 1 : 0] DDS_out;
wire DDS_out_valid;
reg [DDS_PHASE_DW - 1 : 0] DDS_phase;
reg DDS_phase_valid;

always @(posedge clk_i) begin
if (!reset_ni) begin
DDS_phase <= '0;
DDS_phase_valid <= '0;
CFO_DDS_inc_f <= '0;
end
else begin
DDS_phase_valid <= 1;
if (CFO_mode == 0) begin
if (CFO_valid) begin
// CFO_DDS_inc_f <= '0; // deactive CFO correction for debugging
CFO_DDS_inc_f <= CFO_DDS_inc_f - CFO_DDS_inc; // incoming CFO_DDS_inc are relative to last one !
end
if(FIFO_out_tvalid) begin
DDS_phase <= DDS_phase + CFO_DDS_inc_f;
end
end else begin
// manual CFO mode
CFO_DDS_inc_f <= '0;
DDS_phase <= '0;
end
end
end
end

dds #(
.PHASE_DW(DDS_PHASE_DW),
.OUT_DW(DDS_OUT_DW/2),
.USE_TAYLOR(1),
.LUT_DW(16),
.SIN_COS(1),
.NEGATIVE_SINE(0),
.NEGATIVE_COSINE(0),
.USE_LUT_FILE(0)
)
dds_i(
.clk(clk_i),
.reset_n(reset_ni),

.s_axis_phase_tdata(DDS_phase),
.s_axis_phase_tvalid(DDS_phase_valid),

.m_axis_out_tdata(DDS_out),
.m_axis_out_tvalid(DDS_out_valid),

.m_axis_out_sin_tdata(),
.m_axis_out_sin_tvalid(),
.m_axis_out_cos_tdata(),
.m_axis_out_cos_tvalid()
);

complex_multiplier #(
.OPERAND_WIDTH_A(DDS_OUT_DW/2),
.OPERAND_WIDTH_B(IN_DW/2),
.OPERAND_WIDTH_OUT(COMPL_MULT_OUT_DW/2),
.BLOCKING(0),
.GROWTH_BITS(-2), // input is rotating vector with length 2^(IN_DW/2 - 1), therefore bit growth is 2 bits less than worst case
// TODO: WARNING, this can create an overflow if the DDS is not perfect (outputs vector with length > 1)
.BYTE_ALIGNED(0)
)
complex_multiplier_i(
.aclk(clk_i),
.aresetn(reset_ni),

.s_axis_a_tdata(DDS_out),
.s_axis_a_tvalid(DDS_out_valid),
.s_axis_b_tdata(FIFO_out_tdata),
.s_axis_b_tvalid(FIFO_out_tvalid),

.m_axis_dout_tdata(mult_out_tdata),
.m_axis_dout_tvalid(mult_out_tvalid)
);
dds #(
.PHASE_DW(DDS_PHASE_DW),
.OUT_DW(DDS_OUT_DW/2),
.USE_TAYLOR(1),
.LUT_DW(16),
.SIN_COS(1),
.NEGATIVE_SINE(0),
.NEGATIVE_COSINE(0),
.USE_LUT_FILE(0)
)
dds_i(
.clk(clk_i),
.reset_n(reset_ni),

.s_axis_phase_tdata(DDS_phase),
.s_axis_phase_tvalid(DDS_phase_valid),

.m_axis_out_tdata(DDS_out),
.m_axis_out_tvalid(DDS_out_valid),

.m_axis_out_sin_tdata(),
.m_axis_out_sin_tvalid(),
.m_axis_out_cos_tdata(),
.m_axis_out_cos_tvalid()
);

complex_multiplier #(
.OPERAND_WIDTH_A(DDS_OUT_DW/2),
.OPERAND_WIDTH_B(IN_DW/2),
.OPERAND_WIDTH_OUT(COMPL_MULT_OUT_DW/2),
.BLOCKING(0),
.GROWTH_BITS(-2), // input is rotating vector with length 2^(IN_DW/2 - 1), therefore bit growth is 2 bits less than worst case
// TODO: WARNING, this can create an overflow if the DDS is not perfect (outputs vector with length > 1)
.BYTE_ALIGNED(0)
)
complex_multiplier_i(
.aclk(clk_i),
.aresetn(reset_ni),

.s_axis_a_tdata(DDS_out),
.s_axis_a_tvalid(DDS_out_valid),
.s_axis_b_tdata(FIFO_out_tdata),
.s_axis_b_tvalid(FIFO_out_tvalid),

.m_axis_dout_tdata(mult_out_tdata),
.m_axis_dout_tvalid(mult_out_tvalid)
);
end else begin
always_comb begin
mult_out_tdata <= FIFO_out_tdata;
mult_out_tvalid <= FIFO_out_tvalid;
end
end

assign m_axis_PSS_out_tdata = pss_out_data;
assign m_axis_PSS_out_tvalid = pss_out_valid;
Expand Down Expand Up @@ -450,7 +460,8 @@ PSS_detector #(
.VARIABLE_NOISE_LIMIT(VARIABLE_NOISE_LIMIT),
.INITIAL_DETECTION_SHIFT(INITIAL_DETECTION_SHIFT),
.INITIAL_CFO_MODE(INITIAL_CFO_MODE),
.CIC_RATE(CIC_RATE)
.CIC_RATE(CIC_RATE),
.HAS_CFO_CALC(HAS_CFO_COR)
)
PSS_detector_i(
.clk_i(clk_i),
Expand Down
Loading

0 comments on commit 93078bb

Please sign in to comment.