scipyの新しいShortTimeFFTを使って振幅スペクトルと位相スペクトルを描画した

はじめに

Python短時間フーリエ変換(STFT)を計算するためのツール(ライブラリ)の一つにscipyがある. scipyでSTFTを計算するための関数がstftであったが,最新版(v1.12.0)ではlegacyに位置づけられている.

scipy.signal.stft — SciPy v1.12.0 Manual

その代わりに ”ShortTimeFFT” クラスが新設され,stftはこのクラスのいちメソッドになった.

docs.scipy.org

本記事はこの新しいstftを使ってみて実行結果を眺めてみよう,という主旨のもと,特に位相スペクトルに注目する.

新しいクラスと注目のパラメータ phase_shift

ここでShortTimeFFT クラスのパラメータを見てみよう.

パラメータ 説明
win 分析窓(numpy 配列)
hop ホップ長(フレームシフト長)
fft_mode 両側FFTや片側FFTなどを指定
mfft FFT
dual_win 双対窓
scale_to STFT結果のスケーリングを指定
phase_shift 線形位相シフトの量

本記事では最後のphase_shiftが重要である. このパラメータを指定することで,STFT時の位相スペクトルに線形位相成分が付加される.デフォルト値は0,つまり線形位相成分を付加しない.Noneを指定すると,-mfft//2に比例した線形位相成分が付加される.

docs.scipy.org

このphase_shift,初見では「一体何だこれは?」だろう.

細かい理論はすっ飛ばして,このパラメータの指定いかんで位相スペクトルがどのように変化するかを見ていこう.

スペクトルの描画

JSUTコーパスに含まれる onomatopee300 から 001.wavを選び,そのSTFTを計算して振幅スペクトルと位相スペクトルを描画する. 比較のため,旧stftでSTFTを計算した結果も示す. 以下,図1から図3まで振幅スペクトル(各図上段)と位相スペクトル(各図下段)を描画した結果を示している.

図1:旧stftを使ったときの振幅スペクトルと位相スペクトル

図2:ShortTimeFFTを使ったときの振幅スペクトルと位相スペクトル(phase_shift=0)

図3:ShortTimeFFTを使ったときの振幅スペクトルと位相スペクトル(phase_shift=None)

振幅スペクトルはどれも同じに見えるが,図2の位相スペクトルだけ見かけが大きく異なっていることが分かるだろう. 図1(旧stft)の位相スペクトルと図3(新stft)の位相スペクトルは,「何だかとても見づらい(構造が把握しづらい)」が,見かけは似ている.

描画に使ったコードは以下に置いた.

plot_amp_phase_spec.py · GitHub

仕掛け

STFTに伴って線形位相成分が付与される事情は矢田部先生の解説記事を読むのがよい(5.2節).

www.jstage.jst.go.jp

線形位相成分の議論は同じく矢田部先生よる以下の記事にも詳しい.

www.jstage.jst.go.jp

要するに,STFTでは分析窓の影響で音声本来の位相スペクトルに加えて窓由来の線形位相成分が乗ってしまう.ゆえに図1や図3のような位相スペクトルの見かけになっている. 新stftでphase_shift=0とすると,その線形位相成分が除去された状態の位相スペクトルが手に入る.phase_shift=Noneとすると,旧stftと同じような線形位相成分を乗せる.

線形位相成分が除去された状態の位相スペクトルを使うと分析しやすい事情は上記の記事にも書かれている.

細かい実装はソースコードを見れば分かるのだが,FFT計算の直前にサンプルのシフト(roll)を行っており,これにより線形位相成分をキャンセルしている. scipy/scipy/signal/_short_time_fft.py at v1.12.0 · scipy/scipy · GitHub

まとめ

新stftで位相スペクトルの線形位相成分の除去がやりやすくなったのは嬉しい.

「誤り訂正技術Ⅰ ~基礎編~」および「誤り訂正技術Ⅱ ~応用編~」の各記事へのリンク

ブックマーク程度に。

基礎編

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

応用編

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

【Emacs】dabbrev-completionを強化する

Capeというパッケージを使う。

github.com

取り急ぎ

(global-set-key (kbd "C-M-/") #'cape-dabbrev)

とすれば、効果を実感できる。

補完候補が出すぎて困る場合、cape-dabbrev-check-other-buffersnilにしたり、cape-dabbrev-min-lengthを小さくすると良いだろう。

Conv1d の後段にBatchNorm1dではなくLayerNormを置きたいとき

GroupNormを使う.

nn.BatchNorm1d(out_channels)

から

nn.GroupNorm(1, out_channels)

への置き換えでOK.GroupNormの第1引数はグループ数であり,ここを1に指定するとLayerNormと等価になる.

discuss.pytorch.org

【Emacs】Ubuntu上でC/C++言語のlanguage server (Clangd)を動かすときの設定

Clangdの公式ページに基づいてインストールする.

clangd.llvm.org

sudo apt-get install clangd

上記によりClangdのバイナリがインストールされる.

Emacs側はeglotパッケージを活用する。 Clangdに関する設定を追記する.

(add-hook 'c-mode-hook #'eglot-ensure)
(add-hook 'c++-mode-hook #'eglot-ensure)