1 /*
2 * Copyright (c) 2014 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
11 #include "common_audio/fir_filter.h"
12
13 #include <string.h>
14
15 #include <memory>
16
17 #include "common_audio/fir_filter_factory.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21 namespace {
22
23 static const float kCoefficients[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
24 static const size_t kCoefficientsLength =
25 sizeof(kCoefficients) / sizeof(kCoefficients[0]);
26
27 static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f,
28 6.f, 7.f, 8.f, 9.f, 10.f};
29 static const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
30
VerifyOutput(const float * expected_output,const float * output,size_t length)31 void VerifyOutput(const float* expected_output,
32 const float* output,
33 size_t length) {
34 EXPECT_EQ(
35 0, memcmp(expected_output, output, length * sizeof(expected_output[0])));
36 }
37
38 } // namespace
39
TEST(FIRFilterTest,FilterAsIdentity)40 TEST(FIRFilterTest, FilterAsIdentity) {
41 const float kCoefficients[] = {1.f, 0.f, 0.f, 0.f, 0.f};
42 float output[kInputLength];
43 std::unique_ptr<FIRFilter> filter(
44 CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength));
45 filter->Filter(kInput, kInputLength, output);
46
47 VerifyOutput(kInput, output, kInputLength);
48 }
49
TEST(FIRFilterTest,FilterUsedAsScalarMultiplication)50 TEST(FIRFilterTest, FilterUsedAsScalarMultiplication) {
51 const float kCoefficients[] = {5.f, 0.f, 0.f, 0.f, 0.f};
52 float output[kInputLength];
53 std::unique_ptr<FIRFilter> filter(
54 CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength));
55 filter->Filter(kInput, kInputLength, output);
56
57 EXPECT_FLOAT_EQ(5.f, output[0]);
58 EXPECT_FLOAT_EQ(20.f, output[3]);
59 EXPECT_FLOAT_EQ(25.f, output[4]);
60 EXPECT_FLOAT_EQ(50.f, output[kInputLength - 1]);
61 }
62
TEST(FIRFilterTest,FilterUsedAsInputShifting)63 TEST(FIRFilterTest, FilterUsedAsInputShifting) {
64 const float kCoefficients[] = {0.f, 0.f, 0.f, 0.f, 1.f};
65 float output[kInputLength];
66 std::unique_ptr<FIRFilter> filter(
67 CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength));
68 filter->Filter(kInput, kInputLength, output);
69
70 EXPECT_FLOAT_EQ(0.f, output[0]);
71 EXPECT_FLOAT_EQ(0.f, output[3]);
72 EXPECT_FLOAT_EQ(1.f, output[4]);
73 EXPECT_FLOAT_EQ(2.f, output[5]);
74 EXPECT_FLOAT_EQ(6.f, output[kInputLength - 1]);
75 }
76
TEST(FIRFilterTest,FilterUsedAsArbitraryWeighting)77 TEST(FIRFilterTest, FilterUsedAsArbitraryWeighting) {
78 float output[kInputLength];
79 std::unique_ptr<FIRFilter> filter(
80 CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength));
81 filter->Filter(kInput, kInputLength, output);
82
83 EXPECT_FLOAT_EQ(0.2f, output[0]);
84 EXPECT_FLOAT_EQ(3.4f, output[3]);
85 EXPECT_FLOAT_EQ(5.21f, output[4]);
86 EXPECT_FLOAT_EQ(7.02f, output[5]);
87 EXPECT_FLOAT_EQ(14.26f, output[kInputLength - 1]);
88 }
89
TEST(FIRFilterTest,FilterInLengthLesserOrEqualToCoefficientsLength)90 TEST(FIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) {
91 float output[kInputLength];
92 std::unique_ptr<FIRFilter> filter(
93 CreateFirFilter(kCoefficients, kCoefficientsLength, 2));
94 filter->Filter(kInput, 2, output);
95
96 EXPECT_FLOAT_EQ(0.2f, output[0]);
97 EXPECT_FLOAT_EQ(0.7f, output[1]);
98 filter.reset(
99 CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength));
100 filter->Filter(kInput, kCoefficientsLength, output);
101
102 EXPECT_FLOAT_EQ(0.2f, output[0]);
103 EXPECT_FLOAT_EQ(3.4f, output[3]);
104 EXPECT_FLOAT_EQ(5.21f, output[4]);
105 }
106
TEST(FIRFilterTest,MultipleFilterCalls)107 TEST(FIRFilterTest, MultipleFilterCalls) {
108 float output[kInputLength];
109 std::unique_ptr<FIRFilter> filter(
110 CreateFirFilter(kCoefficients, kCoefficientsLength, 3));
111 filter->Filter(kInput, 2, output);
112 EXPECT_FLOAT_EQ(0.2f, output[0]);
113 EXPECT_FLOAT_EQ(0.7f, output[1]);
114
115 filter->Filter(kInput, 2, output);
116 EXPECT_FLOAT_EQ(1.3f, output[0]);
117 EXPECT_FLOAT_EQ(2.4f, output[1]);
118
119 filter->Filter(kInput, 2, output);
120 EXPECT_FLOAT_EQ(2.81f, output[0]);
121 EXPECT_FLOAT_EQ(2.62f, output[1]);
122
123 filter->Filter(kInput, 2, output);
124 EXPECT_FLOAT_EQ(2.81f, output[0]);
125 EXPECT_FLOAT_EQ(2.62f, output[1]);
126
127 filter->Filter(&kInput[3], 3, output);
128 EXPECT_FLOAT_EQ(3.41f, output[0]);
129 EXPECT_FLOAT_EQ(4.12f, output[1]);
130 EXPECT_FLOAT_EQ(6.21f, output[2]);
131
132 filter->Filter(&kInput[3], 3, output);
133 EXPECT_FLOAT_EQ(8.12f, output[0]);
134 EXPECT_FLOAT_EQ(9.14f, output[1]);
135 EXPECT_FLOAT_EQ(9.45f, output[2]);
136 }
137
TEST(FIRFilterTest,VerifySampleBasedVsBlockBasedFiltering)138 TEST(FIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) {
139 float output_block_based[kInputLength];
140 std::unique_ptr<FIRFilter> filter(
141 CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength));
142 filter->Filter(kInput, kInputLength, output_block_based);
143
144 float output_sample_based[kInputLength];
145 filter.reset(CreateFirFilter(kCoefficients, kCoefficientsLength, 1));
146 for (size_t i = 0; i < kInputLength; ++i) {
147 filter->Filter(&kInput[i], 1, &output_sample_based[i]);
148 }
149
150 EXPECT_EQ(0, memcmp(output_sample_based, output_block_based, kInputLength));
151 }
152
TEST(FIRFilterTest,SimplestHighPassFilter)153 TEST(FIRFilterTest, SimplestHighPassFilter) {
154 const float kCoefficients[] = {1.f, -1.f};
155 const size_t kCoefficientsLength =
156 sizeof(kCoefficients) / sizeof(kCoefficients[0]);
157
158 float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
159 const size_t kConstantInputLength =
160 sizeof(kConstantInput) / sizeof(kConstantInput[0]);
161
162 float output[kConstantInputLength];
163 std::unique_ptr<FIRFilter> filter(CreateFirFilter(
164 kCoefficients, kCoefficientsLength, kConstantInputLength));
165 filter->Filter(kConstantInput, kConstantInputLength, output);
166 EXPECT_FLOAT_EQ(1.f, output[0]);
167 for (size_t i = kCoefficientsLength - 1; i < kConstantInputLength; ++i) {
168 EXPECT_FLOAT_EQ(0.f, output[i]);
169 }
170 }
171
TEST(FIRFilterTest,SimplestLowPassFilter)172 TEST(FIRFilterTest, SimplestLowPassFilter) {
173 const float kCoefficients[] = {1.f, 1.f};
174 const size_t kCoefficientsLength =
175 sizeof(kCoefficients) / sizeof(kCoefficients[0]);
176
177 float kHighFrequencyInput[] = {-1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f};
178 const size_t kHighFrequencyInputLength =
179 sizeof(kHighFrequencyInput) / sizeof(kHighFrequencyInput[0]);
180
181 float output[kHighFrequencyInputLength];
182 std::unique_ptr<FIRFilter> filter(CreateFirFilter(
183 kCoefficients, kCoefficientsLength, kHighFrequencyInputLength));
184 filter->Filter(kHighFrequencyInput, kHighFrequencyInputLength, output);
185 EXPECT_FLOAT_EQ(-1.f, output[0]);
186 for (size_t i = kCoefficientsLength - 1; i < kHighFrequencyInputLength; ++i) {
187 EXPECT_FLOAT_EQ(0.f, output[i]);
188 }
189 }
190
TEST(FIRFilterTest,SameOutputWhenSwapedCoefficientsAndInput)191 TEST(FIRFilterTest, SameOutputWhenSwapedCoefficientsAndInput) {
192 float output[kCoefficientsLength];
193 float output_swaped[kCoefficientsLength];
194 std::unique_ptr<FIRFilter> filter(
195 CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength));
196 // Use kCoefficientsLength for in_length to get same-length outputs.
197 filter->Filter(kInput, kCoefficientsLength, output);
198
199 filter.reset(
200 CreateFirFilter(kInput, kCoefficientsLength, kCoefficientsLength));
201 filter->Filter(kCoefficients, kCoefficientsLength, output_swaped);
202
203 for (size_t i = 0; i < kCoefficientsLength; ++i) {
204 EXPECT_FLOAT_EQ(output[i], output_swaped[i]);
205 }
206 }
207
208 } // namespace webrtc
209