xref: /btstack/3rd-party/lc3-google/test/mdct.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 Ringwaldimport scipy.fft
194930cef6SMatthias Ringwald
204c4eb519SMatthias Ringwaldimport lc3
214930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
224930cef6SMatthias Ringwald
234930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
244930cef6SMatthias Ringwald
254930cef6SMatthias Ringwaldclass Mdct:
264930cef6SMatthias Ringwald
27*6897da5cSDirk Helbig    W = [ [ T.W_2M5_8K , T.W_2M5_16K, T.W_2M5_24K,
28*6897da5cSDirk Helbig            T.W_2M5_32K, T.W_2M5_48K, T.W_2M5_48K_HR, T.W_2M5_96K_HR ],
29*6897da5cSDirk Helbig
30*6897da5cSDirk Helbig          [ T.W_5M_8K  , T.W_5M_16K , T.W_5M_24K ,
31*6897da5cSDirk Helbig            T.W_5M_32K , T.W_5M_48K , T.W_5M_48K_HR , T.W_5M_96K_HR  ],
32*6897da5cSDirk Helbig
33*6897da5cSDirk Helbig          [ T.W_7M5_8K , T.W_7M5_16K, T.W_7M5_24K,
34*6897da5cSDirk Helbig            T.W_7M5_32K, T.W_7M5_48K, None, None ],
35*6897da5cSDirk Helbig
36*6897da5cSDirk Helbig          [ T.W_10M_8K , T.W_10M_16K, T.W_10M_24K,
37*6897da5cSDirk Helbig            T.W_10M_32K, T.W_10M_48K, T.W_10M_48K_HR, T.W_10M_96K_HR ] ]
384930cef6SMatthias Ringwald
394930cef6SMatthias Ringwald    def __init__(self, dt, sr):
404930cef6SMatthias Ringwald
414930cef6SMatthias Ringwald        self.ns = T.NS[dt][sr]
424930cef6SMatthias Ringwald        self.nd = T.ND[dt][sr]
434930cef6SMatthias Ringwald
444930cef6SMatthias Ringwald        self.t = np.zeros(2*self.ns)
454930cef6SMatthias Ringwald        self.w = Mdct.W[dt][sr]
464930cef6SMatthias Ringwald
474930cef6SMatthias Ringwald
484930cef6SMatthias Ringwaldclass MdctForward(Mdct):
494930cef6SMatthias Ringwald
504930cef6SMatthias Ringwald    def __init__(self, dt, sr):
514930cef6SMatthias Ringwald
524930cef6SMatthias Ringwald        super().__init__(dt, sr)
534930cef6SMatthias Ringwald
544930cef6SMatthias Ringwald    def run(self, x):
554930cef6SMatthias Ringwald
564930cef6SMatthias Ringwald        ns = self.ns
574930cef6SMatthias Ringwald        nd = self.nd
584930cef6SMatthias Ringwald
594930cef6SMatthias Ringwald        self.t[nd:nd+ns] = x
604930cef6SMatthias Ringwald        t = self.t * self.w
614930cef6SMatthias Ringwald        self.t[0:nd] = x[ns-nd:]
624930cef6SMatthias Ringwald
634930cef6SMatthias Ringwald        n  = len(t)
644930cef6SMatthias Ringwald        n2 = n // 2
654930cef6SMatthias Ringwald
664930cef6SMatthias Ringwald        z = t * np.exp(-2j * np.pi * np.arange(n) / (2*n))
674930cef6SMatthias Ringwald        z = scipy.fft.fft(z)[:n2]
684930cef6SMatthias Ringwald        z = z * np.exp(-2j * np.pi *
694930cef6SMatthias Ringwald                (n2/2 + 0.5) * (np.arange(n2) + 0.5) / (2 * n2))
704930cef6SMatthias Ringwald        return np.real(z) * np.sqrt(2/n2)
714930cef6SMatthias Ringwald
724930cef6SMatthias Ringwald
734930cef6SMatthias Ringwaldclass MdctInverse(Mdct):
744930cef6SMatthias Ringwald
754930cef6SMatthias Ringwald    def __init__(self, dt, sr):
764930cef6SMatthias Ringwald
774930cef6SMatthias Ringwald        super().__init__(dt, sr)
784930cef6SMatthias Ringwald
794930cef6SMatthias Ringwald    def run(self, x):
804930cef6SMatthias Ringwald
814930cef6SMatthias Ringwald        ns = self.ns
824930cef6SMatthias Ringwald        nd = self.nd
834930cef6SMatthias Ringwald
844930cef6SMatthias Ringwald        n = len(x)
854930cef6SMatthias Ringwald
864930cef6SMatthias Ringwald        x = np.append(x, -x[::-1])
874930cef6SMatthias Ringwald        z = x * np.exp(2j * np.pi * (n/2 + 0.5) * np.arange(2*n) / (2*n))
884930cef6SMatthias Ringwald        z = scipy.fft.ifft(z) * n
894930cef6SMatthias Ringwald        z = z * np.exp(2j * np.pi * (np.arange(2*n) + (n/2 + 0.5)) / (4*n))
904930cef6SMatthias Ringwald        t = np.real(z) * np.sqrt(2/n)
914930cef6SMatthias Ringwald
924930cef6SMatthias Ringwald        t = t * self.w[::-1]
934930cef6SMatthias Ringwald
944930cef6SMatthias Ringwald        y = np.empty(ns)
954930cef6SMatthias Ringwald        y[:nd] = t[ns-nd:ns] + self.t[2*ns-nd:]
964930cef6SMatthias Ringwald        y[nd:] = t[ns:2*ns-nd]
974930cef6SMatthias Ringwald        self.t = t
984930cef6SMatthias Ringwald
994930cef6SMatthias Ringwald        return y
1004930cef6SMatthias Ringwald
1014930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
1024930cef6SMatthias Ringwald
1034930cef6SMatthias Ringwalddef check_forward_unit(rng, dt, sr):
1044930cef6SMatthias Ringwald
1054930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
1064930cef6SMatthias Ringwald    nd = T.ND[dt][sr]
1074930cef6SMatthias Ringwald    ok = True
1084930cef6SMatthias Ringwald
1094930cef6SMatthias Ringwald    x = (2 * rng.random(ns)) - 1
1104930cef6SMatthias Ringwald
1114930cef6SMatthias Ringwald    y   = [ None ] * 2
1124930cef6SMatthias Ringwald    y_c = [ None ] * 2
1134930cef6SMatthias Ringwald
1144930cef6SMatthias Ringwald    mdct = MdctForward(dt, sr)
1154930cef6SMatthias Ringwald    y[0] = mdct.run(x)
1164930cef6SMatthias Ringwald    y[1] = mdct.run(x)
1174930cef6SMatthias Ringwald
1184930cef6SMatthias Ringwald    (y_c[0], d_c) = lc3.mdct_forward(dt, sr, x, np.zeros(nd))
1194930cef6SMatthias Ringwald    y_c[1] = lc3.mdct_forward(dt, sr, x, d_c)[0]
1204930cef6SMatthias Ringwald
1214930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
1224930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
1234930cef6SMatthias Ringwald
1244930cef6SMatthias Ringwald    return ok
1254930cef6SMatthias Ringwald
1264930cef6SMatthias Ringwald
1274930cef6SMatthias Ringwalddef check_forward_appendix_c(dt):
1284930cef6SMatthias Ringwald
129*6897da5cSDirk Helbig    i0 = dt - T.DT_7M5
1304930cef6SMatthias Ringwald    sr = T.SRATE_16K
131*6897da5cSDirk Helbig
1324930cef6SMatthias Ringwald    ok = True
1334930cef6SMatthias Ringwald
134*6897da5cSDirk Helbig    ns = T.NS[dt][sr]
135*6897da5cSDirk Helbig    nd = T.ND[dt][sr]
1364930cef6SMatthias Ringwald
137*6897da5cSDirk Helbig    (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][0], np.zeros(nd))
138*6897da5cSDirk Helbig    ok = ok and np.amax(np.abs(y - C.X[i0][0])) < 1e-1
139*6897da5cSDirk Helbig
140*6897da5cSDirk Helbig    (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][1], d)
141*6897da5cSDirk Helbig    ok = ok and np.amax(np.abs(y - C.X[i0][1])) < 1e-1
1424930cef6SMatthias Ringwald
1434930cef6SMatthias Ringwald    return ok
1444930cef6SMatthias Ringwald
1454930cef6SMatthias Ringwald
1464930cef6SMatthias Ringwalddef check_inverse_unit(rng, dt, sr):
1474930cef6SMatthias Ringwald
1484930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
149*6897da5cSDirk Helbig    nd = T.ND[dt][sr]
1504930cef6SMatthias Ringwald    ok = True
1514930cef6SMatthias Ringwald
1524930cef6SMatthias Ringwald    x  = (2 * rng.random(ns)) - 1
1534930cef6SMatthias Ringwald
1544930cef6SMatthias Ringwald    y   = [ None ] * 2
1554930cef6SMatthias Ringwald    y_c = [ None ] * 2
1564930cef6SMatthias Ringwald
1574930cef6SMatthias Ringwald    mdct = MdctInverse(dt, sr)
1584930cef6SMatthias Ringwald    y[0] = mdct.run(x)
1594930cef6SMatthias Ringwald    y[1] = mdct.run(x)
1604930cef6SMatthias Ringwald
1614930cef6SMatthias Ringwald    (y_c[0], d_c) = lc3.mdct_inverse(dt, sr, x, np.zeros(nd))
1624930cef6SMatthias Ringwald    y_c[1] = lc3.mdct_inverse(dt, sr, x, d_c)[0]
1634930cef6SMatthias Ringwald
1644930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
1654930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
1664930cef6SMatthias Ringwald
1674930cef6SMatthias Ringwald    return ok
1684930cef6SMatthias Ringwald
1694930cef6SMatthias Ringwald
1704930cef6SMatthias Ringwalddef check_inverse_appendix_c(dt):
1714930cef6SMatthias Ringwald
172*6897da5cSDirk Helbig    i0 = dt - T.DT_7M5
1734930cef6SMatthias Ringwald    sr = T.SRATE_16K
174*6897da5cSDirk Helbig
1754930cef6SMatthias Ringwald    ok = True
1764930cef6SMatthias Ringwald
177*6897da5cSDirk Helbig    ns = T.NS[dt][sr]
178*6897da5cSDirk Helbig    nd = T.ND[dt][sr]
179*6897da5cSDirk Helbig
180*6897da5cSDirk Helbig    (y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][0], np.zeros(nd))
181*6897da5cSDirk Helbig    yr = C.T_HAT_MDCT[i0][0][ns-nd:2*ns-nd]
182*6897da5cSDirk Helbig    dr = C.T_HAT_MDCT[i0][0][2*ns-nd:]
1834930cef6SMatthias Ringwald
1844930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(yr - y )) < 1e-1
1854930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(dr - d0)) < 1e-1
1864930cef6SMatthias Ringwald
187*6897da5cSDirk Helbig    (y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][1], d0)
188*6897da5cSDirk Helbig    yr[  :nd] = C.T_HAT_MDCT[i0][1][ns-nd:ns] + d0
189*6897da5cSDirk Helbig    yr[nd:ns] = C.T_HAT_MDCT[i0][1][ns:2*ns-nd]
190*6897da5cSDirk Helbig    dr        = C.T_HAT_MDCT[i0][1][2*ns-nd:]
1914930cef6SMatthias Ringwald
1924930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(yr - y )) < 1e-1
1934930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(dr - d1)) < 1e-1
1944930cef6SMatthias Ringwald
1954930cef6SMatthias Ringwald    return ok
1964930cef6SMatthias Ringwald
1974930cef6SMatthias Ringwald
1984930cef6SMatthias Ringwalddef check():
1994930cef6SMatthias Ringwald
2004930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
2014930cef6SMatthias Ringwald
2024930cef6SMatthias Ringwald    ok  = True
2034930cef6SMatthias Ringwald
2044930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
205*6897da5cSDirk Helbig        for sr in range(T.SRATE_8K, T.SRATE_48K + 1):
2064930cef6SMatthias Ringwald            ok = ok and check_forward_unit(rng, dt, sr)
2074930cef6SMatthias Ringwald            ok = ok and check_inverse_unit(rng, dt, sr)
2084930cef6SMatthias Ringwald
209*6897da5cSDirk Helbig    for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ):
210*6897da5cSDirk Helbig        for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ):
211*6897da5cSDirk Helbig            ok = ok and check_forward_unit(rng, dt, sr)
212*6897da5cSDirk Helbig            ok = ok and check_inverse_unit(rng, dt, sr)
213*6897da5cSDirk Helbig
214*6897da5cSDirk Helbig    for dt in ( T.DT_7M5, T.DT_10M ):
2154930cef6SMatthias Ringwald        ok = ok and check_forward_appendix_c(dt)
2164930cef6SMatthias Ringwald        ok = ok and check_inverse_appendix_c(dt)
2174930cef6SMatthias Ringwald
2184930cef6SMatthias Ringwald    return ok
219