blob: e42a98e6325b29a4676487222c817240a1bcb1f3 [file] [log] [blame]
aluebs4a66e4a2015-10-19 18:02:39 -07001/*
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
Edward Lemurc20978e2017-07-06 19:44:34 +020016#include "webrtc/rtc_base/checks.h"
aluebs4a66e4a2015-10-19 18:02:39 -070017
18namespace webrtc {
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070019namespace {
20
21const float kMaxDotProduct = 1e-6f;
22
23} // namespace
aluebs4a66e4a2015-10-19 18:02:39 -070024
25float GetMinimumSpacing(const std::vector<Point>& array_geometry) {
kwibergaf476c72016-11-28 15:21:39 -080026 RTC_CHECK_GT(array_geometry.size(), 1);
aluebs4a66e4a2015-10-19 18:02:39 -070027 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
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070037Point PairDirection(const Point& a, const Point& b) {
38 return {b.x() - a.x(), b.y() - a.y(), b.z() - a.z()};
39}
40
41float DotProduct(const Point& a, const Point& b) {
42 return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
43}
44
45Point 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
50bool AreParallel(const Point& a, const Point& b) {
51 Point cross_product = CrossProduct(a, b);
52 return DotProduct(cross_product, cross_product) < kMaxDotProduct;
53}
54
55bool ArePerpendicular(const Point& a, const Point& b) {
56 return std::abs(DotProduct(a, b)) < kMaxDotProduct;
57}
58
Karl Wibergbe579832015-11-10 22:34:18 +010059rtc::Optional<Point> GetDirectionIfLinear(
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070060 const std::vector<Point>& array_geometry) {
kwibergaf476c72016-11-28 15:21:39 -080061 RTC_DCHECK_GT(array_geometry.size(), 1);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070062 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)) {
Karl Wibergbe579832015-11-10 22:34:18 +010068 return rtc::Optional<Point>();
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070069 }
70 }
Karl Wibergbe579832015-11-10 22:34:18 +010071 return rtc::Optional<Point>(first_pair_direction);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070072}
73
Karl Wibergbe579832015-11-10 22:34:18 +010074rtc::Optional<Point> GetNormalIfPlanar(
75 const std::vector<Point>& array_geometry) {
kwibergaf476c72016-11-28 15:21:39 -080076 RTC_DCHECK_GT(array_geometry.size(), 1);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070077 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) {
Karl Wibergbe579832015-11-10 22:34:18 +010089 return rtc::Optional<Point>();
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070090 }
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)) {
Karl Wibergbe579832015-11-10 22:34:18 +010096 return rtc::Optional<Point>();
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -070097 }
98 }
Karl Wibergbe579832015-11-10 22:34:18 +010099 return rtc::Optional<Point>(normal_direction);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700100}
101
Karl Wibergbe579832015-11-10 22:34:18 +0100102rtc::Optional<Point> GetArrayNormalIfExists(
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700103 const std::vector<Point>& array_geometry) {
Karl Wibergbe579832015-11-10 22:34:18 +0100104 const rtc::Optional<Point> direction = GetDirectionIfLinear(array_geometry);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700105 if (direction) {
Karl Wibergbe579832015-11-10 22:34:18 +0100106 return rtc::Optional<Point>(Point(direction->y(), -direction->x(), 0.f));
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700107 }
Karl Wibergbe579832015-11-10 22:34:18 +0100108 const rtc::Optional<Point> normal = GetNormalIfPlanar(array_geometry);
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700109 if (normal && normal->z() < kMaxDotProduct) {
110 return normal;
111 }
Karl Wibergbe579832015-11-10 22:34:18 +0100112 return rtc::Optional<Point>();
Alejandro Luebscb3f9bd2015-10-29 18:21:34 -0700113}
114
115Point AzimuthToPoint(float azimuth) {
116 return Point(std::cos(azimuth), std::sin(azimuth), 0.f);
117}
118
aluebs4a66e4a2015-10-19 18:02:39 -0700119} // namespace webrtc