blob: 5dc7b6dc6f29bd6d2896a85a65a92d0e17d78aeb [file] [log] [blame]
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -07001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "common_audio/sparse_fir_filter.h"
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070012
Jonas Olssona4d87372019-07-05 19:08:33 +020013#include <memory>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "common_audio/fir_filter.h"
Patrik Höglundf715c532017-11-17 11:04:15 +010016#include "common_audio/fir_filter_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/arraysize.h"
18#include "test/gtest.h"
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070019
20namespace webrtc {
21namespace {
22
23static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
Yves Gerey665174f2018-06-19 15:03:05 +020024static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f,
25 6.f, 7.f, 8.f, 9.f, 10.f};
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070026
27template <size_t N>
28void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) {
29 EXPECT_EQ(0, memcmp(expected_output, output, sizeof(output)));
30}
31
32} // namespace
33
34TEST(SparseFIRFilterTest, FilterAsIdentity) {
35 const float kCoeff = 1.f;
Peter Kastingdce40cf2015-08-24 14:52:23 -070036 const size_t kNumCoeff = 1;
37 const size_t kSparsity = 3;
38 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070039 float output[arraysize(kInput)];
40 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
41 filter.Filter(kInput, arraysize(kInput), output);
42 VerifyOutput(kInput, output);
43}
44
45TEST(SparseFIRFilterTest, SameOutputForScalarCoefficientAndDifferentSparsity) {
46 const float kCoeff = 2.f;
Peter Kastingdce40cf2015-08-24 14:52:23 -070047 const size_t kNumCoeff = 1;
48 const size_t kLowSparsity = 1;
49 const size_t kHighSparsity = 7;
50 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070051 float low_sparsity_output[arraysize(kInput)];
52 float high_sparsity_output[arraysize(kInput)];
Yves Gerey665174f2018-06-19 15:03:05 +020053 SparseFIRFilter low_sparsity_filter(&kCoeff, kNumCoeff, kLowSparsity,
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070054 kOffset);
Yves Gerey665174f2018-06-19 15:03:05 +020055 SparseFIRFilter high_sparsity_filter(&kCoeff, kNumCoeff, kHighSparsity,
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070056 kOffset);
57 low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output);
58 high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output);
59 VerifyOutput(low_sparsity_output, high_sparsity_output);
60}
61
62TEST(SparseFIRFilterTest, FilterUsedAsScalarMultiplication) {
63 const float kCoeff = 5.f;
Peter Kastingdce40cf2015-08-24 14:52:23 -070064 const size_t kNumCoeff = 1;
65 const size_t kSparsity = 5;
66 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070067 float output[arraysize(kInput)];
68 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
69 filter.Filter(kInput, arraysize(kInput), output);
70 EXPECT_FLOAT_EQ(5.f, output[0]);
71 EXPECT_FLOAT_EQ(20.f, output[3]);
72 EXPECT_FLOAT_EQ(25.f, output[4]);
73 EXPECT_FLOAT_EQ(50.f, output[arraysize(kInput) - 1]);
74}
75
76TEST(SparseFIRFilterTest, FilterUsedAsInputShifting) {
77 const float kCoeff = 1.f;
Peter Kastingdce40cf2015-08-24 14:52:23 -070078 const size_t kNumCoeff = 1;
79 const size_t kSparsity = 1;
80 const size_t kOffset = 4;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070081 float output[arraysize(kInput)];
82 SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
83 filter.Filter(kInput, arraysize(kInput), output);
84 EXPECT_FLOAT_EQ(0.f, output[0]);
85 EXPECT_FLOAT_EQ(0.f, output[3]);
86 EXPECT_FLOAT_EQ(1.f, output[4]);
87 EXPECT_FLOAT_EQ(2.f, output[5]);
88 EXPECT_FLOAT_EQ(6.f, output[arraysize(kInput) - 1]);
89}
90
91TEST(SparseFIRFilterTest, FilterUsedAsArbitraryWeighting) {
Peter Kastingdce40cf2015-08-24 14:52:23 -070092 const size_t kSparsity = 2;
93 const size_t kOffset = 1;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -070094 float output[arraysize(kInput)];
95 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
96 filter.Filter(kInput, arraysize(kInput), output);
97 EXPECT_FLOAT_EQ(0.f, output[0]);
98 EXPECT_FLOAT_EQ(0.9f, output[3]);
99 EXPECT_FLOAT_EQ(1.4f, output[4]);
100 EXPECT_FLOAT_EQ(2.4f, output[5]);
101 EXPECT_FLOAT_EQ(8.61f, output[arraysize(kInput) - 1]);
102}
103
104TEST(SparseFIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700105 const size_t kSparsity = 1;
106 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700107 float output[arraysize(kInput)];
108 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
109 filter.Filter(kInput, 2, output);
110 EXPECT_FLOAT_EQ(0.2f, output[0]);
111 EXPECT_FLOAT_EQ(0.7f, output[1]);
112}
113
114TEST(SparseFIRFilterTest, MultipleFilterCalls) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700115 const size_t kSparsity = 1;
116 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700117 float output[arraysize(kInput)];
118 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
119 filter.Filter(kInput, 2, output);
120 EXPECT_FLOAT_EQ(0.2f, output[0]);
121 EXPECT_FLOAT_EQ(0.7f, output[1]);
122 filter.Filter(kInput, 2, output);
123 EXPECT_FLOAT_EQ(1.3f, output[0]);
124 EXPECT_FLOAT_EQ(2.4f, output[1]);
125 filter.Filter(kInput, 2, output);
126 EXPECT_FLOAT_EQ(2.81f, output[0]);
127 EXPECT_FLOAT_EQ(2.62f, output[1]);
128 filter.Filter(kInput, 2, output);
129 EXPECT_FLOAT_EQ(2.81f, output[0]);
130 EXPECT_FLOAT_EQ(2.62f, output[1]);
131 filter.Filter(&kInput[3], 3, output);
132 EXPECT_FLOAT_EQ(3.41f, output[0]);
133 EXPECT_FLOAT_EQ(4.12f, output[1]);
134 EXPECT_FLOAT_EQ(6.21f, output[2]);
135 filter.Filter(&kInput[3], 3, output);
136 EXPECT_FLOAT_EQ(8.12f, output[0]);
137 EXPECT_FLOAT_EQ(9.14f, output[1]);
138 EXPECT_FLOAT_EQ(9.45f, output[2]);
139}
140
141TEST(SparseFIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700142 const size_t kSparsity = 3;
143 const size_t kOffset = 1;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700144 float output_block_based[arraysize(kInput)];
Yves Gerey665174f2018-06-19 15:03:05 +0200145 SparseFIRFilter filter_block(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700146 filter_block.Filter(kInput, arraysize(kInput), output_block_based);
147 float output_sample_based[arraysize(kInput)];
Yves Gerey665174f2018-06-19 15:03:05 +0200148 SparseFIRFilter filter_sample(kCoeffs, arraysize(kCoeffs), kSparsity,
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700149 kOffset);
150 for (size_t i = 0; i < arraysize(kInput); ++i)
151 filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]);
152 VerifyOutput(output_block_based, output_sample_based);
153}
154
155TEST(SparseFIRFilterTest, SimpleHighPassFilter) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700156 const size_t kSparsity = 2;
157 const size_t kOffset = 2;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700158 const float kHPCoeffs[] = {1.f, -1.f};
Yves Gerey665174f2018-06-19 15:03:05 +0200159 const float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f,
160 1.f, 1.f, 1.f, 1.f, 1.f};
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700161 float output[arraysize(kConstantInput)];
162 SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset);
163 filter.Filter(kConstantInput, arraysize(kConstantInput), output);
164 EXPECT_FLOAT_EQ(0.f, output[0]);
165 EXPECT_FLOAT_EQ(0.f, output[1]);
166 EXPECT_FLOAT_EQ(1.f, output[2]);
167 EXPECT_FLOAT_EQ(1.f, output[3]);
168 for (size_t i = kSparsity + kOffset; i < arraysize(kConstantInput); ++i)
169 EXPECT_FLOAT_EQ(0.f, output[i]);
170}
171
172TEST(SparseFIRFilterTest, SimpleLowPassFilter) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700173 const size_t kSparsity = 2;
174 const size_t kOffset = 2;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700175 const float kLPCoeffs[] = {1.f, 1.f};
Yves Gerey665174f2018-06-19 15:03:05 +0200176 const float kHighFrequencyInput[] = {1.f, 1.f, -1.f, -1.f, 1.f,
177 1.f, -1.f, -1.f, 1.f, 1.f};
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700178 float output[arraysize(kHighFrequencyInput)];
179 SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset);
180 filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output);
181 EXPECT_FLOAT_EQ(0.f, output[0]);
182 EXPECT_FLOAT_EQ(0.f, output[1]);
183 EXPECT_FLOAT_EQ(1.f, output[2]);
184 EXPECT_FLOAT_EQ(1.f, output[3]);
185 for (size_t i = kSparsity + kOffset; i < arraysize(kHighFrequencyInput); ++i)
186 EXPECT_FLOAT_EQ(0.f, output[i]);
187}
188
189TEST(SparseFIRFilterTest, SameOutputWhenSwappedCoefficientsAndInput) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700190 const size_t kSparsity = 1;
191 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700192 float output[arraysize(kCoeffs)];
193 float output_swapped[arraysize(kCoeffs)];
194 SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
195 // Use arraysize(kCoeffs) for in_length to get same-length outputs.
196 filter.Filter(kInput, arraysize(kCoeffs), output);
Yves Gerey665174f2018-06-19 15:03:05 +0200197 SparseFIRFilter filter_swapped(kInput, arraysize(kCoeffs), kSparsity,
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700198 kOffset);
199 filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped);
200 VerifyOutput(output, output_swapped);
201}
202
203TEST(SparseFIRFilterTest, SameOutputAsFIRFilterWhenSparsityOneAndOffsetZero) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700204 const size_t kSparsity = 1;
205 const size_t kOffset = 0;
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700206 float output[arraysize(kInput)];
207 float sparse_output[arraysize(kInput)];
kwibergc2b785d2016-02-24 05:22:32 -0800208 std::unique_ptr<FIRFilter> filter(
Patrik Höglundf715c532017-11-17 11:04:15 +0100209 CreateFirFilter(kCoeffs, arraysize(kCoeffs), arraysize(kInput)));
Yves Gerey665174f2018-06-19 15:03:05 +0200210 SparseFIRFilter sparse_filter(kCoeffs, arraysize(kCoeffs), kSparsity,
Alejandro Luebsa9c0ae22015-04-14 15:51:28 -0700211 kOffset);
212 filter->Filter(kInput, arraysize(kInput), output);
213 sparse_filter.Filter(kInput, arraysize(kInput), sparse_output);
214 for (size_t i = 0; i < arraysize(kInput); ++i) {
215 EXPECT_FLOAT_EQ(output[i], sparse_output[i]);
216 }
217}
218
219} // namespace webrtc