Repository: masahitotogami/python_source_separation Branch: master Commit: e0788b02104e Files: 74 Total size: 331.5 KB Directory structure: gitextract_ib0mjebm/ ├── LICENSE.txt ├── README.md ├── errata.md ├── install.md ├── section10/ │ ├── sample_code_c10_1.py │ └── sample_code_c10_2.py ├── section10.md ├── section11/ │ ├── sample_code_c11_1.py │ └── sample_code_c11_2.py ├── section11.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 ├── section2.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 ├── section3.md ├── section4/ │ └── sample_code_c4_1.py ├── section4.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 ├── section5.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 ├── section6.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 ├── section7.md ├── section8/ │ ├── sample_code_c8_1.py │ ├── sample_code_c8_2.py │ ├── sample_code_c8_3.py │ └── sample_code_c8_4.py ├── section8.md ├── section9/ │ ├── sample_code_c9_1.py │ └── sample_code_c9_2.py └── section9.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE.txt ================================================ MIT License Copyright (c) 2020 Masahito Togami Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## Pythonで学ぶ音源分離(機械学習実践シリーズ)のソースコード ![Python 3.6](https://img.shields.io/badge/Python-3.6-green.svg) ![License](https://img.shields.io/badge/Code%20License-MIT-green.svg) 本リポジトリでは、インプレス社機械学習実践シリーズの「Pythonで学ぶ音源分離」のサンプルコードを管理しています。 なお、本ソースコードは、MITライセンスのもとで公開されています。LICENSE.txtを見てください。 ## 書籍概要 ![Pythonで学ぶ音源分離カバー](cover.jpg) * [Pythonで学ぶ音源分離(機械学習実践シリーズ)](https://book.impress.co.jp/books/1119101154 "Pythonで学ぶ音源分離(機械学習実践シリーズ)") * 価格: 3,500円+税 * 発売日: 2020年8月24日 * ページ数: 352 * サイズ: B5変形判 * 著者: 戸上 真人 * ISBN: 9784295009849 ## 目次 * 序章 * 第1章 音源分離とは? * 第2章 音声処理の基礎 * 第3章 音源分離で用いる数学的知識の基礎(線形代数、ベクトル・行列の微分) * 第4章 「最適化」に関する技法を理解する * 第5章 シミュレーターで音を作ってみる * 第6章 古典的な音源分離方法~ビームフォーミング~ * 第7章 音源方向推定に基づく音源分離 * 第8章 現代的な統計的モデルに基づく音源分離法 * 第9章 響きのある音を響きのない音に変える残響除去法 * 第10章 音源分離と残響除去を統合的に実行する * 第11章 音源分離関連のライブラリ紹介・その他のトピック・参考文献 ## 各章のサンプルコード * [本書の前提](install.md) * [第2章のサンプルコード](section2.md) * [第3章のサンプルコード](section3.md) * [第4章のサンプルコード](section4.md) * [第5章のサンプルコード](section5.md) * [第6章のサンプルコード](section6.md) * [第7章のサンプルコード](section7.md) * [第8章のサンプルコード](section8.md) * [第9章のサンプルコード](section9.md) * [第10章のサンプルコード](section10.md) * [第11章のサンプルコード](section11.md) ## お詫びと訂正 Pythonで学ぶ音源分離(機械学習実践シリーズ)に誤りがありました。ここに謹んでお詫び申し上げますと共に,以下のページに正誤表を 掲載させて頂きます。 [本書の正誤表](errata.md) ## License MIT ================================================ FILE: errata.md ================================================ ## 正誤表 |項番|該当箇所|誤|正|update| |---|---|---|---|---| |1|p.2| pip install itertools | 削除 |2020/08/24| |2|第4章第5節タイトル, p4, p.135 | Maximization-Majorization | Majorization-Minimization | 2020/08/24| |3|p.10| 「知り当たった」|「知り合った」|2020/08/24| |4|第二章|code2.1とcode2.9が欠番。(コードを削除したことに起因)|-|2020/08/24| |5|p.60|code2.14|code2.15|2020/08/24| |6|p.97|code3.9|result3.1|2020/08/24| |7|p.82| 「このとき、m...minj",A,B),np.shape(A)[:-2]+(np.shape(A)[-2]*np.shape(B)[-2],np.shape(A)[-1]*np.shape(B)[-1]))) #x:入力信号( M, Nk, Lt) #D:遅延フレーム数 #Lh:残響除去フィルタのタップ長 #return x_bar: 過去のマイク入力信号(Lh,M,Nk,Lt) def make_x_bar(x,D,Lh): #フレーム数を取得 Lt=np.shape(x)[2] #過去のマイク入力信号の配列を準備 x_bar=np.zeros(shape=(Lh,)+np.shape(x),dtype=np.complex) for tau in range(Lh): x_bar[tau,...,tau+D:]=x[:,:,:-(tau+D)] return(x_bar) #IP法によるLGMのパラメータ推定法 #x:入力信号( M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_mm_lgm(x,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x),V_inverse,x) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) #パラメータを更新 #Rの更新 V_inverseX=np.einsum('ktmn,nkt->ktm',V_inverse,x) V_inverseXV_inverseX=np.einsum('ktm,ktn->ktmn',V_inverseX,np.conjugate(V_inverseX)) A=np.einsum('kst,ktmn->ksmn',v,V_inverse) B=np.einsum('kst,ktmn->ksmn',v,V_inverseXV_inverseX) RBR=np.einsum('ksmn,ksni,ksij->ksmj',R,B,R) invA=np.linalg.pinv(A) A_RBR=np.matmul(A,RBR) R=np.concatenate([np.concatenate([np.matmul(invA[k,s,...],scipy.linalg.sqrtm(A_RBR[k,s,...]))[None,None,...] for k in range(Nk)],axis=0) for s in range(Ns)],axis=1) R=(R+np.transpose(np.conjugate(R),[0,1,3,2]))/(2.0+0.0j) #vの更新 v=v*np.sqrt(np.einsum('ktm,ktn,ksnm->kst',V_inverseX,np.conjugate(V_inverseX),R)/np.maximum(np.einsum('ktmn,ksnm->kst',V_inverse,R) ,1.e-18)) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x) return(R,v,c_bar,cost_buff) #LGMの音源分離と残響除去のパラメータ推定法 #x:入力信号( M, Nk, Lt) #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_mm_lgm_dereverb(x,x_bar,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] Lh=np.shape(x_bar)[0] x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) #共分散行列を計算 x_bar_x_bar_H=np.einsum('ikt,jkt->ktij',x_bar,np.conjugate(x_bar)) #相関行列を計算 x_bar_x_H=np.einsum('ikt,mkt->ktim',x_bar,np.conjugate(x)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V=V+np.eye(M,M)*1.e-8 V_inverse=np.linalg.inv(V) #残響除去フィルタを求める x_barx_H_V_inv=np.einsum("ktim,ktmn->kin",x_bar_x_H,V_inverse) vec_x_bar_x_HV_inv=np.reshape(np.transpose(x_barx_H_V_inv,[0,2,1]),(Nk,Lh*M*M)) #多次元配列対応版のクロネッカー積 V_inverse_x_x_H=batch_kron(np.transpose(V_inverse,(0,1,3,2)),x_bar_x_bar_H) #vecHを求める vec_h=np.einsum("kmr,kr->km",np.linalg.inv(np.sum(V_inverse_x_x_H,axis=1)), vec_x_bar_x_HV_inv) #行列に戻す h=np.transpose(np.reshape(vec_h,(Nk,M,Lh*M)),(0,2,1)) #残響除去を行う x_reverb=np.einsum('kjm,jkt->mkt',np.conjugate(h),x_bar) x_dereverb=x-x_reverb #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x_dereverb),V_inverse,x_dereverb) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) #print(t,cost) #パラメータを更新 #Rの更新 V_inverseX=np.einsum('ktmn,nkt->ktm',V_inverse,x_dereverb) V_inverseXV_inverseX=np.einsum('ktm,ktn->ktmn',V_inverseX,np.conjugate(V_inverseX)) A=np.einsum('kst,ktmn->ksmn',v,V_inverse) B=np.einsum('kst,ktmn->ksmn',v,V_inverseXV_inverseX) RBR=np.einsum('ksmn,ksni,ksij->ksmj',R,B,R) invA=np.linalg.pinv(A) A_RBR=np.matmul(A,RBR) R=np.concatenate([np.concatenate([np.matmul(invA[k,s,...],scipy.linalg.sqrtm(A_RBR[k,s,...]))[None,None,...] for k in range(Nk)],axis=0) for s in range(Ns)],axis=1) R=(R+np.transpose(np.conjugate(R),[0,1,3,2]))/(2.0+0.0j) #vの更新 v=v*np.sqrt(np.einsum('ktm,ktn,ksnm->kst',V_inverseX,np.conjugate(V_inverseX),R)/np.maximum(np.einsum('ktmn,ksnm->kst',V_inverse,R) ,1.e-18)) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x_dereverb) return(R,v,c_bar,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samples...minj",A,B),np.shape(A)[:-2]+(np.shape(A)[-2]*np.shape(B)[-2],np.shape(A)[-1]*np.shape(B)[-1]))) #x:入力信号( M, Nk, Lt) #D:遅延フレーム数 #Lh:残響除去フィルタのタップ長 #return x_bar: 過去のマイク入力信号(Lh,M,Nk,Lt) def make_x_bar(x,D,Lh): #フレーム数を取得 Lt=np.shape(x)[2] #過去のマイク入力信号の配列を準備 x_bar=np.zeros(shape=(Lh,)+np.shape(x),dtype=np.complex) for tau in range(Lh): x_bar[tau,...,tau+D:]=x[:,:,:-(tau+D)] return(x_bar) #コントラスト関数の微分(球対称多次元ラプラス分布を仮定) #s_hat: 分離信号(M, Nk, Lt) def phi_multivariate_laplacian(s_hat): power=np.square(np.abs(s_hat)) norm=np.sqrt(np.sum(power,axis=1,keepdims=True)) phi=s_hat/np.maximum(norm,1.e-18) return(phi) #コントラスト関数の微分(球対称ラプラス分布を仮定) #s_hat: 分離信号(M, Nk, Lt) def phi_laplacian(s_hat): norm=np.abs(s_hat) phi=s_hat/np.maximum(norm,1.e-18) return(phi) #コントラスト関数(球対称ラプラス分布を仮定) #s_hat: 分離信号(M, Nk, Lt) def contrast_laplacian(s_hat): norm=2.*np.abs(s_hat) return(norm) #コントラスト関数(球対称多次元ラプラス分布を仮定) #s_hat: 分離信号(M, Nk, Lt) def contrast_multivariate_laplacian(s_hat): power=np.square(np.abs(s_hat)) norm=2.*np.sqrt(np.sum(power,axis=1,keepdims=True)) return(norm) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma(x,W,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) s_power=np.square(np.abs(s_hat)) #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('skt,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) #P: 音源分離・残響除去フィルタ(Nk,M,(Lh+1)*M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma_t(x,x_bar,P,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] Lh=np.shape(x_bar)[0] x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) x_hat=np.concatenate((x,x_bar),axis=0) #共分散行列を計算 x_hat_x_hat_H=np.einsum('ikt,jkt->ktij',x_hat,np.conjugate(x_hat)) cost_buff=[] for t in range(n_iterations): #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #音源分離と残響除去を行う s_hat=np.einsum('kmj,jkt->mkt',P,x_hat) s_power=np.square(np.abs(s_hat)) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #共分散行列を算出 Q=np.einsum("skt,ktij->tksij",1./np.maximum(v,1.e-18),x_hat_x_hat_H) Q=np.average(Q,axis=0) Q_inverse=np.linalg.pinv(Q) for source_index in range(M): P0=P[:,:,:M] P0_inverse=np.linalg.pinv(P0) #ステアリングベクトル b_steering=P0_inverse[:,:,source_index] b_h_Q_inverse_b=np.einsum("km,kmn,kn->k",np.conjugate(b_steering),Q_inverse[:,source_index,:M,:M],b_steering) Q_inverse_b=np.einsum("kmn,kn->km",Q_inverse[:,source_index,:,:M],b_steering) p=np.einsum("km,k->km",Q_inverse_b,1./np.sqrt(np.maximum(np.abs(b_h_Q_inverse_b),1.e-18))) P[:,source_index,:]=np.conjugate(p) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(P[:,:,:M])) )) cost_buff.append(cost) #print(t,cost) s_hat=np.einsum('kmj,jkt->mkt',P,x_hat) W=P[:,:,:M] return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma_dereverb(x,x_bar,W,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] Lh=np.shape(x_bar)[0] x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) #共分散行列を計算 x_bar_x_bar_H=np.einsum('ikt,jkt->ktij',x_bar,np.conjugate(x_bar)) #相関行列を計算 x_bar_x_H=np.einsum('ikt,mkt->ktim',x_bar,np.conjugate(x)) cost_buff=[] for t in range(n_iterations): #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #入力信号の共分散行列を求める V_inverse=np.einsum("skt,ksm,ksn->ktmn",1./np.maximum(v,1.e-18),np.conjugate(W),W) #残響除去フィルタを求める x_barx_H_V_inv=np.einsum("ktim,ktmn->kin",x_bar_x_H,V_inverse) vec_x_bar_x_HV_inv=np.reshape(np.transpose(x_barx_H_V_inv,[0,2,1]),(Nk,Lh*M*M)) #多次元配列対応版のクロネッカー積 V_inverse_x_x_H=batch_kron(np.transpose(V_inverse,(0,1,3,2)),x_bar_x_bar_H) #vecHを求める vec_h=np.einsum("kmr,kr->km",np.linalg.inv(np.sum(V_inverse_x_x_H,axis=1)), vec_x_bar_x_HV_inv) #行列に戻す h=np.transpose(np.reshape(vec_h,(Nk,M,Lh*M)),(0,2,1)) #残響除去を行う x_reverb=np.einsum('kjm,jkt->mkt',np.conjugate(h),x_bar) x_dereverb=x-x_reverb #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x_dereverb) s_power=np.square(np.abs(s_hat)) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #print(t,cost) #IP法による更新 Q=np.einsum('skt,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x_dereverb,np.conjugate(x_dereverb)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x_dereverb) return(W,s_hat,cost_buff) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesmkt',W,x) #コントラスト関数を計算 G=contrast_func(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #コンストラクト関数の微分を取得 phi=phi_func(s_hat) phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) phi_s=np.mean(phi_s,axis=1) I=np.eye(M,M) if is_use_non_holonomic==False: deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) else: mask=(np.ones((M,M))-I)[None,...] deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) #フィルタを更新する W=W+mu*deltaW #最後に出力信号を分離 s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #EM法によるLGMのパラメータ推定法 #x:入力信号( M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_em_lgm(x,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x),V_inverse,x) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #事後確率計算に必要なパラメータを推定 c_bar=np.einsum('kstmn,nkt->kstm',Wmwf,x) R_bar=np.einsum("kstmi,kstin->kstmn",-1.*Wmwf+np.eye(M),vR) P_bar=R_bar+np.einsum("kstm,kstn->kstmn",c_bar,np.conjugate(c_bar)) #パラメータを更新 R=np.average(P_bar/np.maximum(v,1.e-18)[...,None,None],axis=2) R_inverse=np.linalg.pinv(R) v=np.einsum("ksmi,kstim->kst",R_inverse,P_bar) v=v/np.float(M) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x) return(R,v,c_bar,cost_buff) #IP法によるLGMのパラメータ推定法 #x:入力信号( M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_mm_lgm(x,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x),V_inverse,x) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) #パラメータを更新 #Rの更新 V_inverseX=np.einsum('ktmn,nkt->ktm',V_inverse,x) V_inverseXV_inverseX=np.einsum('ktm,ktn->ktmn',V_inverseX,np.conjugate(V_inverseX)) A=np.einsum('kst,ktmn->ksmn',v,V_inverse) B=np.einsum('kst,ktmn->ksmn',v,V_inverseXV_inverseX) RBR=np.einsum('ksmn,ksni,ksij->ksmj',R,B,R) invA=np.linalg.pinv(A) A_RBR=np.matmul(A,RBR) R=np.concatenate([np.concatenate([np.matmul(invA[k,s,...],scipy.linalg.sqrtm(A_RBR[k,s,...]))[None,None,...] for k in range(Nk)],axis=0) for s in range(Ns)],axis=1) R=(R+np.transpose(np.conjugate(R),[0,1,3,2]))/(2.0+0.0j) #vの更新 v=v*np.sqrt(np.einsum('ktm,ktn,ksnm->kst',V_inverseX,np.conjugate(V_inverseX),R)/np.maximum(np.einsum('ktmn,ksnm->kst',V_inverse,R) ,1.e-18)) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x) return(R,v,c_bar,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_multivariate_laplacian_iva(x,W,n_iterations=20): #マイクロホン数を取得する M=np.shape(x)[0] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) #補助変数を更新する v=np.sqrt(np.sum(np.square(np.abs(s_hat)),axis=1)) #コントラスト関数を計算 G=contrast_multivariate_laplacian(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('st,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma(x,W,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) s_power=np.square(np.abs(s_hat)) #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('skt,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskij',x_bar,np.conjugate(x_bar)) #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) filter=np.linalg.solve(x_bar_x_bar_h,correlation) #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) x_dereverb=x[0,...]-x_reverb return(x_dereverb) #WPEで残響を除去 #x:入力信号( M, Nk, Lt) #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) #return x_dereverb:残響除去後の信号(Nk,Lt) def dereverberation_wpe(x,x_bar,wpe_iterations=10): #マイクロホン数・周波数・フレーム数・タップ長を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] Lh=np.shape(x_bar)[0] #入力信号の形式を変更・変数を初期化 x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) v=np.square(np.abs(x[0,...])) cost_buff=[] for t in range(wpe_iterations): #共分散行列を計算 x_bar_x_bar_h=np.einsum('kt,ikt,jkt->kij',1./v,x_bar,np.conjugate(x_bar)) #相関ベクトルを計算 correlation=np.einsum('kt,ikt,kt->ki',1./v,x_bar,np.conjugate(x[0,...])) #フィルタ算出 filter=np.linalg.solve(x_bar_x_bar_h,correlation) #残響除去実施 x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) x_dereverb=x[0,...]-x_reverb #パラメータ更新 v=np.square(np.abs(x_dereverb)) v=np.maximum(v,1.e-8) #コスト計算 cost=np.mean(np.log(v)) cost_buff.append(cost) return(x_dereverb,cost_buff) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesmn",A,B)) #行列Aと行列Bのアダマール積 B=np.matrix([[-1.,2.,4.],[1.,8.,6.]]) print("A*B= \n",np.multiply(A,B)) #行列Aの転置 print("A^T= \n",A.T) print("A^T= \n",np.transpose(A,axes=(1,0))) print("A^T= \n",np.swapaxes(A,1,0)) #複素行列のエルミート転置 A=np.matrix([[3.,1.+2.j,2.+3.j],[2.,3.-4.j,1.+3.j]]) print("A^H= \n",A.H) print("A^H= \n",np.swapaxes(np.conjugate(A),1,0)) #行列の積に対するエルミート転置 A=np.matrix([[3.,1.+2.j,2.+3.j],[2.,3.-4.j,1.+3.j]]) B=np.matrix([[4.+4.j,2.-3.j],[-1.+1.j,3.-2.j],[1.+3.j,5.+5.j]]) print("(AB)^H= \n",(np.matmul(A,B)).H) print("B^H A^H= \n",np.matmul(B.H,A.H)) #単位行列の定義 I=np.eye(N=3) print("I = \n",I) ================================================ FILE: section3/sample_code_c3_2.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #乱数の種を設定 np.random.seed(0) #テンソルの大きさを設定 L=10 K=5 M=3 R=3 N=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*K*M*R)+np.random.uniform(size=L*K*M*R)*1.j A=np.reshape(A,(L,K,M,R)) B=np.random.uniform(size=K*R*N)+np.random.uniform(size=K*R*N)*1.j B=np.reshape(B,(K,R,N)) #einsumを使って行列積を計算する C=np.einsum("lkmr,krn->lkmn",A,B) #行列Cの大きさを表示 print("shape(C): ",np.shape(C)) #l=0,k=0の要素について検算実施 print("A(0,0)B(0,0)=\n",np.matmul(A[0,0,...],B[0,...])) print("C(0,0)=\n",C[0,0,...]) #einsumを使って行列積をl,k毎に計算した後、かつl方向に和を取る C=np.einsum("lkmr,krn->kmn",A,B) #行列Cの大きさを表示 print("shape(C): ",np.shape(C)) #k=0の要素について検算実施 for l in range(L): if l==0: C_2=np.matmul(A[l,0,...],B[0,...]) else: C_2=C_2+np.matmul(A[l,0,...],B[0,...]) print("C_2(0)=\n",C_2) print("C(0)=\n",C[0,...]) #einsumを使ってアダマール積を計算する C=np.einsum("lkmn,kmn->lkmn",A,B) #行列Cの大きさを表示 print("shape(C): ",np.shape(C)) #l=0,k=0の要素について検算実施 print("A(0,0)B(0,0)=\n",np.multiply(A[0,0,...],B[0,...])) print("C(0,0)=\n",C[0,0,...]) ================================================ FILE: section3/sample_code_c3_3.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #乱数の種を設定 np.random.seed(0) #テンソルの大きさを設定 L=10 K=5 M=3 R=3 S=3 N=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*K*M*R)+np.random.uniform(size=L*K*M*R)*1.j A=np.reshape(A,(L,K,M,R)) B=np.random.uniform(size=K*R*S)+np.random.uniform(size=K*R*S)*1.j B=np.reshape(B,(K,R,S)) C=np.random.uniform(size=L*S*N)+np.random.uniform(size=L*S*N)*1.j C=np.reshape(C,(L,S,N)) #einsumを使って行列積を計算する D=np.einsum("lkmr,krs,lsn->kmn",A,B,C) print(np.shape(D)) #k=0の要素について検算実施 for l in range(L): if l==0: D_2=np.matmul(np.matmul(A[l,0,...],B[0,...]),C[l]) else: D_2=D_2+np.matmul(np.matmul(A[l,0,...],B[0,...]),C[l]) print("D_2(0)=\n",D_2) print("D(0)=\n",D[0,...]) ================================================ FILE: section3/sample_code_c3_4.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #乱数の種を設定 np.random.seed(0) #行列の大きさを設定する L=10 M=3 N=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j A=np.reshape(A,(L,M,N)) #行列式を計算する detA=np.linalg.det(A) print("detA(0): ",detA[0]) #全ての要素を3倍した行列の行列式を計算する det3A=np.linalg.det(3*A) print("det3A(0): ",det3A[0]) #逆行列を計算する A_inv=np.linalg.inv(A) #Aとかけて単位行列になっているかどうかを検算 AA_inv=np.einsum("lmk,lkn->lmn",A,A_inv) print("単位行列?: \n",AA_inv[0]) A_invA=np.einsum("lmk,lkn->lmn",A_inv,A) print("単位行列?: \n",A_invA[0]) #一般化逆行列計算 A_inv=np.linalg.pinv(A) #Aとかけて単位行列になっているかどうかを検算 AA_inv=np.einsum("lmk,lkn->lmn",A,A_inv) print("単位行列?: \n",AA_inv[0]) A_invA=np.einsum("lmk,lkn->lmn",A_inv,A) print("単位行列?: \n",A_invA[0]) ================================================ FILE: section3/sample_code_c3_5.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #行列を定義 A=np.matrix([[3.,1.,2.],[2.,3.,1.]]) #ベクトルを定義 b=np.array([2.,1.,4.]) #行列を表示 print("A= \n",A) #ベクトルを表示 print("b= \n",b) #行列Aにベクトルbをかける print("Ab= \n",np.dot(A,b)) ================================================ FILE: section3/sample_code_c3_6.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #行列を定義 a=np.matrix([3.+2.j,1.-1.j,2.+2.j]) #ベクトルを定義 b=np.array([2.+5.j,1.-1.j,4.+1.j]) #ベクトルの内積計算 print("a^Hb=",np.inner(np.conjugate(a),b)) #ベクトルの内積計算 print("a^Ha=",np.inner(np.conjugate(a),a)) ================================================ FILE: section3/sample_code_c3_7.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #乱数の種を設定 np.random.seed(0) #行列の大きさを設定する L=10 M=3 N=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j A=np.reshape(A,(L,M,N)) #ランダムな複素数のテンソル(ndarray)を定義する b=np.random.uniform(size=L*M)+np.random.uniform(size=L*M)*1.j b=np.reshape(b,(L,M)) #行列Aのtrace print("tr(A)= \n",np.trace(A,axis1=-2,axis2=-1)) #einsumを用いたtrace計算 print("tr(A)= \n",np.einsum("lmm->l",A)) #b^H,A,bの計算 print("b^H A b=\n",np.einsum("lm,lmn,ln->l",np.conjugate(b),A,b)) #b^H,A,bの計算 print("trA bb^H =\n",np.trace(np.einsum("lmn,ln,lk->lmk",A,b,np.conjugate(b)),axis1=-2,axis2=-1)) ================================================ FILE: section3/sample_code_c3_8.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #乱数の種を設定 np.random.seed(0) #行列の大きさを設定する L=10 M=3 N=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*M*N)+np.random.uniform(size=L*M*N)*1.j A=np.reshape(A,(L,M,N)) #正定エルミート行列を作る B=np.einsum("lmk,lnk->lmn",A,np.conjugate(A)) #Aの固有値分解実施 w,v=np.linalg.eig(A) #固有値と固有ベクトルからAを復元できるか検証 A_reconst=np.einsum("lmk,lk,lkn->lmn",v,w,np.linalg.inv(v)) print("A[0]: \n",A[0]) print("A_reconst[0]: \n",A_reconst[0]) #Bの固有値分解実施 w,v=np.linalg.eigh(B) #固有値と固有ベクトルからBを復元できるか検証 B_reconst=np.einsum("lmk,lk,lnk->lmn",v,w,np.conjugate(v)) print("B[0]: \n",B[0]) print("B[0]: \n",B_reconst[0]) ================================================ FILE: section3/sample_code_c3_9.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #A: ...mn #B: ...ij #AとBの最後の二軸以外の次元は一致していることを前提とする def batch_kron(A,B): if np.shape(A)[:-2]!=np.shape(B)[:-2]: print("error") return None else: 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]))) #乱数の種を設定 np.random.seed(0) #行列の大きさを設定する L=10 M=3 R=3 N=3 T=3 #ランダムな複素数のテンソル(ndarray)を定義する A=np.random.uniform(size=L*M*R)+np.random.uniform(size=L*M*R)*1.j A=np.reshape(A,(L,M,R)) X=np.random.uniform(size=R*N)+np.random.uniform(size=R*N)*1.j X=np.reshape(X,(R,N)) B=np.random.uniform(size=L*N*T)+np.random.uniform(size=L*N*T)*1.j B=np.reshape(B,(L,N,T)) D=np.random.uniform(size=L*M*T)+np.random.uniform(size=L*M*T)*1.j D=np.reshape(D,(L,M,T)) #1. 多次元配列対応版のクロネッカー積batch_kronの出力結果とnumpyのkronの出力結果が一致していることを確認 #多次元配列対応版のクロネッカー積 C=batch_kron(np.transpose(B,(0,2,1)),A) #numpyのkronでl=0のデータに対してクロネッカー積を計算 C_2=np.kron(np.transpose(B[0,...],(1,0)),A[0,...]) #多次元配列対応版のクロネッカー積とnumpyのkronとの誤差 print("誤差 = ",np.sum(np.abs(C[0,...]-C_2))) #2. vecAXBとCvecXが一致しているかどうかを確認する #Xをベクトル化する vecX=np.reshape(np.transpose(X,[1,0]),(N*R)) #AXBを計算する AXB=np.einsum("lmr,rn,lnt->lmt",A,X,B) #AXBをベクトル化する vecAXB=np.reshape(np.transpose(AXB,[0,2,1]),(L,T*M)) #CvecX CvecX=np.einsum("lmr,r->lm",C,vecX) #vecAXBとCvecXが一致しているかどうかを確認する print("誤差 = ",np.sum(np.abs(vecAXB-CvecX))) #3. ΣAXB=ΣDを満たすようなXを求める #vecDを求める vecD=np.reshape(np.transpose(D,[0,2,1]),(L,T*M)) #vecXを求める vecX=np.einsum("mr,r->m",np.linalg.inv(np.sum(C,axis=0)), np.sum(vecD,axis=0)) #Xに戻す X=np.transpose(np.reshape(vecX,(N,R)),(1,0)) #答えがあっているかどうかを確認 sum_AXB=np.einsum("lmr,rn,lnt->mt",A,X,B) sum_D=np.sum(D,axis=0) #sum_AXBとsum_Dが一致しているかどうかを確認する print("誤差 = ",np.sum(np.abs(sum_AXB-sum_D))) ================================================ FILE: section3.md ================================================ ## 第3章のサンプルコード * [行列の基本的な演算](section3/sample_code_c3_1.py) * [アインシュタイン縮約記法を用いたテンソル計算](section3/sample_code_c3_2.py) * [アインシュタイン縮約記法を用いたテンソル計算(3つのテンソル)](section3/sample_code_c3_3.py) * [逆行列演算](section3/sample_code_c3_4.py) * [行列とベクトルの掛け算](section3/sample_code_c3_5.py) * [ベクトルの内積計算](section3/sample_code_c3_6.py) * [行列のトレース計算](section3/sample_code_c3_7.py) * [固有値計算](section3/sample_code_c3_8.py) * [クロネッカー積を用いた計算例](section3/sample_code_c3_9.py) ================================================ FILE: section4/sample_code_c4_1.py ================================================ #numpyをインポート(行列を扱う各種関数を含む) import numpy as np #可視化のためにmatplotlibモジュールをインポート import matplotlib.pyplot as plt #アニメーション用のモジュールをインポート import matplotlib.animation as animation #確率密度関数の描画用 from scipy.stats import norm #混合ガウス分布に基づく乱数を生成する np.random.seed(0) #各ガウス分布のサンプル数 n_samples=[200,400,400] #各ガウス分布の平均 means=[-2,3,5] #各ガウス分布の分散 sigmas=[3,2,0.5] #GMMに従う乱数を生成 x=None for n,mean,sigma in zip(n_samples,means,sigmas): samples_for_each_dist=np.random.normal(mean,sigma, int(n)) if x is None: x=samples_for_each_dist else: x=np.concatenate((x,samples_for_each_dist)) #モデルパラメータを初期化する alpha=np.array([1./3.,1./3.,1./3.]) var=np.array([1.,1.,1.]) mu=np.array([-1,0,1]) #GMMを構成するガウス分布の数 n_clusters=len(alpha) #繰り返し計算でパラメータを最適化する(ここでは100回繰り返す) n_iterations=101 log_likelihood=np.zeros(n_iterations) ims=[] for t in range(n_iterations): print("t{}".format(t)) if t==0: alpha_buf=alpha[None,:] var_buf=var[None,:] mu_buf=mu[None,:] else: alpha_buf=np.concatenate((alpha_buf,alpha[None,:]),axis=0) var_buf=np.concatenate((var_buf,var[None,:]),axis=0) mu_buf=np.concatenate((mu_buf,mu[None,:]),axis=0) #Eステップ #係数部 coef=alpha/np.sqrt(2.*np.pi*var) #exponent: n_sample, n_clusters exponent=-1.*np.power(x[:,None]-mu[None,:],2.)/(2*var[None,:]) #βを求める beta=coef[None,:]*np.exp(exponent) likelihood_each_sample=np.maximum(np.sum(beta,axis=1,keepdims=True),1.e-18) beta=beta/likelihood_each_sample #対数尤度を求める current_log_likelihood=np.average(np.log(likelihood_each_sample)) log_likelihood[t]=current_log_likelihood #Mステップ(パラメータを更新する) N=np.maximum(np.sum(beta,axis=0),1.e-18) #事前確率を更新 alpha=N/np.sum(N) #平均値を更新 mu=np.einsum("ij,i->j",beta,x)/N #分散を計算 var=np.einsum("ij,ij->j",beta,np.power(x[:,None]-mu[None,:],2.))/N var=np.maximum(var,1.e-18) #対数ゆう度をグラフ化する plt.figure(figsize=(10,4)) plt.plot(np.arange(0,n_iterations,1),log_likelihood,color="black",linewidth=1,label="log likelihood") plt.xlabel("Number of iterations") plt.legend() plt.savefig("./log_likelihood_gmm.png") plt.show() #パラメータ更新の様子をアニメーションで表示 def animation_update(t): plt.cla() plt.hist(x,bins=50,normed=True,label="observed samples") xmin=-20 xmax=20 plt.xlim([xmin,xmax]) plt.ylim([0,0.40]) x_range=np.arange(-20,20,0.01) #GMMを描画する pdf=None for alpha,var, mu in zip(alpha_buf[t],var_buf[t],mu_buf[t]): pdf_each=alpha*norm.pdf(x_range,mu,np.sqrt(var)) if pdf is None: pdf=pdf_each else: pdf=pdf+pdf_each plt.plot(x_range,pdf,color="black",linewidth=1,label=r"$p(x|\theta^{(t="+str(t)+")})$") plt.legend() if t==0: plt.savefig("./initialized_gmm.png") if t==n_iterations-1: plt.savefig("./learned_gmm.png") #音声データをプロットする fig=plt.figure(figsize=(10,4)) ani=animation.FuncAnimation(fig,animation_update,interval=200,frames=n_iterations) plt.show() ================================================ FILE: section4.md ================================================ ## 第4章のサンプルコード * [(参考)EMアルゴリズムによる混合ガウス分布のパラメータ最適化](section4/sample_code_c4_1.py) ================================================ FILE: section5/sample_code_c5_1.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as signal #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_file="./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav" wav=wave.open(clean_wave_file) data=wav.readframes(wav.getnframes()) data=np.frombuffer(data, dtype=np.int16) data=data/np.iinfo(np.int16).max wav.close() #サンプリング周波数 sample_rate=16000 #畳み込むインパルス応答長 n_impulse_length=512 #インパルス応答を乱数で生成(ダミー) impulse_response=np.random.normal(size=n_impulse_length) conv_data=signal.convolve(data,impulse_response,mode='full') #ファイルに書き込む data_scale_adjust=conv_data*np.iinfo(np.int16).max/20. data_scale_adjust=data_scale_adjust.astype(np.int16) wave_out=wave.open("./conv_out.wav","w") wave_out.setnchannels(1) wave_out.setsampwidth(2) wave_out.setframerate(sample_rate) wave_out.writeframes(data_scale_adjust) wave_out.close() ================================================ FILE: section5/sample_code_c5_2.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #サンプリングレート [Hz] sample_rate=16000 #フレームサイズ N=1024 #周波数の数 Nk=N/2+1 #各ビンの周波数 freqs=np.arange(0,Nk,1)*sample_rate/N #マイクロホンアレイのマイク配置 mic_alignments = np.array( [ [-0.01, 0.0, 0.0], [0.01, 0.0, 0.0], ] ).T #音源の方向 doas=np.array( [[np.pi/2,0], [np.pi/2,np.pi] ] ) #音源とマイクロホンの距離 distance=1 #音源の位置ベクトル source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[2, :] = np.cos(doas[:, 0]) source_locations *= distance #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) near_steering_vectors=calculate_steering_vector(mic_alignments,source_locations,freqs,is_use_far=False) #Far仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) far_steering_vectors=calculate_steering_vector(mic_alignments,source_locations,freqs,is_use_far=True) #内積を計算 inner_product=np.einsum("ksm,ksm->ks",np.conjugate(near_steering_vectors),far_steering_vectors) print(np.average(np.abs(inner_product))) ================================================ FILE: section6/sample_code_c6_10.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #雑音だけの区間のサンプル数を設定 n_noise_only=40000 #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskmn",stft_data[...,:n_noise_only_frame],np.conjugate(stft_data[...,:n_noise_only_frame])) #共分散行列の逆行列を計算する Rcov_inverse=np.linalg.pinv(Rcov) #フィルタを計算する Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] #フィルタをかける s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) #時間領域の波形に戻す t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(mvdr_out[n_noise_only:],"./mlbf_out.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_11.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp import scipy as scipy #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #雑音だけの区間のサンプル数を設定 n_noise_only=40000 #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesktmn",stft_data,np.conjugate(stft_data)) #雑音の共分散行列 freq,mic,mic Rn=np.average(xx_H[:,:n_noise_only_frame,...],axis=1) #入力共分散行列 Rs=np.average(xx_H[:,n_noise_only_frame:,...],axis=1) #一般化固有値分解 max_snr_filter=None for k in range(Nk): w,v=scipy.linalg.eigh(Rs[k,...],Rn[k,...]) if max_snr_filter is None: max_snr_filter=v[None,:,-1] else: max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) Rs_w=np.einsum("kmn,kn->km",Rs,max_snr_filter) beta=Rs_w[:,0]/np.einsum("km,km->k",np.conjugate(max_snr_filter),Rs_w) w_max_snr=beta[:,None]*max_snr_filter #フィルタをかける c_hat=np.einsum("km,mkt->kt",np.conjugate(w_max_snr),stft_data) #時間領域の波形に戻す t,maxsnr_out=sp.istft(c_hat,fs=sample_rate,window="hann",nperseg=N) #大きさを調整する maxsnr_out=maxsnr_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(maxsnr_out[n_noise_only:],"./maxsnr_out.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_12.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp import scipy as scipy #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #雑音だけの区間のサンプル数を設定 n_noise_only=40000 #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesktmn",stft_data,np.conjugate(stft_data)) #雑音の倍率 mu=1.0 #雑音の共分散行列 freq,mic,mic Rn=np.average(xx_H[:,:n_noise_only_frame,...],axis=1) #入力共分散行列 Rs=np.average(xx_H[:,n_noise_only_frame:,...],axis=1)-Rn #固有値分解をして半正定行列に変換 w,v=np.linalg.eigh(Rs) Rs_org=Rs.copy() w[np.real(w)<0]=0 Rs=np.einsum("kmi,ki,kni->kmn",v,w,np.conjugate(v)) #入力共分散行列 Rs_muRn=Rs+Rn*mu invRs_muRn=np.linalg.pinv(Rs_muRn) #フィルタ生成 W_mwf=np.einsum("kmi,kin->kmn",invRs_muRn,Rs) #フィルタをかける c_hat=np.einsum("kim,ikt->mkt",np.conjugate(W_mwf),stft_data) #時間領域の波形に戻す t,mwf_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する mwf_out=mwf_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(mwf_out[n_noise_only:],"./mwf_out_{}.wav".format(mu),sample_rate) ================================================ FILE: section6/sample_code_c6_13.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp import scipy as scipy #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #遅延和アレイを実行する #x:入力信号( M, Nk, Lt) #a:ステアリングベクトル(Nk, M) #return y 出力信号(M, Nk, Lt) def execute_dsbf(x,a): #遅延和アレイを実行する s_hat=np.einsum("km,mkt->kt",np.conjugate(a),x) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,a) return(c_hat) #MVDRを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #a:ステアリングベクトル(Nk, M) #return y 出力信号(M, Nk, Lt) def execute_mvdr(x,y,a): #共分散行列を計算する Rcov=np.einsum("mkt,nkt->kmn",y,np.conjugate(y)) #共分散行列の逆行列を計算する Rcov_inverse=np.linalg.pinv(Rcov) #フィルタを計算する Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,a) a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(a),Rcov_inverse_a) w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] #フィルタをかける s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),x) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,a) return(c_hat) #MaxSNRを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #return y 出力信号(M, Nk, Lt) def execute_max_snr(x,y): #雑音の共分散行列 freq,mic,mic Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) #入力共分散行列 Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) #周波数の数を取得 Nk=np.shape(Rs)[0] #一般化固有値分解 max_snr_filter=None for k in range(Nk): w,v=scipy.linalg.eigh(Rs[k,...],Rn[k,...]) if max_snr_filter is None: max_snr_filter=v[None,:,-1] else: max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) Rs_w=np.einsum("kmn,kn->km",Rs,max_snr_filter) beta=Rs_w/np.einsum("km,km->k",np.conjugate(max_snr_filter),Rs_w)[:,None] w_max_snr=beta[:,None,:]*max_snr_filter[...,None] #フィルタをかける c_hat=np.einsum("kim,ikt->mkt",np.conjugate(w_max_snr),x) return(c_hat) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #ファイルに書き込む #MWFを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #mu: 雑音共分散行列の係数 #return y 出力信号(M, Nk, Lt) def execute_mwf(x,y,mu): #雑音の共分散行列 freq,mic,mic Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) #入力共分散行列 Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) #固有値分解をして半正定行列に変換 w,v=np.linalg.eigh(Rs) Rs_org=Rs.copy() w[np.real(w)<0]=0 Rs=np.einsum("kmi,ki,kni->kmn",v,w,np.conjugate(v)) #入力共分散行列 Rs_muRn=Rs+Rn*mu invRs_muRn=np.linalg.pinv(Rs_muRn) #フィルタ生成 W_mwf=np.einsum("kmi,kin->kmn",invRs_muRn,Rs) #フィルタをかける c_hat=np.einsum("kim,ikt->mkt",np.conjugate(W_mwf),x) return(c_hat) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #雑音だけの区間のサンプル数を設定 n_noise_only=40000 #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #遅延和アレイを実行する #x:入力信号( M, Nk, Lt) #a:ステアリングベクトル(Nk, M) #return y 出力信号(M, Nk, Lt) def execute_dsbf(x,a): #遅延和アレイを実行する s_hat=np.einsum("km,mkt->kt",np.conjugate(a),x) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,a) return(c_hat) #MVDRを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #a:ステアリングベクトル(Nk, M) #return y 出力信号(M, Nk, Lt) def execute_mvdr(x,y,a): #共分散行列を計算する Rcov=np.einsum("mkt,nkt->kmn",y,np.conjugate(y)) #共分散行列の逆行列を計算する Rcov_inverse=np.linalg.pinv(Rcov) #フィルタを計算する Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,a) a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(a),Rcov_inverse_a) w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] #フィルタをかける s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),x) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,a) return(c_hat) #MaxSNRを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #return y 出力信号(M, Nk, Lt) def execute_max_snr(x,y): #雑音の共分散行列 freq,mic,mic Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) #入力共分散行列 Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) #周波数の数を取得 Nk=np.shape(Rs)[0] #一般化固有値分解 max_snr_filter=None for k in range(Nk): w,v=scipy.linalg.eigh(Rs[k,...],Rn[k,...]) if max_snr_filter is None: max_snr_filter=v[None,:,-1] else: max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) Rs_w=np.einsum("kmn,kn->km",Rs,max_snr_filter) beta=Rs_w/np.einsum("km,km->k",np.conjugate(max_snr_filter),Rs_w)[:,None] w_max_snr=beta[:,None,:]*max_snr_filter[...,None] #フィルタをかける c_hat=np.einsum("kim,ikt->mkt",np.conjugate(w_max_snr),x) return(c_hat) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #ファイルに書き込む #MWFを実行する #x:入力信号( M, Nk, Lt) #y:共分散行列を計算する信号(M,Nk,Lt) #mu: 雑音共分散行列の係数 #return y 出力信号(M, Nk, Lt) def execute_mwf(x,y,mu): #雑音の共分散行列 freq,mic,mic Rn=np.average(np.einsum("mkt,nkt->ktmn",y,np.conjugate(y)),axis=1) #入力共分散行列 Rs=np.average(np.einsum("mkt,nkt->ktmn",x,np.conjugate(x)),axis=1) #固有値分解をして半正定行列に変換 w,v=np.linalg.eigh(Rs) Rs_org=Rs.copy() w[np.real(w)<0]=0 Rs=np.einsum("kmi,ki,kni->kmn",v,w,np.conjugate(v)) #入力共分散行列 Rs_muRn=Rs+Rn*mu invRs_muRn=np.linalg.pinv(Rs_muRn) #フィルタ生成 W_mwf=np.einsum("kmi,kin->kmn",invRs_muRn,Rs) #フィルタをかける c_hat=np.einsum("kim,ikt->mkt",np.conjugate(W_mwf),x) return(c_hat) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #雑音だけの区間のサンプル数を設定 n_noise_only=40000 #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) #時間領域の波形に戻す t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する ds_out=ds_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(ds_out,"./ds_out.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_3.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) #時間領域の波形に戻す t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する ds_out=ds_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(ds_out,"./ds_out_m32.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_4.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) #時間領域の波形に戻す t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する ds_out=ds_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(ds_out,"./ds_out.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_5.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesskt",np.conjugate(near_steering_vectors),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("skt,ksm->mskt",s_hat,near_steering_vectors) #時間領域の波形に戻す t,ds_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する ds_out=ds_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(ds_out,"./ds_interference_out_m32.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_6.py ================================================ import numpy as np import scipy.signal as sp import matplotlib.pyplot as plt #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #サンプリング周波数 sample_rate=16000 #フレームサイズ N=1024 #周波数の数 Nk=N/2+1 #各ビンの周波数 freqs=np.arange(0,Nk,1)*sample_rate/N #マイクロホンアレイのマイク配置 mic_alignments = np.array( [[x,0.0,0.0] for x in np.arange(-0.01,0.02,0.02)] ) #マイクロホン数 n_channels=np.shape(mic_alignments)[0] #音源の場所 doas=np.array( [[np.pi/2.,theta] for theta in np.arange(-np.pi,np.pi,1./180.*np.pi)] ) #音源とマイクロホンの距離 distance=1. source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[2, :] = np.cos(doas[:, 0]) source_locations *= distance #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) near_steering_vectors=calculate_steering_vector(mic_alignments.T,source_locations,freqs,is_use_far=False) #theta=0に最も近いステアリングベクトルを取り出す desired_index=np.argmin(np.abs(doas[:,1]),axis=0) #所望音のステアリングベクトル desired_steering_vector=near_steering_vectors[:,desired_index,:] #内積計算 directivity_pattern=np.square(np.abs(np.einsum("km,ksm->ks",np.conjugate(desired_steering_vector),near_steering_vectors))) #スタイル plt.style.use("grayscale") #音声データをプロットする fig=plt.figure(figsize=(7,7)) # plot ax = plt.subplot(111, projection="polar") #グラフの向き、グリッドの線種を指定 ax.set_theta_zero_location('N') ax.set_theta_direction('clockwise') ax.grid(linestyle="--") #y軸のラベル調整 ax.yaxis.labelpad = -250 ylabel=plt.ylabel("Response [dB]") ylabel.set_position((0, 0.6)) ylabel.set_rotation(0) plt.yticks([-20,-10,0]) plt.ylim([-30,0]) #x軸のラベル plt.xlabel("Azimuth [degrees]") #描画する周波数 draw_freqs=np.array([1000,2000,3000,4000]) draw_freq_list=np.argmin(np.abs(freqs[:,None]-draw_freqs[None,:]),axis=0) for draw_freq_index in draw_freq_list: #周波数毎に指向特性を描画 plt.plot(doas[:,1], 10.*np.log10(directivity_pattern[draw_freq_index,:]),lw=3,label="{} [Hz]".format(freqs[draw_freq_index])) plt.legend(loc=(0.2,0.6)) #音声ファイルを画像として保存 plt.savefig("./directivity_pattern.png") #画像を画面に表示 plt.show() ================================================ FILE: section6/sample_code_c6_7.py ================================================ import numpy as np import scipy.signal as sp import matplotlib.pyplot as plt #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #サンプリング周波数 sample_rate=16000 #フレームサイズ N=1024 #周波数の数 Nk=N/2+1 #各ビンの周波数 freqs=np.arange(0,Nk,1)*sample_rate/N #マイクロホンアレイのマイク配置 mic_alignments = np.array( [[x,0.0,0.0] for x in np.arange(-0.31,0.32,0.02)] ) #マイクロホン数 n_channels=np.shape(mic_alignments)[0] #音源の場所 doas=np.array( [[np.pi/2.,theta] for theta in np.arange(-np.pi,np.pi,1./180.*np.pi)] ) #音源とマイクロホンの距離 distance=1. source_locations=np.zeros((3, doas.shape[0]), dtype=doas.dtype) source_locations[0, :] = np.cos(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[1, :] = np.sin(doas[:, 1]) * np.sin(doas[:, 0]) source_locations[2, :] = np.cos(doas[:, 0]) source_locations *= distance #Near仮定に基づくステアリングベクトルを計算: steering_vectors(Nk x Ns x M) near_steering_vectors=calculate_steering_vector(mic_alignments.T,source_locations,freqs,is_use_far=False) #theta=0に最も近いステアリングベクトルを取り出す desired_index=np.argmin(np.abs(doas[:,1]),axis=0) #所望音のステアリングベクトル desired_steering_vector=near_steering_vectors[:,desired_index,:] #内積計算 directivity_pattern=np.square(np.abs(np.einsum("km,ksm->ks",np.conjugate(desired_steering_vector),near_steering_vectors))) #スタイル plt.style.use("grayscale") #音声データをプロットする fig=plt.figure(figsize=(7,7)) # plot ax = plt.subplot(111, projection="polar") #グラフの向き、グリッドの線種を指定 ax.set_theta_zero_location('N') ax.set_theta_direction('clockwise') ax.grid(linestyle="--") ax.yaxis.labelpad = -30 #x軸のラベル plt.xlabel("Azimuth [degrees]") #y軸のラベル ylabel=plt.ylabel("Response [dB]") ylabel.set_position((0, 0.6)) ylabel.set_rotation(0) plt.yticks([-20,-10,0]) plt.ylim([-30,0]) #描画する周波数 draw_freqs=np.array([1000,2000,3000,4000]) draw_freq_list=np.argmin(np.abs(freqs[:,None]-draw_freqs[None,:]),axis=0) for draw_freq_index in draw_freq_list: #周波数毎に指向特性を描画 plt.plot(doas[:,1], 10.*np.log10(directivity_pattern[draw_freq_index,:]),lw=3,label="{} [Hz]".format(freqs[draw_freq_index])) plt.legend(loc=(0.2,0.6)) #音声ファイルを画像として保存 plt.savefig("./directivity_pattern_m32.png") #画像を画面に表示 plt.show() ================================================ FILE: section6/sample_code_c6_8.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskmn",stft_data,np.conjugate(stft_data)) #共分散行列の逆行列を計算する Rcov_inverse=np.linalg.pinv(Rcov) #フィルタを計算する Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] #フィルタをかける s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) #時間領域の波形に戻す t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(mvdr_out,"./mvdr_out.wav",sample_rate) ================================================ FILE: section6/sample_code_c6_9.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp #ステアリングベクトルを算出 #mic_position: 3 x M dimensional ndarray [[x,y,z],[x,y,z]] #source_position: 3x Ns dimensional ndarray [[x,y,z],[x,y,z] ] #freqs: Nk dimensional array [f1,f2,f3...] #sound_speed: 音速 [m/s] #is_use_far: Farを使う場合はTrue, Nearの場合はFalse, #return: steering vector (Nk x Ns x M) def calculate_steering_vector(mic_alignments,source_locations,freqs,sound_speed=340,is_use_far=False): #マイク数を取得 n_channels=np.shape(mic_alignments)[1] #音源数を取得 n_source=np.shape(source_locations)[1] if is_use_far==True: #音源位置を正規化 norm_source_locations=source_locations/np.linalg.norm(source_locations,2,axis=0,keepdims=True) #位相を求める steering_phase=np.einsum('k,ism,ism->ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskmn",stft_data,np.conjugate(stft_data)) #共分散行列の逆行列を計算する Rcov_inverse=np.linalg.pinv(Rcov) #フィルタを計算する Rcov_inverse_a=np.einsum("kmn,kn->km",Rcov_inverse,near_steering_vectors[:,0,:]) a_H_Rcov_inverse_a=np.einsum("kn,kn->k",np.conjugate(near_steering_vectors[:,0,:]),Rcov_inverse_a) w_mvdr=Rcov_inverse_a/np.maximum(a_H_Rcov_inverse_a,1.e-18)[:,None] #フィルタをかける s_hat=np.einsum("km,mkt->kt",np.conjugate(w_mvdr),stft_data) #ステアリングベクトルをかける c_hat=np.einsum("kt,km->mkt",s_hat,near_steering_vectors[:,0,:]) #時間領域の波形に戻す t,mvdr_out=sp.istft(c_hat[0],fs=sample_rate,window="hann",nperseg=N) #大きさを調整する mvdr_out=mvdr_out*np.iinfo(np.int16).max/20. #ファイルに書き込む write_file_from_time_signal(mvdr_out,"./mvdr_interference_out.wav",sample_rate) ================================================ FILE: section6.md ================================================ ## 第6章のサンプルコード * [Far/Nearの両方に対応したステアリングベクトル計算コード](section6/sample_code_c6_1.py) * [遅延和アレイによる雑音抑圧](section6/sample_code_c6_2.py) * [遅延和アレイによる雑音抑圧(マイクロホンの数を変更)](section6/sample_code_c6_3.py) * [他の人の声が混入した際に、遅延和アレイにより音源分離](section6/sample_code_c6_4.py) * [他の人の声が混入した際に、遅延和アレイにより音源分離(マイクロホンの数を変更)](section6/sample_code_c6_5.py) * [指向特性を計算](section6/sample_code_c6_6.py) * [指向特性を計算(マイクロホンの数を変更)](section6/sample_code_c6_7.py) * [最小分散無歪ビームフォーマMVDRを用いた雑音抑圧](section6/sample_code_c6_8.py) * [最小分散無歪ビームフォーマMVDRを用いた干渉音抑圧](section6/sample_code_c6_9.py) * [最ゆうビームフォーマ](section6/sample_code_c6_10.py) * [最大SNRビームフォーマ(MaxSNR)に基づく音源分離](section6/sample_code_c6_11.py) * [マルチチャンネルウィナーフィルタ(MWF)に基づく音源分離](section6/sample_code_c6_12.py) * [DSBF、MVDR、MaxSNR、MWFの全手法のSNR向上率を評価](section6/sample_code_c6_13.py) * [DSBF、MVDR、MaxSNR、MWFの全手法のSNR向上率を評価(音源数を2に設定)](section6/sample_code_c6_14.py) ================================================ FILE: section7/sample_code_c7_1.py ================================================ import wave as wave import pyroomacoustics as pa import numpy as np import scipy.signal as sp import scipy as scipy #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #遅延和アレイを実行する #x_left:左の音源に近いマイクロホン(Nk, Lt) #x_right:右の音源に近いマイクロホン(Nk,Lt) #is_use_amplitude: 振幅差を使って分離を行う場合はTrue #return y_left 左のマイクに近い音源の出力信号(Nk, Lt) # y_right 右のマイクに近い音源の出力信号(Nk,Lt) def execute_two_microphone_sparse_separation(x_left,x_right,is_use_amplitude=False): if is_use_amplitude==True: #振幅比率を使った分離 amp_ratio=np.abs(x_left)/np.maximum(np.abs(x_right),1.e-18) y_left=(amp_ratio > 1.).astype(np.float)*x_left y_right=(amp_ratio <= 1.).astype(np.float)*x_right else: #位相差を用いた分離 phase_difference=np.angle(x_left/x_right) y_left=(phase_difference > 0.).astype(np.float)*x_left y_right=(phase_difference <= 0.).astype(np.float)*x_right return(y_left,y_right) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samples 1.).astype(np.float)*x_left y_right=(amp_ratio <= 1.).astype(np.float)*x_right else: #位相差を用いた分離 phase_difference=np.angle(x_left/x_right) y_left=(phase_difference > 0.).astype(np.float)*x_left y_right=(phase_difference <= 0.).astype(np.float)*x_right return(y_left,y_right) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #スパース性に基づく分離 #input_vectors:マイクロホン入力信号(Nm,Nk, Lt) #steering_vectors:ステアリングベクトル(Nk,|Ω|,Nm) #omega: 目的音の範囲(Ns,|Ω|) #return y:出力信号(Nm,Ns,Nk, Lt) def execute_doa_sparse_separation(input_vectors,steering_vectors,omega): inner_product=np.einsum("kim,mkt->kit",np.conjugate(steering_vectors),input_vectors) n_omega=np.shape(omega)[1] estimate_doas=np.argmax(np.abs(inner_product),axis=1) estimate_doa_mask=np.identity(n_omega)[estimate_doas] output_mask=np.einsum("kti,si->skt",estimate_doa_mask,omega) y=np.einsum("skt,mkt->mskt",output_mask,input_vectors) return(y) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesnp.pi,diff-np.pi*2,diff) return(diff) #所望音の方向から±th度以内 omega=np.array([ np.abs(modify_angle_diff(virtual_doas[:,1]-doas[s,1]))ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #共分散行列からステアリングベクトルを推定する #Rs: 共分散行列(Ns, Nk, M, M) #steering_vector(Ns, Nk, M) def estimate_steering_vector(Rs): #固有値分解を実施して最大固有値を与える固有ベクトルを取得 w,v=np.linalg.eigh(Rs) steering_vector=v[...,-1] return(steering_vector) #マスクと入力信号から共分散行列を推定 #x:入力信号(M,Nk,Lt) #mask:音源毎の時間周波数マスク(Ns, Nk, Lt) #return Rs 音源共分散行列(Ns, Nk,M,M), Rn 雑音共分散行列(Ns, Nk,M,M) def estimate_covariance_matrix(x,mask): #目的音の共分散行列を推定する Rs=np.einsum("skt,mkt,nkt->skmn",mask,x,np.conjugate(x)) sum_mask=np.sum(mask,axis=2) Rs=Rs/np.maximum(sum_mask,1.e-18)[...,None,None] #雑音共分散行列を推定する Rn=np.einsum("skt,mkt,nkt->skmn",1.-mask,x,np.conjugate(x)) sum_noise_mask=np.sum(1.-mask,axis=2) Rn=Rn/np.maximum(sum_noise_mask,1.e-18)[...,None,None] #固有値分解をして半正定行列に変換 w,v=np.linalg.eigh(Rs) Rs_org=Rs.copy() w[np.real(w)<1.e-18]=1.e-18 Rs=np.einsum("skmi,ski,skni->skmn",v,w,np.conjugate(v)) w,v=np.linalg.eigh(Rn) Rn_org=Rn.copy() w[np.real(w)<1.e-18]=1.e-18 Rn=np.einsum("skmi,ski,skni->skmn",v,w,np.conjugate(v)) return(Rs,Rn) #スパース性に基づく分離 #x:入力信号(M,Nk,Lt) #mask:音源毎の時間周波数マスク(Ns, Nk, Lt) #return c_hat:出力信号(Nm,Ns,Nk, Lt) def execute_sparse(x,mask): c_hat=np.einsum("skt,mkt->mskt",mask,x) return(c_hat) #ファイルに書き込む #MWFを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs: 音源共分散行列(Ns, Nk,M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mwf(x,Rn,Rs): #入力信号に対する共分散行列の逆行列を計算 Rx_inverse=np.linalg.pinv(Rn+Rs) #フィルタ生成 W_mwf=np.einsum("skmi,skin->skmn",Rx_inverse,Rs) #フィルタをかける c_hat=np.einsum("skim,ikt->mskt",np.conjugate(W_mwf),x) return(c_hat) #遅延和アレイを実行する #x:入力信号( M, Nk, Lt) #a:ステアリングベクトル(Ns,Nk, M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_dsbf(x,a): #遅延和アレイを実行する s_hat=np.einsum("skm,mkt->skt",np.conjugate(a),x) #ステアリングベクトルをかける c_hat=np.einsum("skt,skm->mskt",s_hat,a) return(c_hat) #MVDRを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #a:ステアリングベクトル(Ns,Nk, M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mvdr(x,Rn,a): #共分散行列の逆行列を計算する Rn_inverse=np.linalg.pinv(Rn) #フィルタを計算する Rn_inverse_a=np.einsum("skmn,skn->skm",Rn_inverse,a) a_H_Rn_inverse_a=np.einsum("skn,skn->sk",np.conjugate(a),Rn_inverse_a) w_mvdr=Rn_inverse_a/np.maximum(a_H_Rn_inverse_a,1.e-18)[...,None] #フィルタをかける s_hat=np.einsum("skm,mkt->skt",np.conjugate(w_mvdr),x) #ステアリングベクトルをかける c_hat=np.einsum("skt,skm->mskt",s_hat,a) return(c_hat) #MVDR2を実行する(共分散行列のみから計算) #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs:目的音の共分散行列(Ns,Nk, M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mvdr2(x,Rn,Rs): #共分散行列の逆行列を計算する Rn_inverse=np.linalg.pinv(Rn) #フィルタを計算する Rn_inverse_Rs=np.einsum("skmi,skin->skmn",Rn_inverse,Rs) w_mvdr=Rn_inverse_Rs/np.maximum(np.trace(Rn_inverse_Rs,axis1=-2,axis2=-1),1.e-18)[...,None,None] #フィルタをかける c_hat=np.einsum("skmn,mkt->nskt",np.conjugate(w_mvdr),x) return(c_hat) #MaxSNRを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs:目的音の共分散行列(Ns,Nk, M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_max_snr(x,Rn,Rs): #音源・周波数・マイクロホンの数を取得 Ns=np.shape(Rs)[0] Nk=np.shape(Rs)[1] M=np.shape(Rs)[2] #一般化固有値分解 max_snr_filter=None for s in range(Ns): for k in range(Nk): w,v=scipy.linalg.eigh(Rs[s,k,...],Rn[s,k,...]) if max_snr_filter is None: max_snr_filter=v[None,:,-1] else: max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) max_snr_filter=np.reshape(max_snr_filter,(Ns,Nk,M)) Rs_w=np.einsum("skmn,skn->skm",Rs,max_snr_filter) beta=Rs_w/np.einsum("skm,skm->sk",np.conjugate(max_snr_filter),Rs_w)[...,None] w_max_snr=beta[...,None,:]*max_snr_filter[...,None] #フィルタをかける c_hat=np.einsum("skim,ikt->mskt",np.conjugate(w_max_snr),x) return(c_hat) #時間周波数マスクを推定する #input_vectors:マイクロホン入力信号(Nm,Nk, Lt) #steering_vectors:ステアリングベクトル(Nk,|Ω|,Nm) #omega: 目的音の範囲(Ns,|Ω|) #return mask:出力信号(Ns,Nk, Lt) def estimate_mask(input_vectors,steering_vectors,omega): inner_product=np.einsum("kim,mkt->kit",np.conjugate(steering_vectors),input_vectors) n_omega=np.shape(omega)[1] estimate_doas=np.argmax(np.abs(inner_product),axis=1) estimate_doa_mask=np.identity(n_omega)[estimate_doas] mask=np.einsum("kti,si->skt",estimate_doa_mask,omega) return(mask) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesnp.pi,diff-np.pi*2,diff) return(diff) #所望音の方向から±th度以内 omega=np.array([ np.abs(modify_angle_diff(virtual_doas[:,1]-doas[s,1]))ksm',2.j*np.pi/sound_speed*freqs,norm_source_locations[...,None],mic_alignments[:,None,:]) #ステアリングベクトルを算出 steering_vector=1./np.sqrt(n_channels)*np.exp(steering_phase) return(steering_vector) else: #音源とマイクの距離を求める #distance: Ns x Nm distance=np.sqrt(np.sum(np.square(source_locations[...,None]-mic_alignments[:,None,:]),axis=0)) #遅延時間(delay) [sec] delay=distance/sound_speed #ステアリングベクトルの位相を求める steering_phase=np.einsum('k,sm->ksm',-2.j*np.pi*freqs,delay) #音量の減衰 steering_decay_ratio=1./distance #ステアリングベクトルを求める steering_vector=steering_decay_ratio[None,...]*np.exp(steering_phase) #大きさを1で正規化する steering_vector=steering_vector/np.linalg.norm(steering_vector,2,axis=2,keepdims=True) return(steering_vector) #共分散行列からステアリングベクトルを推定する #Rs: 共分散行列(Ns, Nk, M, M) #steering_vector(Ns, Nk, M) def estimate_steering_vector(Rs): #固有値分解を実施して最大固有値を与える固有ベクトルを取得 w,v=np.linalg.eigh(Rs) steering_vector=v[...,-1] return(steering_vector) #マスクと入力信号から共分散行列を推定 #x:入力信号(M,Nk,Lt) #mask:音源毎の時間周波数マスク(Ns, Nk, Lt) #return Rs 音源共分散行列(Ns, Nk,M,M), Rn 雑音共分散行列(Ns, Nk,M,M) def estimate_covariance_matrix(x,mask): #目的音の共分散行列を推定する Rs=np.einsum("skt,mkt,nkt->skmn",mask,x,np.conjugate(x)) sum_mask=np.sum(mask,axis=2) Rs=Rs/np.maximum(sum_mask,1.e-18)[...,None,None] #雑音共分散行列を推定する Rn=np.einsum("skt,mkt,nkt->skmn",1.-mask,x,np.conjugate(x)) sum_noise_mask=np.sum(1.-mask,axis=2) Rn=Rn/np.maximum(sum_noise_mask,1.e-18)[...,None,None] #固有値分解をして半正定行列に変換 w,v=np.linalg.eigh(Rs) Rs_org=Rs.copy() w[np.real(w)<1.e-18]=1.e-18 Rs=np.einsum("skmi,ski,skni->skmn",v,w,np.conjugate(v)) w,v=np.linalg.eigh(Rn) Rn_org=Rn.copy() w[np.real(w)<1.e-18]=1.e-18 Rn=np.einsum("skmi,ski,skni->skmn",v,w,np.conjugate(v)) return(Rs,Rn) #スパース性に基づく分離 #x:入力信号(M,Nk,Lt) #mask:音源毎の時間周波数マスク(Ns, Nk, Lt) #return c_hat:出力信号(Nm,Ns,Nk, Lt) def execute_sparse(x,mask): c_hat=np.einsum("skt,mkt->mskt",mask,x) return(c_hat) #ファイルに書き込む #MWFを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs: 音源共分散行列(Ns, Nk,M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mwf(x,Rn,Rs): #入力信号に対する共分散行列の逆行列を計算 Rx_inverse=np.linalg.pinv(Rn+Rs) #フィルタ生成 W_mwf=np.einsum("skmi,skin->skmn",Rx_inverse,Rs) #フィルタをかける c_hat=np.einsum("skim,ikt->mskt",np.conjugate(W_mwf),x) return(c_hat) #遅延和アレイを実行する #x:入力信号( M, Nk, Lt) #a:ステアリングベクトル(Ns,Nk, M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_dsbf(x,a): #遅延和アレイを実行する s_hat=np.einsum("skm,mkt->skt",np.conjugate(a),x) #ステアリングベクトルをかける c_hat=np.einsum("skt,skm->mskt",s_hat,a) return(c_hat) #MVDRを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #a:ステアリングベクトル(Ns,Nk, M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mvdr(x,Rn,a): #共分散行列の逆行列を計算する Rn_inverse=np.linalg.pinv(Rn) #フィルタを計算する Rn_inverse_a=np.einsum("skmn,skn->skm",Rn_inverse,a) a_H_Rn_inverse_a=np.einsum("skn,skn->sk",np.conjugate(a),Rn_inverse_a) w_mvdr=Rn_inverse_a/np.maximum(a_H_Rn_inverse_a,1.e-18)[...,None] #フィルタをかける s_hat=np.einsum("skm,mkt->skt",np.conjugate(w_mvdr),x) #ステアリングベクトルをかける c_hat=np.einsum("skt,skm->mskt",s_hat,a) return(c_hat) #MVDR2を実行する(共分散行列のみから計算) #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs:目的音の共分散行列(Ns,Nk, M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_mvdr2(x,Rn,Rs): #共分散行列の逆行列を計算する Rn_inverse=np.linalg.pinv(Rn) #フィルタを計算する Rn_inverse_Rs=np.einsum("skmi,skin->skmn",Rn_inverse,Rs) w_mvdr=Rn_inverse_Rs/np.maximum(np.trace(Rn_inverse_Rs,axis1=-2,axis2=-1),1.e-18)[...,None,None] #フィルタをかける c_hat=np.einsum("skmn,mkt->nskt",np.conjugate(w_mvdr),x) return(c_hat) #MaxSNRを実行する #x:入力信号( M, Nk, Lt) #Rn: 雑音共分散行列(Ns, Nk,M,M) #Rs:目的音の共分散行列(Ns,Nk, M,M) #return c_hat 出力信号(M, Ns,Nk, Lt) def execute_max_snr(x,Rn,Rs): #音源・周波数・マイクロホンの数を取得 Ns=np.shape(Rs)[0] Nk=np.shape(Rs)[1] M=np.shape(Rs)[2] #一般化固有値分解 max_snr_filter=None for s in range(Ns): for k in range(Nk): w,v=scipy.linalg.eigh(Rs[s,k,...],Rn[s,k,...]) if max_snr_filter is None: max_snr_filter=v[None,:,-1] else: max_snr_filter=np.concatenate((max_snr_filter,v[None,:,-1]),axis=0) max_snr_filter=np.reshape(max_snr_filter,(Ns,Nk,M)) Rs_w=np.einsum("skmn,skn->skm",Rs,max_snr_filter) beta=Rs_w/np.einsum("skm,skm->sk",np.conjugate(max_snr_filter),Rs_w)[...,None] w_max_snr=beta[...,None,:]*max_snr_filter[...,None] #フィルタをかける c_hat=np.einsum("skim,ikt->mskt",np.conjugate(w_max_snr),x) return(c_hat) #時間周波数マスクを推定する #input_vectors:マイクロホン入力信号(Nm,Nk, Lt) #steering_vectors:ステアリングベクトル(Nk,|Ω|,Nm) #omega: 目的音の範囲(Ns,|Ω|) #return mask:出力信号(Ns,Nk, Lt) def estimate_mask(input_vectors,steering_vectors,omega): inner_product=np.einsum("kim,mkt->kit",np.conjugate(steering_vectors),input_vectors) n_omega=np.shape(omega)[1] estimate_doas=np.argmax(np.abs(inner_product),axis=1) estimate_doa_mask=np.identity(n_omega)[estimate_doas] mask=np.einsum("kti,si->skt",estimate_doa_mask,omega) return(mask) #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesnp.pi,diff-np.pi*2,diff) return(diff) #所望音の方向から±th度以内 omega=np.array([ np.abs(modify_angle_diff(virtual_doas[:,1]-doas[s,1]))mkt',W,x) #コントラスト関数を計算 G=contrast_func(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #コンストラクト関数の微分を取得 phi=phi_func(s_hat) phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) phi_s=np.mean(phi_s,axis=1) I=np.eye(M,M) if is_use_non_holonomic==False: deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) else: mask=(np.ones((M,M))-I)[None,...] deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) #フィルタを更新する W=W+mu*deltaW #最後に出力信号を分離 s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesmkt',W,x) #コントラスト関数を計算 G=contrast_func(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #コンストラクト関数の微分を取得 phi=phi_func(s_hat) phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) phi_s=np.mean(phi_s,axis=1) I=np.eye(M,M) if is_use_non_holonomic==False: deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) else: mask=(np.ones((M,M))-I)[None,...] deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) #フィルタを更新する W=W+mu*deltaW #最後に出力信号を分離 s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_multivariate_laplacian_iva(x,W,n_iterations=20): #マイクロホン数を取得する M=np.shape(x)[0] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) #補助変数を更新する v=np.sqrt(np.sum(np.square(np.abs(s_hat)),axis=1)) #コントラスト関数を計算 G=contrast_multivariate_laplacian(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('st,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesmkt',W,x) #コントラスト関数を計算 G=contrast_func(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #コンストラクト関数の微分を取得 phi=phi_func(s_hat) phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) phi_s=np.mean(phi_s,axis=1) I=np.eye(M,M) if is_use_non_holonomic==False: deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) else: mask=(np.ones((M,M))-I)[None,...] deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) #フィルタを更新する W=W+mu*deltaW #最後に出力信号を分離 s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_multivariate_laplacian_iva(x,W,n_iterations=20): #マイクロホン数を取得する M=np.shape(x)[0] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) #補助変数を更新する v=np.sqrt(np.sum(np.square(np.abs(s_hat)),axis=1)) #コントラスト関数を計算 G=contrast_multivariate_laplacian(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('st,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma(x,W,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) s_power=np.square(np.abs(s_hat)) #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('skt,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samplesmkt',W,x) #コントラスト関数を計算 G=contrast_func(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #コンストラクト関数の微分を取得 phi=phi_func(s_hat) phi_s=np.einsum('mkt,nkt->ktmn',phi,np.conjugate(s_hat)) phi_s=np.mean(phi_s,axis=1) I=np.eye(M,M) if is_use_non_holonomic==False: deltaW=np.einsum('kmi,kin->kmn',I[None,...]-phi_s,W) else: mask=(np.ones((M,M))-I)[None,...] deltaW=np.einsum('kmi,kin->kmn',np.multiply(mask,-phi_s),W) #フィルタを更新する W=W+mu*deltaW #最後に出力信号を分離 s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #EM法によるLGMのパラメータ推定法 #x:入力信号( M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_em_lgm(x,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x),V_inverse,x) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #事後確率計算に必要なパラメータを推定 c_bar=np.einsum('kstmn,nkt->kstm',Wmwf,x) R_bar=np.einsum("kstmi,kstin->kstmn",-1.*Wmwf+np.eye(M),vR) P_bar=R_bar+np.einsum("kstm,kstn->kstmn",c_bar,np.conjugate(c_bar)) #パラメータを更新 R=np.average(P_bar/np.maximum(v,1.e-18)[...,None,None],axis=2) R_inverse=np.linalg.pinv(R) v=np.einsum("ksmi,kstim->kst",R_inverse,P_bar) v=v/np.float(M) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x) return(R,v,c_bar,cost_buff) #IP法によるLGMのパラメータ推定法 #x:入力信号( M, Nk, Lt) #Ns: 音源数 #n_iterations: 繰り返しステップ数 #return R 共分散行列(Nk,Ns,M,M) v 時間周波数分散(Nk,Ns,Lt),c_bar 音源分離信号(M,Ns,Nk,Lt), cost_buff コスト (T) def execute_mm_lgm(x,Ns=2,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] #Rとvを初期化する mask=np.random.uniform(size=Nk*Ns*Lt) mask=np.reshape(mask,(Nk,Ns,Lt)) R=np.einsum("kst,mkt,nkt->kstmn",mask,x,np.conjugate(x)) R=np.average(R,axis=2) v=np.random.uniform(size=Nk*Ns*Lt) v=np.reshape(v,(Nk,Ns,Lt)) cost_buff=[] for t in range(n_iterations): #入力信号の共分散行列を求める vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) #コスト計算 cost=np.sum(np.einsum("mkt,ktmn,nkt->kt",np.conjugate(x),V_inverse,x) +np.log(np.abs(np.linalg.det(V)))) cost/=np.float(Lt) cost=np.real(cost) cost_buff.append(cost) #パラメータを更新 #Rの更新 V_inverseX=np.einsum('ktmn,nkt->ktm',V_inverse,x) V_inverseXV_inverseX=np.einsum('ktm,ktn->ktmn',V_inverseX,np.conjugate(V_inverseX)) A=np.einsum('kst,ktmn->ksmn',v,V_inverse) B=np.einsum('kst,ktmn->ksmn',v,V_inverseXV_inverseX) RBR=np.einsum('ksmn,ksni,ksij->ksmj',R,B,R) invA=np.linalg.pinv(A) A_RBR=np.matmul(A,RBR) R=np.concatenate([np.concatenate([np.matmul(invA[k,s,...],scipy.linalg.sqrtm(A_RBR[k,s,...]))[None,None,...] for k in range(Nk)],axis=0) for s in range(Ns)],axis=1) R=(R+np.transpose(np.conjugate(R),[0,1,3,2]))/(2.0+0.0j) #vの更新 v=v*np.sqrt(np.einsum('ktm,ktn,ksnm->kst',V_inverseX,np.conjugate(V_inverseX),R)/np.maximum(np.einsum('ktmn,ksnm->kst',V_inverse,R) ,1.e-18)) vR=np.einsum("kst,ksmn->kstmn",v,R) V=np.sum(vR,axis=1) V_inverse=np.linalg.pinv(V) Wmwf=np.einsum("kstmi,ktin->kstmn",vR,V_inverse) #音源分離信号を得る c_bar=np.einsum('kstmn,nkt->mskt',Wmwf,x) return(R,v,c_bar,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_multivariate_laplacian_iva(x,W,n_iterations=20): #マイクロホン数を取得する M=np.shape(x)[0] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) #補助変数を更新する v=np.sqrt(np.sum(np.square(np.abs(s_hat)),axis=1)) #コントラスト関数を計算 G=contrast_multivariate_laplacian(s_hat) #コスト計算 cost=np.sum(np.mean(G,axis=-1))-np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('st,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #IP法による分離フィルタ更新 #x:入力信号( M, Nk, Lt) #W: 分離フィルタ(Nk,M,M) #a: アクティビティ(B,M,Lt) #b: 基底(Nk,M,B) #n_iterations: 繰り返しステップ数 #return W 分離フィルタ(Nk,M,M) s_hat 出力信号(M,Nk, Lt),cost_buff コスト (T) def execute_ip_time_varying_gaussian_ilrma(x,W,a,b,n_iterations=20): #マイクロホン数・周波数・フレーム数を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] cost_buff=[] for t in range(n_iterations): #音源分離信号を得る s_hat=np.einsum('kmn,nkt->mkt',W,x) s_power=np.square(np.abs(s_hat)) #時間周波数分散を更新 v=np.einsum("bst,ksb->skt",a,b) #アクティビティの更新 a=a*np.sqrt(np.einsum("ksb,skt->bst",b,s_power/np.maximum(v,1.e-18)**2)/np.einsum("ksb,skt->bst",b,1./np.maximum(v,1.e-18))) #基底の更新 b=b*np.sqrt(np.einsum("bst,skt->ksb",a,s_power /np.maximum(v,1.e-18)**2) /np.einsum("bst,skt->ksb",a,1./np.maximum(v,1.e-18))) #時間周波数分散を再度更新 v=np.einsum("bst,ksb->skt",a,b) #コスト計算 cost=np.sum(np.mean(s_power/np.maximum(v,1.e-18)+np.log(v),axis=-1)) -np.sum(2.*np.log(np.abs(np.linalg.det(W)) )) cost_buff.append(cost) #IP法による更新 Q=np.einsum('skt,mkt,nkt->tksmn',1./np.maximum(v,1.e-18),x,np.conjugate(x)) Q=np.average(Q,axis=0) for source_index in range(M): WQ=np.einsum('kmi,kin->kmn',W,Q[:,source_index,:,:]) invWQ=np.linalg.pinv(WQ) W[:,source_index,:]=np.conjugate(invWQ[:,:,source_index]) wVw=np.einsum('km,kmn,kn->k',W[:,source_index,:],Q[:,source_index,:,:],np.conjugate(W[:,source_index,:])) wVw=np.sqrt(np.abs(wVw)) W[:,source_index,:]=W[:,source_index,:]/np.maximum(wVw[:,None],1.e-18) s_hat=np.einsum('kmn,nkt->mkt',W,x) return(W,s_hat,cost_buff) #周波数間の振幅相関に基づくパーミュテーション解法 #s_hat: M,Nk,Lt #return permutation_index_result:周波数毎のパーミュテーション解 def solver_inter_frequency_permutation(s_hat): n_sources=np.shape(s_hat)[0] n_freqs=np.shape(s_hat)[1] n_frames=np.shape(s_hat)[2] s_hat_abs=np.abs(s_hat) norm_amp=np.sqrt(np.sum(np.square(s_hat_abs),axis=0,keepdims=True)) s_hat_abs=s_hat_abs/np.maximum(norm_amp,1.e-18) spectral_similarity=np.einsum('mkt,nkt->k',s_hat_abs,s_hat_abs) frequency_order=np.argsort(spectral_similarity) #音源間の相関が最も低い周波数からパーミュテーションを解く is_first=True permutations=list(itertools.permutations(range(n_sources))) permutation_index_result={} for freq in frequency_order: if is_first==True: is_first=False #初期値を設定する accumurate_s_abs=s_hat_abs[:,frequency_order[0],:] permutation_index_result[freq]=range(n_sources) else: max_correlation=0 max_correlation_perm=None for perm in permutations: s_hat_abs_temp=s_hat_abs[list(perm),freq,:] correlation=np.sum(accumurate_s_abs*s_hat_abs_temp) if max_correlation_perm is None: max_correlation_perm=list(perm) max_correlation=correlation elif max_correlation < correlation: max_correlation=correlation max_correlation_perm=list(perm) permutation_index_result[freq]=max_correlation_perm accumurate_s_abs+=s_hat_abs[max_correlation_perm,freq,:] return(permutation_index_result) #プロジェクションバックで最終的な出力信号を求める #s_hat: M,Nk,Lt #W: 分離フィルタ(Nk,M,M) #retunr c_hat: マイクロホン位置での分離結果(M,M,Nk,Lt) def projection_back(s_hat,W): #ステアリングベクトルを推定 A=np.linalg.pinv(W) c_hat=np.einsum('kmi,ikt->mikt',A,s_hat) return(c_hat) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav","./CMU_ARCTIC/cmu_us_axb_arctic/wav/arctic_a0002.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskij',x_bar,np.conjugate(x_bar)) #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) filter=np.linalg.solve(x_bar_x_bar_h,correlation) #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) x_dereverb=x[0,...]-x_reverb return(x_dereverb) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_sampleskij',x_bar,np.conjugate(x_bar)) #covariance_inverse=np.linalg.pinv(x_bar_x_bar_h) correlation=np.einsum('ikt,kt->ki',x_bar,np.conjugate(x[0,...])) filter=np.linalg.solve(x_bar_x_bar_h,correlation) #filter=np.einsum('kij,kj->ki',covariance_inverse,correlation) x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) x_dereverb=x[0,...]-x_reverb return(x_dereverb) #WPEで残響を除去 #x:入力信号( M, Nk, Lt) #x_bar:過去のマイク入力信号(Lh,M, Nk, Lt) #return x_dereverb:残響除去後の信号(Nk,Lt) def dereverberation_wpe(x,x_bar,wpe_iterations=10): #マイクロホン数・周波数・フレーム数・タップ長を取得する M=np.shape(x)[0] Nk=np.shape(x)[1] Lt=np.shape(x)[2] Lh=np.shape(x_bar)[0] #入力信号の形式を変更・変数を初期化 x_bar=np.reshape(x_bar,[Lh*M,Nk,Lt]) v=np.square(np.abs(x[0,...])) cost_buff=[] for t in range(wpe_iterations): #共分散行列を計算 x_bar_x_bar_h=np.einsum('kt,ikt,jkt->kij',1./v,x_bar,np.conjugate(x_bar)) #相関ベクトルを計算 correlation=np.einsum('kt,ikt,kt->ki',1./v,x_bar,np.conjugate(x[0,...])) #フィルタ算出 filter=np.linalg.solve(x_bar_x_bar_h,correlation) #残響除去実施 x_reverb=np.einsum('kj,jkt->kt',np.conjugate(filter),x_bar) x_dereverb=x[0,...]-x_reverb #パラメータ更新 v=np.square(np.abs(x_dereverb)) v=np.maximum(v,1.e-8) #コスト計算 cost=np.mean(np.log(v)) cost_buff.append(cost) return(x_dereverb,cost_buff) #2バイトに変換してファイルに保存 #signal: time-domain 1d array (float) #file_name: 出力先のファイル名 #sample_rate: サンプリングレート def write_file_from_time_signal(signal,file_name,sample_rate): #2バイトのデータに変換 signal=signal.astype(np.int16) #waveファイルに書き込む wave_out = wave.open(file_name, 'w') #モノラル:1、ステレオ:2 wave_out.setnchannels(1) #サンプルサイズ2byte wave_out.setsampwidth(2) #サンプリング周波数 wave_out.setframerate(sample_rate) #データを書き込み wave_out.writeframes(signal) #ファイルを閉じる wave_out.close() #SNRをはかる #desired: 目的音、Lt #out: 雑音除去後の信号 Lt def calculate_snr(desired,out): wave_length=np.minimum(np.shape(desired)[0],np.shape(out)[0]) #消し残った雑音 desired=desired[:wave_length] out=out[:wave_length] noise=desired-out snr=10.*np.log10(np.sum(np.square(desired))/np.sum(np.square(noise))) return(snr) #乱数の種を初期化 np.random.seed(0) #畳み込みに用いる音声波形 clean_wave_files=["./CMU_ARCTIC/cmu_us_aew_arctic/wav/arctic_a0001.wav"] #音源数 n_sources=len(clean_wave_files) #長さを調べる n_samples=0 #ファイルを読み込む for clean_wave_file in clean_wave_files: wav=wave.open(clean_wave_file) if n_samples