Home | History | Annotate | Download | only in common_audio
      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 "webrtc/common_audio/fir_filter.h"
     12 
     13 #include <string.h>
     14 
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "webrtc/base/scoped_ptr.h"
     17 
     18 namespace webrtc {
     19 namespace {
     20 
     21 static const float kCoefficients[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
     22 static const size_t kCoefficientsLength = sizeof(kCoefficients) /
     23                                        sizeof(kCoefficients[0]);
     24 
     25 static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
     26                                       8.f, 9.f, 10.f};
     27 static const size_t kInputLength = sizeof(kInput) /
     28                                       sizeof(kInput[0]);
     29 
     30 void VerifyOutput(const float* expected_output,
     31                   const float* output,
     32                   size_t length) {
     33   EXPECT_EQ(0, memcmp(expected_output,
     34                       output,
     35                       length * sizeof(expected_output[0])));
     36 }
     37 
     38 }  // namespace
     39 
     40 TEST(FIRFilterTest, FilterAsIdentity) {
     41   const float kCoefficients[] = {1.f, 0.f, 0.f, 0.f, 0.f};
     42   float output[kInputLength];
     43   rtc::scoped_ptr<FIRFilter> filter(
     44       FIRFilter::Create(kCoefficients, kCoefficientsLength, kInputLength));
     45   filter->Filter(kInput, kInputLength, output);
     46 
     47   VerifyOutput(kInput, output, kInputLength);
     48 }
     49 
     50 TEST(FIRFilterTest, FilterUsedAsScalarMultiplication) {
     51   const float kCoefficients[] = {5.f, 0.f, 0.f, 0.f, 0.f};
     52   float output[kInputLength];
     53   rtc::scoped_ptr<FIRFilter> filter(
     54       FIRFilter::Create(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 
     63 TEST(FIRFilterTest, FilterUsedAsInputShifting) {
     64   const float kCoefficients[] = {0.f, 0.f, 0.f, 0.f, 1.f};
     65   float output[kInputLength];
     66   rtc::scoped_ptr<FIRFilter> filter(
     67       FIRFilter::Create(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 
     77 TEST(FIRFilterTest, FilterUsedAsArbitraryWeighting) {
     78   float output[kInputLength];
     79   rtc::scoped_ptr<FIRFilter> filter(
     80       FIRFilter::Create(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 
     90 TEST(FIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) {
     91   float output[kInputLength];
     92   rtc::scoped_ptr<FIRFilter> filter(
     93       FIRFilter::Create(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(FIRFilter::Create(
     99       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 
    107 TEST(FIRFilterTest, MultipleFilterCalls) {
    108   float output[kInputLength];
    109   rtc::scoped_ptr<FIRFilter> filter(
    110       FIRFilter::Create(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 
    138 TEST(FIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) {
    139   float output_block_based[kInputLength];
    140   rtc::scoped_ptr<FIRFilter> filter(
    141       FIRFilter::Create(kCoefficients, kCoefficientsLength, kInputLength));
    142   filter->Filter(kInput, kInputLength, output_block_based);
    143 
    144   float output_sample_based[kInputLength];
    145   filter.reset(FIRFilter::Create(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,
    151                       output_block_based,
    152                       kInputLength));
    153 }
    154 
    155 TEST(FIRFilterTest, SimplestHighPassFilter) {
    156   const float kCoefficients[] = {1.f, -1.f};
    157   const size_t kCoefficientsLength = sizeof(kCoefficients) /
    158                                   sizeof(kCoefficients[0]);
    159 
    160   float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
    161   const size_t kConstantInputLength = sizeof(kConstantInput) /
    162       sizeof(kConstantInput[0]);
    163 
    164   float output[kConstantInputLength];
    165   rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
    166       kCoefficients, kCoefficientsLength, kConstantInputLength));
    167   filter->Filter(kConstantInput, kConstantInputLength, output);
    168   EXPECT_FLOAT_EQ(1.f, output[0]);
    169   for (size_t i = kCoefficientsLength - 1; i < kConstantInputLength; ++i) {
    170     EXPECT_FLOAT_EQ(0.f, output[i]);
    171   }
    172 }
    173 
    174 TEST(FIRFilterTest, SimplestLowPassFilter) {
    175   const float kCoefficients[] = {1.f, 1.f};
    176   const size_t kCoefficientsLength = sizeof(kCoefficients) /
    177                                   sizeof(kCoefficients[0]);
    178 
    179   float kHighFrequencyInput[] = {-1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f};
    180   const size_t kHighFrequencyInputLength = sizeof(kHighFrequencyInput) /
    181                                         sizeof(kHighFrequencyInput[0]);
    182 
    183   float output[kHighFrequencyInputLength];
    184   rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
    185       kCoefficients, kCoefficientsLength, kHighFrequencyInputLength));
    186   filter->Filter(kHighFrequencyInput, kHighFrequencyInputLength, output);
    187   EXPECT_FLOAT_EQ(-1.f, output[0]);
    188   for (size_t i = kCoefficientsLength - 1; i < kHighFrequencyInputLength; ++i) {
    189     EXPECT_FLOAT_EQ(0.f, output[i]);
    190   }
    191 }
    192 
    193 TEST(FIRFilterTest, SameOutputWhenSwapedCoefficientsAndInput) {
    194   float output[kCoefficientsLength];
    195   float output_swaped[kCoefficientsLength];
    196   rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
    197       kCoefficients, kCoefficientsLength, kCoefficientsLength));
    198   // Use kCoefficientsLength for in_length to get same-length outputs.
    199   filter->Filter(kInput, kCoefficientsLength, output);
    200 
    201   filter.reset(FIRFilter::Create(
    202       kInput, kCoefficientsLength, kCoefficientsLength));
    203   filter->Filter(kCoefficients, kCoefficientsLength, output_swaped);
    204 
    205   for (size_t i = 0 ; i < kCoefficientsLength; ++i) {
    206     EXPECT_FLOAT_EQ(output[i], output_swaped[i]);
    207   }
    208 }
    209 
    210 }  // namespace webrtc
    211