diff --git a/hdl/Decimator_Correlator_PeakDetector_FFT.sv b/hdl/Decimator_Correlator_PeakDetector_FFT.sv index d63b7611a..0f9e728a2 100644 --- a/hdl/Decimator_Correlator_PeakDetector_FFT.sv +++ b/hdl/Decimator_Correlator_PeakDetector_FFT.sv @@ -16,6 +16,7 @@ module Decimator_Correlator_PeakDetector_FFT parameter USE_TAP_FILE = 1, parameter TAP_FILE = "", parameter MULT_REUSE = 0, + parameter MULT_REUSE_FFT = 1, parameter INITIAL_DETECTION_SHIFT = 4, localparam FFT_OUT_DW = 32, @@ -58,6 +59,7 @@ PSS_detector #( .ALGO(ALGO), .USE_TAP_FILE(USE_TAP_FILE), .MULT_REUSE(MULT_REUSE), + .MULT_REUSE_FFT(MULT_REUSE_FFT), .INITIAL_DETECTION_SHIFT(INITIAL_DETECTION_SHIFT), .CIC_RATE(CIC_RATE) ) diff --git a/hdl/Decimator_to_SSS_detector.sv b/hdl/Decimator_to_SSS_detector.sv index 58f017542..65119c020 100644 --- a/hdl/Decimator_to_SSS_detector.sv +++ b/hdl/Decimator_to_SSS_detector.sv @@ -18,6 +18,7 @@ module Decimator_to_SSS_detector parameter TAP_FILE_2 = "", parameter NFFT = 8, parameter MULT_REUSE = 0, + parameter MULT_REUSE_FFT = 1, parameter INITIAL_DETECTION_SHIFT = 4, localparam FFT_LEN = 2 ** NFFT, @@ -67,6 +68,7 @@ PSS_detector #( .ALGO(ALGO), .USE_TAP_FILE(USE_TAP_FILE), .MULT_REUSE(MULT_REUSE), + .MULT_REUSE_FFT(MULT_REUSE_FFT), .INITIAL_DETECTION_SHIFT(INITIAL_DETECTION_SHIFT), .CIC_RATE(CIC_RATE) ) diff --git a/hdl/PSS_detector.sv b/hdl/PSS_detector.sv index 0cc5d59ce..039bf208a 100644 --- a/hdl/PSS_detector.sv +++ b/hdl/PSS_detector.sv @@ -20,6 +20,7 @@ module PSS_detector parameter CFO_DW = 24, parameter DDS_DW = 20, parameter MULT_REUSE = 1, + parameter MULT_REUSE_FFT = 1, parameter PEAK_COUNTER = 1, parameter VARIABLE_NOISE_LIMIT = 0, parameter VARIABLE_DETECTION_FACTOR = 0, @@ -533,7 +534,7 @@ reg [1 : 0] state; wire peak_fifo_valid_out; wire data_fifo_ready = peak_fifo_valid_out && ((state == 2) || (state == 0)); wire data_fifo_rd_hs = data_fifo_ready && data_fifo_valid_out; -localparam WAIT_CNT_LEN = $clog2(MULT_REUSE >> 1) > 0 ? $clog2(MULT_REUSE >> 1) : 1; +localparam WAIT_CNT_LEN = $clog2(MULT_REUSE_FFT >> 1) > 0 ? $clog2(MULT_REUSE_FFT >> 1) : 1; reg [WAIT_CNT_LEN : 0] wait_cnt; localparam WAIT_CYCLE_MAX = CIC_RATE > 2 ? CIC_RATE - 2 : 0; reg [$clog2(WAIT_CYCLE_MAX) + 1 : 0] wait_cycle_cnt; @@ -546,9 +547,9 @@ always @(posedge clk_i) begin case (state) 0 : begin if (data_fifo_rd_hs) begin - if (MULT_REUSE <= 2) state <= CIC_RATE > 1 ? 2 : 0; + if (MULT_REUSE_FFT <= 2) state <= CIC_RATE > 1 ? 2 : 0; else begin - wait_cnt <= (MULT_REUSE >> 1) - 2; + wait_cnt <= (MULT_REUSE_FFT >> 1) - 2; state <= 1; end end @@ -562,17 +563,17 @@ always @(posedge clk_i) begin end 2 : begin if (data_fifo_rd_hs) begin - if (MULT_REUSE <= 2) begin + if (MULT_REUSE_FFT <= 2) begin if (wait_cycle_cnt == 0) begin wait_cycle_cnt <= WAIT_CYCLE_MAX; state <= 0; end else begin - wait_cnt <= (MULT_REUSE >> 1) - 2; + wait_cnt <= (MULT_REUSE_FFT >> 1) - 2; wait_cycle_cnt <= wait_cycle_cnt - 1; state <= 2; end end else begin - wait_cnt <= (MULT_REUSE >> 1) - 2; + wait_cnt <= (MULT_REUSE_FFT >> 1) - 2; state <= 3; end end @@ -631,9 +632,8 @@ assign N_id_2_valid_o = peak_fifo_valid_out && peak_fifo_ready && peak_fifo_out[ wire data_fifo_valid_out; wire [31 : 0] data_fifo_level; -// 512 as factor was not large enough for MULT_REUSE = 32 and NFFT = 9 // TODO: make length calculation more systematic -localparam DATA_FIFO_LEN = 4 * 512 * (CIC_RATE > 1 ? CIC_RATE / 2 : 1); +localparam DATA_FIFO_LEN = 512 * (CIC_RATE > 1 ? CIC_RATE / 2 : 1); AXIS_FIFO #( .DATA_WIDTH(IN_DW), diff --git a/hdl/receiver.sv b/hdl/receiver.sv index eadd303f1..5d4948262 100644 --- a/hdl/receiver.sv +++ b/hdl/receiver.sv @@ -21,6 +21,7 @@ module receiver parameter NFFT = 8, parameter XSERIES = "OLD", // use "OLD" for Zynq7, "NEW" for MPSoC parameter MULT_REUSE = 0, + parameter MULT_REUSE_FFT = 1, parameter CLK_FREQ = 3840000, parameter SEPARATE_IQ_IN = 0, parameter VARIABLE_DETECTION_FACTOR = 1, @@ -429,6 +430,7 @@ PSS_detector #( .TAP_FILE_2(TAP_FILE_2), .TAP_FILE_PATH(TAP_FILE_PATH), .MULT_REUSE(MULT_REUSE), + .MULT_REUSE_FFT(MULT_REUSE_FFT), .VARIABLE_DETECTION_FACTOR(VARIABLE_DETECTION_FACTOR), .VARIABLE_NOISE_LIMIT(VARIABLE_NOISE_LIMIT), .INITIAL_DETECTION_SHIFT(INITIAL_DETECTION_SHIFT), diff --git a/tests/test_Decimator_Correlator_PeakDetector_FFT.py b/tests/test_Decimator_Correlator_PeakDetector_FFT.py index fc6ca4648..672822e79 100644 --- a/tests/test_Decimator_Correlator_PeakDetector_FFT.py +++ b/tests/test_Decimator_Correlator_PeakDetector_FFT.py @@ -117,7 +117,10 @@ async def simple_test(dut): SSS_START = FFT_LEN // 2 - (SSS_LEN + 1) // 2 PBCH_LEN = 240 PBCH_START = FFT_LEN // 2 - (PBCH_LEN + 1) // 2 - SAMPLE_CLK_DECIMATION = tb.MULT_REUSE // 2 if tb.MULT_REUSE > 2 else 1 + FREE_CYCLES = int(fs // 1920000) + print(f'FREE_CYCLES = {FREE_CYCLES}') + SAMPLE_CLK_DECIMATION = 1 if FREE_CYCLES >= tb.MULT_REUSE else tb.MULT_REUSE // FREE_CYCLES + print(f'additional idle cycles per sample: {SAMPLE_CLK_DECIMATION - 1}') clk_div = 0 MAX_CLK_CNT = 10000 * FFT_LEN // 256 * SAMPLE_CLK_DECIMATION peaks = [] @@ -338,6 +341,7 @@ def test(IN_DW, OUT_DW, TAP_DW, ALGO, WINDOW_LEN, HALF_CP_ADVANCE, NFFT, USE_TAP parameters['MULT_REUSE'] = MULT_REUSE parameters['INITIAL_DETECTION_SHIFT'] = INITIAL_DETECTION_SHIFT parameters_no_taps = parameters.copy() + parameters['MULT_REUSE_FFT'] = MULT_REUSE // 2 if MULT_REUSE > 2 else 1 folder = 'Decimator_to_FFT_' + '_'.join(('{}={}'.format(*i) for i in parameters_no_taps.items())) + '_' + FILE sim_build= os.path.join('sim_build', folder) os.environ['TEST_FILE'] = FILE @@ -393,4 +397,4 @@ def test_recording(FILE): os.environ['PLOTS'] = "1" # os.environ['SIM'] = 'verilator' # test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, ALGO = 0, WINDOW_LEN = 8, HALF_CP_ADVANCE = 1, NFFT = 8, USE_TAP_FILE = 1, MULT_REUSE = 0, INITIAL_DETECTION_SHIFT = 3, FILE = '772850KHz_3840KSPS_low_gain') - test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, ALGO = 1, WINDOW_LEN = 8, HALF_CP_ADVANCE = 1, NFFT = 8, USE_TAP_FILE = 1, MULT_REUSE = 4, INITIAL_DETECTION_SHIFT = 4) + test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, ALGO = 1, WINDOW_LEN = 8, HALF_CP_ADVANCE = 1, NFFT = 8, USE_TAP_FILE = 1, MULT_REUSE = 8, INITIAL_DETECTION_SHIFT = 4) diff --git a/tests/test_receiver.py b/tests/test_receiver.py index 4a6a14b96..12c696ffc 100644 --- a/tests/test_receiver.py +++ b/tests/test_receiver.py @@ -89,7 +89,10 @@ async def simple_test(dut): fs_dec = fs RND_JITTER = int(os.getenv('RND_JITTER')) - SAMPLE_CLK_DECIMATION = tb.MULT_REUSE // 2 if tb.MULT_REUSE > 2 else 1 + FREE_CYCLES = int(fs // 1920000) + print(f'FREE_CYCLES = {FREE_CYCLES}') + SAMPLE_CLK_DECIMATION = 1 if FREE_CYCLES >= tb.MULT_REUSE else tb.MULT_REUSE // FREE_CYCLES + print(f'additional idle cycles per sample: {SAMPLE_CLK_DECIMATION - 1}') MAX_AMPLITUDE = (2 ** (tb.IN_DW // 2 - 1) - 1) if os.environ['TEST_FILE'] == '30720KSPS_dl_signal': expect_exact_timing = False @@ -284,7 +287,7 @@ async def simple_test(dut): print(f'received {len(corrected_PBCH)} PBCH IQ samples') print(f'received {len(received_PBCH_LLR)} PBCH LLRs samples') - assert len(received_SSS) == N_SSBs * SSS_LEN + assert len(received_SSS) == N_SSBs * SSS_LEN, print(f'expected {N_SSBs * SSS_LEN} SSS carrier but received {len(received_SSS)}') assert len(corrected_PBCH) == 432 * (N_SSBs - 1), print('received PBCH does not have correct length!') assert len(received_PBCH_LLR) == 432 * 2 * (N_SSBs - 1), print('received PBCH LLRs do not have correct length!') assert not np.array_equal(np.array(received_PBCH_LLR), np.zeros(len(received_PBCH_LLR))) @@ -542,10 +545,11 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE, ] PSS_LEN = 128 - SAMPLE_RATE = 3840000 * 2 ** (NFFT) // 256 - CLK_FREQ = str(int(SAMPLE_RATE * (MULT_REUSE // 2 + 0.5 * RND_JITTER))) if MULT_REUSE > 2 else str(SAMPLE_RATE) - print(f'system clock frequency = {CLK_FREQ}') - print(f'sample clock frequency = {SAMPLE_RATE}') + SAMPLE_RATE = 3840000 * (2 ** NFFT) // 256 + MULT_REUSE_FFT = MULT_REUSE // 2 if MULT_REUSE > 2 else 1 + CLK_FREQ = str(int(SAMPLE_RATE * MULT_REUSE_FFT)) + print(f'system clock frequency = {CLK_FREQ} Hz') + print(f'sample clock frequency = {SAMPLE_RATE} Hz') parameters = {} parameters['IN_DW'] = IN_DW parameters['OUT_DW'] = OUT_DW @@ -560,6 +564,7 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE, parameters['CLK_FREQ'] = CLK_FREQ parameters['INITIAL_DETECTION_SHIFT'] = INITIAL_DETECTION_SHIFT parameters['INITIAL_CFO_MODE'] = INITIAL_CFO_MODE + parameters['MULT_REUSE_FFT'] = MULT_REUSE_FFT os.environ['CFO'] = str(CFO) os.environ['RND_JITTER'] = str(RND_JITTER) parameters_dirname = parameters.copy() @@ -608,7 +613,7 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE, extra_env=extra_env, testcase='simple_test', force_compile=True, - waves=True, + waves = os.environ['WAVES'] == '1', defines = ['LUT_PATH=\"../../tests\"'], # used by DDS core compile_args = compile_args ) @@ -616,7 +621,7 @@ def test(IN_DW, OUT_DW, TAP_DW, WINDOW_LEN, CFO, HALF_CP_ADVANCE, USE_TAP_FILE, @pytest.mark.parametrize('FILE', ['772850KHz_3840KSPS_low_gain']) @pytest.mark.parametrize('HALF_CP_ADVANCE', [0, 1]) @pytest.mark.parametrize('MULT_REUSE', [4]) -@pytest.mark.parametrize('RND_JITTER', [1]) +@pytest.mark.parametrize('RND_JITTER', [0]) # disable RND_JITTER for now def test_NFFT8_3840KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER): 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) @@ -624,7 +629,7 @@ def test_NFFT8_3840KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER) @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', [1]) +@pytest.mark.parametrize('RND_JITTER', [0]) def test_NFFT9_7680KSPS_ideal(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER): 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) @@ -632,17 +637,18 @@ def test_NFFT9_7680KSPS_ideal(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER): @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', [1]) +@pytest.mark.parametrize('RND_JITTER', [0]) def test_NFFT9_7680KSPS_recording(FILE, HALF_CP_ADVANCE, MULT_REUSE, RND_JITTER): 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) if __name__ == '__main__': - os.environ['PLOTS'] = '1' os.environ['SIM'] = 'verilator' - if True: + os.environ['PLOTS'] = '1' + os.environ['WAVES'] = '1' + if False: test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, WINDOW_LEN = 8, CFO = 0, HALF_CP_ADVANCE = 1, USE_TAP_FILE = 1, LLR_DW = 8, - NFFT = 9, MULT_REUSE = 0, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = 0, FILE = '763450KHz_7680KSPS_low_gain') + NFFT = 9, MULT_REUSE = 4, INITIAL_DETECTION_SHIFT = 3, INITIAL_CFO_MODE = 1, RND_JITTER = 0, FILE = '763450KHz_7680KSPS_low_gain') else: test(IN_DW = 32, OUT_DW = 32, TAP_DW = 32, WINDOW_LEN = 8, CFO = 0, HALF_CP_ADVANCE = 0, USE_TAP_FILE = 1, LLR_DW = 8, - NFFT = 9, MULT_REUSE = 0, INITIAL_DETECTION_SHIFT = 4, INITIAL_CFO_MODE = 1, RND_JITTER = 0) + NFFT = 9, MULT_REUSE = 1, INITIAL_DETECTION_SHIFT = 4, INITIAL_CFO_MODE = 1, RND_JITTER = 0)