xref: /btstack/3rd-party/lc3-google/test/mdct.py (revision 4c4eb519208b4224604d94b3ed1931841ddd93bb)
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 Ringwaldimport scipy.fft
194930cef6SMatthias Ringwald
20*4c4eb519SMatthias Ringwaldimport lc3
214930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
224930cef6SMatthias Ringwald
234930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
244930cef6SMatthias Ringwald
254930cef6SMatthias Ringwaldclass Mdct:
264930cef6SMatthias Ringwald
274930cef6SMatthias Ringwald    W = [ [ T.W_7M5_60, T.W_7M5_120, T.W_7M5_180, T.W_7M5_240, T.W_7M5_360 ],
284930cef6SMatthias Ringwald          [ T.W_10M_80, T.W_10M_160, T.W_10M_240, T.W_10M_320, T.W_10M_480 ] ]
294930cef6SMatthias Ringwald
304930cef6SMatthias Ringwald    def __init__(self, dt, sr):
314930cef6SMatthias Ringwald
324930cef6SMatthias Ringwald        self.ns = T.NS[dt][sr]
334930cef6SMatthias Ringwald        self.nd = T.ND[dt][sr]
344930cef6SMatthias Ringwald
354930cef6SMatthias Ringwald        self.t = np.zeros(2*self.ns)
364930cef6SMatthias Ringwald        self.w = Mdct.W[dt][sr]
374930cef6SMatthias Ringwald
384930cef6SMatthias Ringwald
394930cef6SMatthias Ringwaldclass MdctForward(Mdct):
404930cef6SMatthias Ringwald
414930cef6SMatthias Ringwald    def __init__(self, dt, sr):
424930cef6SMatthias Ringwald
434930cef6SMatthias Ringwald        super().__init__(dt, sr)
444930cef6SMatthias Ringwald
454930cef6SMatthias Ringwald    def run(self, x):
464930cef6SMatthias Ringwald
474930cef6SMatthias Ringwald        ns = self.ns
484930cef6SMatthias Ringwald        nd = self.nd
494930cef6SMatthias Ringwald
504930cef6SMatthias Ringwald        self.t[nd:nd+ns] = x
514930cef6SMatthias Ringwald        t = self.t * self.w
524930cef6SMatthias Ringwald        self.t[0:nd] = x[ns-nd:]
534930cef6SMatthias Ringwald
544930cef6SMatthias Ringwald        n  = len(t)
554930cef6SMatthias Ringwald        n2 = n // 2
564930cef6SMatthias Ringwald
574930cef6SMatthias Ringwald        z = t * np.exp(-2j * np.pi * np.arange(n) / (2*n))
584930cef6SMatthias Ringwald        z = scipy.fft.fft(z)[:n2]
594930cef6SMatthias Ringwald        z = z * np.exp(-2j * np.pi *
604930cef6SMatthias Ringwald                (n2/2 + 0.5) * (np.arange(n2) + 0.5) / (2 * n2))
614930cef6SMatthias Ringwald        return np.real(z) * np.sqrt(2/n2)
624930cef6SMatthias Ringwald
634930cef6SMatthias Ringwald
644930cef6SMatthias Ringwaldclass MdctInverse(Mdct):
654930cef6SMatthias Ringwald
664930cef6SMatthias Ringwald    def __init__(self, dt, sr):
674930cef6SMatthias Ringwald
684930cef6SMatthias Ringwald        super().__init__(dt, sr)
694930cef6SMatthias Ringwald
704930cef6SMatthias Ringwald    def run(self, x):
714930cef6SMatthias Ringwald
724930cef6SMatthias Ringwald        ns = self.ns
734930cef6SMatthias Ringwald        nd = self.nd
744930cef6SMatthias Ringwald
754930cef6SMatthias Ringwald        n = len(x)
764930cef6SMatthias Ringwald
774930cef6SMatthias Ringwald        x = np.append(x, -x[::-1])
784930cef6SMatthias Ringwald        z = x * np.exp(2j * np.pi * (n/2 + 0.5) * np.arange(2*n) / (2*n))
794930cef6SMatthias Ringwald        z = scipy.fft.ifft(z) * n
804930cef6SMatthias Ringwald        z = z * np.exp(2j * np.pi * (np.arange(2*n) + (n/2 + 0.5)) / (4*n))
814930cef6SMatthias Ringwald        t = np.real(z) * np.sqrt(2/n)
824930cef6SMatthias Ringwald
834930cef6SMatthias Ringwald        t = t * self.w[::-1]
844930cef6SMatthias Ringwald
854930cef6SMatthias Ringwald        y = np.empty(ns)
864930cef6SMatthias Ringwald        y[:nd] = t[ns-nd:ns] + self.t[2*ns-nd:]
874930cef6SMatthias Ringwald        y[nd:] = t[ns:2*ns-nd]
884930cef6SMatthias Ringwald        self.t = t
894930cef6SMatthias Ringwald
904930cef6SMatthias Ringwald        return y
914930cef6SMatthias Ringwald
924930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
934930cef6SMatthias Ringwald
944930cef6SMatthias Ringwalddef check_forward_unit(rng, dt, sr):
954930cef6SMatthias Ringwald
964930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
974930cef6SMatthias Ringwald    nd = T.ND[dt][sr]
984930cef6SMatthias Ringwald    ok = True
994930cef6SMatthias Ringwald
1004930cef6SMatthias Ringwald    x = (2 * rng.random(ns)) - 1
1014930cef6SMatthias Ringwald
1024930cef6SMatthias Ringwald    y   = [ None ] * 2
1034930cef6SMatthias Ringwald    y_c = [ None ] * 2
1044930cef6SMatthias Ringwald
1054930cef6SMatthias Ringwald    mdct = MdctForward(dt, sr)
1064930cef6SMatthias Ringwald    y[0] = mdct.run(x)
1074930cef6SMatthias Ringwald    y[1] = mdct.run(x)
1084930cef6SMatthias Ringwald
1094930cef6SMatthias Ringwald    (y_c[0], d_c) = lc3.mdct_forward(dt, sr, x, np.zeros(nd))
1104930cef6SMatthias Ringwald    y_c[1] = lc3.mdct_forward(dt, sr, x, d_c)[0]
1114930cef6SMatthias Ringwald
1124930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
1134930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
1144930cef6SMatthias Ringwald
1154930cef6SMatthias Ringwald    return ok
1164930cef6SMatthias Ringwald
1174930cef6SMatthias Ringwald
1184930cef6SMatthias Ringwalddef check_forward_appendix_c(dt):
1194930cef6SMatthias Ringwald
1204930cef6SMatthias Ringwald    sr = T.SRATE_16K
1214930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
1224930cef6SMatthias Ringwald    nd = T.ND[dt][sr]
1234930cef6SMatthias Ringwald    ok = True
1244930cef6SMatthias Ringwald
1254930cef6SMatthias Ringwald    (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][0], np.zeros(nd))
1264930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y - C.X[dt][0])) < 1e-1
1274930cef6SMatthias Ringwald
1284930cef6SMatthias Ringwald    (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][1], d)
1294930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y - C.X[dt][1])) < 1e-1
1304930cef6SMatthias Ringwald
1314930cef6SMatthias Ringwald    return ok
1324930cef6SMatthias Ringwald
1334930cef6SMatthias Ringwald
1344930cef6SMatthias Ringwalddef check_inverse_unit(rng, dt, sr):
1354930cef6SMatthias Ringwald
1364930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
1374930cef6SMatthias Ringwald    nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt]
1384930cef6SMatthias Ringwald    ok = True
1394930cef6SMatthias Ringwald
1404930cef6SMatthias Ringwald    x  = (2 * rng.random(ns)) - 1
1414930cef6SMatthias Ringwald
1424930cef6SMatthias Ringwald    y   = [ None ] * 2
1434930cef6SMatthias Ringwald    y_c = [ None ] * 2
1444930cef6SMatthias Ringwald
1454930cef6SMatthias Ringwald    mdct = MdctInverse(dt, sr)
1464930cef6SMatthias Ringwald    y[0] = mdct.run(x)
1474930cef6SMatthias Ringwald    y[1] = mdct.run(x)
1484930cef6SMatthias Ringwald
1494930cef6SMatthias Ringwald    (y_c[0], d_c) = lc3.mdct_inverse(dt, sr, x, np.zeros(nd))
1504930cef6SMatthias Ringwald    y_c[1] = lc3.mdct_inverse(dt, sr, x, d_c)[0]
1514930cef6SMatthias Ringwald
1524930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
1534930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
1544930cef6SMatthias Ringwald
1554930cef6SMatthias Ringwald    return ok
1564930cef6SMatthias Ringwald
1574930cef6SMatthias Ringwald
1584930cef6SMatthias Ringwalddef check_inverse_appendix_c(dt):
1594930cef6SMatthias Ringwald
1604930cef6SMatthias Ringwald    sr = T.SRATE_16K
1614930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
1624930cef6SMatthias Ringwald    nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt]
1634930cef6SMatthias Ringwald    ok = True
1644930cef6SMatthias Ringwald
1654930cef6SMatthias Ringwald    (y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][0], np.zeros(nd))
1664930cef6SMatthias Ringwald    yr = C.T_HAT_MDCT[dt][0][ns-nd:2*ns-nd]
1674930cef6SMatthias Ringwald    dr = C.T_HAT_MDCT[dt][0][2*ns-nd:]
1684930cef6SMatthias Ringwald
1694930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(yr - y )) < 1e-1
1704930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(dr - d0)) < 1e-1
1714930cef6SMatthias Ringwald
1724930cef6SMatthias Ringwald    (y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][1], d0)
1734930cef6SMatthias Ringwald    yr[  :nd] = C.T_HAT_MDCT[dt][1][ns-nd:ns] + d0
1744930cef6SMatthias Ringwald    yr[nd:ns] = C.T_HAT_MDCT[dt][1][ns:2*ns-nd]
1754930cef6SMatthias Ringwald    dr        = C.T_HAT_MDCT[dt][1][2*ns-nd:]
1764930cef6SMatthias Ringwald
1774930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(yr - y )) < 1e-1
1784930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(dr - d1)) < 1e-1
1794930cef6SMatthias Ringwald
1804930cef6SMatthias Ringwald    return ok
1814930cef6SMatthias Ringwald
1824930cef6SMatthias Ringwald
1834930cef6SMatthias Ringwalddef check():
1844930cef6SMatthias Ringwald
1854930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
1864930cef6SMatthias Ringwald
1874930cef6SMatthias Ringwald    ok  = True
1884930cef6SMatthias Ringwald
1894930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
1904930cef6SMatthias Ringwald        for sr in range(T.NUM_SRATE):
1914930cef6SMatthias Ringwald            ok = ok and check_forward_unit(rng, dt, sr)
1924930cef6SMatthias Ringwald            ok = ok and check_inverse_unit(rng, dt, sr)
1934930cef6SMatthias Ringwald
1944930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
1954930cef6SMatthias Ringwald        ok = ok and check_forward_appendix_c(dt)
1964930cef6SMatthias Ringwald        ok = ok and check_inverse_appendix_c(dt)
1974930cef6SMatthias Ringwald
1984930cef6SMatthias Ringwald    return ok
199