summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/resonance-audio/resonance_audio/dsp/filter_coefficient_generators_test.cc
blob: 163b6a6d2a380112e6f7735a1e9d0bf76e17ac72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
Copyright 2018 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS-IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "dsp/filter_coefficient_generators.h"

#include "third_party/googletest/googletest/include/gtest/gtest.h"

namespace vraudio {

namespace {

// Allowable error between filter coefficients.
const float kErrorf = 1e-5f;

// Input into the ComputeLowPassBiquadCoefficients() function.
const int kSampleRate = 44100;
const float kSpecificationFrequency = 13000.0f;
const float kAttenuation = -15.0f;

const float kMonoPoleCoefficient = 0.94863985f;

// These filter coefficients were calculated in MATLAB with a specified Q value
// of 0.17775. The attenuation at the specification frequency was then
// calculated from the MATLAB freqz() calls.
const BiquadCoefficients kIdealCoefficients(3.70224817628938f,
                                            0.555382147099001f,
                                            -1.70224817628938f,
                                            0.63884553677475f, 1.2776910735495f,
                                            0.63884553677475f);

// These filter coefficients were calculated in MATLAB for a centre_frequency of
// 8kHz and a bandwidth of 1 octave.
const BiquadCoefficients kIdealBandpassCoefficients(1.37364799922092f, -1.0f,
                                                    0.626352000779082f,
                                                    0.373647999220918f, 0.0f,
                                                    -0.373647999220918f);

const float kBandPassCenterFrequency = 8000.0f;
const int kBandPassOctaveBandwidth = 1;

// Input into the ComputeDualBandBiquadCoefficients() function.
const int kSampleRate48 = 48000;
const float kCrossoverFrequency = 380.0f;

// Pre-computed coefficients for the phase-matched filter pair (dual-band) with
// the cross-over frequency set at 380Hz and the sample rate 48kHz.
const float kLowPassA[] = {1.0f, -1.9029109f, 0.90526748f};
const float kLowPassB[] = {0.00058914319f, 0.0011782864f, 0.00058914319f};
const float kHighPassA[] = {1.0f, -1.9029109f, 0.90526748f};
const float kHighPassB[] = {0.95204461f, -1.9040892f, 0.95204461f};

TEST(FilterCoefficientGeneratorsTest, ComputeMonoPoleLowpassCoefficientTest) {
  float coefficient =
      ComputeLowPassMonoPoleCoefficient(kCrossoverFrequency, kSampleRate);
  EXPECT_NEAR(kMonoPoleCoefficient, coefficient, kErrorf);

  const float twenty_hertz = 20.0f;
  coefficient = ComputeLowPassMonoPoleCoefficient(twenty_hertz, kSampleRate);
  EXPECT_EQ(0.0f, coefficient);
  // New test for the case where a frequency below 20Hz is passed.
}

// Tests that the BiquadCoefficients generated by
// ComputeBandPassBiquadCoefficients() match those known to be correct as
// directly calculated from MATLAB.
TEST(FilterCoefficientGeneratorsTest, ComputeBandPassBiquadCoefficientsTest) {
  // Perform computation.
  BiquadCoefficients biquad_filter_coefficients =
      ComputeBandPassBiquadCoefficients(kSampleRate48, kBandPassCenterFrequency,
                                        kBandPassOctaveBandwidth);

  // Make sure they are all equal.
  for (size_t i = 0; i < biquad_filter_coefficients.a.size(); ++i) {
    EXPECT_NEAR(kIdealBandpassCoefficients.a[i],
                biquad_filter_coefficients.a[i], kErrorf);
    EXPECT_NEAR(kIdealBandpassCoefficients.b[i],
                biquad_filter_coefficients.b[i], kErrorf);
  }
}

// Tests that the BiquadCoefficients generated by
// ComputeLowPassBiquadCoefficients() match those known to be correct as
// directly calculated from MATLAB. This also tests the validity of the inherent
// 4th order best fit between attenuation at a specified frequency and Q factor.
TEST(FilterCoefficientGeneratorsTest, ComputeLowPassBiquadCoefficientsTest) {
  // Perform computation.
  BiquadCoefficients biquad_filter_coefficients =
      ComputeLowPassBiquadCoefficients(kSampleRate, kSpecificationFrequency,
                                       kAttenuation);

  // Make sure they are all equal.
  for (size_t i = 0; i < biquad_filter_coefficients.a.size(); ++i) {
    EXPECT_NEAR(kIdealCoefficients.a[i], biquad_filter_coefficients.a[i],
                kErrorf);
    EXPECT_NEAR(kIdealCoefficients.b[i], biquad_filter_coefficients.b[i],
                kErrorf);
  }
}

// Tests that the BiquadCoefficients generated by
// ComputeDualBandBiquadCoefficients() match those known to be correct as
// directly calculated from MATLAB. These coefficients are as described in:
// http://www.ai.sri.com/ajh/ambisonics/BLaH3.pdf.
TEST(DualBandBiquadCoefficientsTest, ComputeDualBandBiquadCoefficientsTest) {
  // Generate default bi-quad coefficients and constructs low- and high-pass
  // filter coefficients.
  const BiquadCoefficients kDefaultCoefficients;
  BiquadCoefficients low_pass_coefficients(kDefaultCoefficients);
  BiquadCoefficients high_pass_coefficients(kDefaultCoefficients);

  // Perform computation.
  ComputeDualBandBiquadCoefficients(kSampleRate48, kCrossoverFrequency,
                                    &low_pass_coefficients,
                                    &high_pass_coefficients);

  // Check if arrays with a and b coefficients for both filters are of the
  // same size.
  ASSERT_EQ(low_pass_coefficients.a.size(), low_pass_coefficients.b.size());
  ASSERT_EQ(high_pass_coefficients.a.size(), low_pass_coefficients.a.size());
  ASSERT_EQ(high_pass_coefficients.b.size(), low_pass_coefficients.b.size());

  // Make sure they are all equal.
  for (size_t i = 0; i < low_pass_coefficients.a.size(); ++i) {
    EXPECT_NEAR(low_pass_coefficients.a[i], kLowPassA[i], kErrorf);
    EXPECT_NEAR(low_pass_coefficients.b[i], kLowPassB[i], kErrorf);
    EXPECT_NEAR(high_pass_coefficients.a[i], kHighPassA[i], kErrorf);
    EXPECT_NEAR(high_pass_coefficients.b[i], kHighPassB[i], kErrorf);
  }
}

}  // namespace

}  // namespace vraudio