-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0405896
commit 1360490
Showing
5 changed files
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#pragma once | ||
|
||
#include <etl/algorithm.hpp> | ||
#include <etl/array.hpp> | ||
#include <etl/concepts.hpp> | ||
#include <etl/span.hpp> | ||
|
||
namespace grit { | ||
|
||
/// Calculates coefficents for 2nd order biquad filters | ||
/// \see BiquadTDF2 | ||
/// \ingroup grit-audio-filter | ||
template<etl::floating_point Float> | ||
struct BiquadCoefficients | ||
{ | ||
using value_type = Float; | ||
using SampleType = Float; | ||
|
||
[[nodiscard]] static constexpr auto makeBypass() -> etl::array<Float, 6> | ||
{ | ||
return {Float(1), Float(0), Float(0), Float(1), Float(0), Float(0)}; | ||
} | ||
}; | ||
|
||
/// \brief 2nd order IIR filter using the transpose direct form 2 structure. | ||
/// \ingroup grit-audio-filter | ||
template<etl::floating_point Float> | ||
struct BiquadTDF2 | ||
{ | ||
using value_type = Float; | ||
using SampleType = Float; | ||
using Coefficients = BiquadCoefficients<Float>; | ||
|
||
constexpr BiquadTDF2() = default; | ||
|
||
constexpr auto setCoefficients(etl::span<Float const, 6> coefficients) -> void | ||
{ | ||
etl::copy(coefficients.begin(), coefficients.end(), _coefficients.begin()); | ||
} | ||
|
||
constexpr auto reset() -> void | ||
{ | ||
_z[0] = Float(0); | ||
_z[1] = Float(0); | ||
} | ||
|
||
[[nodiscard]] constexpr auto operator()(Float x) -> Float | ||
{ | ||
auto const b0 = _coefficients[Index::B0]; | ||
auto const b1 = _coefficients[Index::B1]; | ||
auto const b2 = _coefficients[Index::B2]; | ||
auto const a1 = _coefficients[Index::A1]; | ||
auto const a2 = _coefficients[Index::A2]; | ||
|
||
auto const y = b0 * x + _z[0]; | ||
_z[0] = b1 * x - a1 * y + _z[1]; | ||
_z[1] = b2 * x - a2 * y; | ||
return y; | ||
} | ||
|
||
private: | ||
enum Index | ||
{ | ||
B0, | ||
B1, | ||
B2, | ||
A0, | ||
A1, | ||
A2, | ||
NumCoefficients, | ||
}; | ||
|
||
etl::array<Float, NumCoefficients> _coefficients{Coefficients::makeBypass()}; | ||
etl::array<Float, 2> _z{}; | ||
}; | ||
|
||
} // namespace grit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include "biquad.hpp" | ||
|
||
#include <etl/random.hpp> | ||
|
||
#include <catch2/catch_get_random_seed.hpp> | ||
#include <catch2/catch_template_test_macros.hpp> | ||
#include <catch2/matchers/catch_matchers_floating_point.hpp> | ||
|
||
TEMPLATE_TEST_CASE("audio/filter: BiquadCoefficients::makeBypass", "", float, double) | ||
{ | ||
using Float = TestType; | ||
using Coefficients = grit::BiquadCoefficients<Float>; | ||
|
||
static constexpr auto bypass = Coefficients::makeBypass(); | ||
STATIC_REQUIRE(bypass.size() == 6U); | ||
|
||
REQUIRE_THAT(bypass[0], Catch::Matchers::WithinAbs(1.0, 1e-6)); | ||
REQUIRE_THAT(bypass[1], Catch::Matchers::WithinAbs(0.0, 1e-6)); | ||
REQUIRE_THAT(bypass[2], Catch::Matchers::WithinAbs(0.0, 1e-6)); | ||
REQUIRE_THAT(bypass[3], Catch::Matchers::WithinAbs(1.0, 1e-6)); | ||
REQUIRE_THAT(bypass[4], Catch::Matchers::WithinAbs(0.0, 1e-6)); | ||
REQUIRE_THAT(bypass[5], Catch::Matchers::WithinAbs(0.0, 1e-6)); | ||
} | ||
|
||
TEMPLATE_TEST_CASE("audio/filter: BiquadTDF2", "", float, double) | ||
{ | ||
using Float = TestType; | ||
using Filter = grit::BiquadTDF2<Float>; | ||
|
||
static constexpr auto iterations = 1'000; | ||
|
||
auto rng = etl::xoshiro128plusplus{Catch::getSeed()}; | ||
auto dist = etl::uniform_real_distribution<Float>{Float(-1), Float(+1)}; | ||
|
||
SECTION("default coefficents are bypass") | ||
{ | ||
auto filter = Filter{}; | ||
for (auto i{0}; i < iterations; ++i) { | ||
auto const x = dist(rng); | ||
auto const y = filter(x); | ||
REQUIRE_THAT(y, Catch::Matchers::WithinAbs(x, 1e-6)); | ||
} | ||
|
||
filter.setCoefficients(Filter::Coefficients::makeBypass()); | ||
filter.reset(); | ||
|
||
for (auto i{0}; i < iterations; ++i) { | ||
auto const x = dist(rng); | ||
auto const y = filter(x); | ||
REQUIRE_THAT(y, Catch::Matchers::WithinAbs(x, 1e-6)); | ||
} | ||
} | ||
} |