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