Add support for arbitrary array geometries in Beamformer

R=andrew@webrtc.org, mgraczyk@chromium.org

Review URL: https://webrtc-codereview.appspot.com/38299004

Cr-Commit-Position: refs/heads/master@{#8621}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8621 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_processing/beamformer/array_util.h b/webrtc/modules/audio_processing/beamformer/array_util.h
new file mode 100644
index 0000000..8d1cda7
--- /dev/null
+++ b/webrtc/modules/audio_processing/beamformer/array_util.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
+#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
+
+#include <cmath>
+
+namespace webrtc {
+
+// Coordinates in meters.
+template<typename T>
+struct CartesianPoint {
+  CartesianPoint(T x, T y, T z) {
+    c[0] = x;
+    c[1] = y;
+    c[2] = z;
+  }
+  T x() const {
+    return c[0];
+  }
+  T y() const {
+    return c[1];
+  }
+  T z() const {
+    return c[2];
+  }
+  T c[3];
+};
+
+typedef CartesianPoint<float> Point;
+
+template<typename T>
+float Distance(CartesianPoint<T> a, CartesianPoint<T> b) {
+  return std::sqrt((a.x() - b.x()) * (a.x() - b.x()) +
+                   (a.y() - b.y()) * (a.y() - b.y()) +
+                   (a.z() - b.z()) * (a.z() - b.z()));
+}
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
diff --git a/webrtc/modules/audio_processing/beamformer/beamformer.cc b/webrtc/modules/audio_processing/beamformer/beamformer.cc
index 6cbe612..6d78de9 100644
--- a/webrtc/modules/audio_processing/beamformer/beamformer.cc
+++ b/webrtc/modules/audio_processing/beamformer/beamformer.cc
@@ -30,15 +30,16 @@
 
 const float kSpeedOfSoundMeterSeconds = 343;
 
-// For both target and interference angles, 0 is perpendicular to the microphone
-// array, facing forwards. The positive direction goes counterclockwise.
+// For both target and interference angles, PI / 2 is perpendicular to the
+// microphone array, facing forwards. The positive direction goes
+// counterclockwise.
 // The angle at which we amplify sound.
-const float kTargetAngleRadians = 0.f;
+const float kTargetAngleRadians = static_cast<float>(M_PI) / 2.f;
 
-// The angle at which we suppress sound. Suppression is symmetric around 0
+// The angle at which we suppress sound. Suppression is symmetric around PI / 2
 // radians, so sound is suppressed at both +|kInterfAngleRadians| and
-// -|kInterfAngleRadians|. Since the beamformer is robust, this should
-// suppress sound coming from angles near +-|kInterfAngleRadians| as well.
+// PI - |kInterfAngleRadians|. Since the beamformer is robust, this should
+// suppress sound coming from close angles as well.
 const float kInterfAngleRadians = static_cast<float>(M_PI) / 4.f;
 
 // When calculating the interference covariance matrix, this is the weight for
@@ -50,15 +51,6 @@
 // TODO(claguna): need comment here.
 const float kBeamwidthConstant = 0.00002f;
 
-// Width of the boxcar.
-const float kBoxcarHalfWidth = 0.01f;
-
-// We put a gap in the covariance matrix where we expect the target to come
-// from. Warning: This must be very small, ex. < 0.01, because otherwise it can
-// cause the covariance matrix not to be positive semidefinite, and we require
-// that our covariance matrices are positive semidefinite.
-const float kCovUniformGapHalfWidth = 0.01f;
-
 // Alpha coefficient for mask smoothing.
 const float kMaskSmoothAlpha = 0.2f;
 
@@ -151,11 +143,40 @@
   return sum_squares;
 }
 
+// Does |out| = |in|.' * conj(|in|) for row vector |in|.
+void TransposedConjugatedProduct(const ComplexMatrix<float>& in,
+                                 ComplexMatrix<float>* out) {
+  CHECK_EQ(in.num_rows(), 1);
+  CHECK_EQ(out->num_rows(), in.num_columns());
+  CHECK_EQ(out->num_columns(), in.num_columns());
+  const complex<float>* in_elements = in.elements()[0];
+  complex<float>* const* out_elements = out->elements();
+  for (int i = 0; i < out->num_rows(); ++i) {
+    for (int j = 0; j < out->num_columns(); ++j) {
+      out_elements[i][j] = in_elements[i] * conj(in_elements[j]);
+    }
+  }
+}
+
+std::vector<Point> GetCenteredArray(std::vector<Point> array_geometry) {
+  for (int dim = 0; dim < 3; ++dim) {
+    float center = 0.f;
+    for (size_t i = 0; i < array_geometry.size(); ++i) {
+      center += array_geometry[i].c[dim];
+    }
+    center /= array_geometry.size();
+    for (size_t i = 0; i < array_geometry.size(); ++i) {
+      array_geometry[i].c[dim] -= center;
+    }
+  }
+  return array_geometry;
+}
+
 }  // namespace
 
 Beamformer::Beamformer(const std::vector<Point>& array_geometry)
     : num_input_channels_(array_geometry.size()),
-      mic_spacing_(MicSpacingFromGeometry(array_geometry)) {
+      array_geometry_(GetCenteredArray(array_geometry)) {
   WindowGenerator::KaiserBesselDerived(kAlpha, kFftSize, window_);
 }
 
@@ -210,16 +231,14 @@
 }
 
 void Beamformer::InitDelaySumMasks() {
-  float sin_target = sin(kTargetAngleRadians);
   for (int f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
     delay_sum_masks_[f_ix].Resize(1, num_input_channels_);
     CovarianceMatrixGenerator::PhaseAlignmentMasks(f_ix,
                                                    kFftSize,
                                                    sample_rate_hz_,
                                                    kSpeedOfSoundMeterSeconds,
-                                                   mic_spacing_,
-                                                   num_input_channels_,
-                                                   sin_target,
+                                                   array_geometry_,
+                                                   kTargetAngleRadians,
                                                    &delay_sum_masks_[f_ix]);
 
     complex_f norm_factor = sqrt(
@@ -232,45 +251,23 @@
 }
 
 void Beamformer::InitTargetCovMats() {
-  target_cov_mats_[0].Resize(num_input_channels_, num_input_channels_);
-  CovarianceMatrixGenerator::DCCovarianceMatrix(
-      num_input_channels_, kBoxcarHalfWidth, &target_cov_mats_[0]);
-
-  complex_f normalization_factor = target_cov_mats_[0].Trace();
-  target_cov_mats_[0].Scale(1.f / normalization_factor);
-
-  for (int i = 1; i < kNumFreqBins; ++i) {
+  for (int i = 0; i < kNumFreqBins; ++i) {
     target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
-    CovarianceMatrixGenerator::Boxcar(wave_numbers_[i],
-                                      num_input_channels_,
-                                      mic_spacing_,
-                                      kBoxcarHalfWidth,
-                                      &target_cov_mats_[i]);
-
+    TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]);
     complex_f normalization_factor = target_cov_mats_[i].Trace();
     target_cov_mats_[i].Scale(1.f / normalization_factor);
   }
 }
 
 void Beamformer::InitInterfCovMats() {
-  interf_cov_mats_[0].Resize(num_input_channels_, num_input_channels_);
-  CovarianceMatrixGenerator::DCCovarianceMatrix(
-      num_input_channels_, kCovUniformGapHalfWidth, &interf_cov_mats_[0]);
-
-  complex_f normalization_factor = interf_cov_mats_[0].Trace();
-  interf_cov_mats_[0].Scale(1.f / normalization_factor);
-  reflected_interf_cov_mats_[0].PointwiseConjugate(interf_cov_mats_[0]);
-  for (int i = 1; i < kNumFreqBins; ++i) {
+  for (int i = 0; i < kNumFreqBins; ++i) {
     interf_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
     ComplexMatrixF uniform_cov_mat(num_input_channels_, num_input_channels_);
     ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_);
 
-    CovarianceMatrixGenerator::GappedUniformCovarianceMatrix(
-        wave_numbers_[i],
-        num_input_channels_,
-        mic_spacing_,
-        kCovUniformGapHalfWidth,
-        &uniform_cov_mat);
+    CovarianceMatrixGenerator::UniformCovarianceMatrix(wave_numbers_[i],
+                                                       array_geometry_,
+                                                       &uniform_cov_mat);
 
     CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSoundMeterSeconds,
                                                       kInterfAngleRadians,
@@ -278,8 +275,7 @@
                                                       kFftSize,
                                                       kNumFreqBins,
                                                       sample_rate_hz_,
-                                                      num_input_channels_,
-                                                      mic_spacing_,
+                                                      array_geometry_,
                                                       &angled_cov_mat);
     // Normalize matrices before averaging them.
     complex_f normalization_factor = uniform_cov_mat.Trace();
@@ -447,20 +443,6 @@
   }
 }
 
-// This method CHECKs for a uniform linear array.
-float Beamformer::MicSpacingFromGeometry(const std::vector<Point>& geometry) {
-  CHECK_GE(geometry.size(), 2u);
-  float mic_spacing = 0.f;
-  for (size_t i = 0u; i < 3u; ++i) {
-    float difference = geometry[1].c[i] - geometry[0].c[i];
-    for (size_t j = 2u; j < geometry.size(); ++j) {
-      CHECK_LT(geometry[j].c[i] - geometry[j - 1].c[i] - difference, 1e-6);
-    }
-    mic_spacing += difference * difference;
-  }
-  return sqrt(mic_spacing);
-}
-
 void Beamformer::EstimateTargetPresence() {
   const int quantile = (1.f - kMaskQuantile) * high_average_end_bin_ +
                        kMaskQuantile * low_average_start_bin_;
diff --git a/webrtc/modules/audio_processing/beamformer/beamformer.h b/webrtc/modules/audio_processing/beamformer/beamformer.h
index c3b32ff..3407bd3 100644
--- a/webrtc/modules/audio_processing/beamformer/beamformer.h
+++ b/webrtc/modules/audio_processing/beamformer/beamformer.h
@@ -13,7 +13,7 @@
 
 #include "webrtc/common_audio/lapped_transform.h"
 #include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
+#include "webrtc/modules/audio_processing/beamformer/array_util.h"
 
 namespace webrtc {
 
@@ -94,7 +94,6 @@
   // Applies both sets of masks to |input| and store in |output|.
   void ApplyMasks(const complex_f* const* input, complex_f* const* output);
 
-  float MicSpacingFromGeometry(const std::vector<Point>& array_geometry);
   void EstimateTargetPresence();
 
   static const int kFftSize = 256;
@@ -108,7 +107,8 @@
   // Parameters exposed to the user.
   const int num_input_channels_;
   int sample_rate_hz_;
-  const float mic_spacing_;
+
+  const std::vector<Point> array_geometry_;
 
   // Calculated based on user-input and constants in the .cc file.
   int low_average_start_bin_;
diff --git a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc
index 8d592a5..c70bf5e 100644
--- a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc
+++ b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc
@@ -28,57 +28,26 @@
 
 namespace webrtc {
 
-// Calculates the boxcar-angular desired source distribution at a given
-// wavenumber, and stores it in |mat|.
-void CovarianceMatrixGenerator::Boxcar(float wave_number,
-                                       int num_input_channels,
-                                       float mic_spacing,
-                                       float half_width,
-                                       ComplexMatrix<float>* mat) {
-  CHECK_EQ(num_input_channels, mat->num_rows());
-  CHECK_EQ(num_input_channels, mat->num_columns());
+void CovarianceMatrixGenerator::UniformCovarianceMatrix(
+    float wave_number,
+    const std::vector<Point>& geometry,
+    ComplexMatrix<float>* mat) {
+  CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
+  CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
 
-  complex<float>* const* boxcar_elements = mat->elements();
-
-  for (int i = 0; i < num_input_channels; ++i) {
-    for (int j = 0; j < num_input_channels; ++j) {
-      if (i == j) {
-        boxcar_elements[i][j] = complex<float>(2.f * half_width, 0.f);
+  complex<float>* const* mat_els = mat->elements();
+  for (size_t i = 0; i < geometry.size(); ++i) {
+    for (size_t j = 0; j < geometry.size(); ++j) {
+      if (wave_number > 0.f) {
+        mat_els[i][j] =
+            BesselJ0(wave_number * Distance(geometry[i], geometry[j]));
       } else {
-        float factor = (j - i) * wave_number * mic_spacing;
-        float boxcar_real = 2.f * sin(factor * half_width) / factor;
-        boxcar_elements[i][j] = complex<float>(boxcar_real, 0.f);
+        mat_els[i][j] = i == j ? 1.f : 0.f;
       }
     }
   }
 }
 
-void CovarianceMatrixGenerator::GappedUniformCovarianceMatrix(
-    float wave_number,
-    float num_input_channels,
-    float mic_spacing,
-    float gap_half_width,
-    ComplexMatrix<float>* mat) {
-  CHECK_EQ(num_input_channels, mat->num_rows());
-  CHECK_EQ(num_input_channels, mat->num_columns());
-
-  complex<float>* const* mat_els = mat->elements();
-  for (int i = 0; i < num_input_channels; ++i) {
-    for (int j = 0; j < num_input_channels; ++j) {
-      float x = (j - i) * wave_number * mic_spacing;
-      mat_els[i][j] = BesselJ0(x);
-    }
-  }
-
-  ComplexMatrix<float> boxcar_mat(num_input_channels, num_input_channels);
-  CovarianceMatrixGenerator::Boxcar(wave_number,
-                                    num_input_channels,
-                                    mic_spacing,
-                                    gap_half_width,
-                                    &boxcar_mat);
-  mat->Subtract(boxcar_mat);
-}
-
 void CovarianceMatrixGenerator::AngledCovarianceMatrix(
     float sound_speed,
     float angle,
@@ -86,66 +55,44 @@
     int fft_size,
     int num_freq_bins,
     int sample_rate,
-    int num_input_channels,
-    float mic_spacing,
+    const std::vector<Point>& geometry,
     ComplexMatrix<float>* mat) {
-  CHECK_EQ(num_input_channels, mat->num_rows());
-  CHECK_EQ(num_input_channels, mat->num_columns());
+  CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
+  CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
 
-  ComplexMatrix<float> interf_cov_vector(1, num_input_channels);
-  ComplexMatrix<float> interf_cov_vector_transposed(num_input_channels, 1);
+  ComplexMatrix<float> interf_cov_vector(1, geometry.size());
+  ComplexMatrix<float> interf_cov_vector_transposed(geometry.size(), 1);
   PhaseAlignmentMasks(frequency_bin,
                       fft_size,
                       sample_rate,
                       sound_speed,
-                      mic_spacing,
-                      num_input_channels,
-                      sin(angle),
+                      geometry,
+                      angle,
                       &interf_cov_vector);
   interf_cov_vector_transposed.Transpose(interf_cov_vector);
   interf_cov_vector.PointwiseConjugate();
   mat->Multiply(interf_cov_vector_transposed, interf_cov_vector);
 }
 
-void CovarianceMatrixGenerator::DCCovarianceMatrix(int num_input_channels,
-                                                   float half_width,
-                                                   ComplexMatrix<float>* mat) {
-  CHECK_EQ(num_input_channels, mat->num_rows());
-  CHECK_EQ(num_input_channels, mat->num_columns());
-
-  complex<float>* const* elements = mat->elements();
-
-  float diagonal_value = 1.f - 2.f * half_width;
-  for (int i = 0; i < num_input_channels; ++i) {
-    for (int j = 0; j < num_input_channels; ++j) {
-      if (i == j) {
-        elements[i][j] = complex<float>(diagonal_value, 0.f);
-      } else {
-        elements[i][j] = complex<float>(0.f, 0.f);
-      }
-    }
-  }
-}
-
-void CovarianceMatrixGenerator::PhaseAlignmentMasks(int frequency_bin,
-                                                    int fft_size,
-                                                    int sample_rate,
-                                                    float sound_speed,
-                                                    float mic_spacing,
-                                                    int num_input_channels,
-                                                    float sin_angle,
-                                                    ComplexMatrix<float>* mat) {
+void CovarianceMatrixGenerator::PhaseAlignmentMasks(
+    int frequency_bin,
+    int fft_size,
+    int sample_rate,
+    float sound_speed,
+    const std::vector<Point>& geometry,
+    float angle,
+    ComplexMatrix<float>* mat) {
   CHECK_EQ(1, mat->num_rows());
-  CHECK_EQ(num_input_channels, mat->num_columns());
+  CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
 
   float freq_in_hertz =
       (static_cast<float>(frequency_bin) / fft_size) * sample_rate;
 
   complex<float>* const* mat_els = mat->elements();
-  for (int c_ix = 0; c_ix < num_input_channels; ++c_ix) {
-    // TODO(aluebs): Generalize for non-uniform-linear microphone arrays.
-    float distance = mic_spacing * c_ix * sin_angle * -1.f;
-    float phase_shift = 2 * M_PI * distance * freq_in_hertz / sound_speed;
+  for (size_t c_ix = 0; c_ix < geometry.size(); ++c_ix) {
+    float distance = std::cos(angle) * geometry[c_ix].x() +
+                     std::sin(angle) * geometry[c_ix].y();
+    float phase_shift = -2.f * M_PI * distance * freq_in_hertz / sound_speed;
 
     // Euler's formula for mat[0][c_ix] = e^(j * phase_shift).
     mat_els[0][c_ix] = complex<float>(cos(phase_shift), sin(phase_shift));
diff --git a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h
index a3bceef..5979462 100644
--- a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h
+++ b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h
@@ -12,6 +12,7 @@
 #define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
 
 #include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
+#include "webrtc/modules/audio_processing/beamformer/array_util.h"
 
 namespace webrtc {
 
@@ -20,23 +21,11 @@
 // |num_input_channels| x |num_input_channels|.
 class CovarianceMatrixGenerator {
  public:
-  // Generates the covariance matrix of the target. The boxcar implementation
-  // suppresses some high-frequency distortion caused by narrow high-frequency
-  // suppression bands turning on/off too quickly. WARNING: The target angle is
-  // assumed to be 0.
-  static void Boxcar(float wave_number,
-                     int num_input_channels,
-                     float mic_spacing,
-                     float half_width,
-                     ComplexMatrix<float>* mat);
-
   // A uniform covariance matrix with a gap at the target location. WARNING:
   // The target angle is assumed to be 0.
-  static void GappedUniformCovarianceMatrix(float wave_number,
-                                            float num_input_channels,
-                                            float mic_spacing,
-                                            float gap_half_width,
-                                            ComplexMatrix<float>* mat);
+  static void UniformCovarianceMatrix(float wave_number,
+                                      const std::vector<Point>& geometry,
+                                      ComplexMatrix<float>* mat);
 
   // The covariance matrix of a source at the given angle.
   static void AngledCovarianceMatrix(float sound_speed,
@@ -45,15 +34,9 @@
                                      int fft_size,
                                      int num_freq_bins,
                                      int sample_rate,
-                                     int num_input_channels,
-                                     float mic_spacing,
+                                     const std::vector<Point>& geometry,
                                      ComplexMatrix<float>* mat);
 
-  // A base-case covariance matrix for when the frequency is 0 Hertz.
-  static void DCCovarianceMatrix(int num_input_channels,
-                                 float half_width,
-                                 ComplexMatrix<float>* mat);
-
   // Calculates phase shifts that, when applied to a multichannel signal and
   // added together, cause constructive interferernce for sources located at
   // the given angle.
@@ -61,9 +44,8 @@
                                   int fft_size,
                                   int sample_rate,
                                   float sound_speed,
-                                  float mic_spacing,
-                                  int num_input_channels,
-                                  float sin_angle,
+                                  const std::vector<Point>& geometry,
+                                  float angle,
                                   ComplexMatrix<float>* mat);
 };
 
diff --git a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc
index 0c3a1d5..4ea341d 100644
--- a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc
+++ b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc
@@ -21,97 +21,27 @@
 
 using std::complex;
 
-TEST(CovarianceMatrixGeneratorTest, TestBoxcar) {
-  const float kWaveNumber = 10.3861f;
-  const int kNumberMics = 3;
-  const float kMicSpacing = 0.23f;
-  const float kHalfWidth = 0.001f;
-  const float kTolerance = 0.0001f;
-
-  ComplexMatrix<float> actual_boxcar(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::Boxcar(
-      kWaveNumber, kNumberMics, kMicSpacing, kHalfWidth, &actual_boxcar);
-
-  complex<float>* const* actual_els = actual_boxcar.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.002f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 0.002f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
-}
-
-// Test Boxcar with large numbers to generate matrix with varying
-// numbers.
-TEST(CovarianceMatrixGeneratorTest, TestBoxcarLargeNumbers) {
-  const float kWaveNumber = 10.3861f;
-  const int kNumberMics = 3;
-  const float kMicSpacing = 3.f;
-  const float kHalfWidth = 0.1f;
-  const float kTolerance = 0.0001f;
-
-  ComplexMatrix<float> actual_boxcar(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::Boxcar(
-      kWaveNumber, kNumberMics, kMicSpacing, kHalfWidth, &actual_boxcar);
-
-  complex<float>* const* actual_els = actual_boxcar.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 0.2f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), -0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.2f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), -0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.0017f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 0.2f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
-}
-
-TEST(CovarianceMatrixGeneratorTest, TestGappedUniformCovarianceMatrix2Mics) {
+TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix2Mics) {
   const float kWaveNumber = 0.5775f;
   const int kNumberMics = 2;
   const float kMicSpacing = 0.05f;
-  const float kHalfWidth = 0.001f;
   const float kTolerance = 0.0001f;
-
+  std::vector<Point> geometry;
+  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
+  for (int i = 0; i < kNumberMics; ++i) {
+    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
+  }
   ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::GappedUniformCovarianceMatrix(
-      kWaveNumber,
-      kNumberMics,
-      kMicSpacing,
-      kHalfWidth,
-      &actual_covariance_matrix);
+  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
+                                                     geometry,
+                                                     &actual_covariance_matrix);
 
   complex<float>* const* actual_els = actual_covariance_matrix.elements();
 
-  EXPECT_NEAR(actual_els[0][0].real(), 0.998f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.9978f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.9978f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.998f, kTolerance);
+  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][1].real(), 0.9998f, kTolerance);
+  EXPECT_NEAR(actual_els[1][0].real(), 0.9998f, kTolerance);
+  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
 
   EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
   EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
@@ -119,32 +49,32 @@
   EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
 }
 
-TEST(CovarianceMatrixGeneratorTest, TestGappedUniformCovarianceMatrix3Mics) {
+TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix3Mics) {
   const float kWaveNumber = 10.3861f;
   const int kNumberMics = 3;
   const float kMicSpacing = 0.04f;
-  const float kHalfWidth = 0.001f;
   const float kTolerance = 0.0001f;
-
+  std::vector<Point> geometry;
+  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
+  for (int i = 0; i < kNumberMics; ++i) {
+    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
+  }
   ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::GappedUniformCovarianceMatrix(
-      kWaveNumber,
-      kNumberMics,
-      kMicSpacing,
-      kHalfWidth,
-      &actual_covariance_matrix);
+  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
+                                                     geometry,
+                                                     &actual_covariance_matrix);
 
   complex<float>* const* actual_els = actual_covariance_matrix.elements();
 
-  EXPECT_NEAR(actual_els[0][0].real(), 0.998f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.9553f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), 0.8327f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.9553f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.998f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.9553f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), 0.8327f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.9553f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 0.998f, kTolerance);
+  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][1].real(), 0.9573f, kTolerance);
+  EXPECT_NEAR(actual_els[0][2].real(), 0.8347f, kTolerance);
+  EXPECT_NEAR(actual_els[1][0].real(), 0.9573f, kTolerance);
+  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][2].real(), 0.9573f, kTolerance);
+  EXPECT_NEAR(actual_els[2][0].real(), 0.8347f, kTolerance);
+  EXPECT_NEAR(actual_els[2][1].real(), 0.9573f, kTolerance);
+  EXPECT_NEAR(actual_els[2][2].real(), 1.f, kTolerance);
 
   EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
   EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
@@ -157,6 +87,57 @@
   EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
 }
 
+TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix3DArray) {
+  const float kWaveNumber = 1.2345f;
+  const int kNumberMics = 4;
+  const float kTolerance = 0.0001f;
+  std::vector<Point> geometry;
+  geometry.push_back(Point(-0.025f, -0.05f, -0.075f));
+  geometry.push_back(Point(0.075f, -0.05f, -0.075f));
+  geometry.push_back(Point(-0.025f, 0.15f, -0.075f));
+  geometry.push_back(Point(-0.025f, -0.05f, 0.225f));
+  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
+  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
+                                                     geometry,
+                                                     &actual_covariance_matrix);
+
+  complex<float>* const* actual_els = actual_covariance_matrix.elements();
+
+  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][1].real(), 0.9962f, kTolerance);
+  EXPECT_NEAR(actual_els[0][2].real(), 0.9848f, kTolerance);
+  EXPECT_NEAR(actual_els[0][3].real(), 0.9660f, kTolerance);
+  EXPECT_NEAR(actual_els[1][0].real(), 0.9962f, kTolerance);
+  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][2].real(), 0.9810f, kTolerance);
+  EXPECT_NEAR(actual_els[1][3].real(), 0.9623f, kTolerance);
+  EXPECT_NEAR(actual_els[2][0].real(), 0.9848f, kTolerance);
+  EXPECT_NEAR(actual_els[2][1].real(), 0.9810f, kTolerance);
+  EXPECT_NEAR(actual_els[2][2].real(), 1.f, kTolerance);
+  EXPECT_NEAR(actual_els[2][3].real(), 0.9511f, kTolerance);
+  EXPECT_NEAR(actual_els[3][0].real(), 0.9660f, kTolerance);
+  EXPECT_NEAR(actual_els[3][1].real(), 0.9623f, kTolerance);
+  EXPECT_NEAR(actual_els[3][2].real(), 0.9511f, kTolerance);
+  EXPECT_NEAR(actual_els[3][3].real(), 1.f, kTolerance);
+
+  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][2].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[0][3].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][2].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[1][3].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[2][0].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[2][1].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[2][3].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[3][0].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[3][1].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[3][2].imag(), 0.f, kTolerance);
+  EXPECT_NEAR(actual_els[3][3].imag(), 0.f, kTolerance);
+}
+
 TEST(CovarianceMatrixGeneratorTest, TestAngledCovarianceMatrix2Mics) {
   const float kSpeedOfSound = 340;
   const float kAngle = static_cast<float>(M_PI) / 4.f;
@@ -167,6 +148,11 @@
   const int kNumberMics = 2;
   const float kMicSpacing = 0.04f;
   const float kTolerance = 0.0001f;
+  std::vector<Point> geometry;
+  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
+  for (int i = 0; i < kNumberMics; ++i) {
+    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
+  }
   ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
   CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSound,
                                                     kAngle,
@@ -174,8 +160,7 @@
                                                     kFftSize,
                                                     kNumberFrequencyBins,
                                                     kSampleRate,
-                                                    kNumberMics,
-                                                    kMicSpacing,
+                                                    geometry,
                                                     &actual_covariance_matrix);
 
   complex<float>* const* actual_els = actual_covariance_matrix.elements();
@@ -201,7 +186,11 @@
   const int kNumberMics = 3;
   const float kMicSpacing = 0.05f;
   const float kTolerance = 0.0001f;
-
+  std::vector<Point> geometry;
+  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
+  for (int i = 0; i < kNumberMics; ++i) {
+    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
+  }
   ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
   CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSound,
                                                     kAngle,
@@ -209,8 +198,7 @@
                                                     kFftSize,
                                                     kNumberFrequencyBins,
                                                     kSampleRate,
-                                                    kNumberMics,
-                                                    kMicSpacing,
+                                                    geometry,
                                                     &actual_covariance_matrix);
 
   complex<float>* const* actual_els = actual_covariance_matrix.elements();
@@ -236,27 +224,6 @@
   EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
 }
 
-TEST(CovarianceMatrixGeneratorTest, TestDCCovarianceMatrix) {
-  const int kNumberMics = 2;
-  const float kHalfWidth = 0.01f;
-
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::DCCovarianceMatrix(
-      kNumberMics, kHalfWidth, &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 0.98f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.98f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-}
-
 // PhaseAlignmentMasks is tested by AngledCovarianceMatrix and by
 // InitBeamformerWeights in BeamformerUnittest.
 
diff --git a/webrtc/modules/audio_processing/include/audio_processing.h b/webrtc/modules/audio_processing/include/audio_processing.h
index 4004a62..049cfbb 100644
--- a/webrtc/modules/audio_processing/include/audio_processing.h
+++ b/webrtc/modules/audio_processing/include/audio_processing.h
@@ -17,6 +17,7 @@
 
 #include "webrtc/base/platform_file.h"
 #include "webrtc/common.h"
+#include "webrtc/modules/audio_processing/beamformer/array_util.h"
 #include "webrtc/typedefs.h"
 
 struct AecCore;
@@ -84,16 +85,6 @@
   bool enabled;
 };
 
-// Coordinates in meters.
-struct Point {
-  Point(float x, float y, float z) {
-    c[0] = x;
-    c[1] = y;
-    c[2] = z;
-  }
-  float c[3];
-};
-
 // Use to enable beamforming. Must be provided through the constructor. It will
 // have no impact if used with AudioProcessing::SetExtraOptions().
 struct Beamforming {
diff --git a/webrtc/modules/audio_processing/test/audioproc_float.cc b/webrtc/modules/audio_processing/test/audioproc_float.cc
index 805d884..a451d0a 100644
--- a/webrtc/modules/audio_processing/test/audioproc_float.cc
+++ b/webrtc/modules/audio_processing/test/audioproc_float.cc
@@ -101,7 +101,7 @@
           "mic_spacing must a positive value when beamforming is enabled.\n");
     } else {
       for (size_t i = 0; i < num_mics; ++i) {
-        result.push_back(Point(0.0, i * FLAGS_mic_spacing, 0.0));
+        result.push_back(Point(i * FLAGS_mic_spacing, 0.f, 0.f));
       }
     }
   }