summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc')
-rw-r--r--third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc175
1 files changed, 175 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc b/third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc
new file mode 100644
index 0000000000..a53036b08e
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/agc2/biquad_filter_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/biquad_filter.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "rtc_base/gunit.h"
+
+namespace webrtc {
+namespace {
+
+constexpr int kFrameSize = 8;
+constexpr int kNumFrames = 4;
+using FloatArraySequence =
+ std::array<std::array<float, kFrameSize>, kNumFrames>;
+
+constexpr FloatArraySequence kBiQuadInputSeq = {
+ {{{-87.166290f, -8.029022f, 101.619583f, -0.294296f, -5.825764f, -8.890625f,
+ 10.310432f, 54.845333f}},
+ {{-64.647644f, -6.883945f, 11.059189f, -95.242538f, -108.870834f,
+ 11.024944f, 63.044102f, -52.709583f}},
+ {{-32.350529f, -18.108028f, -74.022339f, -8.986874f, -1.525581f,
+ 103.705513f, 6.346226f, -14.319557f}},
+ {{22.645832f, -64.597153f, 55.462521f, -109.393188f, 10.117825f,
+ -40.019642f, -98.612228f, -8.330326f}}}};
+
+// Computed as `scipy.signal.butter(N=2, Wn=60/24000, btype='highpass')`.
+constexpr BiQuadFilter::Config kBiQuadConfig{
+ {0.99446179f, -1.98892358f, 0.99446179f},
+ {-1.98889291f, 0.98895425f}};
+
+// Comparing to scipy. The expected output is generated as follows:
+// zi = np.float32([0, 0])
+// for i in range(4):
+// yn, zi = scipy.signal.lfilter(B, A, x[i], zi=zi)
+// print(yn)
+constexpr FloatArraySequence kBiQuadOutputSeq = {
+ {{{-86.68354497f, -7.02175351f, 102.10290352f, -0.37487333f, -5.87205847f,
+ -8.85521608f, 10.33772563f, 54.51157181f}},
+ {{-64.92531604f, -6.76395978f, 11.15534507f, -94.68073341f, -107.18177856f,
+ 13.24642474f, 64.84288941f, -50.97822629f}},
+ {{-30.1579652f, -15.64850899f, -71.06662821f, -5.5883229f, 1.91175353f,
+ 106.5572003f, 8.57183046f, -12.06298473f}},
+ {{24.84286614f, -62.18094158f, 57.91488056f, -106.65685933f, 13.38760103f,
+ -36.60367134f, -94.44880104f, -3.59920354f}}}};
+
+// Fails for every pair from two equally sized rtc::ArrayView<float> views such
+// that their relative error is above a given threshold. If the expected value
+// of a pair is 0, `tolerance` is used to check the absolute error.
+void ExpectNearRelative(rtc::ArrayView<const float> expected,
+ rtc::ArrayView<const float> computed,
+ const float tolerance) {
+ // The relative error is undefined when the expected value is 0.
+ // When that happens, check the absolute error instead. `safe_den` is used
+ // below to implement such logic.
+ auto safe_den = [](float x) { return (x == 0.0f) ? 1.0f : std::fabs(x); };
+ ASSERT_EQ(expected.size(), computed.size());
+ for (size_t i = 0; i < expected.size(); ++i) {
+ const float abs_diff = std::fabs(expected[i] - computed[i]);
+ // No failure when the values are equal.
+ if (abs_diff == 0.0f) {
+ continue;
+ }
+ SCOPED_TRACE(i);
+ SCOPED_TRACE(expected[i]);
+ SCOPED_TRACE(computed[i]);
+ EXPECT_LE(abs_diff / safe_den(expected[i]), tolerance);
+ }
+}
+
+// Checks that filtering works when different containers are used both as input
+// and as output.
+TEST(BiQuadFilterTest, FilterNotInPlace) {
+ BiQuadFilter filter(kBiQuadConfig);
+ std::array<float, kFrameSize> samples;
+
+ // TODO(https://bugs.webrtc.org/8948): Add when the issue is fixed.
+ // FloatingPointExceptionObserver fpe_observer;
+
+ for (int i = 0; i < kNumFrames; ++i) {
+ SCOPED_TRACE(i);
+ filter.Process(kBiQuadInputSeq[i], samples);
+ ExpectNearRelative(kBiQuadOutputSeq[i], samples, 2e-4f);
+ }
+}
+
+// Checks that filtering works when the same container is used both as input and
+// as output.
+TEST(BiQuadFilterTest, FilterInPlace) {
+ BiQuadFilter filter(kBiQuadConfig);
+ std::array<float, kFrameSize> samples;
+
+ // TODO(https://bugs.webrtc.org/8948): Add when the issue is fixed.
+ // FloatingPointExceptionObserver fpe_observer;
+
+ for (int i = 0; i < kNumFrames; ++i) {
+ SCOPED_TRACE(i);
+ std::copy(kBiQuadInputSeq[i].begin(), kBiQuadInputSeq[i].end(),
+ samples.begin());
+ filter.Process({samples}, {samples});
+ ExpectNearRelative(kBiQuadOutputSeq[i], samples, 2e-4f);
+ }
+}
+
+// Checks that different configurations produce different outputs.
+TEST(BiQuadFilterTest, SetConfigDifferentOutput) {
+ BiQuadFilter filter(/*config=*/{{0.97803048f, -1.95606096f, 0.97803048f},
+ {-1.95557824f, 0.95654368f}});
+
+ std::array<float, kFrameSize> samples1;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples1);
+ }
+
+ filter.SetConfig(
+ {{0.09763107f, 0.19526215f, 0.09763107f}, {-0.94280904f, 0.33333333f}});
+ std::array<float, kFrameSize> samples2;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples2);
+ }
+
+ EXPECT_NE(samples1, samples2);
+}
+
+// Checks that when `SetConfig()` is called but the filter coefficients are the
+// same the filter state is reset.
+TEST(BiQuadFilterTest, SetConfigResetsState) {
+ BiQuadFilter filter(kBiQuadConfig);
+
+ std::array<float, kFrameSize> samples1;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples1);
+ }
+
+ filter.SetConfig(kBiQuadConfig);
+ std::array<float, kFrameSize> samples2;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples2);
+ }
+
+ EXPECT_EQ(samples1, samples2);
+}
+
+// Checks that when `Reset()` is called the filter state is reset.
+TEST(BiQuadFilterTest, Reset) {
+ BiQuadFilter filter(kBiQuadConfig);
+
+ std::array<float, kFrameSize> samples1;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples1);
+ }
+
+ filter.Reset();
+ std::array<float, kFrameSize> samples2;
+ for (int i = 0; i < kNumFrames; ++i) {
+ filter.Process(kBiQuadInputSeq[i], samples2);
+ }
+
+ EXPECT_EQ(samples1, samples2);
+}
+
+} // namespace
+} // namespace webrtc