前回の記事ではPythonでビブラートエフェクトとコーラスエフェクトを実装した。
今回はFM変調とBessel関数に関して面白い記述*1があったのでほとんどパクりだけど(情報は多いほうがいいに決まってるw)それについてみていく
FM変調
FM変調は以下の式で示されるのだった。
- A:原音信号振幅
- fc:原音信号周波数
- fs:サンプリング
- fm:変調周波数
- I:変調深度(エフェクターによくあるdepthつまみ)
このままでもいいのだが書くのがめんどいのでの部分をに置き換えさせてもらう
置き換えるとこうなると思う。
\begin{align*}
y(t) = a_c \sin(\omega_c t + a_m \sin(\omega_m t))
\end{align*}
ここで
\begin{align*}
t &= n / fs\\
\omega_c&= carrier freq\\
\omega_m&=modulation freq
\end{align*}
キャリアは原音信号のこと
この式を加法定理を使って展開しておく。
\begin{align*}
\sin (\alpha+\beta)=\sin\alpha\cos\beta+\cos\alpha\sin\beta
\end{align*}
\begin{align*}
y(t) = a_c (\sin(\omega_c t)\cos(a_m \sin(\omega_m t)) + \cos(\omega_c t)\sin(a_m \sin(\omega_m t)) )
\end{align*}
ベッセル関数とFM基本式
参考文献よりベッセル関数から以下の関係式が得られます。
\begin{align*}
\cos(x \sin(y)) &= \sum_{n=-\infty}^{n=\infty} J_n (x) \cos (ny) \\
\sin(x \sin(y)) &= \sum_{n=-\infty}^{n=\infty} J_n (x) \sin (ny)
\end{align*}
それを用いて上の加法定理の式をそれで置き換えると
\begin{align*}
y(t)=&
a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) (\sin(\omega_c t)\cos(n \omega_m t) + \cos(\omega_c t)\sin(n \omega_m t)) \\
=&
a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) \sin ( (\omega_c + n \omega_m)t )
\end{align*}
となる。
もう一度まとめてみると
\begin{align*}
a_c \sin(\omega_c t + a_m \sin(\omega_m t)) = a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) \sin ( (\omega_c + n \omega_m)t )
\end{align*}
ここからFM変調はベッセル関数と基音+倍音の積で表すことが可能だとわかる。
変調指数の大きさと倍音の関係
次に変調指数についてみていく
第一種ベッセル関数の\(J_{n}(\alpha)\)は一般的に変調指数と呼ばれる。
上で導いたようにFMの変調深度もそれにあたる。
というわけでこいつを大きくしていけばエフェクトとしては深くかかっていく理論。
その時ベッセル関数での挙動はどうなっているのか出してみた。
x軸を第一ベッセル関数の次数にしてy軸をJn(固定)にして表示すればよい
Jn(0.5)の場合
Jn(5)
Jn(10)
変調指数が低いと原音がきちんと聞こえるエフェクトとなるがJn(0.5)の時を見ると元スペクトルが大きく、側波帯が低くなっています。
第一種ベッセル関数は徐々に振幅が下がっていく特性を持つので側波帯のスペクトルは速やかに減衰する。すなわちエフェクトの効果通り原音の色が強い音色となる。
この記事で使ったPythonコード
scipy.specialモジュールを使います
from scipy.special import jv, yv import numpy as np import matplotlib.pyplot as plt z = np.arange(-20,20,0.01)#x軸の範囲 for i in range(0,5):#次数の決定(別に何個でもいい) bessel = (jv(i,z)) plt.plot(z,bessel,label="J"+str(i)) plt.legend() plt.show()
nを横軸にしたグラフのコード
from scipy.special import jv, yv import numpy as np import matplotlib.pyplot as plt z = np.arange(0,50,0.01) x = [] bessel = [] jn = 0.5 jn_index = int(jn*100) for i in range(0,30): bessel.append(jv(i,z[jn_index])) x.append(i) plt.xlabel("bessel order") plt.ylabel("Jn(" +str(jn) + ")") plt.scatter(x, bessel) plt.show()
参考文献
- Frequency modulation (FM) and Bessel functions(原音をcosでおいて加法定理、ベッセル関数の関係の説明)
- 【AdC2015】物理数学:ベッセル関数とFM音源 - 幸福の物理(原音をsinでおいて加法定理、ベッセル関数の関係の説明)
- Special functions (scipy.special) — SciPy v1.3.0 Reference Guide
*1:Analyzing an FM signal [John d .cook氏]