From e38bf4ddfc2b4eaf21b8921f2c3cb9589ff44100 Mon Sep 17 00:00:00 2001 From: Michael Bloom Date: Sat, 4 May 2024 15:23:49 -0400 Subject: [PATCH] Reorg and format testIIR --- test/testIIR.cpp | 312 ++++++++++++++++++++++++++--------------------- 1 file changed, 171 insertions(+), 141 deletions(-) diff --git a/test/testIIR.cpp b/test/testIIR.cpp index e8bf971..e5565b5 100644 --- a/test/testIIR.cpp +++ b/test/testIIR.cpp @@ -1,21 +1,23 @@ #include "catch2/catch_all.hpp" #include "sdsp/casc2orderIIR.h" -#include #include +#include -std::tuple, sdsp::FilterType, double, double, double> csvreadImpulse2(const std::string& filename) +std::tuple, sdsp::FilterType, double, double, double> +csvreadImpulse2(const std::string& filename) { std::ifstream myfile; myfile.open(filename); - unsigned int fType {0}; - char comma {0}; - unsigned int n {0}; - sdsp::FilterType fType_out {sdsp::FilterType::None}; - double fs_out {0.0}; - double f0_out {0.0}; - double Q_out {0.0}; - myfile >> fType >> comma >> fs_out >> comma >> f0_out >> comma >> Q_out >> comma >> n >> comma; + unsigned int fType{ 0 }; + char comma{ 0 }; + unsigned int n{ 0 }; + sdsp::FilterType fType_out{ sdsp::FilterType::None }; + double fs_out{ 0.0 }; + double f0_out{ 0.0 }; + double Q_out{ 0.0 }; + myfile >> fType >> comma >> fs_out >> comma >> f0_out >> comma >> Q_out >> + comma >> n >> comma; fType_out = static_cast(fType); std::vector impulse(n); @@ -24,17 +26,18 @@ std::tuple, sdsp::FilterType, double, double, double> csvrea myfile >> impulse.at(i) >> comma; } myfile >> impulse.back(); - return {impulse, fType_out, fs_out, f0_out, Q_out}; + return { impulse, fType_out, fs_out, f0_out, Q_out }; } -TEST_CASE("Filter test", "[single-file]") +TEST_CASE("Filter test") { - SECTION("Test impulse response") + SECTION("Test impulse response") { std::string path = "../../../test_data/impulse_response"; - for (const auto & entry : std::filesystem::directory_iterator(path)) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { - auto [readImpulse, fType, fs, f0, Q] = csvreadImpulse2(entry.path().string()); + auto [readImpulse, fType, fs, f0, Q] = + csvreadImpulse2(entry.path().string()); sdsp::casc2orderIIR<4> df; if (fType == sdsp::FilterType::LowPass) { @@ -46,27 +49,29 @@ TEST_CASE("Filter test", "[single-file]") } else { throw std::runtime_error("Unknown filter type"); } - sdsp::casc2orderIIR<4> df2 = df; + sdsp::casc2orderIIR<4> df2 = df; std::vector data(readImpulse.size()); data.at(0) = 1.0; df.Process(data.begin(), data.end()); - + std::vector error(readImpulse.size()); for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(data.at(i) - readImpulse.at(i)); } double maxError = *std::max_element(error.begin(), error.end()); - REQUIRE(maxError < 1e-12); //typically error 1e-16 or less + REQUIRE(maxError < 1e-12); // typically error 1e-16 or less - //also check that we can process in blocks and get the same result + // also check that we can process in blocks and get the same result std::vector data2(readImpulse.size()); data2.at(0) = 1.0; - constexpr unsigned int blockSize {32}; - unsigned int index {0}; - for (index = 0; index <= data2.size() - blockSize; index += blockSize) { - df2.Process(std::next(data2.begin(), index), std::next(data2.begin(), index + blockSize)); + constexpr unsigned int blockSize{ 32 }; + unsigned int index{ 0 }; + for (index = 0; index <= data2.size() - blockSize; + index += blockSize) { + df2.Process(std::next(data2.begin(), index), + std::next(data2.begin(), index + blockSize)); } if (index < data2.size()) { @@ -77,15 +82,71 @@ TEST_CASE("Filter test", "[single-file]") } } - SECTION("Test impulse response of LP specialized") + SECTION("Test filter preload") + { + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; + constexpr double Q{ 1.1 }; + constexpr double steadyValue{ 10.0 }; + + { + std::array steadyLP; + std::fill(steadyLP.begin(), steadyLP.end(), steadyValue); + sdsp::casc2orderIIR<4> lpFilter; + lpFilter.SetLPCoeff(f0, fs); + lpFilter.PreloadFilter(steadyValue); + lpFilter.Process(steadyLP.begin(), steadyLP.end()); + auto calcError = [steadyValue](double& n) { + n = std::abs(n - steadyValue); + }; + std::for_each(steadyLP.begin(), steadyLP.end(), calcError); + double maxErrorLP = + *std::max_element(steadyLP.begin(), steadyLP.end()); + REQUIRE(maxErrorLP < 1e-12); + } + + { + std::array steadyHP; + std::fill(steadyHP.begin(), steadyHP.end(), steadyValue); + sdsp::casc2orderIIR<4> hpFilter; + hpFilter.SetHPCoeff(f0, fs); + hpFilter.PreloadFilter(steadyValue); + hpFilter.Process(steadyHP.begin(), steadyHP.end()); + auto calcError = [](double& n) { n = std::abs(n); }; + std::for_each(steadyHP.begin(), steadyHP.end(), calcError); + double maxErrorHP = + *std::max_element(steadyHP.begin(), steadyHP.end()); + REQUIRE(maxErrorHP < 1e-12); + } + + { + std::array steadyBP; + std::fill(steadyBP.begin(), steadyBP.end(), steadyValue); + sdsp::casc2orderIIR<4> bpFilter; + bpFilter.SetBPCoeff(f0, fs, Q); + bpFilter.PreloadFilter(steadyValue); + bpFilter.Process(steadyBP.begin(), steadyBP.end()); + auto calcError = [](double& n) { n = std::abs(n); }; + std::for_each(steadyBP.begin(), steadyBP.end(), calcError); + double maxErrorBP = + *std::max_element(steadyBP.begin(), steadyBP.end()); + REQUIRE(maxErrorBP < 1e-12); + } + } +} + +TEST_CASE("LP compile time filter test") +{ + SECTION("Test impulse response of LP specialized") { std::string path = "../../../test_data/impulse_response"; - for (const auto & entry : std::filesystem::directory_iterator(path)) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { if (entry.path().filename().string().starts_with("LP") == false) continue; - - auto [readImpulse, fType, fs, f0, Q] = csvreadImpulse2(entry.path().string()); + + auto [readImpulse, fType, fs, f0, Q] = + csvreadImpulse2(entry.path().string()); sdsp::casc_2o_IIR_lp<4> df; if (fType == sdsp::FilterType::LowPass) { @@ -93,27 +154,29 @@ TEST_CASE("Filter test", "[single-file]") } else { throw std::runtime_error("Unknown filter type"); } - sdsp::casc_2o_IIR_lp<4> df2 = df; + sdsp::casc_2o_IIR_lp<4> df2 = df; std::vector data(readImpulse.size()); data.at(0) = 1.0; df.process(data.begin(), data.end()); - + std::vector error(readImpulse.size()); for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(data.at(i) - readImpulse.at(i)); } double maxError = *std::max_element(error.begin(), error.end()); - REQUIRE(maxError < 1e-12); //typically error 1e-16 or less + REQUIRE(maxError < 1e-12); // typically error 1e-16 or less - //also check that we can process in blocks and get the same result + // also check that we can process in blocks and get the same result std::vector data2(readImpulse.size()); data2.at(0) = 1.0; - constexpr unsigned int blockSize {32}; - unsigned int index {0}; - for (index = 0; index <= data2.size() - blockSize; index += blockSize) { - df2.process(std::next(data2.begin(), index), std::next(data2.begin(), index + blockSize)); + constexpr unsigned int blockSize{ 32 }; + unsigned int index{ 0 }; + for (index = 0; index <= data2.size() - blockSize; + index += blockSize) { + df2.process(std::next(data2.begin(), index), + std::next(data2.begin(), index + blockSize)); } if (index < data2.size()) { @@ -126,12 +189,12 @@ TEST_CASE("Filter test", "[single-file]") SECTION("Test the LP filter gain") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; - std::array impulse1 {0}; + std::array impulse1{ 0 }; impulse1.at(0) = 1.0; - std::array impulse2 {0}; + std::array impulse2{ 0 }; impulse2.at(0) = 1.0; sdsp::casc_2o_IIR_lp<4> df; @@ -146,7 +209,7 @@ TEST_CASE("Filter test", "[single-file]") auto times_two = [](double& n) { n = 2.0 * n; }; std::for_each(impulse1.begin(), impulse1.end(), times_two); - std::array error {0}; + std::array error{ 0 }; for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(impulse1.at(i) - impulse2.at(i)); @@ -154,16 +217,20 @@ TEST_CASE("Filter test", "[single-file]") double maxError = *std::max_element(error.begin(), error.end()); REQUIRE(maxError < 1e-12); } +} - SECTION("Test impulse response of HP specialized") +TEST_CASE("HP compile time filter test") +{ + SECTION("Test impulse response of HP specialized") { std::string path = "../../../test_data/impulse_response"; - for (const auto & entry : std::filesystem::directory_iterator(path)) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { if (entry.path().filename().string().starts_with("HP") == false) continue; - - auto [readImpulse, fType, fs, f0, Q] = csvreadImpulse2(entry.path().string()); + + auto [readImpulse, fType, fs, f0, Q] = + csvreadImpulse2(entry.path().string()); sdsp::casc_2o_IIR_hp<4> df; if (fType == sdsp::FilterType::HighPass) { @@ -171,27 +238,29 @@ TEST_CASE("Filter test", "[single-file]") } else { throw std::runtime_error("Unknown filter type"); } - sdsp::casc_2o_IIR_hp<4> df2 = df; + sdsp::casc_2o_IIR_hp<4> df2 = df; std::vector data(readImpulse.size()); data.at(0) = 1.0; df.process(data.begin(), data.end()); - + std::vector error(readImpulse.size()); for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(data.at(i) - readImpulse.at(i)); } double maxError = *std::max_element(error.begin(), error.end()); - REQUIRE(maxError < 1e-12); //typically error 1e-16 or less + REQUIRE(maxError < 1e-12); // typically error 1e-16 or less - //also check that we can process in blocks and get the same result + // also check that we can process in blocks and get the same result std::vector data2(readImpulse.size()); data2.at(0) = 1.0; - constexpr unsigned int blockSize {32}; - unsigned int index {0}; - for (index = 0; index <= data2.size() - blockSize; index += blockSize) { - df2.process(std::next(data2.begin(), index), std::next(data2.begin(), index + blockSize)); + constexpr unsigned int blockSize{ 32 }; + unsigned int index{ 0 }; + for (index = 0; index <= data2.size() - blockSize; + index += blockSize) { + df2.process(std::next(data2.begin(), index), + std::next(data2.begin(), index + blockSize)); } if (index < data2.size()) { @@ -204,12 +273,12 @@ TEST_CASE("Filter test", "[single-file]") SECTION("Test the HP filter gain") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; - std::array impulse1 {0}; + std::array impulse1{ 0 }; impulse1.at(0) = 1.0; - std::array impulse2 {0}; + std::array impulse2{ 0 }; impulse2.at(0) = 1.0; sdsp::casc_2o_IIR_hp<4> df; @@ -224,7 +293,7 @@ TEST_CASE("Filter test", "[single-file]") auto times_two = [](double& n) { n = 2.0 * n; }; std::for_each(impulse1.begin(), impulse1.end(), times_two); - std::array error {0}; + std::array error{ 0 }; for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(impulse1.at(i) - impulse2.at(i)); @@ -232,16 +301,20 @@ TEST_CASE("Filter test", "[single-file]") double maxError = *std::max_element(error.begin(), error.end()); REQUIRE(maxError < 1e-12); } +} - SECTION("Test impulse response of BP specialized") +TEST_CASE("BP compile time filter test") +{ + SECTION("Test impulse response of BP specialized") { std::string path = "../../../test_data/impulse_response"; - for (const auto & entry : std::filesystem::directory_iterator(path)) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { if (entry.path().filename().string().starts_with("BP") == false) continue; - - auto [readImpulse, fType, fs, f0, Q] = csvreadImpulse2(entry.path().string()); + + auto [readImpulse, fType, fs, f0, Q] = + csvreadImpulse2(entry.path().string()); sdsp::casc_2o_IIR_bp<4> df; if (fType == sdsp::FilterType::BandPass) { @@ -249,27 +322,29 @@ TEST_CASE("Filter test", "[single-file]") } else { throw std::runtime_error("Unknown filter type"); } - sdsp::casc_2o_IIR_bp<4> df2 = df; + sdsp::casc_2o_IIR_bp<4> df2 = df; std::vector data(readImpulse.size()); data.at(0) = 1.0; df.process(data.begin(), data.end()); - + std::vector error(readImpulse.size()); for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(data.at(i) - readImpulse.at(i)); } double maxError = *std::max_element(error.begin(), error.end()); - REQUIRE(maxError < 1e-12); //typically error 1e-16 or less + REQUIRE(maxError < 1e-12); // typically error 1e-16 or less - //also check that we can process in blocks and get the same result + // also check that we can process in blocks and get the same result std::vector data2(readImpulse.size()); data2.at(0) = 1.0; - constexpr unsigned int blockSize {32}; - unsigned int index {0}; - for (index = 0; index <= data2.size() - blockSize; index += blockSize) { - df2.process(std::next(data2.begin(), index), std::next(data2.begin(), index + blockSize)); + constexpr unsigned int blockSize{ 32 }; + unsigned int index{ 0 }; + for (index = 0; index <= data2.size() - blockSize; + index += blockSize) { + df2.process(std::next(data2.begin(), index), + std::next(data2.begin(), index + blockSize)); } if (index < data2.size()) { @@ -282,13 +357,13 @@ TEST_CASE("Filter test", "[single-file]") SECTION("Test the BP filter gain") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; - constexpr double Q {1.1}; + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; + constexpr double Q{ 1.1 }; - std::array impulse1 {0}; + std::array impulse1{ 0 }; impulse1.at(0) = 1.0; - std::array impulse2 {0}; + std::array impulse2{ 0 }; impulse2.at(0) = 1.0; sdsp::casc_2o_IIR_bp<4> df; @@ -303,7 +378,7 @@ TEST_CASE("Filter test", "[single-file]") auto times_two = [](double& n) { n = 2.0 * n; }; std::for_each(impulse1.begin(), impulse1.end(), times_two); - std::array error {0}; + std::array error{ 0 }; for (size_t i = 0; i < error.size(); i++) { error.at(i) = std::abs(impulse1.at(i) - impulse2.at(i)); @@ -311,69 +386,24 @@ TEST_CASE("Filter test", "[single-file]") double maxError = *std::max_element(error.begin(), error.end()); REQUIRE(maxError < 1e-12); } +} - SECTION("Test filter preload") - { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; - constexpr double Q {1.1}; - constexpr double steadyValue {10.0}; - - { - std::array steadyLP; - std::fill(steadyLP.begin(), steadyLP.end(), steadyValue); - sdsp::casc2orderIIR<4> lpFilter; - lpFilter.SetLPCoeff(f0, fs); - lpFilter.PreloadFilter(steadyValue); - lpFilter.Process(steadyLP.begin(), steadyLP.end()); - auto calcError = [steadyValue](double& n) { n = std::abs(n - steadyValue); }; - std::for_each(steadyLP.begin(), steadyLP.end(), calcError); - double maxErrorLP = *std::max_element(steadyLP.begin(), steadyLP.end()); - REQUIRE(maxErrorLP < 1e-12); - } - - { - std::array steadyHP; - std::fill(steadyHP.begin(), steadyHP.end(), steadyValue); - sdsp::casc2orderIIR<4> hpFilter; - hpFilter.SetHPCoeff(f0, fs); - hpFilter.PreloadFilter(steadyValue); - hpFilter.Process(steadyHP.begin(), steadyHP.end()); - auto calcError = [](double& n) { n = std::abs(n); }; - std::for_each(steadyHP.begin(), steadyHP.end(), calcError); - double maxErrorHP = *std::max_element(steadyHP.begin(), steadyHP.end()); - REQUIRE(maxErrorHP < 1e-12); - } - - { - std::array steadyBP; - std::fill(steadyBP.begin(), steadyBP.end(), steadyValue); - sdsp::casc2orderIIR<4> bpFilter; - bpFilter.SetBPCoeff(f0, fs, Q); - bpFilter.PreloadFilter(steadyValue); - bpFilter.Process(steadyBP.begin(), steadyBP.end()); - auto calcError = [](double& n) { n = std::abs(n); }; - std::for_each(steadyBP.begin(), steadyBP.end(), calcError); - double maxErrorBP = *std::max_element(steadyBP.begin(), steadyBP.end()); - REQUIRE(maxErrorBP < 1e-12); - } - - } - +TEST_CASE("Filter benchmarks") +{ SECTION("LP Filter benchmark section") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; - //constexpr double Q {1.1}; - + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; + // constexpr double Q {1.1}; + sdsp::casc2orderIIR<4> df; df.SetLPCoeff(f0, fs); sdsp::casc_2o_IIR_lp<4> df2; df2.set_coeff(f0, fs); - std::array data {0.0}; - data.at(0) = 1.0; + std::array data{ 0.0 }; + data.at(0) = 1.0; BENCHMARK("Runtime configurable LP filter benchmark") { @@ -391,18 +421,18 @@ TEST_CASE("Filter test", "[single-file]") SECTION("HP Filter benchmark section") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; - //constexpr double Q {1.1}; - + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; + // constexpr double Q {1.1}; + sdsp::casc2orderIIR<4> df; df.SetHPCoeff(f0, fs); sdsp::casc_2o_IIR_hp<4> df2; df2.set_coeff(f0, fs); - std::array data {0.0}; - data.at(0) = 1.0; + std::array data{ 0.0 }; + data.at(0) = 1.0; BENCHMARK("Runtime configurable HP filter benchmark") { @@ -420,18 +450,18 @@ TEST_CASE("Filter test", "[single-file]") SECTION("BP Filter benchmark section") { - constexpr double fs {100e3}; - constexpr double f0 {10e3}; - constexpr double Q {1.1}; - + constexpr double fs{ 100e3 }; + constexpr double f0{ 10e3 }; + constexpr double Q{ 1.1 }; + sdsp::casc2orderIIR<4> df; df.SetBPCoeff(f0, fs, Q); sdsp::casc_2o_IIR_bp<4> df2; df2.set_coeff(f0, fs, Q); - std::array data {0.0}; - data.at(0) = 1.0; + std::array data{ 0.0 }; + data.at(0) = 1.0; BENCHMARK("Runtime configurable BP filter benchmark") {