From aa1ff0436be7b3cdcaf01c81ac6f6881a53aa71b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 19 Oct 2023 22:29:38 +0200 Subject: [PATCH] FPGA: Add SNR threshold to spot finder --- fpga/hdl/action_config.v | 8 +- fpga/hls/hls_jfjoch.h | 2 +- fpga/hls/spot_finder.cpp | 249 +++++++++++++++++++++++++++--- receiver/HLSSimulatedDevice.h | 2 +- tests/FPGASpotFindingUnitTest.cpp | 2 +- 5 files changed, 232 insertions(+), 31 deletions(-) diff --git a/fpga/hdl/action_config.v b/fpga/hdl/action_config.v index 589401de..bd773c7f 100644 --- a/fpga/hdl/action_config.v +++ b/fpga/hdl/action_config.v @@ -91,8 +91,8 @@ module action_config output reg [7:0] nmodules , output reg [3:0] nstorage_cells , output wire [31:0] hbm_size_bytes , - output reg[15:0] spot_finder_count_threshold , - output reg[15:0] spot_finder_snr_threshold , + output reg [15:0] spot_finder_count_threshold, + output reg [7:0] spot_finder_snr_threshold, output reg data_collection_start , output reg data_collection_cancel , @@ -523,14 +523,14 @@ always @(posedge clk) begin if (!resetn) spot_finder_snr_threshold <= 0; else if (w_hs && waddr == `ADDR_SPOT_FINDER_SNR_THR) - spot_finder_snr_threshold <= (s_axi_WDATA[15:0] & wmask[15:0]) | (spot_finder_snr_threshold & !wmask[3:0]); + spot_finder_snr_threshold <= (s_axi_WDATA[7:0] & wmask[7:0]) | (spot_finder_snr_threshold & !wmask[7:0]); end always @(posedge clk) begin if (!resetn) spot_finder_count_threshold <= 0; else if (w_hs && waddr == `ADDR_SPOT_FINDER_CNT_THR) - spot_finder_count_threshold <= (s_axi_WDATA[15:0] & wmask[15:0]) | (spot_finder_count_threshold & !wmask[3:0]); + spot_finder_count_threshold <= (s_axi_WDATA[15:0] & wmask[15:0]) | (spot_finder_count_threshold & !wmask[15:0]); end always @ (posedge clk) begin diff --git a/fpga/hls/hls_jfjoch.h b/fpga/hls/hls_jfjoch.h index 69914f6c..e121b382 100644 --- a/fpga/hls/hls_jfjoch.h +++ b/fpga/hls/hls_jfjoch.h @@ -231,7 +231,7 @@ void spot_finder(STREAM_512 &data_in, STREAM_512 &data_out, hls::stream> &strong_pixel_out, volatile ap_int<16> &in_count_threshold, - volatile ap_uint<16> &in_snr_threshold); + volatile ap_uint<8> &in_snr_threshold); void bitshuffle(STREAM_512 &data_in, STREAM_512 &data_out); diff --git a/fpga/hls/spot_finder.cpp b/fpga/hls/spot_finder.cpp index 52144214..f6fc0133 100644 --- a/fpga/hls/spot_finder.cpp +++ b/fpga/hls/spot_finder.cpp @@ -2,6 +2,14 @@ #include "hls_jfjoch.h" +#define SUM_BITWIDTH 28 // 16 + 11 + 1 +#define SUM2_BITWIDTH 44 // 32 + 11 + 1 +#define VALID_BITWIDTH 11 // 11 + +#ifdef JFJOCH_HLS_NOSYNTH +#include +#endif + ap_uint<32> count_pixels(ap_uint<32> &in) { #pragma HLS INLINE ap_uint<32> ret = 0; @@ -10,40 +18,196 @@ ap_uint<32> count_pixels(ap_uint<32> &in) { return ret; } -void spot_finder(STREAM_512 &data_in, - STREAM_512 &data_out, - hls::stream> &strong_pixel_out, - volatile ap_int<16> &in_count_threshold, - volatile ap_uint<16> &in_snr_threshold) { -#pragma HLS INTERFACE axis port=data_in -#pragma HLS INTERFACE axis port=data_out -#pragma HLS INTERFACE axis port=strong_pixel_out -#pragma HLS INTERFACE ap_none register port=in_count_threshold -#pragma HLS INTERFACE ap_none register port=in_snr_threshold - packet_512_t packet; +struct spot_finder_packet { + ap_uint<512> data; + ap_uint<1> user; + ap_uint<1> last; +}; + +void spot_finder_in_stream(STREAM_512 &data_in, + hls::stream &data_out) { + packet_512_t packet_in; + data_in >> packet_in; + data_out << spot_finder_packet{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; + data_in >> packet_in; + while (!packet_in.user) { +#pragma HLS PIPELINE II=1 + data_out << spot_finder_packet{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; + data_in >> packet_in; + } + data_out << spot_finder_packet{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; +} + +ap_uint<32> calc_mask(ap_int<16> val[32]) { + ap_uint<32> ret = 0; + for (int i = 0; i < 32; i++) { + if ((val[i] == INT16_MAX) || (val[i] == INT16_MIN)) + ret[i] = 0; + else + ret[i] = 1; + } + return ret; +} + +ap_int calc_sum(ap_int<16> val[32], ap_uint<32> mask) { +#pragma HLS PIPELINE II=1 + ap_int ret = 0; + for (int i = 0; i < 32; i++) { + if (mask[i]) + ret += val[i]; + } + return ret; +} + +ap_int calc_sum2(ap_int<16> val[32], ap_uint<32> mask) { +#pragma HLS PIPELINE II=1 + ap_int ret = 0; + for (int i = 0; i < 32; i++) { + if (mask[i]) + ret += val[i] * val[i]; + } + return ret; +} + +ap_int calc_valid(ap_uint<32> mask) { +#pragma HLS PIPELINE II=1 + ap_int ret = 0; + for (int i = 0; i < 32; i++) { + ret += mask[i]; + } + return ret; +} + +void spot_finder_prepare(hls::stream &data_in, + hls::stream &data_out, + hls::stream> &sum_out, + hls::stream> &sum2_out, + hls::stream> &valid_out) { + spot_finder_packet packet; data_in >> packet; data_out << packet; + ap_int sum[32]; + ap_int sum2[32]; + ap_int valid[32]; + + for (int col = 0; col < 32; col++) { + sum[col] = 0; + sum2[col] = 0; + valid[col] = 0; + } + data_in >> packet; while (!packet.user) { - ap_int<16> count_threshold = in_count_threshold; - ap_uint<16> snr_threshold = in_snr_threshold; - ap_uint<32> strong_pixel_count = 0; for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) { #pragma HLS PIPELINE II=1 data_out << packet; - ap_uint<32> strong_pixel = 0; - ap_int<16> data_unpacked[32]; - unpack32(packet.data, data_unpacked); - for (int j = 0; j < 32; j++) { - if (data_unpacked[j] >= count_threshold) - strong_pixel[j] = 1; - else - strong_pixel[j] = 0; + ap_int<16> val[32]; + unpack32(packet.data, val); + ap_uint<32> mask = calc_mask(val); + + if ((i / 32) % 32 == 0) { + sum[i % 32] = calc_sum(val, mask); + sum2[i % 32] = calc_sum2(val, mask); + valid[i % 32] = calc_valid(mask); + } else if ((i / 32) % 32 == 31) { + sum_out << sum[i % 32] + calc_sum(val, mask); + sum2_out << sum2[i % 32] + calc_sum2(val, mask); + valid_out << valid[i % 32] + calc_valid(mask); + } else { + sum[i % 32] += calc_sum(val, mask); + sum2[i % 32] += calc_sum2(val, mask); + valid[i % 32] += calc_valid(mask); } + + data_in >> packet; + } + } + data_out << packet; +} + +ap_uint<32> spot_finder_snr_threshold(ap_int<16> val[32], + ap_uint<8> snr_threshold, + ap_int sum, + ap_int sum2, + ap_int valid_count) { +#pragma HLS PIPELINE II=1 + if (snr_threshold == 0) + return UINT32_MAX; + + ap_int variance = valid_count * sum2 - sum * sum; + ap_int threshold = (variance * snr_threshold * valid_count + 2) / 4; + // snr_threshold is in units of 0.25 + + ap_uint<32> ret = 0; + for (int j = 0; j < 32; j++) { + ap_int in_minus_mean = val[j] * valid_count - sum; + if ((in_minus_mean * in_minus_mean * (valid_count - 1) > threshold) && + (in_minus_mean > 0)) + ret[j] = 1; + else + ret[j] = 0; + } + return ret; +} + +ap_uint<32> spot_finder_count_threshold(ap_int<16> val[32], + ap_int<16> &count_threshold) { +#pragma HLS PIPELINE II=1 + if (count_threshold <= 0) + return UINT32_MAX; + ap_uint<32> ret = 0; + for (int j = 0; j < 32; j++) { + if (val[j] >= count_threshold) + ret[j] = 1; + else + ret[j] = 0; + } + return ret; +} + +void spot_finder_apply_threshold(hls::stream &data_in, + STREAM_512 &data_out, + hls::stream> &sum_in, + hls::stream> &sum2_in, + hls::stream> &valid_in, + hls::stream> &strong_pixel_out, + volatile ap_int<16> &in_count_threshold, + volatile ap_uint<8> &in_snr_threshold) { + spot_finder_packet packet_in; + + data_in >> packet_in; + data_out << packet_512_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; + + ap_int sum[32]; + ap_int sum2[32]; + ap_int valid[32]; + + data_in >> packet_in; + while (!packet_in.user) { + ap_int<16> count_threshold = in_count_threshold; + ap_uint<8> snr_threshold = in_snr_threshold; + ap_uint<32> strong_pixel_count = 0; + for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) { +#pragma HLS PIPELINE II=1 + + if ((i / 32) % 32 == 0) { + sum_in >> sum[i % 32]; + sum2_in >> sum2[i % 32]; + valid_in >> valid[i % 32]; + } + + data_out << packet_512_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; + ap_int<16> data_unpacked[32]; + unpack32(packet_in.data, data_unpacked); + + ap_uint<32> strong_pixel = spot_finder_count_threshold(data_unpacked, count_threshold) & + spot_finder_snr_threshold(data_unpacked, snr_threshold, + sum[i % 32], sum2[i % 32], valid[i % 32]); + strong_pixel_out << ap_axiu<32,1,1,1>{.data = strong_pixel, .user = 0}; strong_pixel_count += count_pixels(strong_pixel); - data_in >> packet; + data_in >> packet_in; } // Save module statistics @@ -55,5 +219,42 @@ void spot_finder(STREAM_512 &data_in, strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 0}; } strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 1}; - data_out << packet; + data_out << packet_512_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last}; +} + + +void spot_finder(STREAM_512 &data_in, + STREAM_512 &data_out, + hls::stream> &strong_pixel_out, + volatile ap_int<16> &in_count_threshold, + volatile ap_uint<8> &in_snr_threshold) { +#pragma HLS INTERFACE axis port=data_in +#pragma HLS INTERFACE axis port=data_out +#pragma HLS INTERFACE axis port=strong_pixel_out +#pragma HLS INTERFACE ap_none register port=in_count_threshold +#pragma HLS INTERFACE ap_none register port=in_snr_threshold +#pragma HLS DATAFLOW + + hls::stream data_0; + hls::stream data_1; +#pragma HLS BIND_STORAGE variable=data_1 type=fifo impl=uram + hls::stream, 64> sum_0; + hls::stream, 64> sum2_0; + hls::stream, 64> valid_0; +#ifndef JFJOCH_HLS_NOSYNTH + spot_finder_in_stream(data_in, data_0); + spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0); + spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0, strong_pixel_out, + in_count_threshold, in_snr_threshold); +#else + std::vector spot_finder_cores; + spot_finder_cores.emplace_back([&] {spot_finder_in_stream(data_in, data_0);}); + spot_finder_cores.emplace_back([&] {spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0);}); + spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0, + strong_pixel_out, in_count_threshold, + in_snr_threshold);}); + for (auto &i : spot_finder_cores) + i.join(); + +#endif } diff --git a/receiver/HLSSimulatedDevice.h b/receiver/HLSSimulatedDevice.h index 355e34c9..f385b3f0 100644 --- a/receiver/HLSSimulatedDevice.h +++ b/receiver/HLSSimulatedDevice.h @@ -19,7 +19,7 @@ class HLSSimulatedDevice : public FPGAAcquisitionDevice { AXI_STREAM dout_eth; ap_int<16> count_threshold = INT16_MAX; - ap_uint<16> snr_threshold = 0; + ap_uint<8> snr_threshold = 0; DataCollectionConfig cfg; diff --git a/tests/FPGASpotFindingUnitTest.cpp b/tests/FPGASpotFindingUnitTest.cpp index 76fcd091..434ad7c4 100644 --- a/tests/FPGASpotFindingUnitTest.cpp +++ b/tests/FPGASpotFindingUnitTest.cpp @@ -11,7 +11,7 @@ TEST_CASE("FPGA_spot_finder_core","[FPGA][SpotFinder]") { hls::stream> strong_pixel; ap_int<16> in_photon_count_threshold = 8; - ap_uint<16> in_strong_pixel_threshold = 16; + ap_uint<8> in_strong_pixel_threshold = 16; std::vector input_frame(RAW_MODULE_SIZE), output_frame(RAW_MODULE_SIZE); for (int i = 0; i < RAW_MODULE_SIZE; i++) {