diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_ChebyshevPolynomials.h b/modules/dsp/chowdsp_math/Math/chowdsp_ChebyshevPolynomials.h new file mode 100644 index 00000000..d97fc6b5 --- /dev/null +++ b/modules/dsp/chowdsp_math/Math/chowdsp_ChebyshevPolynomials.h @@ -0,0 +1,60 @@ +#pragma once + +namespace chowdsp +{ +#ifndef DOXYGEN +namespace cheby_detail +{ + template + constexpr auto cheby0() + { + Polynomial poly {}; + poly.coeffs[0] = static_cast (1); + return poly; + } + + template + constexpr auto cheby1() + { + Polynomial poly {}; + poly.coeffs[1] = static_cast (1); + return poly; + } +} // namespace cheby_detail +#endif + +/** Recursively computes a Chebyshev polynomial given two previous Chebyshev polynomials */ +template +constexpr auto chebyshev_polynomial_recurse (const Polynomial& cheby_n1, + const Polynomial& cheby_n2) +{ + Polynomial cheby_n {}; + cheby_n.coeffs[0] = -cheby_n2.coeffs[0]; + for (size_t i = 1; i < max_order; ++i) + cheby_n.coeffs[i] = (T) 2 * cheby_n1.coeffs[i - 1] - cheby_n2.coeffs[i]; + return cheby_n; +} + +/** Computes a Chebyshev polynomial of a given order. */ +template +constexpr auto chebyshev_polynomial() +{ + if constexpr (order == 0) + return cheby_detail::cheby0(); + + if constexpr (order == 1) + return cheby_detail::cheby1(); + + auto cheby_n2 = cheby_detail::cheby0(); + auto cheby_n1 = cheby_detail::cheby1(); + auto cheby_n = Polynomial {}; + for (size_t i = 2; i <= order; ++i) + { + cheby_n = chebyshev_polynomial_recurse (cheby_n1, cheby_n2); + cheby_n2 = cheby_n1; + cheby_n1 = cheby_n; + } + + return cheby_n; +} +} // namespace chowdsp diff --git a/modules/dsp/chowdsp_math/chowdsp_math.h b/modules/dsp/chowdsp_math/chowdsp_math.h index 65bcc7f5..7c9e1ecb 100644 --- a/modules/dsp/chowdsp_math/chowdsp_math.h +++ b/modules/dsp/chowdsp_math/chowdsp_math.h @@ -36,6 +36,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE #include "Math/chowdsp_OtherMathOps.h" #include "Math/chowdsp_MatrixOps.h" #include "Math/chowdsp_Polynomials.h" +#include "Math/chowdsp_ChebyshevPolynomials.h" #include "Math/chowdsp_Power.h" #include "Math/chowdsp_RandomFloat.h" #include "Math/chowdsp_JacobiElliptic.h" diff --git a/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt b/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt index 53bc40e0..50013f46 100644 --- a/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt +++ b/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(chowdsp_math_test FloatVectorOperationsTest.cpp MatrixOpsTest.cpp PolynomialsTest.cpp + ChebyshevPolynomialTest.cpp PowerTest.cpp OtherMathOpsTest.cpp JacobiEllipticTest.cpp diff --git a/tests/dsp_tests/chowdsp_math_test/ChebyshevPolynomialTest.cpp b/tests/dsp_tests/chowdsp_math_test/ChebyshevPolynomialTest.cpp new file mode 100644 index 00000000..27c8db27 --- /dev/null +++ b/tests/dsp_tests/chowdsp_math_test/ChebyshevPolynomialTest.cpp @@ -0,0 +1,23 @@ +#include +#include + +static void check_poly (const chowdsp::Polynomial& cheby_poly, + std::vector&& actual) +{ + size_t i = 0; + for (; i < actual.size(); ++i) + REQUIRE (cheby_poly.coeffs[i] == Catch::Approx { actual[i] }.margin (1.0e-6)); + for (; i < cheby_poly.coeffs.size(); ++i) + REQUIRE (cheby_poly.coeffs[i] == Catch::Approx { 0.0f }.margin (1.0e-6)); +} + +TEST_CASE ("Chebyshev Polynomials Test", "[dsp][math]") +{ + check_poly (chowdsp::chebyshev_polynomial(), { -1.0f, 0.0f, 2.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { 0.0f, -3.0f, 0.0f, 4.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { 1.0f, 0.0f, -8.0f, 0.0f, 8.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { 0.0f, 5.0f, 0.0f, -20.0f, 0.0f, 16.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { -1.0f, 0.0f, 18.0f, 0.0f, -48.0f, 0.0f, 32.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { 0.0f, -7.0f, 0.0f, 56.0f, 0.0f, -112.0f, 0.0f, 64.0f }); + check_poly (chowdsp::chebyshev_polynomial(), { 1.0f, 0.0f, -32.0f, 0.0f, 160.0f, 0.0f, -256.0f, 0.0f, 128.0f }); +}