Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
windowed_sinc_design.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <algorithm>
7#include <cmath>
8#include <cstddef>
9#include <vector>
10
11namespace pulp::signal {
12
13inline double bessel_i0(double x) {
14 const double half_x = 0.5 * x;
15 double sum = 1.0;
16 double term = 1.0;
17 for (int k = 1; k < 64; ++k) {
18 term *= half_x / static_cast<double>(k);
19 const double squared = term * term;
20 sum += squared;
21 if (squared < 1e-20 * sum)
22 break;
23 }
24 return sum;
25}
26
27inline double kaiser_beta_for_stopband(double stopband_db) {
28 if (stopband_db > 50.0)
29 return 0.1102 * (stopband_db - 8.7);
30 if (stopband_db >= 21.0) {
31 return 0.5842 * std::pow(stopband_db - 21.0, 0.4) + 0.07886 * (stopband_db - 21.0);
32 }
33 return 0.0;
34}
35
36inline std::size_t kaiser_length_for_transition(double stopband_db, double normalized_width) {
37 if (normalized_width <= 0.0)
38 normalized_width = 1e-6;
39 const double order = (stopband_db - 7.95) / (14.36 * normalized_width);
40 std::size_t taps = static_cast<std::size_t>(std::ceil(order)) + 1;
41 if ((taps & 1u) == 0u)
42 ++taps;
43 return std::max<std::size_t>(taps, 3u);
44}
45
46inline void kaiser_window(std::vector<double>& output, double beta) {
47 if (output.empty())
48 return;
49 const double denominator = bessel_i0(beta);
50 const double half = 0.5 * static_cast<double>(output.size() - 1);
51 for (std::size_t i = 0; i < output.size(); ++i) {
52 const double x = (static_cast<double>(i) - half) / half;
53 const double argument = beta * std::sqrt(std::max(0.0, 1.0 - x * x));
54 output[i] = bessel_i0(argument) / denominator;
55 }
56}
57
58inline std::vector<double> design_windowed_sinc(std::size_t taps, double cutoff, double beta) {
59 std::vector<double> coefficients(taps, 0.0);
60 std::vector<double> window(taps, 0.0);
61 kaiser_window(window, beta);
62 const double half = 0.5 * static_cast<double>(taps - 1);
63 constexpr double pi = 3.14159265358979323846;
64 const double doubled_cutoff = 2.0 * cutoff;
65 for (std::size_t i = 0; i < taps; ++i) {
66 const double offset = static_cast<double>(i) - half;
67 const double sinc = std::abs(offset) < 1e-12
68 ? doubled_cutoff
69 : std::sin(pi * doubled_cutoff * offset) / (pi * offset);
70 coefficients[i] = sinc * window[i];
71 }
72 double sum = 0.0;
73 for (double coefficient : coefficients)
74 sum += coefficient;
75 if (std::abs(sum) > 1e-18) {
76 for (double& coefficient : coefficients)
77 coefficient /= sum;
78 }
79 return coefficients;
80}
81
82} // namespace pulp::signal
Definition additive_bank.hpp:218
float sinc(float x)
Sinc function: sin(pi*x) / (pi*x), with sinc(0) = 1.
Definition special_functions.hpp:17
void kaiser_window(std::vector< double > &output, double beta)
Definition windowed_sinc_design.hpp:46
float bessel_i0(float x)
Modified Bessel function of the first kind, order 0 Used in Kaiser window design.
Definition special_functions.hpp:25
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
std::size_t kaiser_length_for_transition(double stopband_db, double normalized_width)
Definition windowed_sinc_design.hpp:36
std::vector< double > design_windowed_sinc(std::size_t taps, double cutoff, double beta)
Definition windowed_sinc_design.hpp:58
double kaiser_beta_for_stopband(double stopband_db)
Definition windowed_sinc_design.hpp:27