Skip to content

Commit 23d322b

Browse files
authored
Merge pull request #25 from woodnx/skotsugi/chapter04
Add chapter04
2 parents aaff2b2 + bd36c1d commit 23d322b

File tree

15 files changed

+300
-0
lines changed

15 files changed

+300
-0
lines changed

skotsugi/chapter04/q01.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import numpy as np
2+
3+
def zero_padding(L: int, S: int, x):
4+
# エラー処理
5+
if L < S:
6+
raise Exception('Shift size must be smaller than window size.')
7+
8+
# 出力信号長の算出
9+
N = len(x)
10+
M = L - S # > 0
11+
A = N + M
12+
B = A // S + 1 # 条件を満たす最小のSの倍数
13+
C = S * B + M
14+
15+
# 出力信号
16+
tilde = np.zeros(C) # 全体をゼロ埋め
17+
tilde[M:M+N] = x
18+
19+
return tilde
20+
21+
if __name__ == "__main__":
22+
x = np.ones(5)
23+
print(x)
24+
print(zero_padding(4, 3,))

skotsugi/chapter04/q02.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import numpy as np
2+
from q01 import zero_padding
3+
4+
def divide_frame(L: int, S: int, x):
5+
# エラー処理
6+
if L < S:
7+
raise Exception('Shift size must be smaller than window size.')
8+
9+
x_tilde = zero_padding(L, S, x)
10+
N = len(x_tilde)
11+
12+
T = np.arange((N - L) // S + 1)
13+
return np.array([ x_tilde[t*S:t*S+L] for t in T ])
14+
15+
if __name__ == "__main__":
16+
x = np.ones(5)
17+
print(x)
18+
print(zero_padding(4, 3, x))
19+
print(divide_frame(4, 3, x))

skotsugi/chapter04/q03.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import numpy as np
2+
from q02 import divide_frame
3+
4+
def stft(L: int, S: int, w, x):
5+
# エラー処理
6+
if L < S:
7+
raise Exception('Shift size must be smaller than window size.')
8+
9+
flames = divide_frame(L, S, x)
10+
11+
ffted = np.fft.rfft(flames*w).T
12+
13+
return ffted

skotsugi/chapter04/q04.png

36.3 KB
Loading

skotsugi/chapter04/q04.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import numpy as np
2+
3+
def sin(A, f, fs, sec):
4+
n = np.arange(0, fs*sec) / fs
5+
return A * np.sin(2 * np.pi * f * n)
6+
7+
def hamming(N: int):
8+
n = np.arange(N)
9+
return 0.54 - 0.46 * np.cos(2 * np.pi * n / (N - 1))
10+
11+
if __name__ == "__main__":
12+
import matplotlib.pyplot as plt
13+
from q03 import stft
14+
15+
L = 1000
16+
S = 500
17+
sec = 0.1
18+
freq = 440
19+
fs = 16000
20+
x = sin(1, freq, fs, sec)
21+
w = hamming(L)
22+
23+
X = stft(L, S, w, x)
24+
F = X.shape[0]
25+
T = X.shape[1]
26+
27+
t = (np.arange(T) + 0.5) * sec / T
28+
f = np.arange(F) / F * fs / 2
29+
30+
A = 20*np.log10(np.abs(X))
31+
ang = np.angle(X)
32+
33+
fig, ax = plt.subplots(1, 2)
34+
35+
cb = ax[0].pcolormesh(t, f, A)
36+
ax[0].set_ylabel('Frequency [Hz]')
37+
ax[0].set_xlabel('Time [sec]')
38+
39+
cb = ax[1].pcolormesh(t, f, ang)
40+
ax[1].set_ylabel('Frequency [Hz]')
41+
ax[1].set_xlabel('Time [sec]')
42+
43+
fig.colorbar(cb, orientation="vertical", ax=ax)
44+
45+
plt.grid()
46+
plt.tight_layout()
47+
plt.savefig('skotsugi/chapter04/q04.png')

skotsugi/chapter04/q05.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import numpy as np
2+
3+
def synthesis_window(S: int, w: np.ndarray):
4+
L = w.size
5+
Q = L // S
6+
7+
s = np.array([
8+
np.sum([
9+
w[l - m*S]**2
10+
for m in range(-(Q-1), Q)
11+
if 0 <= l - m*S and L > l - m*S
12+
]) for l in range(L)
13+
])
14+
15+
return w / s
16+
17+
18+
if __name__ == "__main__":
19+
import matplotlib.pyplot as plt
20+
21+
N = 500
22+
hamming = np.hamming(N)
23+
ws = synthesis_window(N, hamming)
24+
plt.plot(ws)
25+
plt.savefig("./skotsugi/chapter04/q05.png")

skotsugi/chapter04/q06.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import numpy as np
2+
from q05 import synthesis_window
3+
4+
def istft(S: int, w: np.ndarray, X: np.ndarray):
5+
F, T = X.shape
6+
N = 2 * (F - 1)
7+
M = S * (T - 1) + N
8+
9+
hat = np.zeros(M)
10+
11+
z = np.array([ np.fft.irfft(X[:,t]) for t in range(T) ])
12+
13+
if z.shape[1] != N:
14+
raise "len(z[n]) must be 2(F - 1)"
15+
16+
ws = synthesis_window(S, w)
17+
18+
for t in range(T):
19+
idx = t * S
20+
21+
# Overlap add
22+
hat[idx:idx + N] += ws * z[t]
23+
24+
return hat

skotsugi/chapter04/q07.png

65.9 KB
Loading

skotsugi/chapter04/q07.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import matplotlib.pyplot as plt
2+
from q03 import stft
3+
from q04 import sin, hamming
4+
from q06 import istft
5+
6+
L = 1000
7+
S = 500
8+
sec = 0.1
9+
freq = 440
10+
fs = 16000
11+
x = sin(1, freq, fs, sec)
12+
w = hamming(L)
13+
14+
X = stft(L, S, w, x)
15+
x_istft = istft(S, w, X)
16+
17+
plt.plot(x_istft)
18+
plt.grid()
19+
plt.xlim(0)
20+
plt.savefig('skotsugi/chapter04/q07.png')

skotsugi/chapter04/q08.png

58.6 KB
Loading

skotsugi/chapter04/q08.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
from q03 import stft
4+
from q04 import sin, hamming
5+
6+
def istft(S: int, X: np.ndarray):
7+
F, T = X.shape
8+
N = 2 * (F - 1)
9+
M = S * (T - 1) + N
10+
11+
hat = np.zeros(M)
12+
13+
z = np.array([ np.fft.irfft(X[0:F,t]) for t in range(T) ])
14+
15+
if z.shape[1] != N:
16+
raise "len(z[n]) must be 2(F - 1)"
17+
18+
ws = np.ones(N)
19+
20+
for t in range(T):
21+
idx = t * S
22+
23+
# Overlap add
24+
hat[idx:idx + N] = hat[idx:idx + N] + ws * z[t]
25+
26+
return hat
27+
28+
29+
L = 1000
30+
S = 500
31+
sec = 0.1
32+
freq = 440
33+
fs = 16000
34+
x = sin(1, freq, fs, sec)
35+
w = hamming(L)
36+
37+
X = stft(L, S, w, x)
38+
x_istft = istft(S, X)
39+
40+
plt.plot(x_istft)
41+
plt.grid()
42+
plt.xlim(0)
43+
plt.savefig('skotsugi/chapter04/q08.png')

skotsugi/chapter04/q09.png

25.2 KB
Loading

skotsugi/chapter04/q09.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from scipy.signal import chirp
4+
from q03 import stft
5+
from q04 import hamming
6+
7+
sec = 1
8+
fs = 16000
9+
t = np.linspace(0, sec, fs+1)
10+
x = chirp(t, f0=100, f1=16000, t1=sec)
11+
12+
L = 50
13+
S = 25
14+
Xs = []
15+
for i in range(1, 5):
16+
L = L * 2
17+
S = S * 2
18+
w = hamming(L)
19+
X = stft(L, S, w, x)
20+
Xs.append(X)
21+
22+
fig, ax = plt.subplots(4, 1, sharey=True, sharex=True)
23+
for i, X in enumerate(Xs):
24+
A = np.abs(X)
25+
26+
F = X.shape[0]
27+
T = X.shape[1]
28+
29+
cb = ax[i].pcolormesh(A)
30+
31+
plt.tight_layout()
32+
33+
fig.colorbar(cb, ax=ax)
34+
35+
plt.savefig('skotsugi/chapter04/q09.png')

skotsugi/chapter04/q10.png

37 KB
Loading

skotsugi/chapter04/q10.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import numpy as np
2+
3+
def to_quantity(X: np.ndarray, fs: int, S: int):
4+
F = X.shape[0] # 1フレームあたりの信号長
5+
T = X.shape[1] # フレーム数
6+
L = 2 * (F - 1)
7+
8+
t = np.arange(T) * S / fs
9+
f = np.arange(F) * fs / L
10+
11+
print(t)
12+
13+
return t, f
14+
15+
if __name__ == "__main__":
16+
import matplotlib.pyplot as plt
17+
from q03 import stft
18+
from q04 import sin, hamming
19+
20+
L = 1000
21+
S = 500
22+
sec = 0.1
23+
freq = 440
24+
fs = 16000
25+
x = sin(1, freq, fs, sec)
26+
w = hamming(L)
27+
28+
X = stft(L, S, w, x)
29+
30+
t, f = to_quantity(X, fs, S)
31+
32+
A = 20 * np.log10(np.abs(X))
33+
ang = np.angle(X)
34+
35+
fig, ax = plt.subplots(1, 2)
36+
37+
cb = ax[0].pcolormesh(t, f, A)
38+
ax[0].set_ylabel('Frequency [Hz]')
39+
ax[0].set_xlabel('Time [sec]')
40+
41+
cb = ax[1].pcolormesh(t, f, ang)
42+
ax[1].set_ylabel('Frequency [Hz]')
43+
ax[1].set_xlabel('Time [sec]')
44+
45+
plt.tight_layout()
46+
47+
fig.colorbar(cb, ax=ax)
48+
49+
plt.grid()
50+
plt.savefig('skotsugi/chapter04/q10.png')

0 commit comments

Comments
 (0)