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