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