Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numerical evaluation of Fourier transform of Daubechies scaling funct… #921

Merged
merged 9 commits into from
Jun 13, 2023
Binary file added doc/graphs/fourier_transform_daubechies.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions doc/sf/daubechies.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@ The 2 vanishing moment scaling function.
[$../graphs/daubechies_8_scaling.svg]
The 8 vanishing moment scaling function.

Boost.Math also provides numerical evaluation of the Fourier transform of these functions.
This is useful in sparse recovery problems where the measurements are taken in the Fourier basis.
The usage is exhibited below:

#include <boost/math/special_functions/fourier_transform_daubechies_scaling.hpp>
using boost::math::fourier_transform_daubechies_scaling;
// Evaluate the Fourier transform of the 4-vanishing moment Daubechies scaling function at ω=1.8:
std::complex<float> hat_phi = fourier_transform_daubechies_scaling<float, 4>(1.8f);

The Fourier transform convention is unitary with the sign of the imaginary unit being given in Daubechies Ten Lectures.
In particular, this means that `fourier_transform_daubechies_scaling<float, p>(0.0)` returns 1/sqrt(2π).

The implementation computes an infinite product of trigonometric polynomials as can be found from recursive application of the identity 𝓕[φ](ω) = m(ω/2)𝓕[φ](ω/2).
This is neither particularly fast nor accurate, but there appears to be no literature on this extremely useful topic, and hence the naive method must suffice.

[$../graphs/fourier_transform_daubechies.png]

[heading References]

* Daubechies, Ingrid. ['Ten Lectures on Wavelets.] Vol. 61. Siam, 1992.
Expand Down
38 changes: 38 additions & 0 deletions example/calculate_fourier_transform_daubechies_constants.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <utility>
#include <boost/math/filters/daubechies.hpp>
#include <boost/math/tools/polynomial.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/math/constants/constants.hpp>

using std::pow;
using boost::multiprecision::cpp_bin_float_100;
using boost::math::filters::daubechies_scaling_filter;
using boost::math::tools::polynomial;
using boost::math::constants::half;
using boost::math::constants::root_two;

template<typename Real, size_t N>
std::vector<Real> get_constants() {
auto h = daubechies_scaling_filter<cpp_bin_float_100, N>();
auto p = polynomial<cpp_bin_float_100>(h.begin(), h.end());

auto q = polynomial({half<cpp_bin_float_100>(), half<cpp_bin_float_100>()});
q = pow(q, N);
auto l = p/q;
return l.data();
}

template<typename Real>
void print_constants(std::vector<Real> const & l) {
std::cout << std::setprecision(std::numeric_limits<Real>::digits10 -10);
std::cout << "return std::array<Real, " << l.size() << ">{";
for (size_t i = 0; i < l.size() - 1; ++i) {
std::cout << "BOOST_MATH_BIG_CONSTANT(Real, std::numeric_limits<Real>::digits, " << l[i]/root_two<Real>() << "), ";
}
std::cout << "BOOST_MATH_BIG_CONSTANT(Real, std::numeric_limits<Real>::digits, " << l.back()/root_two<Real>() << ")};\n";
}

int main() {
auto constants = get_constants<cpp_bin_float_100, 1>();
print_constants(constants);
}
54 changes: 54 additions & 0 deletions example/fourier_transform_daubechies_ulp_plot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <boost/math/special_functions/fourier_transform_daubechies_scaling.hpp>
#include <boost/math/tools/ulps_plot.hpp>

using boost::math::fourier_transform_daubechies_scaling;
using boost::math::tools::ulps_plot;

template<int p>
void real_part() {
auto phi_real_hi_acc = [](double omega) {
auto z = fourier_transform_daubechies_scaling<double, p>(omega);
return z.real();
};

auto phi_real_lo_acc = [](float omega) {
auto z = fourier_transform_daubechies_scaling<float, p>(omega);
return z.real();
};
auto plot = ulps_plot<decltype(phi_real_hi_acc), double, float>(phi_real_hi_acc, float(0.0), float(100.0), 20000);
plot.ulp_envelope(false);
plot.add_fn(phi_real_lo_acc);
plot.clip(100);
plot.title("Accuracy of 𝔑(𝓕[𝜙](ω)) with " + std::to_string(p) + " vanishing moments.");
plot.write("real_ft_daub_scaling_" + std::to_string(p) + ".svg");

}

template<int p>
void imaginary_part() {
auto phi_imag_hi_acc = [](double omega) {
auto z = fourier_transform_daubechies_scaling<double, p>(omega);
return z.imag();
};

auto phi_imag_lo_acc = [](float omega) {
auto z = fourier_transform_daubechies_scaling<float, p>(omega);
return z.imag();
};
auto plot = ulps_plot<decltype(phi_imag_hi_acc), double, float>(phi_imag_hi_acc, float(0.0), float(100.0), 20000);
plot.ulp_envelope(false);
plot.add_fn(phi_imag_lo_acc);
plot.clip(100);
plot.title("Accuracy of 𝕴(𝓕[𝜙](ω)) with " + std::to_string(p) + " vanishing moments.");
plot.write("imag_ft_daub_scaling_" + std::to_string(p) + ".svg");

}


int main() {
real_part<3>();
imaginary_part<3>();
real_part<6>();
imaginary_part<6>();
return 0;
}
Loading