Skip to content

Commit

Permalink
make cfo correction optional
Browse files Browse the repository at this point in the history
  • Loading branch information
catkira committed Jul 18, 2023
1 parent 19fda9e commit e4f35f3
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 80 deletions.
156 changes: 83 additions & 73 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
23 changes: 16 additions & 7 deletions tests/test_receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ def extract_timestamp(packet):
@pytest.mark.parametrize('INITIAL_CFO_MODE', [0])
@pytest.mark.parametrize('RND_JITTER', [0])
def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE, LLR_DW, NFFT, MULT_REUSE,
INITIAL_DETECTION_SHIFT, INITIAL_CFO_MODE, RND_JITTER, FILE = '30720KSPS_dl_signal'):
INITIAL_DETECTION_SHIFT, INITIAL_CFO_MODE, RND_JITTER, FILE = '30720KSPS_dl_signal', HAS_CFO_COR = 0):
dut = 'receiver'
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut
Expand Down Expand Up @@ -578,6 +578,9 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE,
sim_build = os.path.join('sim_build/', folder)
os.environ['TEST_FILE'] = FILE

# the following parameters don't appear in the filename
parameters['HAS_CFO_COR'] = HAS_CFO_COR

# prepare FFT_demod taps
FFT_LEN = 2 ** NFFT
CP_LEN = int(18 * FFT_LEN / 256) # TODO: only CP2 supported so far! another lut for CP1 symbols is needed or use same CP_ADVANCE for CP1.
Expand Down Expand Up @@ -626,25 +629,31 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE,
@pytest.mark.parametrize('HALF_CP_ADVANCE', [0, 1])
@pytest.mark.parametrize('MULT_REUSE', [4])
@pytest.mark.parametrize('RND_JITTER', [0]) # disable RND_JITTER for now
def test_NFFT8_3840KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER):
@pytest.mark.parametrize('HAS_CFO_COR', [0])
def test_NFFT8_3840KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER, HAS_CFO_COR):
test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, WINDOW_LEN = 8, CFO = 0, HALF_CP_ADVANCE = HALF_CP_ADVANCE, USE_TAP_FILE = 1, LLR_DW = 8,
NFFT = 8, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER, FILE = FILE)
NFFT = 8, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER,
FILE = FILE, HAS_CFO_COR = HAS_CFO_COR)

@pytest.mark.parametrize('FILE', ['30720KSPS_dl_signal'])
@pytest.mark.parametrize('HALF_CP_ADVANCE', [1])
@pytest.mark.parametrize('MULT_REUSE', [4])
@pytest.mark.parametrize('RND_JITTER', [0])
def test_NFFT9_7680KSPS_ideal(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER):
@pytest.mark.parametrize('HAS_CFO_COR', [0])
def test_NFFT9_7680KSPS_ideal(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER, HAS_CFO_COR):
test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, WINDOW_LEN = 8, CFO = 0, HALF_CP_ADVANCE = HALF_CP_ADVANCE, USE_TAP_FILE = 1, LLR_DW = 8,
NFFT = 9, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER, FILE = FILE)
NFFT = 9, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER,
FILE = FILE, HAS_CFO_COR = HAS_CFO_COR)

@pytest.mark.parametrize('FILE', ['763450KHz_7680KSPS_low_gain'])
@pytest.mark.parametrize('HALF_CP_ADVANCE', [1])
@pytest.mark.parametrize('MULT_REUSE', [4])
@pytest.mark.parametrize('RND_JITTER', [0])
def test_NFFT9_7680KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER):
@pytest.mark.parametrize('HAS_CFO_COR', [0])
def test_NFFT9_7680KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER, HAS_CFO_COR):
test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, WINDOW_LEN = 8, CFO = 0, HALF_CP_ADVANCE = HALF_CP_ADVANCE, USE_TAP_FILE = 1, LLR_DW = 8,
NFFT = 9, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER, FILE = FILE)
NFFT = 9, MULT_REUSE = MULT_REUSE, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = RND_JITTER, FILE = FILE,
HAS_CFO_COR = HAS_CFO_COR)

if __name__ == '__main__':
os.environ['SIM'] = 'verilator'
Expand Down

0 comments on commit e4f35f3

Please sign in to comment.