xref: /btstack/3rd-party/lc3-google/test/bwdet.py (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
14930cef6SMatthias Ringwald#
24930cef6SMatthias Ringwald# Copyright 2022 Google LLC
34930cef6SMatthias Ringwald#
44930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License");
54930cef6SMatthias Ringwald# you may not use this file except in compliance with the License.
64930cef6SMatthias Ringwald# You may obtain a copy of the License at
74930cef6SMatthias Ringwald#
84930cef6SMatthias Ringwald#     http://www.apache.org/licenses/LICENSE-2.0
94930cef6SMatthias Ringwald#
104930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software
114930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS,
124930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134930cef6SMatthias Ringwald# See the License for the specific language governing permissions and
144930cef6SMatthias Ringwald# limitations under the License.
154930cef6SMatthias Ringwald#
164930cef6SMatthias Ringwald
174930cef6SMatthias Ringwaldimport numpy as np
184930cef6SMatthias Ringwald
194c4eb519SMatthias Ringwaldimport lc3
204930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
214930cef6SMatthias Ringwald
224930cef6SMatthias Ringwald
234930cef6SMatthias RingwaldBW_START = [
24*6897da5cSDirk Helbig    [ [], [ 24 ], [ 24, 35 ], [ 24, 33, 39 ], [ 22, 31, 37, 41 ] ],
25*6897da5cSDirk Helbig    [ [], [ 39 ], [ 35, 47 ], [ 34, 44, 50 ], [ 32, 42, 48, 52 ] ],
264930cef6SMatthias Ringwald    [ [], [ 51 ], [ 45, 58 ], [ 42, 53, 60 ], [ 40, 51, 57, 61 ] ],
274930cef6SMatthias Ringwald    [ [], [ 53 ], [ 47, 59 ], [ 44, 54, 60 ], [ 41, 51, 57, 61 ] ]
284930cef6SMatthias Ringwald]
294930cef6SMatthias Ringwald
304930cef6SMatthias RingwaldBW_STOP = [
31*6897da5cSDirk Helbig    [ [], [ 34 ], [ 32, 39 ], [ 31, 38, 42 ], [ 29, 35, 40, 43 ] ],
32*6897da5cSDirk Helbig    [ [], [ 49 ], [ 44, 51 ], [ 42, 49, 53 ], [ 40, 46, 51, 54 ] ],
334930cef6SMatthias Ringwald    [ [], [ 63 ], [ 55, 63 ], [ 51, 58, 63 ], [ 48, 55, 60, 63 ] ],
344930cef6SMatthias Ringwald    [ [], [ 63 ], [ 56, 63 ], [ 52, 59, 63 ], [ 49, 55, 60, 63 ] ]
354930cef6SMatthias Ringwald]
364930cef6SMatthias Ringwald
374930cef6SMatthias RingwaldTQ = [ 20, 10, 10, 10 ]
384930cef6SMatthias Ringwald
394930cef6SMatthias RingwaldTC = [ 15, 23, 20, 20 ]
40*6897da5cSDirk HelbigL  = [ [ 4, 4, 3, 1 ], [ 4, 4, 3, 1 ],
41*6897da5cSDirk Helbig       [ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ]
424930cef6SMatthias Ringwald
434930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
444930cef6SMatthias Ringwald
454930cef6SMatthias Ringwaldclass BandwidthDetector:
464930cef6SMatthias Ringwald
474930cef6SMatthias Ringwald    def __init__(self, dt, sr):
484930cef6SMatthias Ringwald
494930cef6SMatthias Ringwald        self.dt = dt
504930cef6SMatthias Ringwald        self.sr = sr
514930cef6SMatthias Ringwald
524930cef6SMatthias Ringwald    def run(self, e):
534930cef6SMatthias Ringwald
544930cef6SMatthias Ringwald        dt = self.dt
554930cef6SMatthias Ringwald        sr = self.sr
564930cef6SMatthias Ringwald
574930cef6SMatthias Ringwald        ### Stage 1, determine bw0 candidate
584930cef6SMatthias Ringwald
594930cef6SMatthias Ringwald        bw0 = 0
604930cef6SMatthias Ringwald
614930cef6SMatthias Ringwald        for bw in range(sr):
624930cef6SMatthias Ringwald            i0 = BW_START[dt][sr][bw]
634930cef6SMatthias Ringwald            i1 = BW_STOP[dt][sr][bw]
644930cef6SMatthias Ringwald            if np.mean(e[i0:i1+1]) >= TQ[bw]:
654930cef6SMatthias Ringwald                bw0 = bw + 1
664930cef6SMatthias Ringwald
674930cef6SMatthias Ringwald        ### Stage 2, Cut-off random coefficients at each steps
684930cef6SMatthias Ringwald
694930cef6SMatthias Ringwald        bw = bw0
704930cef6SMatthias Ringwald
714930cef6SMatthias Ringwald        if bw0 < sr:
724930cef6SMatthias Ringwald            l  = L[dt][bw0]
734930cef6SMatthias Ringwald            i0 = BW_START[dt][sr][bw0] - l
744930cef6SMatthias Ringwald            i1 = BW_START[dt][sr][bw0]
754930cef6SMatthias Ringwald
764930cef6SMatthias Ringwald            c = 10 * np.log10(1e-31 + e[i0-l+1:i1-l+2] / e[i0+1:i1+2])
774930cef6SMatthias Ringwald            if np.amax(c) <= TC[bw0]:
784930cef6SMatthias Ringwald                bw = sr
794930cef6SMatthias Ringwald
804930cef6SMatthias Ringwald        self.bw = bw
814930cef6SMatthias Ringwald        return self.bw
824930cef6SMatthias Ringwald
834930cef6SMatthias Ringwald    def get_nbits(self):
844930cef6SMatthias Ringwald
854930cef6SMatthias Ringwald        return 0 if self.sr == 0 else \
864930cef6SMatthias Ringwald               1 + np.log2(self.sr).astype(int)
874930cef6SMatthias Ringwald
884c4eb519SMatthias Ringwald    def store(self, b):
894930cef6SMatthias Ringwald
904930cef6SMatthias Ringwald        b.write_uint(self.bw, self.get_nbits())
914930cef6SMatthias Ringwald
924c4eb519SMatthias Ringwald    def get(self, b):
934930cef6SMatthias Ringwald
944930cef6SMatthias Ringwald        return b.read_uint(self.get_nbits())
954930cef6SMatthias Ringwald
964930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
974930cef6SMatthias Ringwald
984930cef6SMatthias Ringwalddef check_unit(rng, dt, sr):
994930cef6SMatthias Ringwald
1004930cef6SMatthias Ringwald    ok = True
1014930cef6SMatthias Ringwald
1024930cef6SMatthias Ringwald    bwdet = BandwidthDetector(dt, sr)
1034930cef6SMatthias Ringwald
1044930cef6SMatthias Ringwald    for bw0 in range(sr+1):
1054930cef6SMatthias Ringwald        for drop in range(10):
1064930cef6SMatthias Ringwald
1074930cef6SMatthias Ringwald            ### Generate random 'high' energy and
1084930cef6SMatthias Ringwald            ### scale relevant bands to select 'bw0'
1094930cef6SMatthias Ringwald
1104930cef6SMatthias Ringwald            e = 20 + 100 * rng.random(64)
1114930cef6SMatthias Ringwald
1124930cef6SMatthias Ringwald            for i in range(sr):
1134930cef6SMatthias Ringwald                if i+1 != bw0:
1144930cef6SMatthias Ringwald                    i0 = BW_START[dt][sr][i]
1154930cef6SMatthias Ringwald                    i1 = BW_STOP[dt][sr][i]
1164930cef6SMatthias Ringwald                    e[i0:i1+1] /= (np.mean(e[i0:i1+1]) / TQ[i] + 1e-3)
1174930cef6SMatthias Ringwald
1184930cef6SMatthias Ringwald            ### Stage 2 Condition,
1194930cef6SMatthias Ringwald            ### cut-off random coefficients at each steps
1204930cef6SMatthias Ringwald
1214930cef6SMatthias Ringwald            if bw0 < sr:
1224930cef6SMatthias Ringwald                l  = L[dt][bw0]
1234930cef6SMatthias Ringwald                i0 = BW_START[dt][sr][bw0] - l
1244930cef6SMatthias Ringwald                i1 = BW_START[dt][sr][bw0]
1254930cef6SMatthias Ringwald
1264930cef6SMatthias Ringwald                e[i0-l+1:i1+2] /= np.power(10, np.arange(2*l+1) / (1 + drop))
1274930cef6SMatthias Ringwald
1284930cef6SMatthias Ringwald            ### Check with implementation
1294930cef6SMatthias Ringwald
1304930cef6SMatthias Ringwald            bw_c = lc3.bwdet_run(dt, sr, e)
1314930cef6SMatthias Ringwald
1324930cef6SMatthias Ringwald            ok = ok and bw_c == bwdet.run(e)
1334930cef6SMatthias Ringwald
1344930cef6SMatthias Ringwald    return ok
1354930cef6SMatthias Ringwald
1364930cef6SMatthias Ringwalddef check_appendix_c(dt):
1374930cef6SMatthias Ringwald
138*6897da5cSDirk Helbig    i0 = dt - T.DT_7M5
1394930cef6SMatthias Ringwald    sr = T.SRATE_16K
140*6897da5cSDirk Helbig
1414930cef6SMatthias Ringwald    ok = True
1424930cef6SMatthias Ringwald
143*6897da5cSDirk Helbig    E_B  = C.E_B[i0]
144*6897da5cSDirk Helbig    P_BW = C.P_BW[i0]
1454930cef6SMatthias Ringwald
1464930cef6SMatthias Ringwald    bw = lc3.bwdet_run(dt, sr, E_B[0])
1474930cef6SMatthias Ringwald    ok = ok and bw == P_BW[0]
1484930cef6SMatthias Ringwald
1494930cef6SMatthias Ringwald    bw = lc3.bwdet_run(dt, sr, E_B[1])
1504930cef6SMatthias Ringwald    ok = ok and bw == P_BW[1]
1514930cef6SMatthias Ringwald
1524930cef6SMatthias Ringwald    return ok
1534930cef6SMatthias Ringwald
1544930cef6SMatthias Ringwalddef check():
1554930cef6SMatthias Ringwald
1564930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
1574930cef6SMatthias Ringwald
1584930cef6SMatthias Ringwald    ok = True
1594930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
160*6897da5cSDirk Helbig        for sr in range(T.SRATE_8K, T.SRATE_48K + 1):
1614930cef6SMatthias Ringwald            ok = ok and check_unit(rng, dt, sr)
1624930cef6SMatthias Ringwald
163*6897da5cSDirk Helbig    for dt in ( T.DT_7M5, T.DT_10M ):
1644930cef6SMatthias Ringwald        ok = ok and check_appendix_c(dt)
1654930cef6SMatthias Ringwald
1664930cef6SMatthias Ringwald    return ok
1674930cef6SMatthias Ringwald
1684930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
169