Home | History | Annotate | Download | only in common_audio
      1 /*
      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 
     11 #include "webrtc/common_audio/sparse_fir_filter.h"
     12 
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "webrtc/base/arraysize.h"
     15 #include "webrtc/base/scoped_ptr.h"
     16 #include "webrtc/common_audio/fir_filter.h"
     17 
     18 namespace webrtc {
     19 namespace {
     20 
     21 static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
     22 static const float kInput[] =
     23     {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f};
     24 
     25 template <size_t N>
     26 void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) {
     27   EXPECT_EQ(0, memcmp(expected_output, output, sizeof(output)));
     28 }
     29 
     30 }  // namespace
     31 
     32 TEST(SparseFIRFilterTest, FilterAsIdentity) {
     33   const float kCoeff = 1.f;
     34   const size_t kNumCoeff = 1;
     35   const size_t kSparsity = 3;
     36   const size_t kOffset = 0;
     37   float output[arraysize(kInput)];
     38   SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
     39   filter.Filter(kInput, arraysize(kInput), output);
     40   VerifyOutput(kInput, output);
     41 }
     42 
     43 TEST(SparseFIRFilterTest, SameOutputForScalarCoefficientAndDifferentSparsity) {
     44   const float kCoeff = 2.f;
     45   const size_t kNumCoeff = 1;
     46   const size_t kLowSparsity = 1;
     47   const size_t kHighSparsity = 7;
     48   const size_t kOffset = 0;
     49   float low_sparsity_output[arraysize(kInput)];
     50   float high_sparsity_output[arraysize(kInput)];
     51   SparseFIRFilter low_sparsity_filter(&kCoeff,
     52                                       kNumCoeff,
     53                                       kLowSparsity,
     54                                       kOffset);
     55   SparseFIRFilter high_sparsity_filter(&kCoeff,
     56                                        kNumCoeff,
     57                                        kHighSparsity,
     58                                        kOffset);
     59   low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output);
     60   high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output);
     61   VerifyOutput(low_sparsity_output, high_sparsity_output);
     62 }
     63 
     64 TEST(SparseFIRFilterTest, FilterUsedAsScalarMultiplication) {
     65   const float kCoeff = 5.f;
     66   const size_t kNumCoeff = 1;
     67   const size_t kSparsity = 5;
     68   const size_t kOffset = 0;
     69   float output[arraysize(kInput)];
     70   SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
     71   filter.Filter(kInput, arraysize(kInput), output);
     72   EXPECT_FLOAT_EQ(5.f, output[0]);
     73   EXPECT_FLOAT_EQ(20.f, output[3]);
     74   EXPECT_FLOAT_EQ(25.f, output[4]);
     75   EXPECT_FLOAT_EQ(50.f, output[arraysize(kInput) - 1]);
     76 }
     77 
     78 TEST(SparseFIRFilterTest, FilterUsedAsInputShifting) {
     79   const float kCoeff = 1.f;
     80   const size_t kNumCoeff = 1;
     81   const size_t kSparsity = 1;
     82   const size_t kOffset = 4;
     83   float output[arraysize(kInput)];
     84   SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
     85   filter.Filter(kInput, arraysize(kInput), output);
     86   EXPECT_FLOAT_EQ(0.f, output[0]);
     87   EXPECT_FLOAT_EQ(0.f, output[3]);
     88   EXPECT_FLOAT_EQ(1.f, output[4]);
     89   EXPECT_FLOAT_EQ(2.f, output[5]);
     90   EXPECT_FLOAT_EQ(6.f, output[arraysize(kInput) - 1]);
     91 }
     92 
     93 TEST(SparseFIRFilterTest, FilterUsedAsArbitraryWeighting) {
     94   const size_t kSparsity = 2;
     95   const size_t kOffset = 1;
     96   float output[arraysize(kInput)];
     97   SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
     98   filter.Filter(kInput, arraysize(kInput), output);
     99   EXPECT_FLOAT_EQ(0.f, output[0]);
    100   EXPECT_FLOAT_EQ(0.9f, output[3]);
    101   EXPECT_FLOAT_EQ(1.4f, output[4]);
    102   EXPECT_FLOAT_EQ(2.4f, output[5]);
    103   EXPECT_FLOAT_EQ(8.61f, output[arraysize(kInput) - 1]);
    104 }
    105 
    106 TEST(SparseFIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) {
    107   const size_t kSparsity = 1;
    108   const size_t kOffset = 0;
    109   float output[arraysize(kInput)];
    110   SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
    111   filter.Filter(kInput, 2, output);
    112   EXPECT_FLOAT_EQ(0.2f, output[0]);
    113   EXPECT_FLOAT_EQ(0.7f, output[1]);
    114 }
    115 
    116 TEST(SparseFIRFilterTest, MultipleFilterCalls) {
    117   const size_t kSparsity = 1;
    118   const size_t kOffset = 0;
    119   float output[arraysize(kInput)];
    120   SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
    121   filter.Filter(kInput, 2, output);
    122   EXPECT_FLOAT_EQ(0.2f, output[0]);
    123   EXPECT_FLOAT_EQ(0.7f, output[1]);
    124   filter.Filter(kInput, 2, output);
    125   EXPECT_FLOAT_EQ(1.3f, output[0]);
    126   EXPECT_FLOAT_EQ(2.4f, output[1]);
    127   filter.Filter(kInput, 2, output);
    128   EXPECT_FLOAT_EQ(2.81f, output[0]);
    129   EXPECT_FLOAT_EQ(2.62f, output[1]);
    130   filter.Filter(kInput, 2, output);
    131   EXPECT_FLOAT_EQ(2.81f, output[0]);
    132   EXPECT_FLOAT_EQ(2.62f, output[1]);
    133   filter.Filter(&kInput[3], 3, output);
    134   EXPECT_FLOAT_EQ(3.41f, output[0]);
    135   EXPECT_FLOAT_EQ(4.12f, output[1]);
    136   EXPECT_FLOAT_EQ(6.21f, output[2]);
    137   filter.Filter(&kInput[3], 3, output);
    138   EXPECT_FLOAT_EQ(8.12f, output[0]);
    139   EXPECT_FLOAT_EQ(9.14f, output[1]);
    140   EXPECT_FLOAT_EQ(9.45f, output[2]);
    141 }
    142 
    143 TEST(SparseFIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) {
    144   const size_t kSparsity = 3;
    145   const size_t kOffset = 1;
    146   float output_block_based[arraysize(kInput)];
    147   SparseFIRFilter filter_block(kCoeffs,
    148                                arraysize(kCoeffs),
    149                                kSparsity,
    150                                kOffset);
    151   filter_block.Filter(kInput, arraysize(kInput), output_block_based);
    152   float output_sample_based[arraysize(kInput)];
    153   SparseFIRFilter filter_sample(kCoeffs,
    154                                 arraysize(kCoeffs),
    155                                 kSparsity,
    156                                 kOffset);
    157   for (size_t i = 0; i < arraysize(kInput); ++i)
    158     filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]);
    159   VerifyOutput(output_block_based, output_sample_based);
    160 }
    161 
    162 TEST(SparseFIRFilterTest, SimpleHighPassFilter) {
    163   const size_t kSparsity = 2;
    164   const size_t kOffset = 2;
    165   const float kHPCoeffs[] = {1.f, -1.f};
    166   const float kConstantInput[] =
    167       {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
    168   float output[arraysize(kConstantInput)];
    169   SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset);
    170   filter.Filter(kConstantInput, arraysize(kConstantInput), output);
    171   EXPECT_FLOAT_EQ(0.f, output[0]);
    172   EXPECT_FLOAT_EQ(0.f, output[1]);
    173   EXPECT_FLOAT_EQ(1.f, output[2]);
    174   EXPECT_FLOAT_EQ(1.f, output[3]);
    175   for (size_t i = kSparsity + kOffset; i < arraysize(kConstantInput); ++i)
    176     EXPECT_FLOAT_EQ(0.f, output[i]);
    177 }
    178 
    179 TEST(SparseFIRFilterTest, SimpleLowPassFilter) {
    180   const size_t kSparsity = 2;
    181   const size_t kOffset = 2;
    182   const float kLPCoeffs[] = {1.f, 1.f};
    183   const float kHighFrequencyInput[] =
    184       {1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f};
    185   float output[arraysize(kHighFrequencyInput)];
    186   SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset);
    187   filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output);
    188   EXPECT_FLOAT_EQ(0.f, output[0]);
    189   EXPECT_FLOAT_EQ(0.f, output[1]);
    190   EXPECT_FLOAT_EQ(1.f, output[2]);
    191   EXPECT_FLOAT_EQ(1.f, output[3]);
    192   for (size_t i = kSparsity + kOffset; i < arraysize(kHighFrequencyInput); ++i)
    193     EXPECT_FLOAT_EQ(0.f, output[i]);
    194 }
    195 
    196 TEST(SparseFIRFilterTest, SameOutputWhenSwappedCoefficientsAndInput) {
    197   const size_t kSparsity = 1;
    198   const size_t kOffset = 0;
    199   float output[arraysize(kCoeffs)];
    200   float output_swapped[arraysize(kCoeffs)];
    201   SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
    202   // Use arraysize(kCoeffs) for in_length to get same-length outputs.
    203   filter.Filter(kInput, arraysize(kCoeffs), output);
    204   SparseFIRFilter filter_swapped(kInput,
    205                                  arraysize(kCoeffs),
    206                                  kSparsity,
    207                                  kOffset);
    208   filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped);
    209   VerifyOutput(output, output_swapped);
    210 }
    211 
    212 TEST(SparseFIRFilterTest, SameOutputAsFIRFilterWhenSparsityOneAndOffsetZero) {
    213   const size_t kSparsity = 1;
    214   const size_t kOffset = 0;
    215   float output[arraysize(kInput)];
    216   float sparse_output[arraysize(kInput)];
    217   rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(kCoeffs,
    218                                                       arraysize(kCoeffs),
    219                                                       arraysize(kInput)));
    220   SparseFIRFilter sparse_filter(kCoeffs,
    221                                 arraysize(kCoeffs),
    222                                 kSparsity,
    223                                 kOffset);
    224   filter->Filter(kInput, arraysize(kInput), output);
    225   sparse_filter.Filter(kInput, arraysize(kInput), sparse_output);
    226   for (size_t i = 0; i < arraysize(kInput); ++i) {
    227     EXPECT_FLOAT_EQ(output[i], sparse_output[i]);
    228   }
    229 }
    230 
    231 }  // namespace webrtc
    232