Common FFT convolution helper to eliminate code duplication.
22{
23 if (data_span.empty() || kernel.empty()) {
24 if (return_full_size && !data_span.empty() && !kernel.empty()) {
25 return std::vector<double>(data_span.size() + kernel.size() - 1, 0.0);
26 } else {
27 return std::vector<double>(data_span.size(), 0.0);
28 }
29 }
30
31 size_t conv_size = data_span.size() + kernel.size() - 1;
32
33 size_t fft_size = std::max(256UZ, conv_size);
34 fft_size = 1 << (32 - std::countl_zero(fft_size - 1));
35
36 Eigen::VectorXd padded_input = Eigen::VectorXd::Zero(fft_size);
37 Eigen::VectorXd padded_kernel = Eigen::VectorXd::Zero(fft_size);
38
39 std::ranges::copy(data_span, padded_input.begin());
40 std::ranges::copy(kernel, padded_kernel.begin());
41
42 Eigen::FFT<double> fft;
43 Eigen::VectorXcd input_fft, kernel_fft;
44 fft.fwd(input_fft, padded_input);
45 fft.fwd(kernel_fft, padded_kernel);
46
47 Eigen::VectorXcd result_fft(fft_size);
48 operation(input_fft, kernel_fft, result_fft);
49
50 double scale_factor = 1.0 / fft_size;
51 std::ranges::transform(result_fft, result_fft.begin(),
52 [scale_factor](std::complex<double>& c) {
53 return c * scale_factor;
54 });
55
56 Eigen::VectorXd time_result;
57 fft.inv(time_result, result_fft);
58
59 if (return_full_size) {
60 std::vector<double> result(conv_size);
61 std::ranges::copy(time_result | std::views::take(conv_size), result.begin());
62 return result;
63 } else {
64 std::vector<double> result(data_span.size());
65 std::ranges::copy(time_result | std::views::take(data_span.size()), result.begin());
66 return result;
67 }
68}