Skip to content

Commit

Permalink
works on FPGA for NFFT=9
Browse files Browse the repository at this point in the history
  • Loading branch information
catkira committed May 26, 2023
1 parent d3c765f commit f0659e7
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 24 deletions.
2 changes: 2 additions & 0 deletions hdl/Decimator_Correlator_PeakDetector_FFT.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
)
Expand Down
2 changes: 2 additions & 0 deletions hdl/Decimator_to_SSS_detector.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
)
Expand Down
16 changes: 8 additions & 8 deletions hdl/PSS_detector.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions hdl/receiver.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
8 changes: 6 additions & 2 deletions tests/test_Decimator_Correlator_PeakDetector_FFT.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
34 changes: 20 additions & 14 deletions tests/test_receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -608,41 +613,42 @@ 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
)

@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)

@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)

@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)

0 comments on commit f0659e7

Please sign in to comment.