Home | History | Annotate | Download | only in beamformer
      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 // MSVC++ requires this to be set before any other includes to get M_PI.
     12 #define _USE_MATH_DEFINES
     13 
     14 #include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
     15 
     16 #include <math.h>
     17 
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 namespace webrtc {
     21 namespace {
     22 
     23 const int kChunkSizeMs = 10;
     24 const int kSampleRateHz = 16000;
     25 
     26 SphericalPointf AzimuthToSphericalPoint(float azimuth_radians) {
     27   return SphericalPointf(azimuth_radians, 0.f, 1.f);
     28 }
     29 
     30 void Verify(NonlinearBeamformer* bf, float target_azimuth_radians) {
     31   EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(target_azimuth_radians)));
     32   EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(
     33       target_azimuth_radians - NonlinearBeamformer::kHalfBeamWidthRadians +
     34       0.001f)));
     35   EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(
     36       target_azimuth_radians + NonlinearBeamformer::kHalfBeamWidthRadians -
     37       0.001f)));
     38   EXPECT_FALSE(bf->IsInBeam(AzimuthToSphericalPoint(
     39       target_azimuth_radians - NonlinearBeamformer::kHalfBeamWidthRadians -
     40       0.001f)));
     41   EXPECT_FALSE(bf->IsInBeam(AzimuthToSphericalPoint(
     42       target_azimuth_radians + NonlinearBeamformer::kHalfBeamWidthRadians +
     43       0.001f)));
     44 }
     45 
     46 void AimAndVerify(NonlinearBeamformer* bf, float target_azimuth_radians) {
     47   bf->AimAt(AzimuthToSphericalPoint(target_azimuth_radians));
     48   Verify(bf, target_azimuth_radians);
     49 }
     50 
     51 }  // namespace
     52 
     53 TEST(NonlinearBeamformerTest, AimingModifiesBeam) {
     54   std::vector<Point> array_geometry;
     55   array_geometry.push_back(Point(-0.025f, 0.f, 0.f));
     56   array_geometry.push_back(Point(0.025f, 0.f, 0.f));
     57   NonlinearBeamformer bf(array_geometry);
     58   bf.Initialize(kChunkSizeMs, kSampleRateHz);
     59   // The default constructor parameter sets the target angle to PI / 2.
     60   Verify(&bf, static_cast<float>(M_PI) / 2.f);
     61   AimAndVerify(&bf, static_cast<float>(M_PI) / 3.f);
     62   AimAndVerify(&bf, 3.f * static_cast<float>(M_PI) / 4.f);
     63   AimAndVerify(&bf, static_cast<float>(M_PI) / 6.f);
     64   AimAndVerify(&bf, static_cast<float>(M_PI));
     65 }
     66 
     67 TEST(NonlinearBeamformerTest, InterfAnglesTakeAmbiguityIntoAccount) {
     68   {
     69     // For linear arrays there is ambiguity.
     70     std::vector<Point> array_geometry;
     71     array_geometry.push_back(Point(-0.1f, 0.f, 0.f));
     72     array_geometry.push_back(Point(0.f, 0.f, 0.f));
     73     array_geometry.push_back(Point(0.2f, 0.f, 0.f));
     74     NonlinearBeamformer bf(array_geometry);
     75     bf.Initialize(kChunkSizeMs, kSampleRateHz);
     76     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
     77     EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
     78                     bf.interf_angles_radians_[0]);
     79     EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
     80                     bf.interf_angles_radians_[1]);
     81     bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
     82     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
     83     EXPECT_FLOAT_EQ(M_PI - bf.away_radians_ / 2.f,
     84                     bf.interf_angles_radians_[0]);
     85     EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
     86   }
     87   {
     88     // For planar arrays with normal in the xy-plane there is ambiguity.
     89     std::vector<Point> array_geometry;
     90     array_geometry.push_back(Point(-0.1f, 0.f, 0.f));
     91     array_geometry.push_back(Point(0.f, 0.f, 0.f));
     92     array_geometry.push_back(Point(0.2f, 0.f, 0.f));
     93     array_geometry.push_back(Point(0.1f, 0.f, 0.2f));
     94     array_geometry.push_back(Point(0.f, 0.f, -0.1f));
     95     NonlinearBeamformer bf(array_geometry);
     96     bf.Initialize(kChunkSizeMs, kSampleRateHz);
     97     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
     98     EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
     99                     bf.interf_angles_radians_[0]);
    100     EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
    101                     bf.interf_angles_radians_[1]);
    102     bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
    103     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
    104     EXPECT_FLOAT_EQ(M_PI - bf.away_radians_ / 2.f,
    105                     bf.interf_angles_radians_[0]);
    106     EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
    107   }
    108   {
    109     // For planar arrays with normal not in the xy-plane there is no ambiguity.
    110     std::vector<Point> array_geometry;
    111     array_geometry.push_back(Point(0.f, 0.f, 0.f));
    112     array_geometry.push_back(Point(0.2f, 0.f, 0.f));
    113     array_geometry.push_back(Point(0.f, 0.1f, -0.2f));
    114     NonlinearBeamformer bf(array_geometry);
    115     bf.Initialize(kChunkSizeMs, kSampleRateHz);
    116     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
    117     EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
    118                     bf.interf_angles_radians_[0]);
    119     EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
    120                     bf.interf_angles_radians_[1]);
    121     bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
    122     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
    123     EXPECT_FLOAT_EQ(-bf.away_radians_ / 2.f, bf.interf_angles_radians_[0]);
    124     EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
    125   }
    126   {
    127     // For arrays which are not linear or planar there is no ambiguity.
    128     std::vector<Point> array_geometry;
    129     array_geometry.push_back(Point(0.f, 0.f, 0.f));
    130     array_geometry.push_back(Point(0.1f, 0.f, 0.f));
    131     array_geometry.push_back(Point(0.f, 0.2f, 0.f));
    132     array_geometry.push_back(Point(0.f, 0.f, 0.3f));
    133     NonlinearBeamformer bf(array_geometry);
    134     bf.Initialize(kChunkSizeMs, kSampleRateHz);
    135     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
    136     EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
    137                     bf.interf_angles_radians_[0]);
    138     EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
    139                     bf.interf_angles_radians_[1]);
    140     bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
    141     EXPECT_EQ(2u, bf.interf_angles_radians_.size());
    142     EXPECT_FLOAT_EQ(-bf.away_radians_ / 2.f, bf.interf_angles_radians_[0]);
    143     EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
    144   }
    145 }
    146 
    147 }  // namespace webrtc
    148