1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MDCTで使う窓関数の逆変換

Last updated at Posted at 2020-05-31

MDCTの窓関数の逆変換を実装してみた。

窓関数処理

    for (int i = 0; i < (nsmpl >> 1); i++) {
        p_work[i] = -p_x[3 * nsmpl / 2 - 1 - i] * p_w[nsmpl / 2 + i] -
                         p_x[3 * nsmpl / 2 + i] * p_w[nsmpl / 2 - 1 - i];
        p_work[i]] = p_x[i] * p_w[i] - p_x[nsmpl - 1 - i] * p_w[nsmpl - 1 - i];
    }

というMDCTの窓関数処理の逆変換を実装してみました。

  • nsmpl サンプル数
  • p_x 入力列の配列 サイズはnsmpl*2
  • p_w 窓関数の配列 サイズはnsmpl

 サンプル数4の場合

まず、nsmpl を 4 としてループを展開してみる。

      p_work[0] = -p_x[5] * p_w[2] - p_x[6] * p_w[1];
      p_work[2] =  p_x[0] * p_w[0] - p_x[3] * p_w[3];
      p_work[1] = -p_x[4] * p_w[3] - p_x[7] * p_w[0];
      p_work[3] =  p_x[1] * p_w[1] - p_x[2] * p_w[2];

MDCTなので窓を半分ずつ重複させながら変換する。

この窓が半分ずつ重なっている部分の情報を使うと逆変換でp_x[]を取り出すことができる。

一つ前の変換のp_work[]をp_prv_work[]、p_x[]をp_prv_x[]とする

      p_prv_work[0] = -p_prv_x[5] * p_w[2] - p_prv_x[6] * p_w[1];

重なり部分の要素数はnsmpl == 4 の場合は重なりも4となる。
そうすると、一つ前のp_prv_x[5] と 現在のp_x[1] 、一つ前のp_prv_x[6]と 現在のp_x[2]が同一の値となる。

現在の情報

     sig_cur[0] = p_work[2];
     sig_cur[1] = p_work[3];
     sig_cur[2] = p_work[3];
     sig_cur[3] = p_work[p];

一つ前の情報

     sig_prv[0] = p_prv_work[1];
     sig_prv[1] = p_prv_work[0];
     sig_prv[2] = -p_prv_work[0];
     sig_prv[3] = -p_prv_work[1];

として以下のような変換式が得られる。

     sig_cur[0] * p_w[0] - sig_prv[0] * p_w[3]
   = p_work[2] * p_w[0] - p_prv_work[1] * p_w[3]
   = (p_x[0] * p_w[0] - p_x[3] * p_w[3]) * p_w[0] -  (-p_prv_x[4] * p_w[3] - p_prv_x[7] * p_w[0];)* p_w[3]
   = (p_x[0] * p_w[0] - p_x[3] * p_w[3]) * p_w[0] -  (-p_x[0] * p_w[3] - p_x[3] * p_w[0];)* p_w[3]
     = p_x[0] * p_w[0] * p_w[0] - p_x[3] * p_w[3] * p_w[0] + p_x[0] * p_w[3] * p_w[3] + p_x[3] * p_w[3] * p_w[0]
     = p_x[0] * ( p_w[0] * p_w[0] + p_w[3] * p_w[3]) 

( p_w[0] * p_w[0] + p_w[3] * p_w[3])は窓関数の配列から計算で導出できるので、割り算するとp_x[0]が得られる。

同様の計算でp_x[1]、p_x[2]、p_x[3]が得られる。

    p_x[0] : (sig_cur[0] * p_w[0] - sig_prv[0] * p_w[3]) / (p_w[0] * p_w[0] + p_w[3] * p_w[3]);
    p_x[1] : (sig_cur[1] * p_w[1] - sig_prv[1] * p_w[2]) / (p_w[1] * p_w[1] + p_w[2] * p_w[2]);
    p_x[2] : (sig_cur[2] * p_w[2] - sig_prv[2] * p_w[1]) / (-p_w[1] * p_w[1] - p_w[2] * p_w[2]);
    p_x[3] : (sig_cur[3] * p_w[3] - sig_prv[3] * p_w[0]) / (-p_w[0] * p_w[0] - p_w[3] * p_w[3]);

サンプル数8の場合

サンプル数8の場合の変換式は以下となる。

    sig_cur[0] = p_work[4];
    sig_cur[1] = p_work[5];
    sig_cur[2] = p_work[6];
    sig_cur[3] = p_work[7];
    sig_cur[4] = p_work[7];
    sig_cur[5] = p_work[6];
    sig_cur[6] = p_work[5];
    sig_cur[7] = p_work[4];

    p_z[0] = (sig_cur[0] * p_w[0] - sig_prv[0] * p_w[7]) / (p_w[0] * p_w[0] + p_w[7] * p_w[7]);
    p_z[1] = (sig_cur[1] * p_w[1] - sig_prv[1] * p_w[6]) / (p_w[1] * p_w[1] + p_w[6] * p_w[6]);
    p_z[2] = (sig_cur[2] * p_w[2] - sig_prv[2] * p_w[5]) / (p_w[2] * p_w[2] + p_w[5] * p_w[5]);
    p_z[3] = (sig_cur[3] * p_w[3] - sig_prv[3] * p_w[4]) / (p_w[3] * p_w[3] + p_w[4] * p_w[4]);
    p_z[4] = (sig_cur[4] * p_w[4] - sig_prv[4] * p_w[3]) / (-p_w[3] * p_w[3] - p_w[4] * p_w[4]);
    p_z[5] = (sig_cur[5] * p_w[5] - sig_prv[5] * p_w[2]) / (-p_w[2] * p_w[2] - p_w[5] * p_w[5]);
    p_z[6] = (sig_cur[6] * p_w[6] - sig_prv[6] * p_w[1]) / (-p_w[1] * p_w[1] - p_w[6] * p_w[6]);
    p_z[7] = (sig_cur[7] * p_w[7] - sig_prv[7] * p_w[0]) / (-p_w[0] * p_w[0] - p_w[7] * p_w[7]);

    sig_prv[0] = p_work[3];
    sig_prv[1] = p_work[2];
    sig_prv[2] = p_work[1];
    sig_prv[3] = p_work[0];
    sig_prv[4] = -p_work[0];
    sig_prv[5] = -p_work[1];
    sig_prv[6] = -p_work[2];
    sig_prv[7] = -p_work[3];

サンプル数を可変

サンプル数を可変とすると下記になる。

    for (int i = 0; i < (nsmpl >> 1); i++) {
        sig_cur[i] = p_work[(nsmpl >> 1) + i];
        sig_cur[(nsmpl >> 1) + i] = p_work[nsmpl - 1 - i];
    }
    for (int i = 0; i < (nsmpl >> 1); i++) {
        p_z[i] = (sig_cur[i] * p_w[i] - sig_prv[i] * p_w[nsmpl - 1 - i]) /
                 (p_w[i] * p_w[i] + p_w[nsmpl - 1 - i] * p_w[nsmpl - 1 - i]);
        p_z[(nsmpl >> 1) + i] = -(sig_cur[(nsmpl >> 1) + i] * p_w[(nsmpl >> 1) + i] - sig_prv[(nsmpl >> 1) + i] * p_w[(nsmpl >> 1) - 1 - i]) /
                                 (p_w[(nsmpl >> 1) + i] * p_w[(nsmpl >> 1) + i] + p_w[(nsmpl >> 1) - 1 - i] * p_w[(nsmpl >> 1) - 1 - i]);
   }
   for (int i = 0; i < (nsmpl >> 1); i++) {
        sig_prv[i] = p_work[(nsmpl >> 1) - 1 - i];
        sig_prv[(nsmpl >> 1) + i] = -p_work[i];
   }

という感じです。

MDCTのコードを動かして動作を理解するのと、要素数を少なくして解析するということが重要でした。

一年前に良く分からなくて放置していた課題が解決してよかった。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?