xref: /aosp_15_r20/external/liblc3/test/bwdet.py (revision 49fe348c0058011ee60b6957cdd9d52742df84bc)
1*49fe348cSAndroid Build Coastguard Worker#
2*49fe348cSAndroid Build Coastguard Worker# Copyright 2022 Google LLC
3*49fe348cSAndroid Build Coastguard Worker#
4*49fe348cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*49fe348cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*49fe348cSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*49fe348cSAndroid Build Coastguard Worker#
8*49fe348cSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
9*49fe348cSAndroid Build Coastguard Worker#
10*49fe348cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*49fe348cSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*49fe348cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*49fe348cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*49fe348cSAndroid Build Coastguard Worker# limitations under the License.
15*49fe348cSAndroid Build Coastguard Worker#
16*49fe348cSAndroid Build Coastguard Worker
17*49fe348cSAndroid Build Coastguard Workerimport numpy as np
18*49fe348cSAndroid Build Coastguard Worker
19*49fe348cSAndroid Build Coastguard Workerimport lc3
20*49fe348cSAndroid Build Coastguard Workerimport tables as T, appendix_c as C
21*49fe348cSAndroid Build Coastguard Worker
22*49fe348cSAndroid Build Coastguard Worker
23*49fe348cSAndroid Build Coastguard WorkerBW_START = [
24*49fe348cSAndroid Build Coastguard Worker    [ [], [ 24 ], [ 24, 35 ], [ 24, 33, 39 ], [ 22, 31, 37, 41 ] ],
25*49fe348cSAndroid Build Coastguard Worker    [ [], [ 39 ], [ 35, 47 ], [ 34, 44, 50 ], [ 32, 42, 48, 52 ] ],
26*49fe348cSAndroid Build Coastguard Worker    [ [], [ 51 ], [ 45, 58 ], [ 42, 53, 60 ], [ 40, 51, 57, 61 ] ],
27*49fe348cSAndroid Build Coastguard Worker    [ [], [ 53 ], [ 47, 59 ], [ 44, 54, 60 ], [ 41, 51, 57, 61 ] ]
28*49fe348cSAndroid Build Coastguard Worker]
29*49fe348cSAndroid Build Coastguard Worker
30*49fe348cSAndroid Build Coastguard WorkerBW_STOP = [
31*49fe348cSAndroid Build Coastguard Worker    [ [], [ 34 ], [ 32, 39 ], [ 31, 38, 42 ], [ 29, 35, 40, 43 ] ],
32*49fe348cSAndroid Build Coastguard Worker    [ [], [ 49 ], [ 44, 51 ], [ 42, 49, 53 ], [ 40, 46, 51, 54 ] ],
33*49fe348cSAndroid Build Coastguard Worker    [ [], [ 63 ], [ 55, 63 ], [ 51, 58, 63 ], [ 48, 55, 60, 63 ] ],
34*49fe348cSAndroid Build Coastguard Worker    [ [], [ 63 ], [ 56, 63 ], [ 52, 59, 63 ], [ 49, 55, 60, 63 ] ]
35*49fe348cSAndroid Build Coastguard Worker]
36*49fe348cSAndroid Build Coastguard Worker
37*49fe348cSAndroid Build Coastguard WorkerTQ = [ 20, 10, 10, 10 ]
38*49fe348cSAndroid Build Coastguard Worker
39*49fe348cSAndroid Build Coastguard WorkerTC = [ 15, 23, 20, 20 ]
40*49fe348cSAndroid Build Coastguard WorkerL  = [ [ 4, 4, 3, 1 ], [ 4, 4, 3, 1 ],
41*49fe348cSAndroid Build Coastguard Worker       [ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ]
42*49fe348cSAndroid Build Coastguard Worker
43*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
44*49fe348cSAndroid Build Coastguard Worker
45*49fe348cSAndroid Build Coastguard Workerclass BandwidthDetector:
46*49fe348cSAndroid Build Coastguard Worker
47*49fe348cSAndroid Build Coastguard Worker    def __init__(self, dt, sr):
48*49fe348cSAndroid Build Coastguard Worker
49*49fe348cSAndroid Build Coastguard Worker        self.dt = dt
50*49fe348cSAndroid Build Coastguard Worker        self.sr = sr
51*49fe348cSAndroid Build Coastguard Worker
52*49fe348cSAndroid Build Coastguard Worker    def run(self, e):
53*49fe348cSAndroid Build Coastguard Worker
54*49fe348cSAndroid Build Coastguard Worker        dt = self.dt
55*49fe348cSAndroid Build Coastguard Worker        sr = self.sr
56*49fe348cSAndroid Build Coastguard Worker
57*49fe348cSAndroid Build Coastguard Worker        ### Stage 1, determine bw0 candidate
58*49fe348cSAndroid Build Coastguard Worker
59*49fe348cSAndroid Build Coastguard Worker        bw0 = 0
60*49fe348cSAndroid Build Coastguard Worker
61*49fe348cSAndroid Build Coastguard Worker        for bw in range(sr):
62*49fe348cSAndroid Build Coastguard Worker            i0 = BW_START[dt][sr][bw]
63*49fe348cSAndroid Build Coastguard Worker            i1 = BW_STOP[dt][sr][bw]
64*49fe348cSAndroid Build Coastguard Worker            if np.mean(e[i0:i1+1]) >= TQ[bw]:
65*49fe348cSAndroid Build Coastguard Worker                bw0 = bw + 1
66*49fe348cSAndroid Build Coastguard Worker
67*49fe348cSAndroid Build Coastguard Worker        ### Stage 2, Cut-off random coefficients at each steps
68*49fe348cSAndroid Build Coastguard Worker
69*49fe348cSAndroid Build Coastguard Worker        bw = bw0
70*49fe348cSAndroid Build Coastguard Worker
71*49fe348cSAndroid Build Coastguard Worker        if bw0 < sr:
72*49fe348cSAndroid Build Coastguard Worker            l  = L[dt][bw0]
73*49fe348cSAndroid Build Coastguard Worker            i0 = BW_START[dt][sr][bw0] - l
74*49fe348cSAndroid Build Coastguard Worker            i1 = BW_START[dt][sr][bw0]
75*49fe348cSAndroid Build Coastguard Worker
76*49fe348cSAndroid Build Coastguard Worker            c = 10 * np.log10(1e-31 + e[i0-l+1:i1-l+2] / e[i0+1:i1+2])
77*49fe348cSAndroid Build Coastguard Worker            if np.amax(c) <= TC[bw0]:
78*49fe348cSAndroid Build Coastguard Worker                bw = sr
79*49fe348cSAndroid Build Coastguard Worker
80*49fe348cSAndroid Build Coastguard Worker        self.bw = bw
81*49fe348cSAndroid Build Coastguard Worker        return self.bw
82*49fe348cSAndroid Build Coastguard Worker
83*49fe348cSAndroid Build Coastguard Worker    def get_nbits(self):
84*49fe348cSAndroid Build Coastguard Worker
85*49fe348cSAndroid Build Coastguard Worker        return 0 if self.sr == 0 else \
86*49fe348cSAndroid Build Coastguard Worker               1 + np.log2(self.sr).astype(int)
87*49fe348cSAndroid Build Coastguard Worker
88*49fe348cSAndroid Build Coastguard Worker    def store(self, b):
89*49fe348cSAndroid Build Coastguard Worker
90*49fe348cSAndroid Build Coastguard Worker        b.write_uint(self.bw, self.get_nbits())
91*49fe348cSAndroid Build Coastguard Worker
92*49fe348cSAndroid Build Coastguard Worker    def get(self, b):
93*49fe348cSAndroid Build Coastguard Worker
94*49fe348cSAndroid Build Coastguard Worker        return b.read_uint(self.get_nbits())
95*49fe348cSAndroid Build Coastguard Worker
96*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
97*49fe348cSAndroid Build Coastguard Worker
98*49fe348cSAndroid Build Coastguard Workerdef check_unit(rng, dt, sr):
99*49fe348cSAndroid Build Coastguard Worker
100*49fe348cSAndroid Build Coastguard Worker    ok = True
101*49fe348cSAndroid Build Coastguard Worker
102*49fe348cSAndroid Build Coastguard Worker    bwdet = BandwidthDetector(dt, sr)
103*49fe348cSAndroid Build Coastguard Worker
104*49fe348cSAndroid Build Coastguard Worker    for bw0 in range(sr+1):
105*49fe348cSAndroid Build Coastguard Worker        for drop in range(10):
106*49fe348cSAndroid Build Coastguard Worker
107*49fe348cSAndroid Build Coastguard Worker            ### Generate random 'high' energy and
108*49fe348cSAndroid Build Coastguard Worker            ### scale relevant bands to select 'bw0'
109*49fe348cSAndroid Build Coastguard Worker
110*49fe348cSAndroid Build Coastguard Worker            e = 20 + 100 * rng.random(64)
111*49fe348cSAndroid Build Coastguard Worker
112*49fe348cSAndroid Build Coastguard Worker            for i in range(sr):
113*49fe348cSAndroid Build Coastguard Worker                if i+1 != bw0:
114*49fe348cSAndroid Build Coastguard Worker                    i0 = BW_START[dt][sr][i]
115*49fe348cSAndroid Build Coastguard Worker                    i1 = BW_STOP[dt][sr][i]
116*49fe348cSAndroid Build Coastguard Worker                    e[i0:i1+1] /= (np.mean(e[i0:i1+1]) / TQ[i] + 1e-3)
117*49fe348cSAndroid Build Coastguard Worker
118*49fe348cSAndroid Build Coastguard Worker            ### Stage 2 Condition,
119*49fe348cSAndroid Build Coastguard Worker            ### cut-off random coefficients at each steps
120*49fe348cSAndroid Build Coastguard Worker
121*49fe348cSAndroid Build Coastguard Worker            if bw0 < sr:
122*49fe348cSAndroid Build Coastguard Worker                l  = L[dt][bw0]
123*49fe348cSAndroid Build Coastguard Worker                i0 = BW_START[dt][sr][bw0] - l
124*49fe348cSAndroid Build Coastguard Worker                i1 = BW_START[dt][sr][bw0]
125*49fe348cSAndroid Build Coastguard Worker
126*49fe348cSAndroid Build Coastguard Worker                e[i0-l+1:i1+2] /= np.power(10, np.arange(2*l+1) / (1 + drop))
127*49fe348cSAndroid Build Coastguard Worker
128*49fe348cSAndroid Build Coastguard Worker            ### Check with implementation
129*49fe348cSAndroid Build Coastguard Worker
130*49fe348cSAndroid Build Coastguard Worker            bw_c = lc3.bwdet_run(dt, sr, e)
131*49fe348cSAndroid Build Coastguard Worker
132*49fe348cSAndroid Build Coastguard Worker            ok = ok and bw_c == bwdet.run(e)
133*49fe348cSAndroid Build Coastguard Worker
134*49fe348cSAndroid Build Coastguard Worker    return ok
135*49fe348cSAndroid Build Coastguard Worker
136*49fe348cSAndroid Build Coastguard Workerdef check_appendix_c(dt):
137*49fe348cSAndroid Build Coastguard Worker
138*49fe348cSAndroid Build Coastguard Worker    i0 = dt - T.DT_7M5
139*49fe348cSAndroid Build Coastguard Worker    sr = T.SRATE_16K
140*49fe348cSAndroid Build Coastguard Worker
141*49fe348cSAndroid Build Coastguard Worker    ok = True
142*49fe348cSAndroid Build Coastguard Worker
143*49fe348cSAndroid Build Coastguard Worker    E_B  = C.E_B[i0]
144*49fe348cSAndroid Build Coastguard Worker    P_BW = C.P_BW[i0]
145*49fe348cSAndroid Build Coastguard Worker
146*49fe348cSAndroid Build Coastguard Worker    bw = lc3.bwdet_run(dt, sr, E_B[0])
147*49fe348cSAndroid Build Coastguard Worker    ok = ok and bw == P_BW[0]
148*49fe348cSAndroid Build Coastguard Worker
149*49fe348cSAndroid Build Coastguard Worker    bw = lc3.bwdet_run(dt, sr, E_B[1])
150*49fe348cSAndroid Build Coastguard Worker    ok = ok and bw == P_BW[1]
151*49fe348cSAndroid Build Coastguard Worker
152*49fe348cSAndroid Build Coastguard Worker    return ok
153*49fe348cSAndroid Build Coastguard Worker
154*49fe348cSAndroid Build Coastguard Workerdef check():
155*49fe348cSAndroid Build Coastguard Worker
156*49fe348cSAndroid Build Coastguard Worker    rng = np.random.default_rng(1234)
157*49fe348cSAndroid Build Coastguard Worker
158*49fe348cSAndroid Build Coastguard Worker    ok = True
159*49fe348cSAndroid Build Coastguard Worker    for dt in range(T.NUM_DT):
160*49fe348cSAndroid Build Coastguard Worker        for sr in range(T.SRATE_8K, T.SRATE_48K + 1):
161*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_unit(rng, dt, sr)
162*49fe348cSAndroid Build Coastguard Worker
163*49fe348cSAndroid Build Coastguard Worker    for dt in ( T.DT_7M5, T.DT_10M ):
164*49fe348cSAndroid Build Coastguard Worker        ok = ok and check_appendix_c(dt)
165*49fe348cSAndroid Build Coastguard Worker
166*49fe348cSAndroid Build Coastguard Worker    return ok
167*49fe348cSAndroid Build Coastguard Worker
168*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
169