周波数ワーピング
インターネットに解説があんまり無くて永遠に理解できてなかったけどやっとわかってきた (本を探せばあったのかな……) 変換をちゃんと理解してなかった
参考にしたページ
https://www.rle.mit.edu/dspg/documents/Proc_Frequency_1999.pdf
変換
インパルス応答とかの離散信号をフーリエ変換すると正規化角周波数 (単位が rad / sample のやつ) の式 が得られる。 は から までの数直線上の値 ( ごとにループするけど) である。 数直線上から自由に角周波数 を選んで を計算すると、元の信号がインパルス応答ならその角周波数でのフィルタの振幅特性や位相特性がわかる。
これを、何を思ったか突然 で変数変換してみたものが 変換らしい。このとき と の対応は下のようになる。
つまり、 が数直線上を動くのは、 が単位円上をぐるぐるするのと同じ。 は数直線上しか動かないので は必ず単位円上の値だと考えていい。(本当はだめかも?とりあえず今は大丈夫) ただの変数変換なので、 領域の式 で、 に を代入することで正規化角周波数 のときの周波数特性が求められたりする。
周波数ワーピング
によって、またしても変数変換をする。(この式はオールパスフィルタそのもの。) について解けば、 となる。
変数変換なので、対応を確認することにする。
ってなんだよという感じだが、この値は絶対値を取ると に関わらず 1 になる。実は、 が単位円上にあれば、 も必ず単位円上にある。これは以下のように確認できる。(この式はオールパスフィルタの振幅特性が平坦なことを示すものと同じ。)
式でも確認できるけど、 の分母の絶対値と分子の絶対値が等しいことを言えばいいだけので、図を書いたほうがわかりやすい。 図は なので注意。
のとき、 の絶対値はであることがわかったので、新しい変数 を導入して と表すことができる。 のとき はどんな値になるかも確認したい。(この計算はオールパスフィルタの位相特性の計算と同じ。) さっきと同じように図で考えると、 と は下図の角度になる。
図から、高校数学を駆使して と の関係を計算する。筋のいい方法がなかなか分からなくて大変だった。ネタバレをすると、図の二等辺三角形の各辺の長さを求めて余弦定理を使うと良い。結果は、
となる。 の範囲では、 と の符号が等しいことを使えば、 から が一意に定まる。左辺を にした場合は、
となる。
と の対応を描画してみるとこんな感じ。
描画コード
import numpy as np import matplotlib.pyplot as plt plt.figure(figsize=(4, 4), dpi=200) for alpha in [0.8, 0.4, 0.0, -0.4, -0.8]: omega = np.linspace(0, np.pi, 1000) omega_tilde = np.arccos( (-2 * alpha + (1 + alpha * alpha) * np.cos(omega)) / ((1 + alpha * alpha) - 2 * alpha * np.cos(omega)) ) plt.plot(omega, omega_tilde, label=fr"$\alpha={alpha:.1f}$") plt.legend() plt.xlabel(r"$\omega$") plt.ylabel(r"$\widetilde\omega$") plt.xlim(0, np.pi) plt.ylim(0, np.pi) plt.xticks(np.linspace(0, np.pi, 5), [r"$0$", r"$\pi/4$", r"$\pi/2$", r"$3\pi/4$", r"$\pi$"]) plt.yticks(np.linspace(0, np.pi, 5), [r"$0$", r"$\pi/4$", r"$\pi/2$", r"$3\pi/4$", r"$\pi$"]) plt.grid() plt.show()
結局、ここまで長い道のりを辿ってやったのは、 で表されたフーリエ変換の式 を、変数変換によって で表したことである。 と の関係はさっき計算した通りなので、 の値から周波数特性を求められるようになった。
オールパスフィルタ
適当なフィルタ を考える。イメージしやすいようにとりあえず のローパスフィルタとしておく。このフィルタの周波数特性 は、
と求められる。
ここで、唐突にフィルタ内の遅延要素 をオールパスフィルタ で置き換えたフィルタ を考えると、
となる。
この式にさっきの変数変換を適用すれば、
と表せる。
の周波数特性を考える。置き換える前のフィルタ の周波数特性は なので、置き換えたフィルタの周波数特性は同様の計算で となる。
これにより、遅延要素をオールパスフィルタで置き換えたフィルタの特性は、元のフィルタの周波数特性の、周波数の軸を伸縮させたものになっているとわかる。
メル目盛の近似
サンプリング周波数が 16kHz のとき、 くらいにするとメル目盛をよく近似する周波数目盛になる……とよく言われるけど 0.42 の根拠をあんまり見たことが無かった気がするので、描画して確認してみる。
描画コード
plt.figure(figsize=(4, 4), dpi=200) alpha = 0.42 sample_rate = 16000 omega = np.linspace(0, np.pi, 1000) omega_tilde = np.arccos( (-2 * alpha + (1 + alpha * alpha) * np.cos(omega)) / ((1 + alpha * alpha) - 2 * alpha * np.cos(omega)) ) plt.plot(omega, omega_tilde, label=fr"$\alpha={alpha:.2f}$") freq = omega * sample_rate / (2.0 * np.pi) mel = 1000 * np.log2(freq / 1000.0 + 1.0) max_mel = mel[-1] target_omega = mel * (np.pi / max_mel) plt.plot(omega, target_omega, color="black", label="mel") plt.legend() plt.xlabel(r"$\omega$") plt.ylabel(r"$\widetilde\omega$") plt.xlim(0, np.pi) plt.ylim(0, np.pi) plt.xticks(np.linspace(0, np.pi, 5), [r"$0$", r"$\pi/4$", r"$\pi/2$", r"$3\pi/4$", r"$\pi$"]) plt.yticks(np.linspace(0, np.pi, 5), [r"$0$", r"$\pi/4$", r"$\pi/2$", r"$3\pi/4$", r"$\pi$"]) plt.grid() plt.show()
よく近似できてるっぽい。
おわりに
SPTK の freqt がどういう仕組みになっているのかわかりません だれかおしえてください