回答編集履歴
6
文法の修正
test
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
|
13
|
-
よって、**ウインドウがぴったりと切り
|
13
|
+
よって、**ウインドウがぴったりと切り分けられるように入力配列の後ろを少し削る**修正をしました。これでエラーが解消されました。
|
14
14
|
|
15
15
|
|
16
16
|
|
@@ -70,7 +70,7 @@
|
|
70
70
|
|
71
71
|
|
72
72
|
|
73
|
-
# ★修正 ウインドウがぴったりと切り
|
73
|
+
# ★修正 ウインドウがぴったりと切り分けられるように入力配列の後ろを少し削る
|
74
74
|
|
75
75
|
x = x[:-((len(x) - window_num) % stride_num)]
|
76
76
|
|
5
補足追記
test
CHANGED
@@ -30,11 +30,11 @@
|
|
30
30
|
|
31
31
|
|
32
32
|
|
33
|
-
一方、[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Axis along which the STFT is computed; the default is over the last axis (i.e. axis=-1).と書かれており、時間方向が最後(-1)の次元がデフォルトです。よってこのギャップが原因で、モノラルだと通るけど、ステレオだとエラーが出る、ということになっていました。
|
33
|
+
一方、[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Axis along which the STFT is computed; the default is over the last axis (i.e. axis=-1).と書かれており、時間方向が最後(-1)の次元がデフォルトです。よってこのギャップが原因で、モノラルだと通るけど、ステレオだとエラーが出る、ということになっていました。デフォルト設定でステレオ音声を入力すると、時間方向の配列の長さが2しか無いことになり、最初かつ唯一のウインドウサイズ(=nperseg)が小さすぎて、設定されたnoverlapと比較して変だよ、というエラーになっていたものと思います。原因がわかるとエラーの意味もわかります。
|
34
34
|
|
35
35
|
|
36
36
|
|
37
|
-
よって、scipy.signal処理の時に音声配列を転置(.T)してしまうのが解決策です。これにより、このエラーを解消することができました。なお、質問者様の音声ファイルはモノラルなのでエラーが発生していなかったと思われます。
|
37
|
+
対策としてaxisオプションでこの動作を変えることも可能ですが、istftも同様の思想なので、**「soundで取り込んだファイルをscipy.signalで分析する場合は、次元を入れ替えてしまったほうが早い」**と思います。よって、scipy.signal処理の時に音声配列を転置(.T)してしまうのが解決策です。これにより、このエラーを解消することができました。なお、質問者様の音声ファイルはモノラルなのでエラーが発生していなかったと思われます。
|
38
38
|
|
39
39
|
|
40
40
|
|
4
文法の修正
test
CHANGED
@@ -6,11 +6,11 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Notesに、In order to enable inversion of an STFT via the inverse STFT in istft, the signal windowing must obey the constraint of “Nonzero OverLap Add” (NOLA), and the input signal must have complete windowing coverage (i.e. (x.shape[axis] - nperseg) % (nperseg-noverlap) == 0).と記載されて
|
9
|
+
[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Notesに、In order to enable inversion of an STFT via the inverse STFT in istft, the signal windowing must obey the constraint of “Nonzero OverLap Add” (NOLA), and the input signal must have complete windowing coverage (i.e. (x.shape[axis] - nperseg) % (nperseg-noverlap) == 0).と記載されています。ちゃんとistftしたいのであれば、入力シグナルがぴったりとウインドウに切り分けられるように(x.shape[axis] - nperseg) % (nperseg-noverlap) == 0 であること、という意味です。すなわち、入力シグナルがウインドウで切り分けた余りがあることが、エラーの原因でした。実際には、paddedのデフォルトオプションによって、余りが自動補完されて1つ余計にウインドウが計算され、変換結果の方が膨らんでしまっていました。
|
10
10
|
|
11
11
|
|
12
12
|
|
13
|
-
よって、**ウインドウがぴったりと切り取れるように入力配列の後ろを少し切り取る**こ
|
13
|
+
よって、**ウインドウがぴったりと切り取れるように入力配列の後ろを少し切り取る**修正をしました。これでエラーが解消されました。
|
14
14
|
|
15
15
|
|
16
16
|
|
3
より正確な記載に修正
test
CHANGED
@@ -6,7 +6,11 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
|
9
|
+
[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Notesに、In order to enable inversion of an STFT via the inverse STFT in istft, the signal windowing must obey the constraint of “Nonzero OverLap Add” (NOLA), and the input signal must have complete windowing coverage (i.e. (x.shape[axis] - nperseg) % (nperseg-noverlap) == 0).と記載されており、ちゃんとistftしたいのであれば、入力シグナルがぴったりとウインドウに切り分けられるように(x.shape[axis] - nperseg) % (nperseg-noverlap) == 0 であること、という記載があります。すなわち、入力シグナルがウインドウで切り分けた余りがあることが、エラーの原因でした。実際には、paddedのデフォルトオプションによって、余りが補完されて、変換結果の方が膨らんでしまっています。
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
よって、**ウインドウがぴったりと切り取れるように入力配列の後ろを少し切り取る**ことで、このエラーが解消されます。
|
10
14
|
|
11
15
|
|
12
16
|
|
@@ -26,7 +30,7 @@
|
|
26
30
|
|
27
31
|
|
28
32
|
|
29
|
-
一方、stftの
|
33
|
+
一方、[stftのドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html)には、Axis along which the STFT is computed; the default is over the last axis (i.e. axis=-1).と書かれており、時間方向が最後(-1)の次元がデフォルトです。よってこのギャップが原因で、モノラルだと通るけど、ステレオだとエラーが出る、ということになっていました。axisオプションでこの動作を変えることも可能ですが、istftも同様の思想なので、**「soundで取り込んだファイルをscipy.signalで分析する場合は、次元を入れ替えてしまったほうが早い」**と思います。
|
30
34
|
|
31
35
|
|
32
36
|
|
@@ -63,6 +67,12 @@
|
|
63
67
|
window_num = 256 # 窓幅のデータ数
|
64
68
|
|
65
69
|
stride_num = 128 # ストライド幅のデータ数
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
# ★修正 ウインドウがぴったりと切り取れるように入力配列の後ろを少し切り取る。
|
74
|
+
|
75
|
+
x = x[:-((len(x) - window_num) % stride_num)]
|
66
76
|
|
67
77
|
|
68
78
|
|
@@ -110,10 +120,6 @@
|
|
110
120
|
|
111
121
|
plt.figure('Signal difference waveform')
|
112
122
|
|
113
|
-
# ★修正 配列の長さを揃える
|
114
|
-
|
115
|
-
min_len = min(len(x), len(y))
|
116
|
-
|
117
|
-
plt.plot(x
|
123
|
+
plt.plot(x-y)
|
118
124
|
|
119
125
|
```
|
2
一部修正
test
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
質問のエラーについて
|
1
|
+
**質問のエラーについて**
|
2
2
|
|
3
3
|
|
4
4
|
|
@@ -6,19 +6,31 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
|
9
|
+
ちょっとこれ、stft → istftで同じ長さに戻すオプションの付け方とかあるのかもしれませんが、未確認です。
|
10
10
|
|
11
11
|
|
12
12
|
|
13
|
-
|
13
|
+
**質問に無いエラーについて**
|
14
14
|
|
15
15
|
|
16
16
|
|
17
|
-
|
17
|
+
ところが、上記に至るまでに別のエラーで悩まされました。`f, t, X1 = sg.stft(x, fs=fs, nperseg=window_num, noverlap=window_num-stride_num)`のところで、別のエラー`ValueError: noverlap must be less than nperseg.`が発生するのです。
|
18
18
|
|
19
19
|
|
20
20
|
|
21
|
-
|
21
|
+
結論としては、soundfileでの音声ファイルは、モノラルでは1次元、ステレオでは2次元の配列になっていること、および2次元の時の次元の意味がstftの期待とズレていることが原因でした。
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
実際に、[モノラルとステレオ両方のサンプルを提供しているサイト](https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/audio-samples.html)にてwavファイルを取得して、soundfileの取り込み形式を比較して確認しました。shapeを見ると、モノラルだと(8250520,)、ステレオだと(8250624, 2)といった形をしています。時間方向は最初の次元であることに注意してください。
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
一方、stftの方は、Axis along which the STFT is computed; the default is over the last axis (i.e. axis=-1).と書かれており、時間方向が最後(-1)の次元がデフォルトです。よってこのギャップが原因で、モノラルだと通るけど、ステレオだとエラーが出る、ということになっていました。axisオプションでこの動作を変えることも可能ですが、istftも同様の思想なので、**「soundで取り込んだファイルをscipy.signalで分析する場合は、次元を入れ替えてしまったほうが早い」**と思います。
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
よって、scipy.signal処理の時に音声配列を転置(.T)してしまうのが解決策です。これにより、このエラーを解消することができました。なお、質問者様の音声ファイルはモノラルなのでエラーが発生していなかったと思われます。
|
22
34
|
|
23
35
|
|
24
36
|
|
@@ -54,23 +66,19 @@
|
|
54
66
|
|
55
67
|
|
56
68
|
|
57
|
-
# ★修正
|
69
|
+
# ★修正 sg計算の前後で転置する。
|
58
|
-
|
59
|
-
if x.ndim > 1:
|
60
|
-
|
61
|
-
x = x[:,0]
|
62
|
-
|
63
|
-
|
64
70
|
|
65
71
|
# スペクトログラムの計算
|
66
72
|
|
67
|
-
f, t, X1 = sg.stft(x, fs=fs, nperseg=window_num, noverlap=(window_num-stride_num))
|
73
|
+
f, t, X1 = sg.stft(x.T, fs=fs, nperseg=window_num, noverlap=(window_num-stride_num))
|
68
74
|
|
69
75
|
|
70
76
|
|
71
77
|
# 逆STFTによる復号
|
72
78
|
|
73
79
|
_, y = sg.istft(X1, fs=fs, nperseg=window_num, noverlap=(window_num-stride_num))
|
80
|
+
|
81
|
+
y = y.T
|
74
82
|
|
75
83
|
|
76
84
|
|
1
質問修正に伴う回答修正
test
CHANGED
@@ -1,13 +1,111 @@
|
|
1
|
-
質問
|
1
|
+
質問のエラーについて
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
-
|
5
|
+
stftしてistftすると、元の配列から長さが変わるようです。そのため、長さを揃えて計算しないと、`plt.plot(x-y)`のところで、`ValueError: operands could not be broadcast together with shapes (27200,) (27264,)`といったエラーが出ます。これが質問者様の報告されたエラーです。
|
6
|
-
|
7
|
-
よって、Pythonとそのライブラリ群を前提に、コードを再度検討いただき、改めてご質問ください。
|
8
6
|
|
9
7
|
|
10
8
|
|
11
|
-
|
9
|
+
質問に無いエラーについて
|
12
10
|
|
13
|
-
|
11
|
+
|
12
|
+
|
13
|
+
ところが、上記に至るまでに別のエラーで悩まされました。`f, t, X1 = sg.stft(x, fs=fs, nperseg=window_num, noverlap=window_num-stride_num)`のところで、別のエラー`ValueError: noverlap must be less than nperseg.`が発生するのです。soundfileで音声を取り込んでstftをする例がネットに無く、waveによる取り込みが主でした。よって、waveによる取り込みとsoundfileによる取り込みを比較して、ステレオ時にsoundfileで取り込む形式が、その後のstftに悪影響を与えていることを関連付けました。
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
結論としては、soundfileでの音声ファイルは、モノラルでは1次元、ステレオでは2次元の配列になっていることが原因でした。実際に、[モノラルとステレオ両方のサンプルを提供しているサイト](https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/audio-samples.html)にてwavファイルを取得して、soundfileの取り込み形式を比較して確認しました。一方、stftは1次元配列を前提としています。
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
そのため、soundfileの入力がモノラルかステレオかを区別して、ステレオの際には、片側の音声のみ1次元配列として取り出す対処をする必要があります。これにより、このエラーを解消することができました。なお、質問者様の音声ファイルはモノラルなのでエラーが発生していなかったと思われます。
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
以上2点の修正を加えたソースです。
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
```Python
|
30
|
+
|
31
|
+
# モジュールのインポート
|
32
|
+
|
33
|
+
import numpy as np
|
34
|
+
|
35
|
+
import matplotlib.pyplot as plt
|
36
|
+
|
37
|
+
import soundfile as sf
|
38
|
+
|
39
|
+
import scipy
|
40
|
+
|
41
|
+
from scipy import signal as sg
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
# 音声の読み込み
|
46
|
+
|
47
|
+
x, fs = sf.read('speech1.wav')
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
window_num = 256 # 窓幅のデータ数
|
52
|
+
|
53
|
+
stride_num = 128 # ストライド幅のデータ数
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
# ★修正 マルチチャネルなら最初きチャネルのみを取り出す
|
58
|
+
|
59
|
+
if x.ndim > 1:
|
60
|
+
|
61
|
+
x = x[:,0]
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
# スペクトログラムの計算
|
66
|
+
|
67
|
+
f, t, X1 = sg.stft(x, fs=fs, nperseg=window_num, noverlap=(window_num-stride_num))
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
# 逆STFTによる復号
|
72
|
+
|
73
|
+
_, y = sg.istft(X1, fs=fs, nperseg=window_num, noverlap=(window_num-stride_num))
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
# 出力音声の保存
|
78
|
+
|
79
|
+
sf.write('outout.wav', y, fs)
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
# グラフに表示
|
84
|
+
|
85
|
+
# - 波形
|
86
|
+
|
87
|
+
plt.figure('Original waveform')
|
88
|
+
|
89
|
+
plt.plot(x)
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
# - 復号した波形
|
94
|
+
|
95
|
+
plt.figure('Decryption waveform')
|
96
|
+
|
97
|
+
plt.plot(y)
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
# - 信号差の波形(ここが分からない。入力信号xと出力信号yの差信号x−yが求めたい)
|
102
|
+
|
103
|
+
plt.figure('Signal difference waveform')
|
104
|
+
|
105
|
+
# ★修正 配列の長さを揃える
|
106
|
+
|
107
|
+
min_len = min(len(x), len(y))
|
108
|
+
|
109
|
+
plt.plot(x[:min_len]-y[:min_len])
|
110
|
+
|
111
|
+
```
|