├── LICENSE.txt ├── README.md ├── cover.jpg ├── eq_2_11.png ├── eq_2_32.png ├── eq_2_36.png ├── eq_2_46.png ├── err_eq_2_11.png ├── err_eq_2_32.png ├── err_eq_2_36.png ├── err_eq_2_46.png ├── err_fig_5_5.png ├── errata.md ├── fig_5_5.png ├── install.md ├── section10.md ├── section10 ├── sample_code_c10_1.py └── sample_code_c10_2.py ├── section11.md ├── section11 ├── sample_code_c11_1.py └── sample_code_c11_2.py ├── section2.md ├── section2 ├── sample_code_c2_1.py ├── sample_code_c2_10.py ├── sample_code_c2_11.py ├── sample_code_c2_12.py ├── sample_code_c2_13.py ├── sample_code_c2_14.py ├── sample_code_c2_2.py ├── sample_code_c2_3.py ├── sample_code_c2_4.py ├── sample_code_c2_5.py ├── sample_code_c2_6.py ├── sample_code_c2_7.py ├── sample_code_c2_8.py └── sample_code_c2_9.py ├── section3.md ├── section3 ├── sample_code_c3_1.py ├── sample_code_c3_2.py ├── sample_code_c3_3.py ├── sample_code_c3_4.py ├── sample_code_c3_5.py ├── sample_code_c3_6.py ├── sample_code_c3_7.py ├── sample_code_c3_8.py └── sample_code_c3_9.py ├── section4.md ├── section4 └── sample_code_c4_1.py ├── section5.md ├── section5 ├── sample_code_c5_1.py ├── sample_code_c5_2.py ├── sample_code_c5_3.py ├── sample_code_c5_4.py ├── sample_code_c5_5.py ├── sample_code_c5_6.py └── sample_code_c5_7.py ├── section6.md ├── section6 ├── sample_code_c6_1.py ├── sample_code_c6_10.py ├── sample_code_c6_11.py ├── sample_code_c6_12.py ├── sample_code_c6_13.py ├── sample_code_c6_14.py ├── sample_code_c6_2.py ├── sample_code_c6_3.py ├── sample_code_c6_4.py ├── sample_code_c6_5.py ├── sample_code_c6_6.py ├── sample_code_c6_7.py ├── sample_code_c6_8.py └── sample_code_c6_9.py ├── section7.md ├── section7 ├── sample_code_c7_1.py ├── sample_code_c7_2.py ├── sample_code_c7_3.py ├── sample_code_c7_4.py └── sample_code_c7_5.py ├── section8.md ├── section8 ├── sample_code_c8_1.py ├── sample_code_c8_2.py ├── sample_code_c8_3.py └── sample_code_c8_4.py ├── section9.md └── section9 ├── sample_code_c9_1.py └── sample_code_c9_2.py /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Masahito Togami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Pythonで学ぶ音源分離(機械学習実践シリーズ)のソースコード 2 | 3 | ![Python 3.6](https://img.shields.io/badge/Python-3.6-green.svg) 4 | ![License](https://img.shields.io/badge/Code%20License-MIT-green.svg) 5 | 6 | 本リポジトリでは、インプレス社機械学習実践シリーズの「Pythonで学ぶ音源分離」のサンプルコードを管理しています。 7 | なお、本ソースコードは、MITライセンスのもとで公開されています。LICENSE.txtを見てください。 8 | 9 | ## 書籍概要 10 | 11 | ![Pythonで学ぶ音源分離カバー](cover.jpg) 12 | * [Pythonで学ぶ音源分離(機械学習実践シリーズ)](https://book.impress.co.jp/books/1119101154 "Pythonで学ぶ音源分離(機械学習実践シリーズ)") 13 | * 価格: 3,500円+税 14 | * 発売日: 2020年8月24日 15 | * ページ数: 352 16 | * サイズ: B5変形判 17 | * 著者: 戸上 真人 18 | * ISBN: 9784295009849 19 | 20 | ## 目次 21 | * 序章 22 | * 第1章 音源分離とは? 23 | * 第2章 音声処理の基礎 24 | * 第3章 音源分離で用いる数学的知識の基礎(線形代数、ベクトル・行列の微分) 25 | * 第4章 「最適化」に関する技法を理解する 26 | * 第5章 シミュレーターで音を作ってみる 27 | * 第6章 古典的な音源分離方法~ビームフォーミング~ 28 | * 第7章 音源方向推定に基づく音源分離 29 | * 第8章 現代的な統計的モデルに基づく音源分離法 30 | * 第9章 響きのある音を響きのない音に変える残響除去法 31 | * 第10章 音源分離と残響除去を統合的に実行する 32 | * 第11章 音源分離関連のライブラリ紹介・その他のトピック・参考文献 33 | 34 | ## 各章のサンプルコード 35 | * [本書の前提](install.md) 36 | * [第2章のサンプルコード](section2.md) 37 | * [第3章のサンプルコード](section3.md) 38 | * [第4章のサンプルコード](section4.md) 39 | * [第5章のサンプルコード](section5.md) 40 | * [第6章のサンプルコード](section6.md) 41 | * [第7章のサンプルコード](section7.md) 42 | * [第8章のサンプルコード](section8.md) 43 | * [第9章のサンプルコード](section9.md) 44 | * [第10章のサンプルコード](section10.md) 45 | * [第11章のサンプルコード](section11.md) 46 | ## お詫びと訂正 47 | Pythonで学ぶ音源分離(機械学習実践シリーズ)に誤りがありました。ここに謹んでお詫び申し上げますと共に,以下のページに正誤表を 48 | 掲載させて頂きます。 49 | 50 | [本書の正誤表](errata.md) 51 | 52 | ## License 53 | MIT 54 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/cover.jpg -------------------------------------------------------------------------------- /eq_2_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/eq_2_11.png -------------------------------------------------------------------------------- /eq_2_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/eq_2_32.png -------------------------------------------------------------------------------- /eq_2_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/eq_2_36.png -------------------------------------------------------------------------------- /eq_2_46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/eq_2_46.png -------------------------------------------------------------------------------- /err_eq_2_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/err_eq_2_11.png -------------------------------------------------------------------------------- /err_eq_2_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/err_eq_2_32.png -------------------------------------------------------------------------------- /err_eq_2_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/err_eq_2_36.png -------------------------------------------------------------------------------- /err_eq_2_46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/err_eq_2_46.png -------------------------------------------------------------------------------- /err_fig_5_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masahitotogami/python_source_separation/e0788b02104e8fedaf5fc2e87842cf778865c923/err_fig_5_5.png -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | ## 正誤表 2 | |項番|該当箇所|誤|正|update| 3 | |---|---|---|---|---| 4 | |1|p.2| pip install itertools | 削除 |2020/08/24| 5 | |2|第4章第5節タイトル, p4, p.135 | Maximization-Majorization | Majorization-Minimization | 2020/08/24| 6 | |3|p.10| 「知り当たった」|「知り合った」|2020/08/24| 7 | |4|第二章|code2.1とcode2.9が欠番。(コードを削除したことに起因)|-|2020/08/24| 8 | |5|p.60|code2.14|code2.15|2020/08/24| 9 | |6|p.97|code3.9|result3.1|2020/08/24| 10 | |7|p.82| 「このとき、mkij',x_bar,np.conjugate(x_bar)) 46 | #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) 47 | 48 | correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) 49 | 50 | filter=np.linalg.solve(x_bar_x_bar_h,correlation) 51 | 52 | #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) 53 | x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) 54 | 55 | x_dereverb=x[0,...]-x_reverb 56 | 57 | return(x_dereverb) 58 | 59 | #WPEで残響を除去 60 | #x:入力信号( M, Nk, Lt) 61 | #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) 62 | #return x_dereverb:残響除去後の信号(Nk,Lt) 63 | def dereverberation_wpe(x,x_bar,wpe_iterations=10): 64 | 65 | #マイクロホン数・周波数・フレーム数・タップ長を取得する 66 | M=np.shape(x)[0] 67 | Nk=np.shape(x)[1] 68 | Lt=np.shape(x)[2] 69 | Lh=np.shape(x_bar)[0] 70 | 71 | #入力信号の形式を変更・変数を初期化 72 | x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) 73 | v=np.square(np.abs(x[0,...])) 74 | 75 | cost_buff=[] 76 | for t in range(wpe_iterations): 77 | #共分散行列を計算 78 | x_bar_x_bar_h=np.einsum('kt,ikt,jkt->kij',1./v,x_bar,np.conjugate(x_bar)) 79 | 80 | #相関ベクトルを計算 81 | correlation=np.einsum('kt,ikt,kt->ki',1./v,x_bar,np.conjugate(x[0,...])) 82 | 83 | #フィルタ算出 84 | filter=np.linalg.solve(x_bar_x_bar_h,correlation) 85 | 86 | #残響除去実施 87 | x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) 88 | x_dereverb=x[0,...]-x_reverb 89 | 90 | #パラメータ更新 91 | v=np.square(np.abs(x_dereverb)) 92 | v=np.maximum(v,1.e-8) 93 | 94 | #コスト計算 95 | cost=np.mean(np.log(v)) 96 | cost_buff.append(cost) 97 | return(x_dereverb,cost_buff) 98 | 99 | 100 | #2バイトに変換してファイルに保存 101 | #signal: time-domain 1d array (float) 102 | #file_name: 出力先のファイル名 103 | #sample_rate: サンプリングレート 104 | def write_file_from_time_signal(signal,file_name,sample_rate): 105 | #2バイトのデータに変換 106 | signal=signal.astype(np.int16) 107 | 108 | #waveファイルに書き込む 109 | wave_out = wave.open(file_name, 'w') 110 | 111 | #モノラル:1、ステレオ:2 112 | wave_out.setnchannels(1) 113 | 114 | #サンプルサイズ2byte 115 | wave_out.setsampwidth(2) 116 | 117 | #サンプリング周波数 118 | wave_out.setframerate(sample_rate) 119 | 120 | #データを書き込み 121 | wave_out.writeframes(signal) 122 | 123 | #ファイルを閉じる 124 | wave_out.close() 125 | 126 | #SNRをはかる 127 | #desired: 目的音、Lt 128 | #out: 雑音除去後の信号 Lt 129 | def calculate_snr(desired,out): 130 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 131 | 132 | #消し残った雑音 133 | desired=desired[:wave_length] 134 | out=out[:wave_length] 135 | noise=desired-out 136 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 137 | 138 | return(snr) 139 | 140 | #乱数の種を初期化 141 | np.random.seed(0) 142 | 143 | #畳み込みに用いる音声波形 144 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 145 | 146 | #音源数 147 | n_sources=len(clean_wave_files) 148 | 149 | #長さを調べる 150 | n_samples=0 151 | #ファイルを読み込む 152 | for clean_wave_file in clean_wave_files: 153 | wav=wave.open(clean_wave_file) 154 | if n_samplesmn",A,B)) 27 | 28 | 29 | #行列Aと行列Bのアダマール積 30 | B=np.matrix([[-1.,2.,4.],[1.,8.,6.]]) 31 | print("A*B= \n",np.multiply(A,B)) 32 | 33 | #行列Aの転置 34 | print("A^T= \n",A.T) 35 | print("A^T= \n",np.transpose(A,axes=(1,0))) 36 | print("A^T= \n",np.swapaxes(A,1,0)) 37 | 38 | #複素行列のエルミート転置 39 | A=np.matrix([[3.,1.+2.j,2.+3.j],[2.,3.-4.j,1.+3.j]]) 40 | print("A^H= \n",A.H) 41 | print("A^H= \n",np.swapaxes(np.conjugate(A),1,0)) 42 | 43 | #行列の積に対するエルミート転置 44 | A=np.matrix([[3.,1.+2.j,2.+3.j],[2.,3.-4.j,1.+3.j]]) 45 | B=np.matrix([[4.+4.j,2.-3.j],[-1.+1.j,3.-2.j],[1.+3.j,5.+5.j]]) 46 | print("(AB)^H= \n",(np.matmul(A,B)).H) 47 | print("B^H A^H= \n",np.matmul(B.H,A.H)) 48 | 49 | #単位行列の定義 50 | I=np.eye(N=3) 51 | print("I = \n",I) 52 | -------------------------------------------------------------------------------- /section3/sample_code_c3_2.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | #numpyをインポート(行列を扱う各種関数を含む) 4 | import numpy as np 5 | 6 | #乱数の種を設定 7 | np.random.seed(0) 8 | 9 | #テンソルの大きさを設定 10 | L=10 11 | K=5 12 | M=3 13 | R=3 14 | N=3 15 | #ランダムな複素数のテンソル(ndarray)を定義する 16 | A=np.random.uniform(size=L*K*M*R)+np.random.uniform(size=L*K*M*R)*1.j 17 | A=np.reshape(A,(L,K,M,R)) 18 | 19 | B=np.random.uniform(size=K*R*N)+np.random.uniform(size=K*R*N)*1.j 20 | B=np.reshape(B,(K,R,N)) 21 | 22 | #einsumを使って行列積を計算する 23 | C=np.einsum("lkmr,krn->lkmn",A,B) 24 | 25 | #行列Cの大きさを表示 26 | print("shape(C): ",np.shape(C)) 27 | 28 | #l=0,k=0の要素について検算実施 29 | print("A(0,0)B(0,0)=\n",np.matmul(A[0,0,...],B[0,...])) 30 | print("C(0,0)=\n",C[0,0,...]) 31 | 32 | 33 | #einsumを使って行列積をl,k毎に計算した後、かつl方向に和を取る 34 | C=np.einsum("lkmr,krn->kmn",A,B) 35 | 36 | #行列Cの大きさを表示 37 | print("shape(C): ",np.shape(C)) 38 | 39 | #k=0の要素について検算実施 40 | for l in range(L): 41 | if l==0: 42 | C_2=np.matmul(A[l,0,...],B[0,...]) 43 | else: 44 | C_2=C_2+np.matmul(A[l,0,...],B[0,...]) 45 | 46 | print("C_2(0)=\n",C_2) 47 | print("C(0)=\n",C[0,...]) 48 | 49 | #einsumを使ってアダマール積を計算する 50 | C=np.einsum("lkmn,kmn->lkmn",A,B) 51 | 52 | #行列Cの大きさを表示 53 | print("shape(C): ",np.shape(C)) 54 | 55 | #l=0,k=0の要素について検算実施 56 | print("A(0,0)B(0,0)=\n",np.multiply(A[0,0,...],B[0,...])) 57 | print("C(0,0)=\n",C[0,0,...]) 58 | 59 | 60 | -------------------------------------------------------------------------------- /section3/sample_code_c3_3.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | #numpyをインポート(行列を扱う各種関数を含む) 4 | import numpy as np 5 | 6 | #乱数の種を設定 7 | np.random.seed(0) 8 | 9 | #テンソルの大きさを設定 10 | L=10 11 | K=5 12 | M=3 13 | R=3 14 | S=3 15 | N=3 16 | #ランダムな複素数のテンソル(ndarray)を定義する 17 | A=np.random.uniform(size=L*K*M*R)+np.random.uniform(size=L*K*M*R)*1.j 18 | A=np.reshape(A,(L,K,M,R)) 19 | 20 | B=np.random.uniform(size=K*R*S)+np.random.uniform(size=K*R*S)*1.j 21 | B=np.reshape(B,(K,R,S)) 22 | 23 | 24 | C=np.random.uniform(size=L*S*N)+np.random.uniform(size=L*S*N)*1.j 25 | C=np.reshape(C,(L,S,N)) 26 | 27 | #einsumを使って行列積を計算する 28 | D=np.einsum("lkmr,krs,lsn->kmn",A,B,C) 29 | 30 | print(np.shape(D)) 31 | 32 | #k=0の要素について検算実施 33 | for l in range(L): 34 | if l==0: 35 | D_2=np.matmul(np.matmul(A[l,0,...],B[0,...]),C[l]) 36 | else: 37 | D_2=D_2+np.matmul(np.matmul(A[l,0,...],B[0,...]),C[l]) 38 | 39 | print("D_2(0)=\n",D_2) 40 | print("D(0)=\n",D[0,...]) -------------------------------------------------------------------------------- /section3/sample_code_c3_4.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #乱数の種を設定 6 | np.random.seed(0) 7 | 8 | #行列の大きさを設定する 9 | L=10 10 | M=3 11 | N=3 12 | #ランダムな複素数のテンソル(ndarray)を定義する 13 | A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j 14 | A=np.reshape(A,(L,M,N)) 15 | 16 | #行列式を計算する 17 | detA=np.linalg.det(A) 18 | 19 | print("detA(0): ",detA[0]) 20 | 21 | #全ての要素を3倍した行列の行列式を計算する 22 | det3A=np.linalg.det(3*A) 23 | 24 | print("det3A(0): ",det3A[0]) 25 | 26 | 27 | #逆行列を計算する 28 | A_inv=np.linalg.inv(A) 29 | 30 | #Aとかけて単位行列になっているかどうかを検算 31 | AA_inv=np.einsum("lmk,lkn->lmn",A,A_inv) 32 | print("単位行列?: \n",AA_inv[0]) 33 | 34 | A_invA=np.einsum("lmk,lkn->lmn",A_inv,A) 35 | print("単位行列?: \n",A_invA[0]) 36 | 37 | #一般化逆行列計算 38 | A_inv=np.linalg.pinv(A) 39 | 40 | #Aとかけて単位行列になっているかどうかを検算 41 | AA_inv=np.einsum("lmk,lkn->lmn",A,A_inv) 42 | print("単位行列?: \n",AA_inv[0]) 43 | 44 | A_invA=np.einsum("lmk,lkn->lmn",A_inv,A) 45 | print("単位行列?: \n",A_invA[0]) -------------------------------------------------------------------------------- /section3/sample_code_c3_5.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #行列を定義 6 | A=np.matrix([[3.,1.,2.],[2.,3.,1.]]) 7 | 8 | #ベクトルを定義 9 | b=np.array([2.,1.,4.]) 10 | 11 | #行列を表示 12 | print("A= \n",A) 13 | 14 | #ベクトルを表示 15 | print("b= \n",b) 16 | 17 | #行列Aにベクトルbをかける 18 | print("Ab= \n",np.dot(A,b)) 19 | 20 | -------------------------------------------------------------------------------- /section3/sample_code_c3_6.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #行列を定義 6 | a=np.matrix([3.+2.j,1.-1.j,2.+2.j]) 7 | 8 | #ベクトルを定義 9 | b=np.array([2.+5.j,1.-1.j,4.+1.j]) 10 | 11 | #ベクトルの内積計算 12 | print("a^Hb=",np.inner(np.conjugate(a),b)) 13 | 14 | #ベクトルの内積計算 15 | print("a^Ha=",np.inner(np.conjugate(a),a)) 16 | 17 | 18 | -------------------------------------------------------------------------------- /section3/sample_code_c3_7.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #乱数の種を設定 6 | np.random.seed(0) 7 | 8 | #行列の大きさを設定する 9 | L=10 10 | M=3 11 | N=3 12 | #ランダムな複素数のテンソル(ndarray)を定義する 13 | A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j 14 | A=np.reshape(A,(L,M,N)) 15 | 16 | #ランダムな複素数のテンソル(ndarray)を定義する 17 | b=np.random.uniform(size=L*M)+np.random.uniform(size=L*M)*1.j 18 | b=np.reshape(b,(L,M)) 19 | 20 | #行列Aのtrace 21 | print("tr(A)= \n",np.trace(A,axis1=-2,axis2=-1)) 22 | 23 | #einsumを用いたtrace計算 24 | print("tr(A)= \n",np.einsum("lmm->l",A)) 25 | 26 | #b^H,A,bの計算 27 | print("b^H A b=\n",np.einsum("lm,lmn,ln->l",np.conjugate(b),A,b)) 28 | #b^H,A,bの計算 29 | print("trA bb^H =\n",np.trace(np.einsum("lmn,ln,lk->lmk",A,b,np.conjugate(b)),axis1=-2,axis2=-1)) 30 | 31 | -------------------------------------------------------------------------------- /section3/sample_code_c3_8.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #乱数の種を設定 6 | np.random.seed(0) 7 | 8 | #行列の大きさを設定する 9 | L=10 10 | M=3 11 | N=3 12 | #ランダムな複素数のテンソル(ndarray)を定義する 13 | A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j 14 | A=np.reshape(A,(L,M,N)) 15 | 16 | #正定エルミート行列を作る 17 | B=np.einsum("lmk,lnk->lmn",A,np.conjugate(A)) 18 | 19 | #Aの固有値分解実施 20 | w,v=np.linalg.eig(A) 21 | 22 | #固有値と固有ベクトルからAを復元できるか検証 23 | A_reconst=np.einsum("lmk,lk,lkn->lmn",v,w,np.linalg.inv(v)) 24 | print("A[0]: \n",A[0]) 25 | print("A_reconst[0]: \n",A_reconst[0]) 26 | 27 | #Bの固有値分解実施 28 | w,v=np.linalg.eigh(B) 29 | 30 | #固有値と固有ベクトルからBを復元できるか検証 31 | B_reconst=np.einsum("lmk,lk,lnk->lmn",v,w,np.conjugate(v)) 32 | print("B[0]: \n",B[0]) 33 | print("B[0]: \n",B_reconst[0]) -------------------------------------------------------------------------------- /section3/sample_code_c3_9.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #A: ...mn 6 | #B: ...ij 7 | #AとBの最後の二軸以外の次元は一致していることを前提とする 8 | def batch_kron(A,B): 9 | if np.shape(A)[:-2]!=np.shape(B)[:-2]: 10 | print("error") 11 | return None 12 | else: 13 | return(np.reshape(np.einsum("...mn,...ij->...minj",A,B),np.shape(A)[:-2]+(np.shape(A)[-2]*np.shape(B)[-2],np.shape(A)[-1]*np.shape(B)[-1]))) 14 | 15 | 16 | #乱数の種を設定 17 | np.random.seed(0) 18 | 19 | 20 | 21 | #行列の大きさを設定する 22 | L=10 23 | M=3 24 | R=3 25 | N=3 26 | T=3 27 | #ランダムな複素数のテンソル(ndarray)を定義する 28 | A=np.random.uniform(size=L*M*R)+np.random.uniform(size=L*M*R)*1.j 29 | A=np.reshape(A,(L,M,R)) 30 | 31 | X=np.random.uniform(size=R*N)+np.random.uniform(size=R*N)*1.j 32 | X=np.reshape(X,(R,N)) 33 | 34 | B=np.random.uniform(size=L*N*T)+np.random.uniform(size=L*N*T)*1.j 35 | B=np.reshape(B,(L,N,T)) 36 | 37 | 38 | D=np.random.uniform(size=L*M*T)+np.random.uniform(size=L*M*T)*1.j 39 | D=np.reshape(D,(L,M,T)) 40 | 41 | 42 | #1. 多次元配列対応版のクロネッカー積batch_kronの出力結果とnumpyのkronの出力結果が一致していることを確認 43 | 44 | #多次元配列対応版のクロネッカー積 45 | C=batch_kron(np.transpose(B,(0,2,1)),A) 46 | 47 | #numpyのkronでl=0のデータに対してクロネッカー積を計算 48 | C_2=np.kron(np.transpose(B[0,...],(1,0)),A[0,...]) 49 | 50 | #多次元配列対応版のクロネッカー積とnumpyのkronとの誤差 51 | print("誤差 = ",np.sum(np.abs(C[0,...]-C_2))) 52 | 53 | #2. vecAXBとCvecXが一致しているかどうかを確認する 54 | 55 | #Xをベクトル化する 56 | vecX=np.reshape(np.transpose(X,[1,0]),(N*R)) 57 | 58 | #AXBを計算する 59 | AXB=np.einsum("lmr,rn,lnt->lmt",A,X,B) 60 | 61 | #AXBをベクトル化する 62 | vecAXB=np.reshape(np.transpose(AXB,[0,2,1]),(L,T*M)) 63 | 64 | #CvecX 65 | CvecX=np.einsum("lmr,r->lm",C,vecX) 66 | 67 | #vecAXBとCvecXが一致しているかどうかを確認する 68 | print("誤差 = ",np.sum(np.abs(vecAXB-CvecX))) 69 | 70 | #3. ΣAXB=ΣDを満たすようなXを求める 71 | 72 | #vecDを求める 73 | vecD=np.reshape(np.transpose(D,[0,2,1]),(L,T*M)) 74 | 75 | #vecXを求める 76 | vecX=np.einsum("mr,r->m",np.linalg.inv(np.sum(C,axis=0)), np.sum(vecD,axis=0)) 77 | 78 | #Xに戻す 79 | X=np.transpose(np.reshape(vecX,(N,R)),(1,0)) 80 | 81 | #答えがあっているかどうかを確認 82 | sum_AXB=np.einsum("lmr,rn,lnt->mt",A,X,B) 83 | 84 | sum_D=np.sum(D,axis=0) 85 | 86 | #sum_AXBとsum_Dが一致しているかどうかを確認する 87 | print("誤差 = ",np.sum(np.abs(sum_AXB-sum_D))) 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /section4.md: -------------------------------------------------------------------------------- 1 | 2 | ## 第4章のサンプルコード 3 | 4 | * [(参考)EMアルゴリズムによる混合ガウス分布のパラメータ最適化](section4/sample_code_c4_1.py) 5 | -------------------------------------------------------------------------------- /section4/sample_code_c4_1.py: -------------------------------------------------------------------------------- 1 | 2 | #numpyをインポート(行列を扱う各種関数を含む) 3 | import numpy as np 4 | 5 | #可視化のためにmatplotlibモジュールをインポート 6 | import matplotlib.pyplot as plt 7 | 8 | #アニメーション用のモジュールをインポート 9 | import matplotlib.animation as animation 10 | 11 | #確率密度関数の描画用 12 | from scipy.stats import norm 13 | 14 | 15 | 16 | #混合ガウス分布に基づく乱数を生成する 17 | np.random.seed(0) 18 | 19 | #各ガウス分布のサンプル数 20 | n_samples=[200,400,400] 21 | 22 | #各ガウス分布の平均 23 | means=[-2,3,5] 24 | 25 | #各ガウス分布の分散 26 | sigmas=[3,2,0.5] 27 | 28 | #GMMに従う乱数を生成 29 | x=None 30 | for n,mean,sigma in zip(n_samples,means,sigmas): 31 | samples_for_each_dist=np.random.normal(mean,sigma, int(n)) 32 | if x is None: 33 | x=samples_for_each_dist 34 | else: 35 | x=np.concatenate((x,samples_for_each_dist)) 36 | 37 | #モデルパラメータを初期化する 38 | alpha=np.array([1./3.,1./3.,1./3.]) 39 | var=np.array([1.,1.,1.]) 40 | mu=np.array([-1,0,1]) 41 | 42 | #GMMを構成するガウス分布の数 43 | n_clusters=len(alpha) 44 | 45 | #繰り返し計算でパラメータを最適化する(ここでは100回繰り返す) 46 | n_iterations=101 47 | log_likelihood=np.zeros(n_iterations) 48 | ims=[] 49 | for t in range(n_iterations): 50 | print("t{}".format(t)) 51 | if t==0: 52 | alpha_buf=alpha[None,:] 53 | var_buf=var[None,:] 54 | mu_buf=mu[None,:] 55 | else: 56 | alpha_buf=np.concatenate((alpha_buf,alpha[None,:]),axis=0) 57 | var_buf=np.concatenate((var_buf,var[None,:]),axis=0) 58 | mu_buf=np.concatenate((mu_buf,mu[None,:]),axis=0) 59 | #Eステップ 60 | 61 | #係数部 62 | coef=alpha/np.sqrt(2.*np.pi*var) 63 | 64 | #exponent: n_sample, n_clusters 65 | exponent=-1.*np.power(x[:,None]-mu[None,:],2.)/(2*var[None,:]) 66 | 67 | #βを求める 68 | beta=coef[None,:]*np.exp(exponent) 69 | likelihood_each_sample=np.maximum(np.sum(beta,axis=1,keepdims=True),1.e-18) 70 | beta=beta/likelihood_each_sample 71 | 72 | #対数尤度を求める 73 | current_log_likelihood=np.average(np.log(likelihood_each_sample)) 74 | log_likelihood[t]=current_log_likelihood 75 | 76 | #Mステップ(パラメータを更新する) 77 | N=np.maximum(np.sum(beta,axis=0),1.e-18) 78 | 79 | #事前確率を更新 80 | alpha=N/np.sum(N) 81 | 82 | #平均値を更新 83 | mu=np.einsum("ij,i->j",beta,x)/N 84 | #分散を計算 85 | var=np.einsum("ij,ij->j",beta,np.power(x[:,None]-mu[None,:],2.))/N 86 | var=np.maximum(var,1.e-18) 87 | 88 | #対数ゆう度をグラフ化する 89 | plt.figure(figsize=(10,4)) 90 | plt.plot(np.arange(0,n_iterations,1),log_likelihood,color="black",linewidth=1,label="log likelihood") 91 | plt.xlabel("Number of iterations") 92 | plt.legend() 93 | plt.savefig("./log_likelihood_gmm.png") 94 | plt.show() 95 | 96 | 97 | #パラメータ更新の様子をアニメーションで表示 98 | def animation_update(t): 99 | plt.cla() 100 | plt.hist(x,bins=50,normed=True,label="observed samples") 101 | 102 | xmin=-20 103 | xmax=20 104 | plt.xlim([xmin,xmax]) 105 | plt.ylim([0,0.40]) 106 | x_range=np.arange(-20,20,0.01) 107 | 108 | 109 | #GMMを描画する 110 | pdf=None 111 | for alpha,var, mu in zip(alpha_buf[t],var_buf[t],mu_buf[t]): 112 | pdf_each=alpha*norm.pdf(x_range,mu,np.sqrt(var)) 113 | if pdf is None: 114 | pdf=pdf_each 115 | else: 116 | pdf=pdf+pdf_each 117 | 118 | plt.plot(x_range,pdf,color="black",linewidth=1,label=r"$p(x|\theta^{(t="+str(t)+")})$") 119 | plt.legend() 120 | 121 | if t==0: 122 | plt.savefig("./initialized_gmm.png") 123 | if t==n_iterations-1: 124 | plt.savefig("./learned_gmm.png") 125 | 126 | #音声データをプロットする 127 | fig=plt.figure(figsize=(10,4)) 128 | 129 | ani=animation.FuncAnimation(fig,animation_update,interval=200,frames=n_iterations) 130 | plt.show() 131 | -------------------------------------------------------------------------------- /section5.md: -------------------------------------------------------------------------------- 1 | ## 第5章のサンプルコード 2 | 3 | * [インパルス応答の畳み込みの例](section5/sample_code_c5_1.py) 4 | * [Pyroomacousticsを用いた室内伝達関数のシミュレーションと畳み込み](section5/sample_code_c5_2.py) 5 | * [マイクロホンの数を変更](section5/sample_code_c5_3.py) 6 | * [残響の量を変更](section5/sample_code_c5_4.py) 7 | * [雑音を考慮したシミュレーション](section5/sample_code_c5_5.py) 8 | * [インパルス応答の取得と残響時間(RT60)の取得](section5/sample_code_c5_6.py) 9 | * [インパルス応答の取得と残響時間(RT60)の取得(残響の量を変更)](section5/sample_code_c5_7.py) 10 | -------------------------------------------------------------------------------- /section5/sample_code_c5_1.py: -------------------------------------------------------------------------------- 1 | 2 | import wave as wave 3 | import pyroomacoustics as pa 4 | import numpy as np 5 | import scipy.signal as signal 6 | 7 | #乱数の種を初期化 8 | np.random.seed(0) 9 | 10 | #畳み込みに用いる音声波形 11 | clean_wave_file="./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav" 12 | 13 | wav=wave.open(clean_wave_file) 14 | data=wav.readframes(wav.getnframes()) 15 | data=np.frombuffer(data, dtype=np.int16) 16 | data=data/np.iinfo(np.int16).max 17 | wav.close() 18 | 19 | #サンプリング周波数 20 | sample_rate=16000 21 | 22 | #畳み込むインパルス応答長 23 | n_impulse_length=512 24 | 25 | #インパルス応答を乱数で生成(ダミー) 26 | impulse_response=np.random.normal(size=n_impulse_length) 27 | 28 | conv_data=signal.convolve(data,impulse_response,mode='full') 29 | 30 | #ファイルに書き込む 31 | data_scale_adjust=conv_data*np.iinfo(np.int16).max/20. 32 | data_scale_adjust=data_scale_adjust.astype(np.int16) 33 | wave_out=wave.open("./conv_out.wav","w") 34 | wave_out.setnchannels(1) 35 | wave_out.setsampwidth(2) 36 | wave_out.setframerate(sample_rate) 37 | wave_out.writeframes(data_scale_adjust) 38 | wave_out.close() 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /section5/sample_code_c5_2.py: -------------------------------------------------------------------------------- 1 | 2 | import wave as wave 3 | import pyroomacoustics as pa 4 | import numpy as np 5 | 6 | #乱数の種を初期化 7 | np.random.seed(0) 8 | 9 | #畳み込みに用いる音声波形 10 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 11 | 12 | #音源数 13 | n_sources=len(clean_wave_files) 14 | 15 | #長さを調べる 16 | n_samples=0 17 | #ファイルを読み込む 18 | for clean_wave_file in clean_wave_files: 19 | wav=wave.open(clean_wave_file) 20 | if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 24 | 25 | #ステアリングベクトルを算出 26 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 27 | 28 | return(steering_vector) 29 | 30 | else: 31 | 32 | #音源とマイクの距離を求める 33 | #distance: Ns x Nm 34 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 35 | 36 | #遅延時間(delay) [sec] 37 | delay=distance/sound_speed 38 | 39 | #ステアリングベクトルの位相を求める 40 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 41 | 42 | #音量の減衰 43 | steering_decay_ratio=1./distance 44 | 45 | #ステアリングベクトルを求める 46 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 47 | 48 | #大きさを1で正規化する 49 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 50 | 51 | return(steering_vector) 52 | 53 | #サンプリングレート [Hz] 54 | sample_rate=16000 55 | 56 | #フレームサイズ 57 | N=1024 58 | 59 | #周波数の数 60 | Nk=N/2+1 61 | 62 | #各ビンの周波数 63 | freqs=np.arange(0,Nk,1)*sample_rate/N 64 | 65 | #マイクロホンアレイのマイク配置 66 | mic_alignments = np.array( 67 | [ 68 | [-0.01, 0.0, 0.0], 69 | [0.01, 0.0, 0.0], 70 | ] 71 | ).T 72 | 73 | #音源の方向 74 | doas=np.array( 75 | [[np.pi/2,0], 76 | [np.pi/2,np.pi] 77 | ] ) 78 | 79 | #音源とマイクロホンの距離 80 | distance=1 81 | 82 | #音源の位置ベクトル 83 | source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) 84 | source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) 85 | source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) 86 | source_locations[2, :] = np.cos(doas[:, 0]) 87 | source_locations *= distance 88 | 89 | #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) 90 | near_steering_vectors=calculate_steering_vector(mic_alignments,source_locations,freqs,is_use_far=False) 91 | 92 | #Far仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) 93 | far_steering_vectors=calculate_steering_vector(mic_alignments,source_locations,freqs,is_use_far=True) 94 | 95 | #内積を計算 96 | inner_product=np.einsum("ksm,ksm->ks",np.conjugate(near_steering_vectors),far_steering_vectors) 97 | print(np.average(np.abs(inner_product))) 98 | -------------------------------------------------------------------------------- /section6/sample_code_c6_10.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 88 | 89 | 90 | #雑音だけの区間のサンプル数を設定 91 | n_noise_only=40000 92 | 93 | #音源数 94 | n_sources=len(clean_wave_files) 95 | 96 | #長さを調べる 97 | n_samples=0 98 | #ファイルを読み込む 99 | for clean_wave_file in clean_wave_files: 100 | wav=wave.open(clean_wave_file) 101 | if n_sampleskmn",stft_data[...,:n_noise_only_frame],np.conjugate(stft_data[...,:n_noise_only_frame])) 201 | 202 | #共分散行列の逆行列を計算する 203 | Rcov_inverse=np.linalg.pinv(Rcov) 204 | 205 | #フィルタを計算する 206 | Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) 207 | a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) 208 | w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] 209 | 210 | #フィルタをかける 211 | s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) 212 | 213 | #ステアリングベクトルをかける 214 | c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) 215 | 216 | #時間領域の波形に戻す 217 | t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 218 | 219 | #大きさを調整する 220 | mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. 221 | 222 | #ファイルに書き込む 223 | write_file_from_time_signal(mvdr_out[n_noise_only:],"./mlbf_out.wav",sample_rate) 224 | 225 | 226 | -------------------------------------------------------------------------------- /section6/sample_code_c6_11.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | import scipy as scipy 8 | 9 | #ステアリングベクトルを算出 10 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 11 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 12 | #freqs: Nk dimensional array [f1,f2,f3...] 13 | #sound_speed: 音速 [m/s] 14 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 15 | #return: steering vector (Nk x Ns x M) 16 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 17 | #マイク数を取得 18 | n_channels=np.shape(mic_alignments)[1] 19 | 20 | #音源数を取得 21 | n_source=np.shape(source_locations)[1] 22 | 23 | if is_use_far==True: 24 | #音源位置を正規化 25 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 26 | 27 | #位相を求める 28 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 29 | 30 | #ステアリングベクトルを算出 31 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 32 | 33 | return(steering_vector) 34 | 35 | else: 36 | 37 | #音源とマイクの距離を求める 38 | #distance: Ns x Nm 39 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 40 | 41 | #遅延時間(delay) [sec] 42 | delay=distance/sound_speed 43 | 44 | #ステアリングベクトルの位相を求める 45 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 46 | 47 | #音量の減衰 48 | steering_decay_ratio=1./distance 49 | 50 | #ステアリングベクトルを求める 51 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 52 | 53 | #大きさを1で正規化する 54 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 55 | 56 | return(steering_vector) 57 | 58 | #2バイトに変換してファイルに保存 59 | #signal: time-domain 1d array (float) 60 | #file_name: 出力先のファイル名 61 | #sample_rate: サンプリングレート 62 | def write_file_from_time_signal(signal,file_name,sample_rate): 63 | #2バイトのデータに変換 64 | signal=signal.astype(np.int16) 65 | 66 | #waveファイルに書き込む 67 | wave_out = wave.open(file_name, 'w') 68 | 69 | #モノラル:1、ステレオ:2 70 | wave_out.setnchannels(1) 71 | 72 | #サンプルサイズ2byte 73 | wave_out.setsampwidth(2) 74 | 75 | #サンプリング周波数 76 | wave_out.setframerate(sample_rate) 77 | 78 | #データを書き込み 79 | wave_out.writeframes(signal) 80 | 81 | #ファイルを閉じる 82 | wave_out.close() 83 | 84 | #乱数の種を初期化 85 | np.random.seed(0) 86 | 87 | #畳み込みに用いる音声波形 88 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 89 | 90 | 91 | #雑音だけの区間のサンプル数を設定 92 | n_noise_only=40000 93 | 94 | #音源数 95 | n_sources=len(clean_wave_files) 96 | 97 | #長さを調べる 98 | n_samples=0 99 | #ファイルを読み込む 100 | for clean_wave_file in clean_wave_files: 101 | wav=wave.open(clean_wave_file) 102 | if n_samplesktmn",stft_data,np.conjugate(stft_data)) 201 | 202 | #雑音の共分散行列 freq,mic,mic 203 | Rn=np.average(xx_H[:,:n_noise_only_frame,...],axis=1) 204 | 205 | #入力共分散行列 206 | Rs=np.average(xx_H[:,n_noise_only_frame:,...],axis=1) 207 | 208 | #一般化固有値分解 209 | max_snr_filter=None 210 | for k in range(Nk): 211 | w,v=scipy.linalg.eigh(Rs[k,...],Rn[k,...]) 212 | if max_snr_filter is None: 213 | max_snr_filter=v[None,:,-1] 214 | else: 215 | max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) 216 | 217 | 218 | Rs_w=np.einsum("kmn,kn->km",Rs,max_snr_filter) 219 | beta=Rs_w[:,0]/np.einsum("km,km->k",np.conjugate(max_snr_filter),Rs_w) 220 | w_max_snr=beta[:,None]*max_snr_filter 221 | 222 | #フィルタをかける 223 | c_hat=np.einsum("km,mkt->kt",np.conjugate(w_max_snr),stft_data) 224 | 225 | #時間領域の波形に戻す 226 | t,maxsnr_out=sp.istft(c_hat,fs=sample_rate,window="hann",nperseg=N) 227 | 228 | #大きさを調整する 229 | maxsnr_out=maxsnr_out*np.iinfo(np.int16).max/20. 230 | 231 | #ファイルに書き込む 232 | write_file_from_time_signal(maxsnr_out[n_noise_only:],"./maxsnr_out.wav",sample_rate) 233 | -------------------------------------------------------------------------------- /section6/sample_code_c6_12.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | import scipy as scipy 8 | 9 | #ステアリングベクトルを算出 10 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 11 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 12 | #freqs: Nk dimensional array [f1,f2,f3...] 13 | #sound_speed: 音速 [m/s] 14 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 15 | #return: steering vector (Nk x Ns x M) 16 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 17 | #マイク数を取得 18 | n_channels=np.shape(mic_alignments)[1] 19 | 20 | #音源数を取得 21 | n_source=np.shape(source_locations)[1] 22 | 23 | if is_use_far==True: 24 | #音源位置を正規化 25 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 26 | 27 | #位相を求める 28 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 29 | 30 | #ステアリングベクトルを算出 31 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 32 | 33 | return(steering_vector) 34 | 35 | else: 36 | 37 | #音源とマイクの距離を求める 38 | #distance: Ns x Nm 39 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 40 | 41 | #遅延時間(delay) [sec] 42 | delay=distance/sound_speed 43 | 44 | #ステアリングベクトルの位相を求める 45 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 46 | 47 | #音量の減衰 48 | steering_decay_ratio=1./distance 49 | 50 | #ステアリングベクトルを求める 51 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 52 | 53 | #大きさを1で正規化する 54 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 55 | 56 | return(steering_vector) 57 | 58 | #2バイトに変換してファイルに保存 59 | #signal: time-domain 1d array (float) 60 | #file_name: 出力先のファイル名 61 | #sample_rate: サンプリングレート 62 | def write_file_from_time_signal(signal,file_name,sample_rate): 63 | #2バイトのデータに変換 64 | signal=signal.astype(np.int16) 65 | 66 | #waveファイルに書き込む 67 | wave_out = wave.open(file_name, 'w') 68 | 69 | #モノラル:1、ステレオ:2 70 | wave_out.setnchannels(1) 71 | 72 | #サンプルサイズ2byte 73 | wave_out.setsampwidth(2) 74 | 75 | #サンプリング周波数 76 | wave_out.setframerate(sample_rate) 77 | 78 | #データを書き込み 79 | wave_out.writeframes(signal) 80 | 81 | #ファイルを閉じる 82 | wave_out.close() 83 | 84 | #乱数の種を初期化 85 | np.random.seed(0) 86 | 87 | #畳み込みに用いる音声波形 88 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 89 | 90 | 91 | #雑音だけの区間のサンプル数を設定 92 | n_noise_only=40000 93 | 94 | #音源数 95 | n_sources=len(clean_wave_files) 96 | 97 | #長さを調べる 98 | n_samples=0 99 | #ファイルを読み込む 100 | for clean_wave_file in clean_wave_files: 101 | wav=wave.open(clean_wave_file) 102 | if n_samplesktmn",stft_data,np.conjugate(stft_data)) 201 | 202 | #雑音の倍率 203 | mu=1.0 204 | 205 | #雑音の共分散行列 freq,mic,mic 206 | Rn=np.average(xx_H[:,:n_noise_only_frame,...],axis=1) 207 | 208 | #入力共分散行列 209 | Rs=np.average(xx_H[:,n_noise_only_frame:,...],axis=1)-Rn 210 | 211 | #固有値分解をして半正定行列に変換 212 | w,v=np.linalg.eigh(Rs) 213 | Rs_org=Rs.copy() 214 | w[np.real(w)<0]=0 215 | Rs=np.einsum("kmi,ki,kni->kmn",v,w,np.conjugate(v)) 216 | 217 | #入力共分散行列 218 | Rs_muRn=Rs+Rn*mu 219 | invRs_muRn=np.linalg.pinv(Rs_muRn) 220 | 221 | #フィルタ生成 222 | W_mwf=np.einsum("kmi,kin->kmn",invRs_muRn,Rs) 223 | 224 | #フィルタをかける 225 | c_hat=np.einsum("kim,ikt->mkt",np.conjugate(W_mwf),stft_data) 226 | 227 | #時間領域の波形に戻す 228 | t,mwf_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 229 | 230 | #大きさを調整する 231 | mwf_out=mwf_out*np.iinfo(np.int16).max/20. 232 | 233 | #ファイルに書き込む 234 | write_file_from_time_signal(mwf_out[n_noise_only:],"./mwf_out_{}.wav".format(mu),sample_rate) 235 | -------------------------------------------------------------------------------- /section6/sample_code_c6_13.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | import scipy as scipy 8 | 9 | #ステアリングベクトルを算出 10 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 11 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 12 | #freqs: Nk dimensional array [f1,f2,f3...] 13 | #sound_speed: 音速 [m/s] 14 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 15 | #return: steering vector (Nk x Ns x M) 16 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 17 | #マイク数を取得 18 | n_channels=np.shape(mic_alignments)[1] 19 | 20 | #音源数を取得 21 | n_source=np.shape(source_locations)[1] 22 | 23 | if is_use_far==True: 24 | #音源位置を正規化 25 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 26 | 27 | #位相を求める 28 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 29 | 30 | #ステアリングベクトルを算出 31 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 32 | 33 | return(steering_vector) 34 | 35 | else: 36 | 37 | #音源とマイクの距離を求める 38 | #distance: Ns x Nm 39 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 40 | 41 | #遅延時間(delay) [sec] 42 | delay=distance/sound_speed 43 | 44 | #ステアリングベクトルの位相を求める 45 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 46 | 47 | #音量の減衰 48 | steering_decay_ratio=1./distance 49 | 50 | #ステアリングベクトルを求める 51 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 52 | 53 | #大きさを1で正規化する 54 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 55 | 56 | return(steering_vector) 57 | 58 | #2バイトに変換してファイルに保存 59 | #signal: time-domain 1d array (float) 60 | #file_name: 出力先のファイル名 61 | #sample_rate: サンプリングレート 62 | def write_file_from_time_signal(signal,file_name,sample_rate): 63 | #2バイトのデータに変換 64 | signal=signal.astype(np.int16) 65 | 66 | #waveファイルに書き込む 67 | wave_out = wave.open(file_name, 'w') 68 | 69 | #モノラル:1、ステレオ:2 70 | wave_out.setnchannels(1) 71 | 72 | #サンプルサイズ2byte 73 | wave_out.setsampwidth(2) 74 | 75 | #サンプリング周波数 76 | wave_out.setframerate(sample_rate) 77 | 78 | #データを書き込み 79 | wave_out.writeframes(signal) 80 | 81 | #ファイルを閉じる 82 | wave_out.close() 83 | 84 | #遅延和アレイを実行する 85 | #x:入力信号( M, Nk, Lt) 86 | #a:ステアリングベクトル(Nk, M) 87 | #return y 出力信号(M, Nk, Lt) 88 | def execute_dsbf(x,a): 89 | #遅延和アレイを実行する 90 | s_hat=np.einsum("km,mkt->kt",np.conjugate(a),x) 91 | 92 | #ステアリングベクトルをかける 93 | c_hat=np.einsum("kt,km->mkt",s_hat,a) 94 | 95 | return(c_hat) 96 | 97 | #MVDRを実行する 98 | #x:入力信号( M, Nk, Lt) 99 | #y:共分散行列を計算する信号(M,Nk,Lt) 100 | #a:ステアリングベクトル(Nk, M) 101 | #return y 出力信号(M, Nk, Lt) 102 | def execute_mvdr(x,y,a): 103 | 104 | #共分散行列を計算する 105 | Rcov=np.einsum("mkt,nkt->kmn",y,np.conjugate(y)) 106 | 107 | #共分散行列の逆行列を計算する 108 | Rcov_inverse=np.linalg.pinv(Rcov) 109 | 110 | #フィルタを計算する 111 | Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,a) 112 | a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(a),Rcov_inverse_a) 113 | w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] 114 | 115 | #フィルタをかける 116 | s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),x) 117 | 118 | #ステアリングベクトルをかける 119 | c_hat=np.einsum("kt,km->mkt",s_hat,a) 120 | 121 | return(c_hat) 122 | 123 | #MaxSNRを実行する 124 | #x:入力信号( M, Nk, Lt) 125 | #y:共分散行列を計算する信号(M,Nk,Lt) 126 | #return y 出力信号(M, Nk, Lt) 127 | def execute_max_snr(x,y): 128 | 129 | #雑音の共分散行列 freq,mic,mic 130 | Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) 131 | 132 | #入力共分散行列 133 | Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) 134 | 135 | #周波数の数を取得 136 | Nk=np.shape(Rs)[0] 137 | 138 | #一般化固有値分解 139 | max_snr_filter=None 140 | for k in range(Nk): 141 | w,v=scipy.linalg.eigh(Rs[k,...],Rn[k,...]) 142 | if max_snr_filter is None: 143 | max_snr_filter=v[None,:,-1] 144 | else: 145 | max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) 146 | 147 | 148 | Rs_w=np.einsum("kmn,kn->km",Rs,max_snr_filter) 149 | beta=Rs_w/np.einsum("km,km->k",np.conjugate(max_snr_filter),Rs_w)[:,None] 150 | w_max_snr=beta[:,None,:]*max_snr_filter[...,None] 151 | 152 | #フィルタをかける 153 | c_hat=np.einsum("kim,ikt->mkt",np.conjugate(w_max_snr),x) 154 | 155 | return(c_hat) 156 | 157 | #SNRをはかる 158 | #desired: 目的音、Lt 159 | #out: 雑音除去後の信号 Lt 160 | def calculate_snr(desired,out): 161 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 162 | 163 | #消し残った雑音 164 | desired=desired[:wave_length] 165 | out=out[:wave_length] 166 | noise=desired-out 167 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 168 | 169 | return(snr) 170 | 171 | #ファイルに書き込む 172 | #MWFを実行する 173 | #x:入力信号( M, Nk, Lt) 174 | #y:共分散行列を計算する信号(M,Nk,Lt) 175 | #mu: 雑音共分散行列の係数 176 | #return y 出力信号(M, Nk, Lt) 177 | def execute_mwf(x,y,mu): 178 | 179 | #雑音の共分散行列 freq,mic,mic 180 | Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) 181 | 182 | #入力共分散行列 183 | Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) 184 | 185 | #固有値分解をして半正定行列に変換 186 | w,v=np.linalg.eigh(Rs) 187 | Rs_org=Rs.copy() 188 | w[np.real(w)<0]=0 189 | Rs=np.einsum("kmi,ki,kni->kmn",v,w,np.conjugate(v)) 190 | 191 | #入力共分散行列 192 | Rs_muRn=Rs+Rn*mu 193 | invRs_muRn=np.linalg.pinv(Rs_muRn) 194 | 195 | #フィルタ生成 196 | W_mwf=np.einsum("kmi,kin->kmn",invRs_muRn,Rs) 197 | 198 | #フィルタをかける 199 | c_hat=np.einsum("kim,ikt->mkt",np.conjugate(W_mwf),x) 200 | 201 | return(c_hat) 202 | 203 | #乱数の種を初期化 204 | np.random.seed(0) 205 | 206 | #畳み込みに用いる音声波形 207 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 208 | 209 | #雑音だけの区間のサンプル数を設定 210 | n_noise_only=40000 211 | 212 | #音源数 213 | n_sources=len(clean_wave_files) 214 | 215 | #長さを調べる 216 | n_samples=0 217 | #ファイルを読み込む 218 | for clean_wave_file in clean_wave_files: 219 | wav=wave.open(clean_wave_file) 220 | if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 88 | 89 | #音源数 90 | n_sources=len(clean_wave_files) 91 | 92 | #長さを調べる 93 | n_samples=0 94 | #ファイルを読み込む 95 | for clean_wave_file in clean_wave_files: 96 | wav=wave.open(clean_wave_file) 97 | if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) 193 | 194 | #ステアリングベクトルをかける 195 | c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) 196 | 197 | #時間領域の波形に戻す 198 | t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 199 | 200 | #大きさを調整する 201 | ds_out=ds_out*np.iinfo(np.int16).max/20. 202 | 203 | #ファイルに書き込む 204 | write_file_from_time_signal(ds_out,"./ds_out.wav",sample_rate) 205 | 206 | 207 | -------------------------------------------------------------------------------- /section6/sample_code_c6_3.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 88 | 89 | #音源数 90 | n_sources=len(clean_wave_files) 91 | 92 | #長さを調べる 93 | n_samples=0 94 | #ファイルを読み込む 95 | for clean_wave_file in clean_wave_files: 96 | wav=wave.open(clean_wave_file) 97 | if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) 192 | 193 | #ステアリングベクトルをかける 194 | c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) 195 | 196 | #時間領域の波形に戻す 197 | t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 198 | 199 | #大きさを調整する 200 | ds_out=ds_out*np.iinfo(np.int16).max/20. 201 | 202 | #ファイルに書き込む 203 | write_file_from_time_signal(ds_out,"./ds_out_m32.wav",sample_rate) 204 | 205 | 206 | -------------------------------------------------------------------------------- /section6/sample_code_c6_4.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 88 | 89 | 90 | #音源数 91 | n_sources=len(clean_wave_files) 92 | 93 | #長さを調べる 94 | n_samples=0 95 | #ファイルを読み込む 96 | for clean_wave_file in clean_wave_files: 97 | wav=wave.open(clean_wave_file) 98 | if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) 195 | 196 | #ステアリングベクトルをかける 197 | c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) 198 | 199 | #時間領域の波形に戻す 200 | t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 201 | 202 | #大きさを調整する 203 | ds_out=ds_out*np.iinfo(np.int16).max/20. 204 | 205 | #ファイルに書き込む 206 | write_file_from_time_signal(ds_out,"./ds_out.wav",sample_rate) 207 | 208 | 209 | -------------------------------------------------------------------------------- /section6/sample_code_c6_5.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 88 | 89 | 90 | #音源数 91 | n_sources=len(clean_wave_files) 92 | 93 | #長さを調べる 94 | n_samples=0 95 | #ファイルを読み込む 96 | for clean_wave_file in clean_wave_files: 97 | wav=wave.open(clean_wave_file) 98 | if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) 194 | 195 | #ステアリングベクトルをかける 196 | c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) 197 | 198 | #時間領域の波形に戻す 199 | t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 200 | 201 | #大きさを調整する 202 | ds_out=ds_out*np.iinfo(np.int16).max/20. 203 | 204 | #ファイルに書き込む 205 | write_file_from_time_signal(ds_out,"./ds_interference_out_m32.wav",sample_rate) 206 | 207 | 208 | -------------------------------------------------------------------------------- /section6/sample_code_c6_6.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import numpy as np 4 | import scipy.signal as sp 5 | import matplotlib.pyplot as plt 6 | 7 | #ステアリングベクトルを算出 8 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 9 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 10 | #freqs: Nk dimensional array [f1,f2,f3...] 11 | #sound_speed: 音速 [m/s] 12 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 13 | #return: steering vector (Nk x Ns x M) 14 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 15 | #マイク数を取得 16 | n_channels=np.shape(mic_alignments)[1] 17 | 18 | #音源数を取得 19 | n_source=np.shape(source_locations)[1] 20 | 21 | if is_use_far==True: 22 | #音源位置を正規化 23 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 24 | 25 | #位相を求める 26 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 27 | 28 | #ステアリングベクトルを算出 29 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 30 | 31 | return(steering_vector) 32 | 33 | else: 34 | 35 | #音源とマイクの距離を求める 36 | #distance: Ns x Nm 37 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 38 | 39 | #遅延時間(delay) [sec] 40 | delay=distance/sound_speed 41 | 42 | #ステアリングベクトルの位相を求める 43 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 44 | 45 | #音量の減衰 46 | steering_decay_ratio=1./distance 47 | 48 | #ステアリングベクトルを求める 49 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 50 | 51 | #大きさを1で正規化する 52 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 53 | 54 | return(steering_vector) 55 | 56 | 57 | #サンプリング周波数 58 | sample_rate=16000 59 | 60 | #フレームサイズ 61 | N=1024 62 | 63 | #周波数の数 64 | Nk=N/2+1 65 | 66 | #各ビンの周波数 67 | freqs=np.arange(0,Nk,1)*sample_rate/N 68 | 69 | #マイクロホンアレイのマイク配置 70 | mic_alignments = np.array( 71 | [[x,0.0,0.0] for x in np.arange(-0.01,0.02,0.02)] 72 | ) 73 | 74 | #マイクロホン数 75 | n_channels=np.shape(mic_alignments)[0] 76 | 77 | #音源の場所 78 | doas=np.array( 79 | [[np.pi/2.,theta] for theta in np.arange(-np.pi,np.pi,1./180.*np.pi)] 80 | ) 81 | 82 | #音源とマイクロホンの距離 83 | distance=1. 84 | source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) 85 | source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) 86 | source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) 87 | source_locations[2, :] = np.cos(doas[:, 0]) 88 | source_locations *= distance 89 | 90 | #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) 91 | near_steering_vectors=calculate_steering_vector(mic_alignments.T,source_locations,freqs,is_use_far=False) 92 | 93 | #theta=0に最も近いステアリングベクトルを取り出す 94 | desired_index=np.argmin(np.abs(doas[:,1]),axis=0) 95 | 96 | #所望音のステアリングベクトル 97 | desired_steering_vector=near_steering_vectors[:,desired_index,:] 98 | 99 | #内積計算 100 | directivity_pattern=np.square(np.abs(np.einsum("km,ksm->ks",np.conjugate(desired_steering_vector),near_steering_vectors))) 101 | 102 | #スタイル 103 | plt.style.use("grayscale") 104 | #音声データをプロットする 105 | fig=plt.figure(figsize=(7,7)) 106 | 107 | # plot 108 | ax = plt.subplot(111, projection="polar") 109 | 110 | #グラフの向き、グリッドの線種を指定 111 | ax.set_theta_zero_location('N') 112 | ax.set_theta_direction('clockwise') 113 | ax.grid(linestyle="--") 114 | 115 | #y軸のラベル調整 116 | ax.yaxis.labelpad = -250 117 | ylabel=plt.ylabel("Response [dB]") 118 | ylabel.set_position((0, 0.6)) 119 | ylabel.set_rotation(0) 120 | plt.yticks([-20,-10,0]) 121 | plt.ylim([-30,0]) 122 | 123 | #x軸のラベル 124 | plt.xlabel("Azimuth [degrees]") 125 | 126 | 127 | #描画する周波数 128 | draw_freqs=np.array([1000,2000,3000,4000]) 129 | 130 | draw_freq_list=np.argmin(np.abs(freqs[:,None]-draw_freqs[None,:]),axis=0) 131 | 132 | 133 | for draw_freq_index in draw_freq_list: 134 | #周波数毎に指向特性を描画 135 | plt.plot(doas[:,1], 10.*np.log10(directivity_pattern[draw_freq_index,:]),lw=3,label="{} [Hz]".format(freqs[draw_freq_index])) 136 | 137 | plt.legend(loc=(0.2,0.6)) 138 | 139 | #音声ファイルを画像として保存 140 | plt.savefig("./directivity_pattern.png") 141 | 142 | #画像を画面に表示 143 | plt.show() 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /section6/sample_code_c6_7.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import numpy as np 4 | import scipy.signal as sp 5 | import matplotlib.pyplot as plt 6 | 7 | #ステアリングベクトルを算出 8 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 9 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 10 | #freqs: Nk dimensional array [f1,f2,f3...] 11 | #sound_speed: 音速 [m/s] 12 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 13 | #return: steering vector (Nk x Ns x M) 14 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 15 | #マイク数を取得 16 | n_channels=np.shape(mic_alignments)[1] 17 | 18 | #音源数を取得 19 | n_source=np.shape(source_locations)[1] 20 | 21 | if is_use_far==True: 22 | #音源位置を正規化 23 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 24 | 25 | #位相を求める 26 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 27 | 28 | #ステアリングベクトルを算出 29 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 30 | 31 | return(steering_vector) 32 | 33 | else: 34 | 35 | #音源とマイクの距離を求める 36 | #distance: Ns x Nm 37 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 38 | 39 | #遅延時間(delay) [sec] 40 | delay=distance/sound_speed 41 | 42 | #ステアリングベクトルの位相を求める 43 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 44 | 45 | #音量の減衰 46 | steering_decay_ratio=1./distance 47 | 48 | #ステアリングベクトルを求める 49 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 50 | 51 | #大きさを1で正規化する 52 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 53 | 54 | return(steering_vector) 55 | 56 | 57 | #サンプリング周波数 58 | sample_rate=16000 59 | 60 | #フレームサイズ 61 | N=1024 62 | 63 | #周波数の数 64 | Nk=N/2+1 65 | 66 | #各ビンの周波数 67 | freqs=np.arange(0,Nk,1)*sample_rate/N 68 | 69 | #マイクロホンアレイのマイク配置 70 | mic_alignments = np.array( 71 | [[x,0.0,0.0] for x in np.arange(-0.31,0.32,0.02)] 72 | ) 73 | 74 | #マイクロホン数 75 | n_channels=np.shape(mic_alignments)[0] 76 | 77 | #音源の場所 78 | doas=np.array( 79 | [[np.pi/2.,theta] for theta in np.arange(-np.pi,np.pi,1./180.*np.pi)] 80 | ) 81 | 82 | #音源とマイクロホンの距離 83 | distance=1. 84 | source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) 85 | source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) 86 | source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) 87 | source_locations[2, :] = np.cos(doas[:, 0]) 88 | source_locations *= distance 89 | 90 | #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) 91 | near_steering_vectors=calculate_steering_vector(mic_alignments.T,source_locations,freqs,is_use_far=False) 92 | 93 | #theta=0に最も近いステアリングベクトルを取り出す 94 | desired_index=np.argmin(np.abs(doas[:,1]),axis=0) 95 | 96 | #所望音のステアリングベクトル 97 | desired_steering_vector=near_steering_vectors[:,desired_index,:] 98 | 99 | #内積計算 100 | directivity_pattern=np.square(np.abs(np.einsum("km,ksm->ks",np.conjugate(desired_steering_vector),near_steering_vectors))) 101 | 102 | #スタイル 103 | plt.style.use("grayscale") 104 | #音声データをプロットする 105 | fig=plt.figure(figsize=(7,7)) 106 | 107 | # plot 108 | ax = plt.subplot(111, projection="polar") 109 | 110 | #グラフの向き、グリッドの線種を指定 111 | ax.set_theta_zero_location('N') 112 | ax.set_theta_direction('clockwise') 113 | ax.grid(linestyle="--") 114 | ax.yaxis.labelpad = -30 115 | 116 | #x軸のラベル 117 | plt.xlabel("Azimuth [degrees]") 118 | 119 | #y軸のラベル 120 | ylabel=plt.ylabel("Response [dB]") 121 | 122 | ylabel.set_position((0, 0.6)) 123 | ylabel.set_rotation(0) 124 | 125 | plt.yticks([-20,-10,0]) 126 | plt.ylim([-30,0]) 127 | 128 | #描画する周波数 129 | draw_freqs=np.array([1000,2000,3000,4000]) 130 | 131 | draw_freq_list=np.argmin(np.abs(freqs[:,None]-draw_freqs[None,:]),axis=0) 132 | 133 | 134 | for draw_freq_index in draw_freq_list: 135 | #周波数毎に指向特性を描画 136 | plt.plot(doas[:,1], 10.*np.log10(directivity_pattern[draw_freq_index,:]),lw=3,label="{} [Hz]".format(freqs[draw_freq_index])) 137 | 138 | plt.legend(loc=(0.2,0.6)) 139 | 140 | #音声ファイルを画像として保存 141 | plt.savefig("./directivity_pattern_m32.png") 142 | 143 | #画像を画面に表示 144 | plt.show() 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /section6/sample_code_c6_8.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 88 | 89 | #音源数 90 | n_sources=len(clean_wave_files) 91 | 92 | #長さを調べる 93 | n_samples=0 94 | #ファイルを読み込む 95 | for clean_wave_file in clean_wave_files: 96 | wav=wave.open(clean_wave_file) 97 | if n_sampleskmn",stft_data,np.conjugate(stft_data)) 194 | 195 | #共分散行列の逆行列を計算する 196 | Rcov_inverse=np.linalg.pinv(Rcov) 197 | 198 | #フィルタを計算する 199 | Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) 200 | a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) 201 | w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] 202 | 203 | #フィルタをかける 204 | s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) 205 | 206 | #ステアリングベクトルをかける 207 | c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) 208 | 209 | #時間領域の波形に戻す 210 | t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 211 | 212 | #大きさを調整する 213 | mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. 214 | 215 | #ファイルに書き込む 216 | write_file_from_time_signal(mvdr_out,"./mvdr_out.wav",sample_rate) 217 | 218 | 219 | -------------------------------------------------------------------------------- /section6/sample_code_c6_9.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | 8 | #ステアリングベクトルを算出 9 | #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] 10 | #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] 11 | #freqs: Nk dimensional array [f1,f2,f3...] 12 | #sound_speed: 音速 [m/s] 13 | #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, 14 | #return: steering vector (Nk x Ns x M) 15 | def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): 16 | #マイク数を取得 17 | n_channels=np.shape(mic_alignments)[1] 18 | 19 | #音源数を取得 20 | n_source=np.shape(source_locations)[1] 21 | 22 | if is_use_far==True: 23 | #音源位置を正規化 24 | norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) 25 | 26 | #位相を求める 27 | steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 28 | 29 | #ステアリングベクトルを算出 30 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 31 | 32 | return(steering_vector) 33 | 34 | else: 35 | 36 | #音源とマイクの距離を求める 37 | #distance: Ns x Nm 38 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 39 | 40 | #遅延時間(delay) [sec] 41 | delay=distance/sound_speed 42 | 43 | #ステアリングベクトルの位相を求める 44 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 45 | 46 | #音量の減衰 47 | steering_decay_ratio=1./distance 48 | 49 | #ステアリングベクトルを求める 50 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 51 | 52 | #大きさを1で正規化する 53 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 54 | 55 | return(steering_vector) 56 | 57 | #2バイトに変換してファイルに保存 58 | #signal: time-domain 1d array (float) 59 | #file_name: 出力先のファイル名 60 | #sample_rate: サンプリングレート 61 | def write_file_from_time_signal(signal,file_name,sample_rate): 62 | #2バイトのデータに変換 63 | signal=signal.astype(np.int16) 64 | 65 | #waveファイルに書き込む 66 | wave_out = wave.open(file_name, 'w') 67 | 68 | #モノラル:1、ステレオ:2 69 | wave_out.setnchannels(1) 70 | 71 | #サンプルサイズ2byte 72 | wave_out.setsampwidth(2) 73 | 74 | #サンプリング周波数 75 | wave_out.setframerate(sample_rate) 76 | 77 | #データを書き込み 78 | wave_out.writeframes(signal) 79 | 80 | #ファイルを閉じる 81 | wave_out.close() 82 | 83 | #乱数の種を初期化 84 | np.random.seed(0) 85 | 86 | #畳み込みに用いる音声波形 87 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 88 | 89 | 90 | #音源数 91 | n_sources=len(clean_wave_files) 92 | 93 | #長さを調べる 94 | n_samples=0 95 | #ファイルを読み込む 96 | for clean_wave_file in clean_wave_files: 97 | wav=wave.open(clean_wave_file) 98 | if n_sampleskmn",stft_data,np.conjugate(stft_data)) 195 | 196 | #共分散行列の逆行列を計算する 197 | Rcov_inverse=np.linalg.pinv(Rcov) 198 | 199 | #フィルタを計算する 200 | Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) 201 | a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) 202 | w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] 203 | 204 | #フィルタをかける 205 | s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) 206 | 207 | #ステアリングベクトルをかける 208 | c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) 209 | 210 | #時間領域の波形に戻す 211 | t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) 212 | 213 | #大きさを調整する 214 | mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. 215 | 216 | #ファイルに書き込む 217 | write_file_from_time_signal(mvdr_out,"./mvdr_interference_out.wav",sample_rate) 218 | -------------------------------------------------------------------------------- /section7.md: -------------------------------------------------------------------------------- 1 | ## 第7章のサンプルコード 2 | 3 | * [音声のスパース性に基づく音源分離](section7/sample_code_c7_1.py) 4 | * [音声のスパース性に基づく音源分離(マイクロホンの間隔40センチ)](section7/sample_code_c7_2.py) 5 | * [音声のスパース性に基づく任意マイクロホン配置の音源分離](section7/sample_code_c7_3.py) 6 | * [音声のスパース性に基づくビームフォーマ法](section7/sample_code_c7_4.py) 7 | * [音声のスパース性に基づくビームフォーマ法(残響環境)](section7/sample_code_c7_5.py) 8 | -------------------------------------------------------------------------------- /section7/sample_code_c7_1.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import wave as wave 4 | import pyroomacoustics as pa 5 | import numpy as np 6 | import scipy.signal as sp 7 | import scipy as scipy 8 | 9 | 10 | 11 | #2バイトに変換してファイルに保存 12 | #signal: time-domain 1d array (float) 13 | #file_name: 出力先のファイル名 14 | #sample_rate: サンプリングレート 15 | def write_file_from_time_signal(signal,file_name,sample_rate): 16 | #2バイトのデータに変換 17 | signal=signal.astype(np.int16) 18 | 19 | #waveファイルに書き込む 20 | wave_out = wave.open(file_name, 'w') 21 | 22 | #モノラル:1、ステレオ:2 23 | wave_out.setnchannels(1) 24 | 25 | #サンプルサイズ2byte 26 | wave_out.setsampwidth(2) 27 | 28 | #サンプリング周波数 29 | wave_out.setframerate(sample_rate) 30 | 31 | #データを書き込み 32 | wave_out.writeframes(signal) 33 | 34 | #ファイルを閉じる 35 | wave_out.close() 36 | 37 | #遅延和アレイを実行する 38 | #x_left:左の音源に近いマイクロホン(Nk, Lt) 39 | #x_right:右の音源に近いマイクロホン(Nk,Lt) 40 | #is_use_amplitude: 振幅差を使って分離を行う場合はTrue 41 | #return y_left 左のマイクに近い音源の出力信号(Nk, Lt) 42 | # y_right 右のマイクに近い音源の出力信号(Nk,Lt) 43 | def execute_two_microphone_sparse_separation(x_left,x_right,is_use_amplitude=False): 44 | 45 | if is_use_amplitude==True: 46 | #振幅比率を使った分離 47 | amp_ratio=np.abs(x_left)/np.maximum(np.abs(x_right),1.e-18) 48 | 49 | y_left=(amp_ratio > 1.).astype(np.float)*x_left 50 | 51 | y_right=(amp_ratio <= 1.).astype(np.float)*x_right 52 | 53 | else: 54 | #位相差を用いた分離 55 | phase_difference=np.angle(x_left/x_right) 56 | 57 | y_left=(phase_difference > 0.).astype(np.float)*x_left 58 | 59 | y_right=(phase_difference <= 0.).astype(np.float)*x_right 60 | 61 | return(y_left,y_right) 62 | 63 | 64 | #SNRをはかる 65 | #desired: 目的音、Lt 66 | #out: 雑音除去後の信号 Lt 67 | def calculate_snr(desired,out): 68 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 69 | 70 | #消し残った雑音 71 | desired=desired[:wave_length] 72 | out=out[:wave_length] 73 | noise=desired-out 74 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 75 | 76 | return(snr) 77 | 78 | #乱数の種を初期化 79 | np.random.seed(0) 80 | 81 | #畳み込みに用いる音声波形 82 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 83 | 84 | #音源数 85 | n_sources=len(clean_wave_files) 86 | 87 | #長さを調べる 88 | n_samples=0 89 | #ファイルを読み込む 90 | for clean_wave_file in clean_wave_files: 91 | wav=wave.open(clean_wave_file) 92 | if n_samples 1.).astype(np.float)*x_left 50 | 51 | y_right=(amp_ratio <= 1.).astype(np.float)*x_right 52 | 53 | else: 54 | #位相差を用いた分離 55 | phase_difference=np.angle(x_left/x_right) 56 | 57 | y_left=(phase_difference > 0.).astype(np.float)*x_left 58 | 59 | y_right=(phase_difference <= 0.).astype(np.float)*x_right 60 | 61 | return(y_left,y_right) 62 | 63 | 64 | #SNRをはかる 65 | #desired: 目的音、Lt 66 | #out: 雑音除去後の信号 Lt 67 | def calculate_snr(desired,out): 68 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 69 | 70 | #消し残った雑音 71 | desired=desired[:wave_length] 72 | out=out[:wave_length] 73 | noise=desired-out 74 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 75 | 76 | return(snr) 77 | 78 | #乱数の種を初期化 79 | np.random.seed(0) 80 | 81 | #畳み込みに用いる音声波形 82 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 83 | 84 | #音源数 85 | n_sources=len(clean_wave_files) 86 | 87 | #長さを調べる 88 | n_samples=0 89 | #ファイルを読み込む 90 | for clean_wave_file in clean_wave_files: 91 | wav=wave.open(clean_wave_file) 92 | if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) 58 | 59 | #ステアリングベクトルを算出 60 | steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) 61 | 62 | return(steering_vector) 63 | 64 | else: 65 | 66 | #音源とマイクの距離を求める 67 | #distance: Ns x Nm 68 | distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) 69 | 70 | #遅延時間(delay) [sec] 71 | delay=distance/sound_speed 72 | 73 | #ステアリングベクトルの位相を求める 74 | steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) 75 | 76 | #音量の減衰 77 | steering_decay_ratio=1./distance 78 | 79 | #ステアリングベクトルを求める 80 | steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) 81 | 82 | #大きさを1で正規化する 83 | steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) 84 | 85 | return(steering_vector) 86 | 87 | 88 | #スパース性に基づく分離 89 | #input_vectors:マイクロホン入力信号(Nm,Nk, Lt) 90 | #steering_vectors:ステアリングベクトル(Nk,|Ω|,Nm) 91 | #omega: 目的音の範囲(Ns,|Ω|) 92 | #return y:出力信号(Nm,Ns,Nk, Lt) 93 | def execute_doa_sparse_separation(input_vectors,steering_vectors,omega): 94 | inner_product=np.einsum("kim,mkt->kit",np.conjugate(steering_vectors),input_vectors) 95 | 96 | n_omega=np.shape(omega)[1] 97 | 98 | estimate_doas=np.argmax(np.abs(inner_product),axis=1) 99 | 100 | estimate_doa_mask=np.identity(n_omega)[estimate_doas] 101 | 102 | output_mask=np.einsum("kti,si->skt",estimate_doa_mask,omega) 103 | 104 | y=np.einsum("skt,mkt->mskt",output_mask,input_vectors) 105 | 106 | return(y) 107 | 108 | 109 | #SNRをはかる 110 | #desired: 目的音、Lt 111 | #out: 雑音除去後の信号 Lt 112 | def calculate_snr(desired,out): 113 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 114 | 115 | #消し残った雑音 116 | desired=desired[:wave_length] 117 | out=out[:wave_length] 118 | noise=desired-out 119 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 120 | 121 | return(snr) 122 | 123 | #乱数の種を初期化 124 | np.random.seed(0) 125 | 126 | #畳み込みに用いる音声波形 127 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 128 | 129 | #音源数 130 | n_sources=len(clean_wave_files) 131 | 132 | #長さを調べる 133 | n_samples=0 134 | #ファイルを読み込む 135 | for clean_wave_file in clean_wave_files: 136 | wav=wave.open(clean_wave_file) 137 | if n_samplesnp.pi,diff-np.pi*2,diff) 246 | return(diff) 247 | 248 | #所望音の方向から±th度以内 249 | omega=np.array([ np.abs(modify_angle_diff(virtual_doas[:,1]-doas[s,1]))mkt',W,x) 49 | 50 | #コントラスト関数を計算 51 | G=contrast_func(s_hat) 52 | 53 | #コスト計算 54 | cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) 55 | cost_buff.append(cost) 56 | 57 | #コンストラクト関数の微分を取得 58 | phi=phi_func(s_hat) 59 | 60 | phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) 61 | phi_s=np.mean(phi_s,axis=1) 62 | 63 | I=np.eye(M,M) 64 | if is_use_non_holonomic==False: 65 | deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) 66 | else: 67 | mask=(np.ones((M,M))-I)[None,...] 68 | deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) 69 | 70 | #フィルタを更新する 71 | W=W+mu*deltaW 72 | 73 | #最後に出力信号を分離 74 | s_hat=np.einsum('kmn,nkt->mkt',W,x) 75 | 76 | return(W,s_hat,cost_buff) 77 | 78 | #周波数間の振幅相関に基づくパーミュテーション解法 79 | #s_hat: M,Nk,Lt 80 | #return permutation_index_result:周波数毎のパーミュテーション解 81 | def solver_inter_frequency_permutation(s_hat): 82 | n_sources=np.shape(s_hat)[0] 83 | n_freqs=np.shape(s_hat)[1] 84 | n_frames=np.shape(s_hat)[2] 85 | 86 | s_hat_abs=np.abs(s_hat) 87 | 88 | norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) 89 | s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) 90 | 91 | spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) 92 | 93 | frequency_order=np.argsort(spectral_similarity) 94 | 95 | #音源間の相関が最も低い周波数からパーミュテーションを解く 96 | is_first=True 97 | permutations=list(itertools.permutations(range(n_sources))) 98 | permutation_index_result={} 99 | 100 | for freq in frequency_order: 101 | 102 | if is_first==True: 103 | is_first=False 104 | 105 | #初期値を設定する 106 | accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] 107 | permutation_index_result[freq]=range(n_sources) 108 | else: 109 | max_correlation=0 110 | max_correlation_perm=None 111 | for perm in permutations: 112 | s_hat_abs_temp=s_hat_abs[list(perm),freq,:] 113 | correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) 114 | 115 | 116 | if max_correlation_perm is None: 117 | max_correlation_perm=list(perm) 118 | max_correlation=correlation 119 | elif max_correlation < correlation: 120 | max_correlation=correlation 121 | max_correlation_perm=list(perm) 122 | permutation_index_result[freq]=max_correlation_perm 123 | accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] 124 | 125 | return(permutation_index_result) 126 | 127 | #プロジェクションバックで最終的な出力信号を求める 128 | #s_hat: M,Nk,Lt 129 | #W: 分離フィルタ(Nk,M,M) 130 | #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) 131 | def projection_back(s_hat,W): 132 | 133 | #ステアリングベクトルを推定 134 | A=np.linalg.pinv(W) 135 | c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) 136 | return(c_hat) 137 | 138 | 139 | #2バイトに変換してファイルに保存 140 | #signal: time-domain 1d array (float) 141 | #file_name: 出力先のファイル名 142 | #sample_rate: サンプリングレート 143 | def write_file_from_time_signal(signal,file_name,sample_rate): 144 | #2バイトのデータに変換 145 | signal=signal.astype(np.int16) 146 | 147 | #waveファイルに書き込む 148 | wave_out = wave.open(file_name, 'w') 149 | 150 | #モノラル:1、ステレオ:2 151 | wave_out.setnchannels(1) 152 | 153 | #サンプルサイズ2byte 154 | wave_out.setsampwidth(2) 155 | 156 | #サンプリング周波数 157 | wave_out.setframerate(sample_rate) 158 | 159 | #データを書き込み 160 | wave_out.writeframes(signal) 161 | 162 | #ファイルを閉じる 163 | wave_out.close() 164 | 165 | #SNRをはかる 166 | #desired: 目的音、Lt 167 | #out: 雑音除去後の信号 Lt 168 | def calculate_snr(desired,out): 169 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 170 | 171 | #消し残った雑音 172 | desired=desired[:wave_length] 173 | out=out[:wave_length] 174 | noise=desired-out 175 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 176 | 177 | return(snr) 178 | 179 | #乱数の種を初期化 180 | np.random.seed(0) 181 | 182 | #畳み込みに用いる音声波形 183 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] 184 | 185 | #音源数 186 | n_sources=len(clean_wave_files) 187 | 188 | #長さを調べる 189 | n_samples=0 190 | #ファイルを読み込む 191 | for clean_wave_file in clean_wave_files: 192 | wav=wave.open(clean_wave_file) 193 | if n_sampleskij',x_bar,np.conjugate(x_bar)) 43 | #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) 44 | 45 | correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) 46 | 47 | filter=np.linalg.solve(x_bar_x_bar_h,correlation) 48 | 49 | #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) 50 | x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) 51 | 52 | x_dereverb=x[0,...]-x_reverb 53 | 54 | return(x_dereverb) 55 | 56 | #2バイトに変換してファイルに保存 57 | #signal: time-domain 1d array (float) 58 | #file_name: 出力先のファイル名 59 | #sample_rate: サンプリングレート 60 | def write_file_from_time_signal(signal,file_name,sample_rate): 61 | #2バイトのデータに変換 62 | signal=signal.astype(np.int16) 63 | 64 | #waveファイルに書き込む 65 | wave_out = wave.open(file_name, 'w') 66 | 67 | #モノラル:1、ステレオ:2 68 | wave_out.setnchannels(1) 69 | 70 | #サンプルサイズ2byte 71 | wave_out.setsampwidth(2) 72 | 73 | #サンプリング周波数 74 | wave_out.setframerate(sample_rate) 75 | 76 | #データを書き込み 77 | wave_out.writeframes(signal) 78 | 79 | #ファイルを閉じる 80 | wave_out.close() 81 | 82 | #SNRをはかる 83 | #desired: 目的音、Lt 84 | #out: 雑音除去後の信号 Lt 85 | def calculate_snr(desired,out): 86 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 87 | 88 | #消し残った雑音 89 | desired=desired[:wave_length] 90 | out=out[:wave_length] 91 | noise=desired-out 92 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 93 | 94 | return(snr) 95 | 96 | #乱数の種を初期化 97 | np.random.seed(0) 98 | 99 | #畳み込みに用いる音声波形 100 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 101 | 102 | #音源数 103 | n_sources=len(clean_wave_files) 104 | 105 | #長さを調べる 106 | n_samples=0 107 | #ファイルを読み込む 108 | for clean_wave_file in clean_wave_files: 109 | wav=wave.open(clean_wave_file) 110 | if n_sampleskij',x_bar,np.conjugate(x_bar)) 43 | #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) 44 | 45 | correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) 46 | 47 | filter=np.linalg.solve(x_bar_x_bar_h,correlation) 48 | 49 | #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) 50 | x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) 51 | 52 | x_dereverb=x[0,...]-x_reverb 53 | 54 | return(x_dereverb) 55 | 56 | #WPEで残響を除去 57 | #x:入力信号( M, Nk, Lt) 58 | #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) 59 | #return x_dereverb:残響除去後の信号(Nk,Lt) 60 | def dereverberation_wpe(x,x_bar,wpe_iterations=10): 61 | 62 | #マイクロホン数・周波数・フレーム数・タップ長を取得する 63 | M=np.shape(x)[0] 64 | Nk=np.shape(x)[1] 65 | Lt=np.shape(x)[2] 66 | Lh=np.shape(x_bar)[0] 67 | 68 | #入力信号の形式を変更・変数を初期化 69 | x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) 70 | v=np.square(np.abs(x[0,...])) 71 | 72 | cost_buff=[] 73 | for t in range(wpe_iterations): 74 | #共分散行列を計算 75 | x_bar_x_bar_h=np.einsum('kt,ikt,jkt->kij',1./v,x_bar,np.conjugate(x_bar)) 76 | 77 | #相関ベクトルを計算 78 | correlation=np.einsum('kt,ikt,kt->ki',1./v,x_bar,np.conjugate(x[0,...])) 79 | 80 | #フィルタ算出 81 | filter=np.linalg.solve(x_bar_x_bar_h,correlation) 82 | 83 | #残響除去実施 84 | x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) 85 | x_dereverb=x[0,...]-x_reverb 86 | 87 | #パラメータ更新 88 | v=np.square(np.abs(x_dereverb)) 89 | v=np.maximum(v,1.e-8) 90 | 91 | #コスト計算 92 | cost=np.mean(np.log(v)) 93 | cost_buff.append(cost) 94 | return(x_dereverb,cost_buff) 95 | 96 | 97 | #2バイトに変換してファイルに保存 98 | #signal: time-domain 1d array (float) 99 | #file_name: 出力先のファイル名 100 | #sample_rate: サンプリングレート 101 | def write_file_from_time_signal(signal,file_name,sample_rate): 102 | #2バイトのデータに変換 103 | signal=signal.astype(np.int16) 104 | 105 | #waveファイルに書き込む 106 | wave_out = wave.open(file_name, 'w') 107 | 108 | #モノラル:1、ステレオ:2 109 | wave_out.setnchannels(1) 110 | 111 | #サンプルサイズ2byte 112 | wave_out.setsampwidth(2) 113 | 114 | #サンプリング周波数 115 | wave_out.setframerate(sample_rate) 116 | 117 | #データを書き込み 118 | wave_out.writeframes(signal) 119 | 120 | #ファイルを閉じる 121 | wave_out.close() 122 | 123 | #SNRをはかる 124 | #desired: 目的音、Lt 125 | #out: 雑音除去後の信号 Lt 126 | def calculate_snr(desired,out): 127 | wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) 128 | 129 | #消し残った雑音 130 | desired=desired[:wave_length] 131 | out=out[:wave_length] 132 | noise=desired-out 133 | snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) 134 | 135 | return(snr) 136 | 137 | #乱数の種を初期化 138 | np.random.seed(0) 139 | 140 | #畳み込みに用いる音声波形 141 | clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] 142 | 143 | #音源数 144 | n_sources=len(clean_wave_files) 145 | 146 | #長さを調べる 147 | n_samples=0 148 | #ファイルを読み込む 149 | for clean_wave_file in clean_wave_files: 150 | wav=wave.open(clean_wave_file) 151 | if n_samples