• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear License
5  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6  * License was not distributed with this source code in the LICENSE file, you
7  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8  * Alliance for Open Media Patent License 1.0 was not distributed with this
9  * source code in the PATENTS file, you can obtain it at
10  * www.aomedia.org/license/patent.
11  */
12 
13 #include "iamf/cli/ambisonic_encoder/associated_legendre_polynomials_generator.h"
14 
15 #include <cmath>
16 #include <cstddef>
17 #include <vector>
18 
19 #include "gtest/gtest.h"
20 #include "iamf/cli/ambisonic_encoder/ambisonic_utils.h"
21 
22 namespace iamf_tools {
23 namespace {
24 
25 // Tolerated test error margin for single-precision floating points.
26 const float kEpsilon = 1e-5f;
27 
28 // Generates associated Legendre polynomials up to and including the 4th degree,
29 // with the Condon-Shortley phase and negative orders included.
GenerateExpectedValuesFourthDegree(float x)30 std::vector<float> GenerateExpectedValuesFourthDegree(float x) {
31   // From http://en.wikipedia.org/wiki/Associated_Legendre_polynomials
32   // Comments are (degree, order).
33   const std::vector<float> expected_values = {
34       1.0f,                                                  // (0, 0)
35       0.5f * std::sqrt(1.0f - x * x),                        // (1, -1)
36       x,                                                     // (1, 0)
37       -std::sqrt(1.0f - x * x),                              // (1, 1)
38       1.0f / 8.0f * (1.0f - x * x),                          // (2, -2)
39       0.5f * x * std::sqrt(1.0f - x * x),                    // (2, -1)
40       0.5f * (3.0f * x * x - 1.0f),                          // (2, 0)
41       -3.0f * x * std::sqrt(1.0f - x * x),                   // (2, 1)
42       3.0f * (1.0f - x * x),                                 // (2, 2)
43       15.0f / 720.0f * std::pow(1.0f - x * x, 3.0f / 2.0f),  // (3, -3)
44       15.0f / 120.0f * x * (1.0f - x * x),                   // (3, -2)
45       3.0f / 24.0f * (5.0f * x * x - 1.0f) *
46           std::sqrt(1.0f - x * x),                  // (3, -1)
47       0.5f * (5.0f * IntegerPow(x, 3) - 3.0f * x),  // (3, 0)
48       -3.0f / 2.0f * (5.0f * x * x - 1.0f) * std::sqrt(1.0f - x * x),  // (3, 1)
49       15.0f * x * (1.0f - x * x),                                      // (3, 2)
50       -15.0f * std::pow(1.0f - x * x, 3.0f / 2.0f),                    // (3, 3)
51       105.0f / 40320.0f * IntegerPow(1.0f - x * x, 2),             // (4, -4)
52       105.0f / 5040.0f * x * std::pow(1.0f - x * x, 3.0f / 2.0f),  // (4, -3)
53       15.0f / 720.0f * (7.0f * x * x - 1.0f) * (1.0f - x * x),     // (4, -2)
54       5.0f / 40.0f * (7.0f * IntegerPow(x, 3) - 3.0f * x) *
55           std::sqrt(1.0f - x * x),  // (4, -1)
56       1.0f / 8.0f *
57           (35.0f * IntegerPow(x, 4) - 30.0f * x * x + 3.0f),  // (4, 0)
58       -5.0f / 2.0f * (7.0f * IntegerPow(x, 3) - 3.0f * x) *
59           std::sqrt(1.0f - x * x),                            // (4, 1)
60       15.0f / 2.0f * (7.0f * x * x - 1.0f) * (1.0f - x * x),  // (4, 2)
61       -105.0f * x * std::pow(1.0f - x * x, 3.0f / 2.0f),      // (4, 3)
62       105.0f * IntegerPow(1.0f - x * x, 2)                    // (4, 4)
63   };
64 
65   return expected_values;
66 }
67 
68 // Tests that the values given by GetIndex are successive indices (n, n+1, n+2,
69 // and so on).
TEST(AssociatedLegendrePolynomialsGeneratorTest,GetIndex_SuccessiveIndices)70 TEST(AssociatedLegendrePolynomialsGeneratorTest, GetIndex_SuccessiveIndices) {
71   const int kMaxDegree = 5;
72   const AssociatedLegendrePolynomialsGenerator alp_generator(kMaxDegree, false,
73                                                              true);
74   int last_index = -1;
75   for (int degree = 0; degree <= kMaxDegree; ++degree) {
76     for (int order = -degree; order <= degree; ++order) {
77       int index = static_cast<int>(alp_generator.GetIndex(degree, order));
78       EXPECT_EQ(last_index + 1, index);
79       last_index = index;
80     }
81   }
82 }
83 
84 // Tests that the zeroth-degree, zeroth-order ALP is always 1.
TEST(AssociatedLegendrePolynomialsGeneratorTest,Generate_ZerothElementIsOne)85 TEST(AssociatedLegendrePolynomialsGeneratorTest, Generate_ZerothElementIsOne) {
86   const int kMaxDegree = 10;
87   for (int max_degree = 0; max_degree <= kMaxDegree; ++max_degree) {
88     for (int condon_shortley_phase = 0; condon_shortley_phase <= 1;
89          ++condon_shortley_phase) {
90       for (int compute_negative_order = 0; compute_negative_order <= 1;
91            ++compute_negative_order) {
92         AssociatedLegendrePolynomialsGenerator alp_generator(
93             max_degree, condon_shortley_phase != 0,
94             compute_negative_order != 0);
95 
96         const float kVariableStep = 0.2f;
97         for (float x = -1.0f; x <= 1.0f; x += kVariableStep) {
98           const std::vector<float> values = alp_generator.Generate(x);
99 
100           EXPECT_NEAR(values[0], 1.0f, kEpsilon);
101         }
102       }
103     }
104   }
105 }
106 
107 // Tests that the polynomials generated are correct until the 4th degree.
TEST(AssociatedLegendrePolynomialsGeneratorTest,Generate_CorrectFourthDegree)108 TEST(AssociatedLegendrePolynomialsGeneratorTest, Generate_CorrectFourthDegree) {
109   const int kMaxDegree = 4;
110   const bool kCondonShortleyPhase = true;
111   const bool kComputeNegativeOrder = true;
112   const AssociatedLegendrePolynomialsGenerator alp_generator(
113       kMaxDegree, kCondonShortleyPhase, kComputeNegativeOrder);
114 
115   const float kVariableStep = 0.05f;
116   for (float x = -1.0f; x <= 1.0f; x += kVariableStep) {
117     const std::vector<float> generated_values = alp_generator.Generate(x);
118     const std::vector<float> expected_values =
119         GenerateExpectedValuesFourthDegree(x);
120     ASSERT_EQ(expected_values.size(), generated_values.size());
121     for (size_t i = 0; i < expected_values.size(); ++i) {
122       EXPECT_NEAR(generated_values[i], expected_values[i], kEpsilon)
123           << " at index " << i;
124     }
125   }
126 }
127 
128 // Tests that the Condon-Shortley phase is correctly applied.
TEST(AssociatedLegendrePolynomialsGeneratorTest,Generate_CondonShortleyPhase)129 TEST(AssociatedLegendrePolynomialsGeneratorTest, Generate_CondonShortleyPhase) {
130   const int kMaxDegree = 10;
131   const float kValue = 0.12345f;
132   for (int max_degree = 0; max_degree <= kMaxDegree; ++max_degree) {
133     for (int compute_negative_order = 0; compute_negative_order <= 1;
134          ++compute_negative_order) {
135       const AssociatedLegendrePolynomialsGenerator alp_generator_without_phase(
136           max_degree, false, compute_negative_order != 0);
137       const std::vector<float> values_without_phase =
138           alp_generator_without_phase.Generate(kValue);
139 
140       const AssociatedLegendrePolynomialsGenerator alp_generator_with_phase(
141           max_degree, true, compute_negative_order != 0);
142       const std::vector<float> values_with_phase =
143           alp_generator_with_phase.Generate(kValue);
144 
145       ASSERT_EQ(values_with_phase.size(), values_without_phase.size());
146       for (int degree = 0; degree <= max_degree; ++degree) {
147         const int start_order = compute_negative_order ? -degree : 0;
148         for (int order = start_order; order <= degree; ++order) {
149           const size_t index =
150               alp_generator_without_phase.GetIndex(degree, order);
151           const float expected = values_without_phase[index] *
152                                  std::pow(-1.0f, static_cast<float>(order));
153           EXPECT_NEAR(values_with_phase[index], expected, kEpsilon)
154               << " at degree " << degree << " and order " << order;
155         }
156       }
157     }
158   }
159 }
160 
161 }  // namespace
162 }  // namespace iamf_tools
163