MDCT(修正離散コサイン変換)とフィルタバンク:TDAC・完全再構成の理論とPython実装

MDCT(修正離散コサイン変換)のTDAC・完全再構成の理論とPython実装を体系解説。numpyフルスクラッチのMDCT/IMDCTで再構成誤差が機械精度(1e-14〜1e-13)に収まることを実測し、scipy.signal.get_window によるKBD窓・sine窓のPrincen-Bradley条件検証、scipy.fft.dct によるブロックDCTとの境界アーティファクト比較、numpy.random.default_rng を用いた数値実験、コサイン変調フィルタバンク・ポリフェーズ解釈までカバーします。

はじめに:なぜブロックDCTでは境界アーティファクトが出るのか

離散コサイン変換(DCT)は優れたエネルギー集中性をもち、JPEG では 8×8 ブロック DCT が中核を担っています。しかし信号を重なりのないブロックに分割して独立に変換・量子化すると、各ブロックの復元誤差はブロック内で閉じる一方、隣接ブロックとの連続性は何も保証されません。その結果、量子化誤差がブロック境界に不連続として現れます。JPEG のブロックノイズがまさにこれで、音声では境界ごとの不連続が周期的なクリック音(blocking artifact)として知覚され、画像よりはるかに耳につきます。

解決の方向性は自然に「フレームをオーバーラップさせる」ことです。ところが素朴に 50% オーバーラップさせた DCT を使うと、\(M\) サンプル進むごとに \(2M\) 個の係数が出るため、データ量が2 倍に冗長化してしまいます。圧縮が目的なのに情報量が倍増しては本末転倒です。

この「オーバーラップによる滑らかさ」と「臨界サンプリング(入力サンプル数=係数数)」を両立するのが MDCT(Modified Discrete Cosine Transform、修正離散コサイン変換)です。\(2M\) 点の入力からあえて半分の \(M\) 点しか係数を作らないことで、50% オーバーラップさせても全体の係数数は入力サンプル数と一致します。半分に減らした際に生じる時間領域のエイリアシングは、隣接フレームとのオーバーラップ加算で厳密に相殺されます。この仕組みが **TDAC(Time-Domain Aliasing Cancellation、時間領域エイリアシング相殺)**です。

MDCT は MP3(ハイブリッドフィルタバンクの後段)・AAC・Vorbis・Opus(CELT レイヤー)・AC-3 と、現代の音声符号化のほぼすべてで採用されています。本記事では MDCT の定義と TDAC の仕組みを数式で導出し、窓関数の完全再構成条件(Princen-Bradley 条件)、コサイン変調フィルタバンクとしての解釈を整理したうえで、numpy フルスクラッチの実装で完全再構成を数値検証し、ブロック DCT との境界アーティファクト比較実験を行います。

MDCTの定義とTDAC

順変換と逆変換

長さ \(2M\) のフレーム \(x[n]\) (\(n = 0, \ldots, 2M-1\) )と窓 \(w[n]\) に対し、MDCT は \(M\) 個の係数を出力します。

\[ X[k] = \sum_{n=0}^{2M-1} w[n]\, x[n] \cos\left(\frac{\pi}{M}\left(n + \frac{1}{2} + \frac{M}{2}\right)\left(k + \frac{1}{2}\right)\right), \quad k = 0, \ldots, M-1 \tag{1} \]

逆 MDCT(IMDCT)は \(M\) 個の係数から長さ \(2M\) の信号を生成します。

\[ \hat{x}[n] = \frac{2}{M}\, w[n] \sum_{k=0}^{M-1} X[k] \cos\left(\frac{\pi}{M}\left(n + \frac{1}{2} + \frac{M}{2}\right)\left(k + \frac{1}{2}\right)\right) \tag{2} \]

入力 \(2M\) 点に対して出力 \(M\) 点なので、単一フレームだけでは情報が半分失われており、逆変換しても元には戻りません。\(2M \to M\) の写像は非正則(カーネルが \(M\) 次元)だからです。DCT-II が \(N\) 点 \(\to\) \(N\) 点の直交変換で単独可逆だったのとは決定的に異なります。

フレームをホップ幅 \(M\) (50% オーバーラップ)でずらしながら式 \((1)\) を適用すると、\(M\) サンプルあたり \(M\) 係数、つまり臨界サンプリングが達成されます。

時間領域エイリアシングの構造

失われた半分の情報はどこへ行ったのでしょうか。フレームを長さ \(M/2\) の 4 分割 \(x = (a, b, c, d)\) で表し、\(R(\cdot)\) を時間反転とすると、窓なし(\(w[n] = 1\) )の場合に次の恒等式が成り立ちます。

\[ \text{IMDCT}(\text{MDCT}(x)) = \bigl(a - R(b),\; b - R(a),\; c + R(d),\; d + R(c)\bigr) \tag{3} \]

つまり単一フレームの復元結果は、元の信号に時間反転した折り返し成分(時間領域エイリアシング)が混入した形になります。前半では奇対称(\(-R\) )、後半では偶対称(\(+R\) )に折り返されるのがポイントです。これは、周波数領域のダウンサンプリングが時間領域の折り返しを生む——マルチレート信号処理で見た「間引きはエイリアシングを生む」の時間・周波数を入れ替えた双対な現象です。

TDAC:オーバーラップ加算による相殺

フレーム \(i\) の後半 \((c, d)\) は、フレーム \(i+1\) の前半 \((a', b') = (c, d)\) として再度変換されます。式 \((3)\) より、同じ区間に対して

  • フレーム \(i\) の復元:\(c + R(d)\) , \(d + R(c)\) (偶対称の折り返し)
  • フレーム \(i+1\) の復元:\(c - R(d)\) , \(d - R(c)\) (奇対称の折り返し)

が得られ、両者を加算するとエイリアシング項 \(\pm R(\cdot)\) が符号違いで厳密に打ち消し合い、\(2c\) , \(2d\) が残ります(式 \((2)\) の係数 \(2/M\) はこの 2 倍を含めて正規化してあります)。これが TDAC の本質です:単一フレームでは復元不能でも、隣接フレームが互いのエイリアシングの「解毒剤」を持っているため、オーバーラップ加算(OLA)後は完全再構成が成立します。

窓 \(w[n]\) を入れた場合は、分析側と合成側で同じ窓が 2 回掛かるため、相殺の条件は窓の対称性と振幅条件に帰着します。これが次節の Princen-Bradley 条件です。

窓関数の完全再構成条件

Princen-Bradley 条件

対称な窓 \(w[2M-1-n] = w[n]\) に対し、オーバーラップ加算後の振幅が全サンプルで 1 になる条件は

\[ w[n]^2 + w[n+M]^2 = 1, \quad n = 0, \ldots, M-1 \tag{4} \]

です(Princen-Bradley 条件)。導出の骨子は次のとおりです。式 \((3)\) に窓を入れると、オーバーラップ区間のサンプル \(n\) には (i) 信号成分に \(w[n+M]^2 + w[n]^2\) 、(ii) エイリアシング成分に \(w[n+M]\,w_R[n+M] - w[n]\,w_R[n]\) の係数が掛かります。窓が対称なら (ii) は恒等的にゼロとなってエイリアシングが相殺され、(i) が式 \((4)\) を満たせば振幅も保存されます。スペクトログラム実践で扱った STFT の COLA 条件(\(\sum w = \text{const}\) )と役割は同じですが、MDCT では分析・合成で窓が 2 回掛かるため窓の 2 乗和の条件になる点が異なります。

sine 窓

式 \((4)\) を満たす最も簡単な窓が sine 窓です。

\[ w[n] = \sin\left(\frac{\pi}{2M}\left(n + \frac{1}{2}\right)\right), \quad n = 0, \ldots, 2M-1 \tag{5} \]

\(\sin^2\theta + \cos^2\theta = 1\) からただちに式 \((4)\) が従います。MP3 や Vorbis で採用されており、この窓を使った MDCT は Malvar の **MLT(Modulated Lapped Transform)**と一致します。

KBD 窓

KBD(Kaiser-Bessel Derived)窓は、Kaiser 窓 \(v[j]\) (長さ \(M+1\) )の累積和の平方根として構成されます。

\[ w[n] = \sqrt{\frac{\sum_{j=0}^{n} v[j]}{\sum_{j=0}^{M} v[j]}}, \quad n = 0, \ldots, M-1 \tag{6} \]

(後半は対称に折り返し)。累積和の平方根という構成そのものが式 \((4)\) を自動的に満たします。sine 窓よりメインローブは広い代わりにストップバンド減衰が大きく、AAC では信号の性質に応じて sine 窓と KBD 窓を切り替えます。Kaiser 窓のパラメータ \(\alpha\) で漏れと分解能のトレードオフを調整できるのは、STFT の窓選択と同じ設計感覚です。

フィルタバンクとしてのMDCT

コサイン変調フィルタバンク

MDCT は変換であると同時に、\(M\) バンドの臨界サンプリング完全再構成フィルタバンクでもあります。式 \((1)\) は、長さ \(2M\) の分析フィルタ

\[ h_k[n] = w[n] \cos\left(\frac{\pi}{M}\left(n + \frac{1}{2} + \frac{M}{2}\right)\left(k + \frac{1}{2}\right)\right) \tag{7} \]

で信号を畳み込み、出力を \(M\) 分の 1 に間引く操作と等価です。\(h_k\) は単一のプロトタイプ窓(ローパス)\(w[n]\) を中心周波数 \(\omega_k = \frac{\pi}{M}\left(k + \frac{1}{2}\right)\) にコサイン変調したもので、このため MDCT はコサイン変調フィルタバンクの一種に分類されます。\(M\) 本のバンドパスフィルタがナイキスト帯域を均等分割し、各バンドをレート \(1/M\) でサンプリングする——マルチレート信号処理で扱ったデシメーションの枠組みそのものです。

各バンド単独ではエイリアシングだらけ(フィルタ遷移帯域が隣接バンドに大きく重なる)ですが、合成側で全バンドを足し合わせるとエイリアシングが相殺される、という構造は TDAC の周波数領域での言い換えです。

ポリフェーズ表現と高速計算

フィルタ長が \(2M\) 、間引き率が \(M\) なので、ポリフェーズ分解すると各ポリフェーズ成分はわずか 2 タップです。この構造から、MDCT の実装は

  1. 窓掛け+折り畳み(folding):\(2M\) 点の窓掛け信号を、式 \((3)\) の対称性を使って \(M\) 点に折り畳む(\(O(M)\) )
  2. DCT-IV:折り畳んだ \(M\) 点に DCT-IV を適用(FFT 経由で \(O(M \log M)\) )

の 2 段に分解できます。MDCT が「窓掛け・折り畳みという前処理付きの DCT-IV」だという事実は、素朴な行列積 \(O(M^2)\) を \(O(M \log M)\) に落とす実用上の鍵です。なお MP3 は歴史的経緯から 32 バンドの PQMF(擬似 QMF フィルタバンク)と 18 点 MDCT のハイブリッド構成を採り、AAC 以降は単一の MDCT(\(M = 1024/128\) の窓切替)に一本化されました。

Python実装:MDCT/IMDCTと完全再構成の数値検証

窓関数と Princen-Bradley 条件の確認

scipy.signal.get_window で Kaiser 窓を生成し、式 \((6)\) に従って KBD 窓を構成します。

import numpy as np
from scipy.signal import get_window

def sine_window(N):
    """sine窓:Princen-Bradley条件を満たす最も簡単な窓"""
    n = np.arange(N)
    return np.sin(np.pi / N * (n + 0.5))

def kbd_window(N, alpha=4.0):
    """Kaiser-Bessel Derived(KBD)窓:AACで採用"""
    M = N // 2
    kaiser = get_window(("kaiser", np.pi * alpha), M + 1, fftbins=False)
    csum = np.cumsum(kaiser)
    half = np.sqrt(csum[:M] / csum[M])
    return np.concatenate([half, half[::-1]])

# Princen-Bradley条件 w_n^2 + w_{n+M}^2 = 1 の検証
N = 512
for name, w in [("sine", sine_window(N)), ("KBD (alpha=4)", kbd_window(N))]:
    err = np.max(np.abs(w[: N // 2] ** 2 + w[N // 2 :] ** 2 - 1.0))
    print(f"{name:14s}: max |w_n^2 + w_(n+M)^2 - 1| = {err:.2e}")
sine          : max |w_n^2 + w_(n+M)^2 - 1| = 4.44e-16
KBD (alpha=4) : max |w_n^2 + w_(n+M)^2 - 1| = 5.55e-16

どちらの窓も Princen-Bradley 条件を機械精度で満たしています。

MDCT/IMDCT 本体

式 \((1)\) , \((2)\) を素直に行列積で実装します(学習用。実用では前節の折り畳み+DCT-IV を使います)。

def mdct(frame, w):
    """1フレームのMDCT:長さ 2M の入力から M 個の係数を計算(式1)"""
    N = len(frame)
    M = N // 2
    n = np.arange(N)
    k = np.arange(M)
    C = np.cos(np.pi / M * (n[None, :] + 0.5 + M / 2) * (k[:, None] + 0.5))
    return C @ (w * frame)

def imdct(X, w):
    """1フレームの逆MDCT:M 個の係数から長さ 2M の信号を復元(式2)"""
    M = len(X)
    n = np.arange(2 * M)
    k = np.arange(M)
    C = np.cos(np.pi / M * (n[:, None] + 0.5 + M / 2) * (k[None, :] + 0.5))
    return (2.0 / M) * w * (C @ X)

def mdct_analysis(x, w):
    """ホップ M(50%オーバーラップ)で全フレームのMDCT係数を計算"""
    N = len(w)
    M = N // 2
    n_frames = len(x) // M - 1
    return np.stack([mdct(x[i * M : i * M + N], w) for i in range(n_frames)])

def mdct_synthesis(coeffs, w, length):
    """逆MDCT + オーバーラップ加算(OLA)で信号を再構成"""
    n_frames, M = coeffs.shape
    y = np.zeros(length)
    for i in range(n_frames):
        y[i * M : i * M + 2 * M] += imdct(coeffs[i], w)
    return y

TDAC 恒等式の確認

窓なしの単一フレームで式 \((3)\) のエイリアシング構造を直接検証します。

rng = np.random.default_rng(42)
M = 8
x = rng.standard_normal(2 * M)
y_single = imdct(mdct(x, np.ones(2 * M)), np.ones(2 * M))  # 窓なし

h = M // 2
a, b, c, d = x[:h], x[h : 2 * h], x[2 * h : 3 * h], x[3 * h :]
R = lambda v: v[::-1]
tdac_expected = np.concatenate([a - R(b), b - R(a), c + R(d), d + R(c)])
print(f"TDAC恒等式の検証誤差: {np.max(np.abs(y_single - tdac_expected)):.2e}")
TDAC恒等式の検証誤差: 6.00e-15

単一フレームの復元は確かに \((a - R(b),\ b - R(a),\ c + R(d),\ d + R(c))\) というエイリアシング付きの形になっており、式 \((3)\) が機械精度で成立しています。

完全再構成の数値検証

numpy.random.default_rng で生成した乱数信号に対し、分析→合成の往復誤差を測ります。

for M in [32, 64, 256, 512]:
    L = 64 * M
    x = rng.standard_normal(L)
    for name, w in [("sine", sine_window(2 * M)), ("KBD ", kbd_window(2 * M))]:
        coeffs = mdct_analysis(x, w)
        y = mdct_synthesis(coeffs, w, L)
        err = np.max(np.abs(x[M:-M] - y[M:-M]))  # 両端 M 点はOLA相手がない
        print(f"M={M:4d}, {name}窓: 完全再構成誤差 = {err:.2e}")
M=  32, sine窓: 完全再構成誤差 = 3.77e-14
M=  32, KBD 窓: 完全再構成誤差 = 3.54e-14
M=  64, sine窓: 完全再構成誤差 = 6.75e-14
M=  64, KBD 窓: 完全再構成誤差 = 6.57e-14
M= 256, sine窓: 完全再構成誤差 = 3.39e-13
M= 256, KBD 窓: 完全再構成誤差 = 3.30e-13
M= 512, sine窓: 完全再構成誤差 = 6.59e-13
M= 512, KBD 窓: 完全再構成誤差 = 7.28e-13

再構成誤差は \(10^{-14}\) 〜\(10^{-13}\) オーダー、すなわち倍精度の機械精度(1 係数あたり長さ \(2M\) の内積を取るため、丸め誤差が \(O(M)\) で緩やかに蓄積して \(\varepsilon \approx 10^{-16}\) の数百倍程度になる)に収まっており、TDAC による完全再構成が数値的に確認できました。量子化を一切しなければ MDCT は情報を 1 ビットも失わない、臨界サンプリングかつ可逆な表現です。なお信号の両端 \(M\) 点はオーバーラップの相手がいないため相殺が起きません。実用コーデックがフレーム長分のアルゴリズム遅延(先読み)を持つのはこのためです。

実験:チャープ信号でのブロックDCT vs MDCT

境界アーティファクトの差を見るため、チャープ(200→3000 Hz)+定常トーンの合成信号に対して「係数の絶対値上位 \(p\%\) だけを保持して残りをゼロにする」という簡易圧縮を、同じブロック長 \(M = 256\) の非オーバーラップ・ブロック DCT(scipy.fft.dct)と MDCT で比較します。

from scipy.fft import dct, idct

fs = 8000
t = np.arange(fs) / fs                              # 1秒
sig = np.sin(2 * np.pi * (200 * t + 1400 * t**2))   # 200→3000 Hz チャープ
sig += 0.3 * np.sin(2 * np.pi * 440 * t)            # 定常トーン

M = 256
w = sine_window(2 * M)
L = len(sig)
pad = M  # 両端のOLA用パディング
xpad = np.concatenate([np.zeros(pad), sig, np.zeros(pad + (-(L + 2 * pad)) % M)])

def keep_top(coeffs, ratio):
    """絶対値上位 ratio 割合の係数だけを残す(圧縮の簡易モデル)"""
    flat = np.abs(coeffs).ravel()
    thr = np.sort(flat)[::-1][int(flat.size * ratio) - 1]
    return np.where(np.abs(coeffs) >= thr, coeffs, 0.0)

nblk = L // M
sd = sig[: nblk * M]
for ratio in [0.10, 0.05]:
    # MDCT(50%オーバーラップ・臨界サンプリング)
    cm = keep_top(mdct_analysis(xpad, w), ratio)
    ym = mdct_synthesis(cm, w, len(xpad))[pad : pad + L]
    snr_m = 10 * np.log10(np.sum(sig**2) / np.sum((sig - ym) ** 2))
    # 非オーバーラップのブロックDCT(同じブロック長 M)
    cd = keep_top(dct(sd.reshape(nblk, M), type=2, norm="ortho", axis=1), ratio)
    yd = idct(cd, type=2, norm="ortho", axis=1).ravel()
    snr_d = 10 * np.log10(np.sum(sd**2) / np.sum((sd - yd) ** 2))
    # 境界近傍(各ブロック端8点)と内部の誤差を分離
    idx = np.arange(len(sd))
    near = (idx % M < 8) | (idx % M >= M - 8)
    ed, em = np.abs(sd - yd), np.abs(sig - ym)[: nblk * M]
    print(f"係数保持率 {ratio*100:.0f}%:")
    print(f"  ブロックDCT: SNR {snr_d:5.2f} dB | "
          f"境界RMS {np.sqrt(np.mean(ed[near]**2)):.4f} / 内部RMS {np.sqrt(np.mean(ed[~near]**2)):.4f}")
    print(f"  MDCT       : SNR {snr_m:5.2f} dB | "
          f"境界RMS {np.sqrt(np.mean(em[near]**2)):.4f} / 内部RMS {np.sqrt(np.mean(em[~near]**2)):.4f}")
係数保持率 10%:
  ブロックDCT: SNR 17.88 dB | 境界RMS 0.3096 / 内部RMS 0.0560
  MDCT       : SNR 37.94 dB | 境界RMS 0.0191 / 内部RMS 0.0079
係数保持率 5%:
  ブロックDCT: SNR 13.39 dB | 境界RMS 0.4551 / 内部RMS 0.1140
  MDCT       : SNR 23.80 dB | 境界RMS 0.0708 / 内部RMS 0.0433

結果は明快です。

  • SNR:係数 10% 保持で MDCT が約 20 dB 上回る(37.94 dB vs 17.88 dB)
  • 境界アーティファクト:ブロック DCT はブロック端 8 点の誤差 RMS が内部の 5.5 倍(0.3096 vs 0.0560)に達し、誤差が境界に集中している。MDCT は境界/内部比が 2.4 倍程度に留まり、しかも絶対値が 1 桁小さい

ブロック DCT では、チャープの瞬時周波数がブロック内で変化するため打ち切りによる不連続が境界に露出しますが、MDCT では窓掛け+オーバーラップが不連続を滑らかに吸収します。

係数の疎性

同じ信号での係数のエネルギー集中も比較します。

cm = mdct_analysis(xpad, w)
cd = dct(sd.reshape(nblk, M), type=2, norm="ortho", axis=1)
for name, cc in [("MDCT", cm), ("ブロックDCT", cd)]:
    e = np.sort((cc**2).ravel())[::-1]
    frac = np.cumsum(e) / np.sum(e)
    n99 = np.searchsorted(frac, 0.99) + 1
    print(f"{name}: 99%エネルギーに必要な係数 {n99}/{frac.size} ({n99/frac.size*100:.1f}%)")
MDCT: 99%エネルギーに必要な係数 364/8448 (4.3%)
ブロックDCT: 99%エネルギーに必要な係数 1090/7936 (13.7%)

99% のエネルギーを表すのに MDCT は全係数の 4.3% で足りるのに対し、ブロック DCT は 13.7% 必要です。窓掛けによりフレーム端が滑らかにゼロへ落ちるため矩形打ち切りに伴うスペクトル漏れがなく、係数がより疎になる——これが音声コーデックで MDCT が選ばれ続ける理由です。

比較表:DCT / STFT / MDCT / ウェーブレットパケット

時間周波数表現としての位置づけを整理します。ホップ幅 \(H\) 、窓長・フレーム長を \(N_w\) とします。

項目ブロックDCTSTFTMDCTウェーブレットパケット
冗長性1倍(臨界)\(N_w/H\) 倍(50%重畳で2倍)1倍(臨界)1倍(直交基底選択時)
オーバーラップなしあり(COLA条件)あり(TDAC)フィルタ長に依存
完全再構成可(量子化なしなら)可(NOLA/COLA下で)可(Princen-Bradley下で)可(直交ウェーブレット)
境界アーティファクト出る(量子化誤差が境界露出)出にくい出にくい境界処理に依存
アルゴリズム遅延\(M\)\(N_w\)\(2M\) (1フレーム先読み)分解深さ×フィルタ長
周波数分割均一 \(M\) バンド均一均一 \(M\) バンド適応的(不均一可)
位相情報なし(実係数)あり(複素)なし(実係数)なし(実係数)
主な用途JPEG・動画のイントラ圧縮解析・音声強調・位相加工音声圧縮(MP3/AAC/Opus)適応基底・特徴抽出・denoising

使い分けの目安は次のとおりです。

  • 圧縮(ビット数最小化が目的)→ 冗長性 1 倍の MDCT。位相を捨てられる代わりに臨界サンプリングと滑らかな再構成を両立
  • 解析・加工(スペクトログラムを見る・位相を操作する)→ 冗長でも複素の STFT。スペクトログラム実践のパラメータ設計がそのまま活きる
  • 不均一な周波数分割が欲しい(過渡と定常が混在)→ ウェーブレットパケットの Best Basis 選択

まとめ

  • ブロック DCT は臨界サンプリングだが量子化誤差がブロック境界に露出する。素朴なオーバーラップは冗長性が 2 倍になる。MDCT は \(2M \to M\) のラップド変換によりオーバーラップと臨界サンプリングを両立する
  • 単一フレームの IMDCT は時間領域エイリアシング \((a - R(b),\ b - R(a),\ c + R(d),\ d + R(c))\) を含むが、隣接フレームとのオーバーラップ加算で厳密に相殺される(TDAC)
  • 完全再構成の窓条件は Princen-Bradley 条件 \(w_n^2 + w_{n+M}^2 = 1\) 。sine 窓・KBD 窓がこれを満たし、numpy 実装での再構成誤差は \(10^{-14}\) 〜\(10^{-13}\) (機械精度)だった
  • MDCT は窓をプロトタイプとするコサイン変調フィルタバンクであり、ポリフェーズ成分 2 タップ、実装上は「折り畳み+DCT-IV」で \(O(M \log M)\)
  • チャープ信号の係数 10% 保持実験で、ブロック DCT(SNR 17.9 dB、境界誤差が内部の 5.5 倍)に対し MDCT は SNR 37.9 dB・境界集中なしと大差がついた。99% エネルギーに必要な係数も 13.7% → 4.3% に減り、疎性でも MDCT が優位

関連記事

参考文献

  • Princen, J. P., & Bradley, A. B. (1986). “Analysis/synthesis filter bank design based on time domain aliasing cancellation.” IEEE Transactions on Acoustics, Speech, and Signal Processing, 34(5), 1153-1161.
  • Princen, J. P., Johnson, A. W., & Bradley, A. B. (1987). “Subband/transform coding using filter bank designs based on time domain aliasing cancellation.” Proc. IEEE ICASSP, 2161-2164.
  • Malvar, H. S. (1992). Signal Processing with Lapped Transforms. Artech House.
  • Bosi, M., & Goldberg, R. E. (2003). Introduction to Digital Audio Coding and Standards. Springer.
  • Vaidyanathan, P. P. (1993). Multirate Systems and Filter Banks. Prentice Hall.