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 #include "webrtc/modules/audio_processing/beamformer/array_util.h"
     12 
     13 #include <algorithm>
     14 #include <limits>
     15 
     16 #include "webrtc/base/checks.h"
     17 
     18 namespace webrtc {
     19 namespace {
     20 
     21 const float kMaxDotProduct = 1e-6f;
     22 
     23 }  // namespace
     24 
     25 float GetMinimumSpacing(const std::vector<Point>& array_geometry) {
     26   RTC_CHECK_GT(array_geometry.size(), 1u);
     27   float mic_spacing = std::numeric_limits<float>::max();
     28   for (size_t i = 0; i < (array_geometry.size() - 1); ++i) {
     29     for (size_t j = i + 1; j < array_geometry.size(); ++j) {
     30       mic_spacing =
     31           std::min(mic_spacing, Distance(array_geometry[i], array_geometry[j]));
     32     }
     33   }
     34   return mic_spacing;
     35 }
     36 
     37 Point PairDirection(const Point& a, const Point& b) {
     38   return {b.x() - a.x(), b.y() - a.y(), b.z() - a.z()};
     39 }
     40 
     41 float DotProduct(const Point& a, const Point& b) {
     42   return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
     43 }
     44 
     45 Point CrossProduct(const Point& a, const Point& b) {
     46   return {a.y() * b.z() - a.z() * b.y(), a.z() * b.x() - a.x() * b.z(),
     47           a.x() * b.y() - a.y() * b.x()};
     48 }
     49 
     50 bool AreParallel(const Point& a, const Point& b) {
     51   Point cross_product = CrossProduct(a, b);
     52   return DotProduct(cross_product, cross_product) < kMaxDotProduct;
     53 }
     54 
     55 bool ArePerpendicular(const Point& a, const Point& b) {
     56   return std::abs(DotProduct(a, b)) < kMaxDotProduct;
     57 }
     58 
     59 rtc::Optional<Point> GetDirectionIfLinear(
     60     const std::vector<Point>& array_geometry) {
     61   RTC_DCHECK_GT(array_geometry.size(), 1u);
     62   const Point first_pair_direction =
     63       PairDirection(array_geometry[0], array_geometry[1]);
     64   for (size_t i = 2u; i < array_geometry.size(); ++i) {
     65     const Point pair_direction =
     66         PairDirection(array_geometry[i - 1], array_geometry[i]);
     67     if (!AreParallel(first_pair_direction, pair_direction)) {
     68       return rtc::Optional<Point>();
     69     }
     70   }
     71   return rtc::Optional<Point>(first_pair_direction);
     72 }
     73 
     74 rtc::Optional<Point> GetNormalIfPlanar(
     75     const std::vector<Point>& array_geometry) {
     76   RTC_DCHECK_GT(array_geometry.size(), 1u);
     77   const Point first_pair_direction =
     78       PairDirection(array_geometry[0], array_geometry[1]);
     79   Point pair_direction(0.f, 0.f, 0.f);
     80   size_t i = 2u;
     81   bool is_linear = true;
     82   for (; i < array_geometry.size() && is_linear; ++i) {
     83     pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
     84     if (!AreParallel(first_pair_direction, pair_direction)) {
     85       is_linear = false;
     86     }
     87   }
     88   if (is_linear) {
     89     return rtc::Optional<Point>();
     90   }
     91   const Point normal_direction =
     92       CrossProduct(first_pair_direction, pair_direction);
     93   for (; i < array_geometry.size(); ++i) {
     94     pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
     95     if (!ArePerpendicular(normal_direction, pair_direction)) {
     96       return rtc::Optional<Point>();
     97     }
     98   }
     99   return rtc::Optional<Point>(normal_direction);
    100 }
    101 
    102 rtc::Optional<Point> GetArrayNormalIfExists(
    103     const std::vector<Point>& array_geometry) {
    104   const rtc::Optional<Point> direction = GetDirectionIfLinear(array_geometry);
    105   if (direction) {
    106     return rtc::Optional<Point>(Point(direction->y(), -direction->x(), 0.f));
    107   }
    108   const rtc::Optional<Point> normal = GetNormalIfPlanar(array_geometry);
    109   if (normal && normal->z() < kMaxDotProduct) {
    110     return normal;
    111   }
    112   return rtc::Optional<Point>();
    113 }
    114 
    115 Point AzimuthToPoint(float azimuth) {
    116   return Point(std::cos(azimuth), std::sin(azimuth), 0.f);
    117 }
    118 
    119 }  // namespace webrtc
    120