├── Baseline.m ├── Generate_STFT_Signals.m ├── Generate_Signals.m ├── Get_Y_Tilde_by_NLMS.m ├── LPF_Function.m ├── Nonlinear_System.slx ├── Nonlinear_System.slxc ├── README.md ├── SA1.WAV ├── SA2_FEMALE.WAV ├── SA2_MALE.WAV ├── SI1194.WAV ├── SI1271.WAV ├── SI1824.WAV ├── SI564.WAV ├── SX294.WAV ├── Spatial_LCMV_Method.m ├── Update_Freq_Domain_NLMS_Filter.m ├── biorwin.m ├── istft_changed_by_Yuval.m ├── lnshift.m ├── main.m ├── omlsa_changed_by_Yuval.m ├── shiftcir.m ├── stft_changed_by_Yuval.m └── vars.mat /Baseline.m: -------------------------------------------------------------------------------- 1 | function [ERLE, DI, NRF, U_Hat, u_hat] = Baseline(fs, frames, win_length, STFT_jump, beta, L, D, U, Y, V, Y_tilde, ... 2 | lambda, Short_Time_Average_Frames) 3 | %% This function implements the temporal MVDR filter minus the corresponding NLMS output. 4 | %% Define Parameters. 5 | freqs= win_length / 2 + 1; 6 | Summation_Last_Frame= Short_Time_Average_Frames + L - 1; 7 | %% Implements the total MVDR beamformer. 8 | Current_phi_d= zeros(freqs, L, L); 9 | Current_phi_y_tilde= zeros(freqs, L, L); 10 | Phi_d= zeros(freqs, L, L); 11 | Phi_y_tilde= zeros(freqs, L, L); 12 | Phi_u_c= zeros(freqs, L, L); 13 | U_f= zeros(freqs, frames); 14 | Y_re= zeros(freqs, frames); 15 | V_re= zeros(freqs, frames); 16 | U_Hat= zeros(freqs, frames); 17 | for n= L : frames 18 | First_Frame= n - L + 1; 19 | d_vec= transpose(D(:, n : -1 : First_Frame)); 20 | y_tilde_vec= transpose(Y_tilde(:, n : -1 : First_Frame)); 21 | y_vec= transpose(Y(:, n : -1 : First_Frame)); 22 | u_vec= transpose(U(:, n : -1 : First_Frame)); 23 | v_vec= transpose(V(:, n : -1 : First_Frame)); 24 | for k= 1 : freqs 25 | Current_phi_d(k, :, :)= d_vec(:, k) * d_vec(:, k)'; 26 | Current_phi_y_tilde(k, :, :)= y_tilde_vec(:, k) * y_tilde_vec(:, k)'; 27 | end 28 | if(n < Summation_Last_Frame) 29 | Phi_d= Phi_d + Current_phi_d; 30 | Phi_y_tilde= Phi_y_tilde + Current_phi_y_tilde; 31 | else 32 | if(n==Summation_Last_Frame) 33 | Phi_d= (Phi_d + Current_phi_d) / Short_Time_Average_Frames; 34 | Phi_y_tilde= (Phi_y_tilde + Current_phi_y_tilde) / Short_Time_Average_Frames; 35 | else 36 | Phi_d= lambda * Phi_d + (1 - lambda) * Current_phi_d; 37 | Phi_y_tilde= lambda * Phi_y_tilde + (1 - lambda) * Current_phi_y_tilde; 38 | end 39 | end 40 | Phi_u= Phi_d - Phi_y_tilde; 41 | phi_u= Phi_u(:, 1, 1); 42 | gamma_u= Phi_u(:, :, 1) ./ phi_u; 43 | for k=1 : freqs 44 | phi_u_freq= phi_u(k); 45 | gamma_u_freq(:, 1)= gamma_u(k, :); 46 | Phi_u_c(k, :, :)= phi_u_freq * (gamma_u_freq * gamma_u_freq'); 47 | end 48 | Phi_in= Phi_y_tilde + Phi_u - Phi_u_c; 49 | for k= 1 : freqs 50 | Phi_in_freq(:, :)= Phi_in(k, :, :); 51 | gamma_u_freq(:, 1)= gamma_u(k, :); 52 | Expression_freq= (Phi_in_freq \ gamma_u_freq); 53 | h= Expression_freq / (gamma_u_freq' * Expression_freq); 54 | U_f(k, n)= h' * u_vec(:, k); 55 | Y_re(k, n)= h' * y_vec(:, k); 56 | U_Hat(k, n)= h' * d_vec(:, k); 57 | V_re(k, n)= h' * v_vec(:, k); 58 | end 59 | end 60 | %% Find ISTFTs. 61 | U_f((freqs + 1) : win_length, :)= conj(U_f(((freqs - 1) : -1 : 2), :)); 62 | u_f= istft_changed_by_Yuval(U_f, win_length, STFT_jump, 1, beta); 63 | U((freqs + 1) : win_length, :, :)= conj(U(((freqs - 1) : -1 : 2), :, :)); 64 | u_reference= istft_changed_by_Yuval(U(:, :, 1), win_length, STFT_jump, 1, beta); 65 | U_Hat((freqs + 1) : win_length, :)= conj(U_Hat(((freqs - 1) : -1 : 2), :)); 66 | u_hat= istft_changed_by_Yuval(U_Hat, win_length, STFT_jump, 1, beta); 67 | Y((freqs + 1) : win_length, :, :)= conj(Y(((freqs - 1) : -1 : 2), :, :)); 68 | y_reference= istft_changed_by_Yuval(Y(:, :, 1), win_length, STFT_jump, 1, beta); 69 | V((freqs + 1) : win_length, :, :)= conj(V(((freqs - 1) : -1 : 2), :, :)); 70 | v_reference= istft_changed_by_Yuval(V(:, :, 1), win_length, STFT_jump, 1, beta); 71 | Y_re((freqs + 1) : win_length, :)= conj(Y_re(((freqs - 1) : -1 : 2), :)); 72 | y_re= istft_changed_by_Yuval(Y_re, win_length, STFT_jump, 1, beta); 73 | V_re((freqs + 1) : win_length, :)= conj(V_re(((freqs - 1) : -1 : 2), :)); 74 | v_re= istft_changed_by_Yuval(V_re, win_length, STFT_jump, 1, beta); 75 | %% Find ERFs and Distortion indeces. 76 | ERLE= LPF_Function(y_reference.^2)./LPF_Function((y_re).^2); 77 | DI= LPF_Function((u_reference - u_f).^2)./ LPF_Function(u_reference.^2); 78 | NRF= LPF_Function(v_reference.^2)./LPF_Function((v_re).^2); 79 | %% Return Positive frequencies for U_Hat. 80 | U_Hat= U_Hat(1 : freqs, :); 81 | audiowrite('U_Hat_Baseline.wav', u_hat, fs); 82 | end -------------------------------------------------------------------------------- /Generate_STFT_Signals.m: -------------------------------------------------------------------------------- 1 | function [D, Y, U, X, V, frames] = Generate_STFT_Signals(d, y, u, x, v, win_length, STFT_jump, beta, freqs, Mics) 2 | %% This function finds All the STFT Signals. 3 | %% Calculate STFTs. 4 | X= stft_changed_by_Yuval(x, win_length, STFT_jump, 1, beta); 5 | for m= 1 : Mics 6 | D(:, :, m)= stft_changed_by_Yuval(d(:, m), win_length, STFT_jump, 1, beta); 7 | Y(:, :, m)= stft_changed_by_Yuval(y(:, m), win_length, STFT_jump, 1, beta); 8 | U(:, :, m)= stft_changed_by_Yuval(u(:, m), win_length, STFT_jump, 1, beta); 9 | V(:, :, m)= stft_changed_by_Yuval(v(:, m), win_length, STFT_jump, 1, beta); 10 | end 11 | X= X(1 : freqs, :); 12 | D= D(1 : freqs, :, :); 13 | Y= Y(1 : freqs, :, :); 14 | U= U(1 : freqs, :, :); 15 | V= V(1 : freqs, :, :); 16 | %% Find the Number of Frames. 17 | frames= size(D, 2); 18 | end -------------------------------------------------------------------------------- /Generate_Signals.m: -------------------------------------------------------------------------------- 1 | function [y, u, v, d] = Generate_Signals(M, x_First_Loudspeaker, x_Second_Loudspeaker, s_First_Speaker, s_Second_Speaker, fs, segment_length) 2 | %% This function generates the received signals by the microphones. 3 | c= 340; 4 | Radius= 0.075; 5 | T_60= 0.3; 6 | SNR_dB= 30; 7 | Room_Dims= [6, 6, 4.5]; 8 | First_Loudspeaker_Location= [3, 3, 0.1]; 9 | Second_Loudspeaker_Location= [3, 3, 0.5]; 10 | First_Speaker_Location= [3.5, 3, 0.5]; 11 | Second_Speaker_Location= [2.5, 3, 0.5]; 12 | theta_vec= (linspace(0, 2 * pi * (M - 1) / M, M))'; 13 | for m= 1: M 14 | Sensor_First_Array= First_Loudspeaker_Location + [Radius * cos(theta_vec(m)), Radius * sin(theta_vec(m)), 0]; 15 | Sensor_Second_Array= Second_Loudspeaker_Location + [Radius * cos(theta_vec(m)), Radius * sin(theta_vec(m)), 0]; 16 | g_First_Array_First_Loudspeaker= rir_generator(c, fs, Sensor_First_Array, First_Loudspeaker_Location, Room_Dims, T_60); 17 | g_First_Array_Second_Loudspeaker= rir_generator(c, fs, Sensor_First_Array, Second_Loudspeaker_Location, Room_Dims, T_60); 18 | g_Second_Array_First_Loudspeaker= rir_generator(c, fs, Sensor_Second_Array, First_Loudspeaker_Location, Room_Dims, T_60); 19 | g_Second_Array_Second_Loudspeaker= rir_generator(c, fs, Sensor_Second_Array, Second_Loudspeaker_Location, Room_Dims, T_60); 20 | y_First_Array= fftfilt(g_First_Array_First_Loudspeaker, x_First_Loudspeaker) + fftfilt(g_First_Array_Second_Loudspeaker, x_Second_Loudspeaker); 21 | y_Second_Array= fftfilt(g_Second_Array_First_Loudspeaker, x_First_Loudspeaker) + fftfilt(g_Second_Array_Second_Loudspeaker, x_Second_Loudspeaker); 22 | y(:, m)= [y_First_Array(1 : (3 * segment_length)) ; y_Second_Array((3 * segment_length + 1) : (5 * segment_length))]; 23 | audiowrite(strcat('Y_m=', num2str(m), '_M=', num2str(M), '.wav'), y(:, m), fs); 24 | g_First_Array_First_Speaker= rir_generator(c, fs, Sensor_First_Array, First_Speaker_Location, Room_Dims, T_60); 25 | g_First_Array_Second_Speaker= rir_generator(c, fs, Sensor_First_Array, Second_Speaker_Location, Room_Dims, T_60); 26 | g_Second_Array_First_Speaker= rir_generator(c, fs, Sensor_Second_Array, First_Speaker_Location, Room_Dims, T_60); 27 | g_Second_Array_Second_Speaker= rir_generator(c, fs, Sensor_Second_Array, Second_Speaker_Location, Room_Dims, T_60); 28 | u_First_Array= fftfilt(g_First_Array_First_Speaker, s_First_Speaker) + fftfilt(g_First_Array_Second_Speaker, s_Second_Speaker); 29 | u_Second_Array= fftfilt(g_Second_Array_First_Speaker, s_First_Speaker) + fftfilt(g_Second_Array_Second_Speaker, s_Second_Speaker); 30 | u(:, m)= [u_First_Array(1 : (3 * segment_length)) ; u_Second_Array((3 * segment_length + 1) : (5 * segment_length))]; 31 | audiowrite(strcat('U_m=', num2str(m), '_M=', num2str(M), '.wav'), u(:, m), fs); 32 | clean_d= u(:, m) + y(:, m); 33 | v(:, m)= rms(clean_d) / db2mag(SNR_dB) * randn(size(clean_d)); 34 | d(:, m)= clean_d + v(:, m); 35 | audiowrite(strcat('D_m=', num2str(m), '_M=', num2str(M), '.wav'), d(:, m), fs); 36 | end 37 | end -------------------------------------------------------------------------------- /Get_Y_Tilde_by_NLMS.m: -------------------------------------------------------------------------------- 1 | function Y_Tilde = Get_Y_Tilde_by_NLMS(d, fs, beta, win_length, overlap, freqs, X, D, frames, Last_NLMS_Adaptation_Frame) 2 | %% This Function Finds the initila guess for U With the NLMS Algorithm. 3 | %% Create Y_tilde. 4 | Y_Tilde= zeros(freqs, frames); 5 | audiowrite('temp_in.wav', d, fs); 6 | fin= 'temp_in.wav'; 7 | fout= 'temp_out'; 8 | [~, ~, sigma_v_squared]= omlsa_changed_by_Yuval(fin, fout, beta, fs, win_length, overlap); 9 | sigma_e_squared= zeros(freqs, 1); 10 | sigma_x_squared= zeros(freqs, 1); 11 | K= 2; 12 | Q_tag= 20; 13 | L_NLMS= (2 * K + 1) * Q_tag; 14 | h_NLMS= zeros(L_NLMS, freqs); 15 | for n= Q_tag : frames 16 | for k= 1 : freqs 17 | freq_indeces= mod((k - K - 1 : k + K - 1), freqs) + 1; 18 | frame_indeces= n : -1 : (n - Q_tag + 1); 19 | x_NLMS= reshape(X(freq_indeces, frame_indeces), L_NLMS, 1); 20 | if(n <= Last_NLMS_Adaptation_Frame) 21 | [h_NLMS(:, k), sigma_e_squared(k), sigma_x_squared(k)]= Update_Freq_Domain_NLMS_Filter(h_NLMS(:, k), sigma_e_squared(k), sigma_x_squared(k), x_NLMS, ... 22 | sigma_v_squared(k, n), D(k, n), Q_tag, K); 23 | else 24 | [~, sigma_e_squared(k), sigma_x_squared(k)]= Update_Freq_Domain_NLMS_Filter(h_NLMS(:, k), sigma_e_squared(k), sigma_x_squared(k), x_NLMS, sigma_v_squared(k, n), D(k, n), Q_tag, K); 25 | end 26 | Y_Tilde(k, n)= h_NLMS(:, k)' * x_NLMS; 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /LPF_Function.m: -------------------------------------------------------------------------------- 1 | function LPF_Function = LPF_Function(sig) 2 | %% Implements a LPF. 3 | filter_length= 4096; 4 | sig_length= length(sig); 5 | extended_sig= [zeros(filter_length - 1, 1); sig]; 6 | LPF_Function= zeros(sig_length, 1); 7 | for i= 1 : sig_length 8 | LPF_Function(i)= sum(extended_sig(i : (i + filter_length - 1))); 9 | end 10 | end -------------------------------------------------------------------------------- /Nonlinear_System.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/Nonlinear_System.slx -------------------------------------------------------------------------------- /Nonlinear_System.slxc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/Nonlinear_System.slxc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multichannel Acoustic Echo Cancellation with Beamforming in Dynamic Environments 2 | This folder contains the code for the following paper: "Multichannel Acoustic Echo Cancellation with Beamforming in Dynamic Environments" 3 | Link to paper: TBD 4 | 5 | Activating 'main.m' creates the figures that appear in the paper. 6 | 7 | ### Important: 8 | * Matlab R2022b is required 9 | * C compiler is required 10 | * the code uses three external code packages, please download them from their original source: 11 | 1. RIR Generator by Emanuël Habets: https://www.audiolabs-erlangen.de/fau/professor/habets/software/rir-generator 12 | 2. Nonlinear Modeling of a Moving Coil Loudspeaker, by Stephen Thompson: https://www.mathworks.com/matlabcentral/fileexchange/121263-nonlinear-modeling-of-a-moving-coil-loudspeaker 13 | 3. Acoustical Domain for Simscape, by Stephen Thompson: https://www.mathworks.com/matlabcentral/fileexchange/109029-acoustical-domain-for-simscape 14 | -------------------------------------------------------------------------------- /SA1.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SA1.WAV -------------------------------------------------------------------------------- /SA2_FEMALE.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SA2_FEMALE.WAV -------------------------------------------------------------------------------- /SA2_MALE.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SA2_MALE.WAV -------------------------------------------------------------------------------- /SI1194.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SI1194.WAV -------------------------------------------------------------------------------- /SI1271.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SI1271.WAV -------------------------------------------------------------------------------- /SI1824.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SI1824.WAV -------------------------------------------------------------------------------- /SI564.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SI564.WAV -------------------------------------------------------------------------------- /SX294.WAV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/SX294.WAV -------------------------------------------------------------------------------- /Spatial_LCMV_Method.m: -------------------------------------------------------------------------------- 1 | function [ERLE, DI, NRF, U_Hat, u_hat] = Spatial_LCMV_Method(fs, frames, win_length, STFT_jump, beta, M, L, X, D, U, Y, V) 2 | %% This function implements the spatial MVDR filter minus the corresponding NLMS output. 3 | %% Define Parameters. 4 | freqs= win_length / 2 + 1; 5 | %% Implements the total MVDR beamformer. 6 | U_f= zeros(freqs, frames); 7 | Y_re= zeros(freqs, frames); 8 | V_re= zeros(freqs, frames); 9 | U_Hat= zeros(freqs, frames); 10 | Y_tilde= zeros(freqs, frames, M); 11 | ms= nchoosek(1 : M, 2); 12 | ls= nchoosek(1 : L, 2); 13 | m_couples= size(ms, 1); 14 | l_couples= size(ls, 1); 15 | Equations= m_couples * l_couples; 16 | res_vec= zeros(freqs, Equations); 17 | Mat_g= zeros(freqs, Equations, M); 18 | Current_res_vec= zeros(freqs, Equations); 19 | Current_Mat_g= zeros(freqs, Equations, M); 20 | g_vec= zeros(M, freqs); 21 | Current_u_tilde_expectation_vec= zeros(freqs, M); 22 | for n= L : frames 23 | for k= 1 : freqs 24 | for o= 1 : m_couples 25 | m1= ms(o, 1); 26 | m2= ms(o, 2); 27 | for p= 1 : l_couples 28 | l1= ls(p, 1); 29 | l2= ls(p, 2); 30 | equation= (o - 1) * l_couples + p; 31 | Current_res_vec(k, equation)= D(k, n - l1 + 1, m1) * D(k, n - l2 + 1, m2) - D(k, n - l2 + 1, m1) * D(k, n - l1 + 1, m2); 32 | Current_Mat_g(k, equation, m1)= X(k, n - l1 + 1) * D(k, n - l2 + 1, m2) - X(k, n - l2 + 1) * D(k, n - l1 + 1, m2); 33 | Current_Mat_g(k, equation, m2)= X(k, n - l2 + 1) * D(k, n - l1 + 1, m1) - X(k, n - l1 + 1) * D(k, n - l2 + 1, m1); 34 | end 35 | end 36 | end 37 | res_vec(:, :)= Current_res_vec; 38 | Mat_g(:, :, :)=Current_Mat_g(:, :, :); 39 | d_vec= transpose(reshape(D(:, n, :), freqs, M)); 40 | y_vec= transpose(reshape(Y(:, n, :), freqs, M)); 41 | u_vec= transpose(reshape(U(:, n, :), freqs, M)); 42 | v_vec= transpose(reshape(V(:, n, :), freqs, M)); 43 | for k= 1 : freqs 44 | Mat_g_freq(:, :)= Mat_g(k, :, :); 45 | res_vec_freq(:, 1)= res_vec(k, :); 46 | g_vec(:, k)= pinv(Mat_g_freq) * res_vec_freq; 47 | Y_tilde(k, n, :)= g_vec(:, k) * X(k, n); 48 | Current_u_tilde_expectation_vec(k, :)= D(k, n, :) - Y_tilde(k, n, :); 49 | end 50 | U_tilde_expectation_vec= Current_u_tilde_expectation_vec; 51 | q_vec= transpose(U_tilde_expectation_vec ./ U_tilde_expectation_vec(:, 1)); 52 | for k=1 : freqs 53 | C= [q_vec(:, k), g_vec(:, k)]; 54 | h= C * ((C' * C) \ [1 ; 0]); 55 | U_f(k, n)= h' * u_vec(:, k); 56 | Y_re(k, n)= h' * y_vec(:, k); 57 | V_re(k, n)= h' * v_vec(:, k); 58 | U_Hat(k, n)= h' * d_vec(:, k); 59 | end 60 | end 61 | %% Find ISTFTs. 62 | U_f((freqs + 1) : win_length, :)= conj(U_f(((freqs - 1) : -1 : 2), :)); 63 | u_f= istft_changed_by_Yuval(U_f, win_length, STFT_jump, 1, beta); 64 | U((freqs + 1) : win_length, :, :)= conj(U(((freqs - 1) : -1 : 2), :, :)); 65 | u_reference= istft_changed_by_Yuval(U(:, :, 1), win_length, STFT_jump, 1, beta); 66 | U_Hat((freqs + 1) : win_length, :)= conj(U_Hat(((freqs - 1) : -1 : 2), :)); 67 | u_hat= istft_changed_by_Yuval(U_Hat, win_length, STFT_jump, 1, beta); 68 | Y((freqs + 1) : win_length, :, :)= conj(Y(((freqs - 1) : -1 : 2), :, :)); 69 | y_reference= istft_changed_by_Yuval(Y(:, :, 1), win_length, STFT_jump, 1, beta); 70 | V((freqs + 1) : win_length, :, :)= conj(V(((freqs - 1) : -1 : 2), :, :)); 71 | v_reference= istft_changed_by_Yuval(V(:, :, 1), win_length, STFT_jump, 1, beta); 72 | Y_re((freqs + 1) : win_length, :)= conj(Y_re(((freqs - 1) : -1 : 2), :)); 73 | y_re= istft_changed_by_Yuval(Y_re, win_length, STFT_jump, 1, beta); 74 | V_re((freqs + 1) : win_length, :)= conj(V_re(((freqs - 1) : -1 : 2), :)); 75 | v_re= istft_changed_by_Yuval(V_re, win_length, STFT_jump, 1, beta); 76 | %% Find ERFs and Distortion indeces. 77 | ERLE= LPF_Function(y_reference.^2)./LPF_Function((y_re).^2); 78 | DI= LPF_Function((u_reference - u_f).^2)./ LPF_Function(u_reference.^2); 79 | NRF= LPF_Function(v_reference.^2)./LPF_Function((v_re).^2); 80 | %% Take Positive Frequencies of U_Hat. 81 | U_Hat= U_Hat(1 : freqs, :); 82 | audiowrite(strcat('U_Hat_M=', num2str(M), '_L=', num2str(L), '.wav'), u_hat, fs); 83 | end -------------------------------------------------------------------------------- /Update_Freq_Domain_NLMS_Filter.m: -------------------------------------------------------------------------------- 1 | function [h_NLMS, sigma_e_squared, sigma_x_squared] = Update_Freq_Domain_NLMS_Filter(h_NLMS, sigma_e_squared, sigma_x_squared, x_NLMS, sigma_v_squared, D, Q_tag, K) 2 | %% Implements the Frequency Domain NLMS Filter. 3 | epsilon= 1e-8; 4 | constant= 20; 5 | beta= 1 - 1 / (6 * Q_tag); 6 | e= D - h_NLMS' * x_NLMS; 7 | sigma_x_squared= beta * sigma_x_squared + (1 - beta) * abs(x_NLMS(K + 1))^2; 8 | sigma_e_squared= beta * sigma_e_squared + (1 - beta) * abs(e)^2; 9 | miu= 1 / (epsilon + constant * sigma_x_squared + x_NLMS' * x_NLMS) * (1 - sqrt(sigma_v_squared) / (epsilon + sqrt(sigma_e_squared))); 10 | h_NLMS= h_NLMS + miu * x_NLMS * e'; 11 | end 12 | 13 | -------------------------------------------------------------------------------- /biorwin.m: -------------------------------------------------------------------------------- 1 | function win=biorwin(wins,dM,dN); 2 | % biorbin : Find Biorthogonal analysis Window for STFT 3 | % ***************************************************************@ 4 | % Inputs: 5 | % wins, synthesis window; 6 | % dM, sampling step in Time; 7 | % dN, sampling step in Frequency; 8 | % Output: 9 | % win, analysis window; 10 | % Usage: 11 | % win=biorwin(wins,dM,dN); 12 | % Defaults: 13 | % noverlap=length(wins)/2; 14 | 15 | % Copyright (c) 2000. Dr Israel Cohen. 16 | % All rights reserved. Created 5/12/00. 17 | % ***************************************************************@ 18 | 19 | wins=wins(:); 20 | L=length(wins); 21 | N=L/dN; 22 | win=zeros(L,1); 23 | mu=zeros(2*dN-1,1); 24 | mu(1)=1; 25 | %mu(1)=1/N; 26 | for k=1:dM 27 | H=zeros(2*dN-1,ceil((L-k+1)/dM)); 28 | for q=0:2*dN-2 29 | h=shiftcir(wins,q*N); 30 | H(q+1,:)=h(k:dM:L)'; 31 | end 32 | win(k:dM:L)=pinv(H)*mu; 33 | end 34 | 35 | %win=win/max(win); 36 | -------------------------------------------------------------------------------- /istft_changed_by_Yuval.m: -------------------------------------------------------------------------------- 1 | function x=istft_changed_by_Yuval(Y,nfft,dM,dN, beta) 2 | % istft : Inverse Short Time Fourier Transform 3 | % ***************************************************************@ 4 | % Inputs: 5 | % Y, stft of x; 6 | % nfft, window length; 7 | % dM, sampling step in Time; 8 | % dN, sampling step in Frequency; 9 | % wintype, window type; 10 | % Inputs: 11 | % x, signal; 12 | % Usage: 13 | % x=istft(Y,nfft,dM,dN,wintype); 14 | % Defaults: 15 | % wintype='Hanning'; 16 | % dN = 1; 17 | % dM = 0.5*nfft; 18 | % nfft=2*(size(Y,1)-1); 19 | 20 | % Copyright (c) 2000. Dr Israel Cohen. 21 | % All rights reserved. Created 17/12/00. 22 | % ***************************************************************@ 23 | 24 | % Changed by Yuval to use kaiser window with beta parameter. 25 | 26 | if nargin == 1 27 | nfft = 2*(size(Y,1)-1); 28 | end 29 | if nargin < 3 30 | dM = 0.5*nfft; 31 | dN = 1; 32 | end 33 | if nargin < 5 34 | wintype = 'Hanning'; 35 | end 36 | 37 | %if exist(wintype) 38 | % win=eval([lower(wintype),sprintf('(%g)',nfft)]); 39 | %else 40 | % error(['Undefined window type: ',wintype]) 41 | %end 42 | 43 | win= kaiser(nfft, beta); 44 | 45 | %extend the anti-symmetric range of the spectum 46 | N=nfft/dN; 47 | N2=N/2; 48 | Y(N2+2:N,:)=conj(Y(N2:-1:2,:)); 49 | Y=real(ifft(Y)); 50 | Y=Y((1:N)'*ones(1,dN),:); 51 | 52 | % Apply the synthesis window 53 | ncol=size(Y,2); 54 | Y = win(:,ones(1,ncol)).*Y; 55 | 56 | % Overlapp & add 57 | x=zeros((ncol-1)*dM+nfft,1); 58 | idx=(1:nfft)'; 59 | start=0; 60 | for l=1:ncol 61 | x(start+idx)=x(start+idx)+Y(:,l); 62 | start=start+dM; 63 | end 64 | -------------------------------------------------------------------------------- /lnshift.m: -------------------------------------------------------------------------------- 1 | function y = lnshift(x,t) 2 | % lnshift -- t circular left shift of 1-d signal 3 | % Usage 4 | % y = lnshift(x,t) 5 | % Inputs 6 | % x 1-d signal 7 | % Outputs 8 | % y 1-d signal 9 | % y(i) = x(i+t) for i+t < n 10 | % y(i) = x(i+t-n) else 11 | 12 | % Copyright (c) 2000. Dr Israel Cohen. 13 | % All rights reserved. Created 3/8/00. 14 | % ***************************************************************@ 15 | 16 | szX=size(x); 17 | if szX(1)>1 18 | n=szX(1); 19 | y=[x((1+t):n); x(1:t)]; 20 | else 21 | n=szX(2); 22 | y=[x((1+t):n) x(1:t)]; 23 | end 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | %% Clear previous data. 2 | clear all; 3 | close all; 4 | clc; 5 | %% General Parameters. 6 | fs= 16000; % If this is changed or the .wav files are changed, might need to change and downsample / sample more of all signals. Also, might need to change simulink files. 7 | Ts= 1 / fs; 8 | overlap= 0.75; 9 | win_length= 512; 10 | lambda= 0.35; 11 | beta= 5; 12 | Short_Time_Average_Frames= 100; 13 | STFT_jump= (1 - overlap) * win_length; 14 | freqs= win_length / 2 + 1; 15 | f_vec= (linspace(0, fs / 2, freqs))'; 16 | Segment_time= 10; 17 | segment_length= Segment_time * fs; 18 | Forefront_frames= overlap / (1 - overlap); 19 | Correlation_Estimation_Last_Frame= Segment_time * fs / STFT_jump - Forefront_frames; 20 | %% Simulated Room Parameters. 21 | mex -setup C++ 22 | mex rir_generator.cpp rir_generator_core.cpp 23 | %% Create Signals for Simulated Room Experiment. 24 | [far_sig_1, ~]= audioread('SA1.wav'); 25 | [far_sig_2, ~]= audioread('SA2_FEMALE.wav'); 26 | [far_sig_3, ~]= audioread('SI1271.wav'); 27 | [near_sig_1, ~]= audioread('SA2_MALE.wav'); 28 | [near_sig_2, ~]= audioread('SI564.wav'); 29 | [near_sig_3, ~]= audioread('SI1194.wav'); 30 | [near_sig_4, ~]= audioread('SI1824.wav'); % If fs changes might need to decimate signals. 31 | x= [far_sig_1; far_sig_2; far_sig_3]; 32 | s= [near_sig_1; near_sig_2; near_sig_3; near_sig_4]; 33 | x= x(1 : segment_length); 34 | s= s(1 : segment_length); 35 | audiowrite('X.wav', x, fs); 36 | audiowrite('S.wav', s, fs); 37 | silence= zeros(segment_length, 1); 38 | Simulink_sim_time= Segment_time - Ts; 39 | Simulink_time_vec= transpose(0 : Ts : Simulink_sim_time); 40 | x_forsimulink= [Simulink_time_vec, x]; 41 | open('acoustical_lib.slx'); 42 | sim('NonLinear_System.slx', Simulink_sim_time); 43 | x_NL(:, 1)= ans.x_NL(1, 1, 1 : segment_length); 44 | x_NL_First_Loudspeaker= [x_NL; x_NL ; x_NL; silence ; silence]; 45 | x_NL_Second_Loudspeaker= [silence; silence; silence; x_NL; x_NL]; 46 | s_First_Speaker=[silence; s; silence; s; silence]; 47 | s_Second_Speaker= [silence; silence; s; silence; s]; 48 | x_NL= x_NL_First_Loudspeaker + x_NL_Second_Loudspeaker; 49 | x= [x; x; x; x; x]; 50 | %% Plot Signals for M=L= 4. 51 | M= 4; 52 | L= 4; 53 | [y, u, v, d] = Generate_Signals(M, x_NL_First_Loudspeaker, x_NL_Second_Loudspeaker, s_First_Speaker, s_Second_Speaker, fs, segment_length); 54 | [D, Y, U, X, V, frames]= Generate_STFT_Signals(d, y, u, x, v, win_length, STFT_jump, beta, freqs, M); 55 | Last_Time= (overlap * win_length + STFT_jump * frames)/ fs; 56 | SER_First_Loudspeaker_First_Speaker= mag2db(rms(u((segment_length + 1) : (2 * segment_length), 1)) / rms(y((segment_length + 1) : (2 * segment_length), 1))) 57 | SER_First_Loudspeaker_Second_Speaker= mag2db(rms(u((2 * segment_length + 1) : (3 * segment_length), 1)) / rms(y((2 * segment_length + 1) : (3 * segment_length), 1))) 58 | SER_Second_Loudspeaker_First_Speaker= mag2db(rms(u((3 * segment_length + 1) : (4 * segment_length), 1)) / rms(y((3 * segment_length + 1) : (4 * segment_length), 1))) 59 | SER_Second_Loudspeaker_Second_Speaker= mag2db(rms(u((4 * segment_length + 1) : (5 * segment_length), 1)) / rms(y((4 * segment_length + 1) : (5 * segment_length), 1))) 60 | [~, ~, ~, ~, u_Hat_Spatial_LCMV]= Spatial_LCMV_Method(fs, frames, win_length, STFT_jump, beta, M, L, X, D, U, Y, V); 61 | audiowrite('U_Hat_Proposed_M=4_L=4.wav', u_Hat_Spatial_LCMV, fs); 62 | figure; 63 | subplot(4, 1, 1); 64 | plot(linspace(0, Last_Time, length(d(:, 1))) - Segment_time, d(:, 1), 'LineWidth', 0.001); 65 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 66 | ylabel('Amplitude', 'Interpreter', 'latex'); 67 | set(gca, 'FontSize', 7.5); 68 | title('(a)', 'Interpreter', 'latex'); 69 | xline(Segment_time, 'c', 'LineWidth', 2); 70 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 71 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 72 | xlim([0, Last_Time - Segment_time]); 73 | ylim([-0.15, 0.15]); 74 | yticks([-0.15, 0.15]); 75 | subplot(4, 1, 2); 76 | plot(linspace(0, Last_Time, length(y(:, 1))) - Segment_time, y(:, 1), 'LineWidth', 0.001); 77 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 78 | ylabel('Amplitude', 'Interpreter', 'latex'); 79 | set(gca, 'FontSize', 7.5); 80 | title('(b)', 'Interpreter', 'latex'); 81 | xline(Segment_time, 'c', 'LineWidth', 2); 82 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 83 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 84 | xlim([0, Last_Time - Segment_time]); 85 | ylim([-0.15, 0.15]); 86 | yticks([-0.15, 0.15]); 87 | subplot(4, 1, 3); 88 | plot(linspace(0, Last_Time, length(u(:, 1))) - Segment_time, u(:, 1), 'LineWidth', 0.001); 89 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 90 | ylabel('Amplitude', 'Interpreter', 'latex'); 91 | set(gca, 'FontSize', 7.5); 92 | title('(c)', 'Interpreter', 'latex'); 93 | xline(Segment_time, 'c', 'LineWidth', 2); 94 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 95 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 96 | xlim([0, Last_Time - Segment_time]); 97 | ylim([-0.15, 0.15]); 98 | yticks([-0.15, 0.15]); 99 | subplot(4, 1, 4); 100 | plot(linspace(0, Last_Time, length(u_Hat_Spatial_LCMV)) - Segment_time, u_Hat_Spatial_LCMV, 'LineWidth', 0.001); 101 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 102 | ylabel('Amplitude', 'Interpreter', 'latex'); 103 | set(gca, 'FontSize', 7.5); 104 | title('(d)', 'Interpreter', 'latex'); 105 | xline(Segment_time, 'c', 'LineWidth', 2); 106 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 107 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 108 | xlim([0, Last_Time - Segment_time]); 109 | ylim([-0.15, 0.15]); 110 | yticks([-0.15, 0.15]); 111 | set(gcf, 'PaperUnits', 'inches', 'Units', 'inches'); 112 | set(gcf, 'PaperPosition', [0 0 7.9 5]); 113 | set(gcf, 'PaperSize', [7.9 5]); 114 | saveas(gcf, 'Signals_Time_Domain', 'pdf'); 115 | %% Run as function of M. 116 | figure; 117 | L= 4; 118 | for M= 2 : 5 119 | [y, u, v, d] = Generate_Signals(M, x_NL_First_Loudspeaker, x_NL_Second_Loudspeaker, s_First_Speaker, s_Second_Speaker, fs, segment_length); 120 | [D, Y, U, X, V, frames]= Generate_STFT_Signals(d, y, u, x, v, win_length, STFT_jump, beta, freqs, M); 121 | Last_Time= (overlap * win_length + STFT_jump * frames)/ fs; 122 | [ERLE_Spatial_LCMV, DI_Spatial_LCMV, ~, ~, u_Hat_Spatial_LCMV]= Spatial_LCMV_Method(fs, frames, win_length, STFT_jump, beta, ... 123 | M, L, X, D, U, Y, V); 124 | audiowrite(strcat('U_Hat_Proposed_M=', num2str(M), '_L=4.wav'), u_Hat_Spatial_LCMV, fs); 125 | subplot(2, 1, 1); 126 | plot(linspace(0, Last_Time, length(ERLE_Spatial_LCMV)) - Segment_time, pow2db(ERLE_Spatial_LCMV), ... 127 | 'LineWidth', 0.001); 128 | hold on; 129 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 130 | ylabel('[dB]', 'Interpreter', 'latex'); 131 | set(gca, 'FontSize', 7.5); 132 | title('(a)', 'Interpreter', 'latex'); 133 | xline(Segment_time, 'c', 'LineWidth', 2); 134 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 135 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 136 | xlim([0, Last_Time - Segment_time]); 137 | ylim([0, 40]); 138 | subplot(2, 1, 2); 139 | plot(linspace(0, Last_Time, length(DI_Spatial_LCMV)) - Segment_time, pow2db(DI_Spatial_LCMV), 'LineWidth', 0.001); 140 | hold on; 141 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 142 | ylabel('[dB]', 'Interpreter', 'latex'); 143 | set(gca, 'FontSize', 7.5); 144 | title('(b)', 'Interpreter', 'latex'); 145 | xline(Segment_time, 'c', 'LineWidth', 2); 146 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 147 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 148 | xlim([0, Last_Time - Segment_time]); 149 | ylim([-20, 15]); 150 | end 151 | set(gcf, 'PaperUnits', 'inches', 'Units', 'inches'); 152 | set(gcf, 'PaperPosition', [0 0 7.9 5]); 153 | set(gcf, 'PaperSize', [7.9 5]); 154 | saveas(gcf, 'ERLE_DI_Varying_M', 'pdf'); 155 | %% Run as Function of L. 156 | figure; 157 | M= 4; 158 | [y, u, v, d] = Generate_Signals(M, x_NL_First_Loudspeaker, x_NL_Second_Loudspeaker, s_First_Speaker, s_Second_Speaker, fs, segment_length); 159 | [D, Y, U, X, V, frames]= Generate_STFT_Signals(d, y, u, x, v, win_length, STFT_jump, beta, freqs, M); 160 | Last_Time= (overlap * win_length + STFT_jump * frames)/ fs; 161 | for L= 2 : 5 162 | [ERLE_Spatial_LCMV, DI_Spatial_LCMV, ~, ~, u_Hat_Spatial_LCMV]= Spatial_LCMV_Method(fs, frames, win_length, STFT_jump, beta, ... 163 | M, L, X, D, U, Y, V); 164 | audiowrite(strcat('U_Hat_Proposed_M=4_L=', num2str(L), '.wav'), u_Hat_Spatial_LCMV, fs); 165 | subplot(2, 1, 1); 166 | plot(linspace(0, Last_Time, length(ERLE_Spatial_LCMV)) - Segment_time, pow2db(ERLE_Spatial_LCMV), ... 167 | 'LineWidth', 0.001); 168 | hold on; 169 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 170 | ylabel('[dB]', 'Interpreter', 'latex'); 171 | set(gca, 'FontSize', 7.5); 172 | title('(a)', 'Interpreter', 'latex'); 173 | xline(Segment_time, 'c', 'LineWidth', 2); 174 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 175 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 176 | xlim([0, Last_Time - Segment_time]); 177 | ylim([0, 40]); 178 | subplot(2, 1, 2); 179 | plot(linspace(0, Last_Time, length(DI_Spatial_LCMV)) - Segment_time, pow2db(DI_Spatial_LCMV), 'LineWidth', 0.001); 180 | hold on; 181 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 182 | ylabel('[dB]', 'Interpreter', 'latex'); 183 | set(gca, 'FontSize', 7.5); 184 | title('(b)', 'Interpreter', 'latex'); 185 | xline(Segment_time, 'c', 'LineWidth', 2); 186 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 187 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 188 | xlim([0, Last_Time - Segment_time]); 189 | ylim([-20, 15]); 190 | end 191 | set(gcf, 'PaperUnits', 'inches', 'Units', 'inches'); 192 | set(gcf, 'PaperPosition', [0 0 7.9 5]); 193 | set(gcf, 'PaperSize', [7.9 5]); 194 | saveas(gcf, 'ERLE_DI_Varying_L', 'pdf'); 195 | %% Compare with Baseline. 196 | figure; 197 | L=4; 198 | M=4; 199 | [y, u, v, d] = Generate_Signals(M, x_NL_First_Loudspeaker, x_NL_Second_Loudspeaker, s_First_Speaker, s_Second_Speaker, fs, segment_length); 200 | [D, Y, U, X, V, frames]= Generate_STFT_Signals(d, y, u, x, v, win_length, STFT_jump, beta, freqs, M); 201 | Last_Time= (overlap * win_length + STFT_jump * frames)/ fs; 202 | [ERLE_Spatial_LCMV, DI_Spatial_LCMV, ~, ~, u_Hat_Spatial_LCMV]= Spatial_LCMV_Method(fs, frames, win_length, STFT_jump, beta, M, ... 203 | L, X, D, U, Y, V); 204 | Y_tilde=Get_Y_Tilde_by_NLMS(d, fs, beta, win_length, overlap, freqs, X, D(:, :, 1), frames, Correlation_Estimation_Last_Frame); 205 | [ERLE_Baseline, DI_Baseline, ~, ~, u_Hat_Baseline]= Baseline(fs, frames, win_length, STFT_jump, beta, L, D(:, :, 1), U(:, :, 1), Y(:, :, 1), ... 206 | V(:, :, 1), Y_tilde, lambda, Short_Time_Average_Frames); 207 | audiowrite(strcat('U_Hat_Baseline.wav'), u_Hat_Baseline, fs); 208 | audiowrite(strcat('U_Hat_Proposed.wav'), u_Hat_Spatial_LCMV, fs); 209 | subplot(2, 1, 1); 210 | plot(linspace(0, Last_Time, length(ERLE_Spatial_LCMV))- Segment_time, pow2db(ERLE_Spatial_LCMV), ... 211 | 'LineWidth', 0.001); 212 | hold on; 213 | plot(linspace(0, Last_Time, length(ERLE_Baseline))- Segment_time, pow2db(ERLE_Baseline), ... 214 | 'LineWidth', 0.001); 215 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 216 | ylabel('[dB]', 'Interpreter', 'latex'); 217 | set(gca, 'FontSize', 7.5); 218 | title('(a)', 'Interpreter', 'latex'); 219 | xline(Segment_time, 'c', 'LineWidth', 2); 220 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 221 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 222 | xlim([0, Last_Time - Segment_time]); 223 | ylim([0, 40]); 224 | subplot(2, 1, 2); 225 | plot(linspace(0, Last_Time, length(DI_Spatial_LCMV)) - Segment_time, pow2db(DI_Spatial_LCMV), 'LineWidth', 0.001); 226 | hold on; 227 | plot(linspace(0, Last_Time, length(DI_Baseline))- Segment_time, pow2db(DI_Baseline), 'LineWidth', 0.001); 228 | hold on; 229 | xlabel('$t\left(s\right)$', 'Interpreter', 'latex'); 230 | ylabel('[dB]', 'Interpreter', 'latex'); 231 | set(gca, 'FontSize', 7.5); 232 | title('(b)', 'Interpreter', 'latex'); 233 | xline(Segment_time, 'c', 'LineWidth', 2); 234 | xline(2 * Segment_time, 'c', 'LineWidth', 2); 235 | xline(3 * Segment_time, 'c', 'LineWidth', 2); 236 | xlim([0, Last_Time - Segment_time]); 237 | ylim([-20, 15]); 238 | set(gcf, 'PaperUnits', 'inches', 'Units', 'inches'); 239 | set(gcf, 'PaperPosition', [0 0 7.9 5]); 240 | set(gcf, 'PaperSize', [7.9 5]); 241 | saveas(gcf, 'ERLE_DI_Competing_Methods', 'pdf'); -------------------------------------------------------------------------------- /omlsa_changed_by_Yuval.m: -------------------------------------------------------------------------------- 1 | function [y, out, sigma_v_squared]=omlsa_changed_by_Yuval(fin, fout, beta, Fs_ref, M_ref, overlap) 2 | % omlsa : Single Channel OM-LSA with IMCRA noise estimator 3 | % ***************************************************************@ 4 | % Inputs: 5 | % fin, input file name (wav file) 6 | % fout, output file name (wav file) 7 | % Output: 8 | % in, samples of the input file 9 | % out, samples of the output file 10 | % Usage: 11 | % [in, out]=omlsa(fin,fout); 12 | % 13 | % Copyright (c) 2003. Prof Israel Cohen. 14 | % All rights reserved. 15 | % ***************************************************************@ 16 | 17 | % The following code was changed by Yuval Konforti to: 18 | % - have a kaiser window with some input beta parameter. 19 | % - export the estimate of noise variance 20 | % - Fs_ref, window length, and overlap to be given as input. 21 | 22 | % 1) Parameters of Short Time Fourier Analysis: - Changed by Yuval Konforti 23 | %Fs_ref=16e3; % 1.1) Reference Sampling frequency 24 | %M_ref=512; % 1.2) Size of analysis window 25 | %Mo_ref=0.75*M_ref; % 1.3) Number of overlapping samples in consecutive frames 26 | Mo_ref= overlap * M_ref; 27 | 28 | % 2) Parameters of Noise Spectrum Estimate 29 | w=1; % 2.1) Size of frequency smoothing window function=2*w+1 30 | alpha_s_ref=0.9; % 2.2) Recursive averaging parameter for the smoothing operation 31 | Nwin=8; % 2.3) Resolution of local minima search 32 | Vwin=15; 33 | delta_s=1.67; % 2.4) Local minimum factor 34 | Bmin=1.66; 35 | delta_y=4.6; % 2.4) Local minimum factor 36 | delta_yt=3; 37 | alpha_d_ref=0.85; % 2.7) Recursive averaging parameter for the noise 38 | 39 | % 3) Parameters of a Priori Probability for Signal-Absence Estimate 40 | alpha_xi_ref=0.7; % 3.1) Recursive averaging parameter 41 | w_xi_local=1; % 3.2) Size of frequency local smoothing window function 42 | w_xi_global=15; % 3.3) Size of frequency local smoothing window function 43 | f_u=10e3; % 3.4) Upper frequency threshold for global decision 44 | f_l=50; % 3.5) Lower frequency threshold for global decision 45 | P_min=0.005; % 3.6) Lower bound constraint 46 | xi_lu_dB=-5; % 3.7) Upper threshold for local decision 47 | xi_ll_dB=-10; % 3.8) Lower threshold for local decision 48 | xi_gu_dB=-5; % 3.9) Upper threshold for global decision 49 | xi_gl_dB=-10; % 3.10) Lower threshold for global decision 50 | xi_fu_dB=-5; % 3.11) Upper threshold for local decision 51 | xi_fl_dB=-10; % 3.12) Lower threshold for local decision 52 | xi_mu_dB=10; % 3.13) Upper threshold for xi_m 53 | xi_ml_dB=0; % 3.14) Lower threshold for xi_m 54 | q_max=0.998; % 3.15) Upper limit constraint 55 | 56 | % 4) Parameters of "Decision-Directed" a Priori SNR Estimate 57 | alpha_eta_ref=0.95; % 4.1) Recursive averaging parameter 58 | eta_min_dB=-18; % 4.2) Lower limit constraint 59 | 60 | % 5) Flags 61 | broad_flag=1; % broad band flag % new version 62 | tone_flag=1; % pure tone flag % new version 63 | nonstat='medium'; %Non stationarity % new version 64 | 65 | % Read input data 66 | [y,Fs]=audioread(fin); % read size of input data, Fs and NBITS 67 | N=length(y); 68 | N = N(1); 69 | 70 | % Adjust parameters according to the actual sampling frequency 71 | if Fs~=Fs_ref 72 | M=2^round(log2(Fs/Fs_ref*M_ref)); 73 | Mo=Mo_ref/M_ref*M; 74 | alpha_s=alpha_s_ref^(M_ref/M*Fs/Fs_ref); 75 | alpha_d=alpha_d_ref^(M_ref/M*Fs/Fs_ref); 76 | alpha_eta=alpha_eta_ref^(M_ref/M*Fs/Fs_ref); 77 | alpha_xi=alpha_xi_ref^(M_ref/M*Fs/Fs_ref); 78 | else 79 | M=M_ref; 80 | Mo=Mo_ref; 81 | alpha_s=alpha_s_ref; 82 | alpha_d=alpha_d_ref; 83 | alpha_eta=alpha_eta_ref; 84 | alpha_xi=alpha_xi_ref; 85 | end 86 | alpha_d_long=0.99; 87 | eta_min=10^(eta_min_dB/10); 88 | G_f=eta_min^0.5; % Gain floor 89 | 90 | % window function 91 | %win=hamming(M); --- Changed by Yuval Konforti. 92 | win= kaiser(M, beta); 93 | % find a normalization factor for the window 94 | win2=win.^2; 95 | Mno=M-Mo; 96 | W0=win2(1:Mno); 97 | for k=Mno:Mno:M-1 98 | swin2=lnshift(win2,k); 99 | W0=W0+swin2(1:Mno); 100 | end 101 | W0=mean(W0)^0.5; 102 | win=win/W0; 103 | Cwin=sum(win.^2)^0.5; 104 | win=win/Cwin; 105 | 106 | Nframes=fix((N-Mo)/Mno); % number of frames 107 | out=zeros(M,1); 108 | b=hanning(2*w+1); 109 | b=b/sum(b); % normalize the window function 110 | b_xi_local=hanning(2*w_xi_local+1); 111 | b_xi_local=b_xi_local/sum(b_xi_local); % normalize the window function 112 | b_xi_global=hanning(2*w_xi_global+1); 113 | b_xi_global=b_xi_global/sum(b_xi_global); % normalize the window function 114 | l_mod_lswitch=0; 115 | M21=M/2+1; 116 | k_u=round(f_u/Fs*M+1); % Upper frequency bin for global decision 117 | k_l=round(f_l/Fs*M+1); % Lower frequency bin for global decision 118 | k_u=min(k_u,M21); 119 | k2_local=round(500/Fs*M+1); 120 | k3_local=round(3500/Fs*M+1); 121 | eta_2term=1; xi=0; xi_frame=0; 122 | Ncount=round(Nframes/10); 123 | waitHandle=waitbar(0,'Please wait...'); 124 | l_fnz=1; % counter for the first frame which is non-zero % new version omlsa3 125 | fnz_flag=0; % flag for the first frame which is non-zero % new version omlsa3 126 | zero_thres=1e-10; % new version omlsa3 127 | % zero_thres is a threshold for discriminating between zero and nonzero sample. 128 | % You may choose zero_thres=0, but then the program handles samples which are identically zero (and not ?epsilon? values). 129 | 130 | finID = fopen(fin,'r'); 131 | sigma_v_squared= zeros(M21, Nframes); % --- Added by Yuval Konforti. 132 | for l=1:Nframes 133 | if l==1 134 | %[y,Fs,~,fidx]=readwav(fin,'rf',M,0); % open input file and read one frame of data 135 | initfin=fread(finID,22,'int16'); 136 | y=fread(finID,M,'int16')/2^15; 137 | else 138 | %[y0,Fs,~,fidx]=readwav(fidx,'rf',Mno); 139 | y0=fread(finID,Mno,'int16')/2^15; 140 | y=[y(Mno+1:M,:) ; y0]; % update the frame of data 141 | end 142 | 143 | if (~fnz_flag && abs(y(1))>zero_thres) || (fnz_flag && any(abs(y)>zero_thres)) % new version omlsa3 144 | fnz_flag=1; % new version omlsa3 145 | 146 | % 1. Short Time Fourier Analysis 147 | Y=fft(win.*y); 148 | Ya2=abs(Y(1:M21)).^2; 149 | 150 | % if l==1 % new version omlsa3 151 | if l==l_fnz % new version omlsa3 152 | lambda_d=Ya2; 153 | end 154 | gamma=Ya2./max(lambda_d,1e-10); 155 | eta=alpha_eta*eta_2term+(1-alpha_eta)*max(gamma-1,0); 156 | eta=max(eta,eta_min); 157 | v=gamma.*eta./(1+eta); 158 | 159 | % 2.1. smooth over frequency 160 | Sf=conv(b,Ya2); % smooth over frequency 161 | Sf=Sf(w+1:M21+w); 162 | % if l==1 % new version omlsa3 163 | if l==l_fnz % new version omlsa3 164 | Sy=Ya2; 165 | S=Sf; 166 | St=Sf; 167 | lambda_dav=Ya2; 168 | else 169 | S=alpha_s*S+(1-alpha_s)*Sf; % smooth over time 170 | end 171 | % if l<15 % new version omlsa3 172 | if l<14+l_fnz % new version omlsa3 173 | Smin=S; 174 | SMact=S; 175 | else 176 | Smin=min(Smin,S); 177 | SMact=min(SMact,S); 178 | end 179 | % Local Minima Search 180 | I_f=double(Ya2 192 | end 193 | end 194 | % if l<15 % new version omlsa3 195 | if l<14+l_fnz % new version omlsa3 196 | St=S; 197 | Smint=St; 198 | SMactt=St; 199 | else 200 | St=alpha_s*St+(1-alpha_s)*Sft; 201 | Smint=min(Smint,St); 202 | SMactt=min(SMactt,St); 203 | end 204 | qhat=ones(M21,1); 205 | phat=zeros(M21,1); 206 | % gamma_mint=Ya2./Bmin./max(Smint,1e-10); % new version 207 | % zetat=S./Bmin./max(Smint,1e-10); % new version 208 | switch nonstat % new version 209 | case 'low' % new version 210 | gamma_mint=Ya2./Bmin./max(Smin,1e-10); % new version 211 | zetat=S./Bmin./max(Smin,1e-10); % new version 212 | otherwise % new version 213 | gamma_mint=Ya2./Bmin./max(Smint,1e-10); % new version 214 | zetat=S./Bmin./max(Smint,1e-10); % new version 215 | end % new version 216 | idx=find(gamma_mint>1 & gamma_mint=delta_yt | zetat>=delta_s)=1; 220 | alpha_dt=alpha_d+(1-alpha_d)*phat; 221 | lambda_dav=alpha_dt.*lambda_dav+(1-alpha_dt).*Ya2; 222 | % if l<15 % new version omlsa3 223 | if l<14+l_fnz % new version omlsa3 224 | lambda_dav_long=lambda_dav; 225 | else 226 | alpha_dt_long=alpha_d_long+(1-alpha_d_long)*phat; 227 | lambda_dav_long=alpha_dt_long.*lambda_dav_long+(1-alpha_dt_long).*Ya2; 228 | end 229 | l_mod_lswitch=l_mod_lswitch+1; 230 | if l_mod_lswitch==Vwin 231 | l_mod_lswitch=0; 232 | % if l==Vwin % new version omlsa3 233 | if l==Vwin-1+l_fnz % new version omlsa3 234 | SW=repmat(S,1,Nwin); 235 | SWt=repmat(St,1,Nwin); 236 | else 237 | SW=[SW(:,2:Nwin) SMact]; 238 | Smin=min(SW,[],2); 239 | SMact=S; 240 | SWt=[SWt(:,2:Nwin) SMactt]; 241 | Smint=min(SWt,[],2); 242 | SMactt=St; 243 | end 244 | end 245 | % 2.4. Noise Spectrum Estimate 246 | % lambda_d=1.4685*lambda_dav; % new version 247 | switch nonstat % new version 248 | case 'high' % new version 249 | lambda_d=2*lambda_dav; % new version 250 | otherwise % new version 251 | lambda_d=1.4685*lambda_dav; % new version 252 | end % new version 253 | sigma_v_squared(:, l)= lambda_d;% --- Added by Yuval Konforti. 254 | 255 | 256 | % 4. A Priori Probability for Signal-Absence Estimate 257 | xi=alpha_xi*xi+(1-alpha_xi)*eta; 258 | xi_local=conv(xi,b_xi_local); 259 | xi_local=xi_local(w_xi_local+1:M21+w_xi_local); 260 | xi_global=conv(xi,b_xi_global); 261 | xi_global=xi_global(w_xi_global+1:M21+w_xi_global); 262 | dxi_frame=xi_frame; 263 | xi_frame=mean(xi(k_l:k_u)); 264 | dxi_frame=xi_frame-dxi_frame; 265 | if xi_local>0, xi_local_dB=10*log10(xi_local); else; xi_local_dB=-100; end 266 | if xi_global>0, xi_global_dB=10*log10(xi_global); else; xi_global_dB=-100; end 267 | if xi_frame>0, xi_frame_dB=10*log10(xi_frame); else; xi_frame_dB=-100; end 268 | 269 | P_local=ones(M21,1); 270 | P_local(xi_local_dB<=xi_ll_dB)=P_min; 271 | idx=find(xi_local_dB>xi_ll_dB & xi_local_dBxi_gl_dB & xi_global_dB500Hz) for low probability of speech presence 282 | end 283 | if tone_flag % new version 284 | if (m_P_local<0.5) && (l>120) 285 | idx=find( lambda_dav_long(8:(M21-8)) > 2.5*(lambda_dav_long(10:(M21-6))+lambda_dav_long(6:(M21-10))) ); 286 | P_local([idx+6;idx+7;idx+8])=P_min; % remove interfering tonals 287 | end 288 | end % new version 289 | 290 | if xi_frame_dB<=xi_fl_dB 291 | P_frame=P_min; 292 | elseif dxi_frame>=0 293 | xi_m_dB=min(max(xi_frame_dB,xi_ml_dB),xi_mu_dB); 294 | P_frame=1; 295 | elseif xi_frame_dB>=xi_m_dB+xi_fu_dB 296 | P_frame=1; 297 | elseif xi_frame_dB<=xi_m_dB+xi_fl_dB 298 | P_frame=P_min; 299 | else 300 | P_frame=P_min+(xi_frame_dB-xi_m_dB-xi_fl_dB)/(xi_fu_dB-xi_fl_dB)*(1-P_min); 301 | end 302 | 303 | % q=1-P_global.*P_local*P_frame; % new version 304 | if broad_flag % new version 305 | q=1-P_global.*P_local*P_frame; % new version 306 | else % new version 307 | q=1-P_local*P_frame; %#ok % new version 308 | end % new version 309 | q=min(q,q_max); 310 | 311 | gamma=Ya2./max(lambda_d,1e-10); 312 | eta=alpha_eta*eta_2term+(1-alpha_eta)*max(gamma-1,0); 313 | eta=max(eta,eta_min); 314 | v=gamma.*eta./(1+eta); 315 | PH1=zeros(M21,1); 316 | idx=find(q<0.9); 317 | PH1(idx)=1./(1+q(idx)./(1-q(idx)).*(1+eta(idx)).*exp(-v(idx))); 318 | 319 | % 7. Spectral Gain 320 | GH1=ones(M21,1); 321 | idx=find(v>5); 322 | GH1(idx)=eta(idx)./(1+eta(idx)); 323 | idx=find(v<=5 & v>0); 324 | GH1(idx)=eta(idx)./(1+eta(idx)).*exp(0.5*expint(v(idx))); 325 | 326 | % Smint_global=[Smint [Smint(2:M21);Smint(M21)] [Smint(3:M21);Smint(M21-1:M21)] [Smint(4:M21);Smint(M21-2:M21)] [Smint(1);Smint(1:M21-1)] [Smint(1:2);Smint(1:M21-2)] [Smint(1:3);Smint(1:M21-3)]]; % new version 327 | % Smint_global=min(Smint_global,[],2); % new version 328 | % lambda_d_global=1.5*Bmin*Smint_global; % new version 329 | % Sy=0.8*Sy+0.2*Ya2; % new version 330 | % GH0=G_f*(lambda_d_global./Sy).^0.5; % new version 331 | if tone_flag % new version 332 | lambda_d_global=lambda_d; % new version 333 | lambda_d_global(4:M21-3)=min([lambda_d_global(4:M21-3),lambda_d_global(1:M21-6),lambda_d_global(7:M21)],[],2); % new version 334 | Sy=0.8*Sy+0.2*Ya2; % new version 335 | % GH0=G_f*(lambda_d_global./Sy).^0.5; % new version % new version omlsa3 336 | GH0=G_f*(lambda_d_global./(Sy+1e-10)).^0.5; % new version omlsa3 337 | else % new version 338 | GH0=G_f; %#ok % new version 339 | end % new version 340 | G=GH1.^PH1.*GH0.^(1-PH1); 341 | eta_2term=GH1.^2.*gamma; 342 | 343 | 344 | X=[zeros(3,1); G(4:M21-1).*Y(4:M21-1); 0]; 345 | %X=[zeros(2,1); G(3:M21-1).*Y(3:M21-1); 0]; 346 | X(M21+1:M)=conj(X(M21-1:-1:2)); %extend the anti-symmetric range of the spectum 347 | x=Cwin^2*win.*real(ifft(X)); 348 | out=out+x; 349 | else % new version omlsa3 350 | if ~fnz_flag % new version omlsa3 351 | l_fnz=l_fnz+1; % new version omlsa3 352 | end % new version omlsa3 353 | end % new version omlsa3 354 | if l==1 355 | foutID = fopen([fout '.wav'],'w'); % open output file and write first output samples 356 | fwrite(foutID,[initfin; out(1:Mno)*2^15],'int16'); 357 | else 358 | fwrite(foutID,out(1:Mno)*2^15,'int16'); % write to output file 359 | end 360 | out=[out(Mno+1:M); zeros(Mno,1)]; % update output frame 361 | if ~mod(l,Ncount) 362 | %disp([sprintf('%3.0f',100*l/Nframes) '%']); 363 | waitbar(l/Nframes); 364 | end % dispaly percentage of the processing stage 365 | end 366 | close(waitHandle) 367 | fwrite(foutID,out(1:M-Mno)*2^15,'int16'); % write to output file the last output samples 368 | fclose(finID); % close input file 369 | fclose(foutID); % close output file 370 | 371 | 372 | 373 | 374 | function y = lnshift(x,t) 375 | % lnshift -- t circular left shift of 1-d signal 376 | % Usage 377 | % y = lnshift(x,t) 378 | % Inputs 379 | % x 1-d signal 380 | % Outputs 381 | % y 1-d signal 382 | % y(i) = x(i+t) for i+t < n 383 | % y(i) = x(i+t-n) else 384 | % 385 | % Copyright (c) 2000. Prof Israel Cohen. 386 | % All rights reserved. 387 | % ***************************************************************@ 388 | szX=size(x); 389 | if szX(1)>1 390 | n=szX(1); 391 | y=[x((1+t):n); x(1:t)]; 392 | else 393 | n=szX(2); 394 | y=[x((1+t):n) x(1:t)]; 395 | end 396 | 397 | 398 | 399 | 400 | 401 | -------------------------------------------------------------------------------- /shiftcir.m: -------------------------------------------------------------------------------- 1 | function y = shiftcir(x,k) 2 | % SHIFTCIR: SHIFT CIRcular. 3 | % *******************************************************************@ 4 | % Inputs: 5 | % x, signal vector; 6 | % k, shift length; 7 | % Outputs: 8 | % y, circularly shifted signal vector; 9 | % Usage: 10 | % y = shiftcir(x,k); 11 | % Notes: 12 | % col vectors shifted up/down; row vectors shifted left/right; 13 | % k > 0 shifts up/left; k < 0 shifts down/right; 14 | % Functions: 15 | % mod; 16 | % Copyright (c) 1992-93 Carl Taswell. 17 | % All rights reserved. Created 5/8/92, last modified 6/6/93. 18 | % *******************************************************************@ 19 | [r,c] = size(x); n = max(r,c); 20 | k = mod(k,n); 21 | if c==1 22 | y = [x(k+1:n);x(1:k)]; % up/down for col vector 23 | else 24 | y = [x(k+1:n),x(1:k)]; % left/right for row vector 25 | end 26 | -------------------------------------------------------------------------------- /stft_changed_by_Yuval.m: -------------------------------------------------------------------------------- 1 | function Y=stft_changed_by_Yuval(x,nfft,dM,dN, beta) 2 | % stft : Short Time Fourier Transform 3 | % ***************************************************************@ 4 | % Inputs: 5 | % x, signal; 6 | % nfft, window length; 7 | % dM, sampling step in Time; 8 | % dN, sampling step in Frequency; 9 | % wintype, window type; 10 | % Usage: 11 | % Y=stft(x,nfft,dM,dN,wintype); 12 | % Defaults: 13 | % wintype='Hanning'; 14 | % dN = 1; 15 | % dM = 0.5*nfft; 16 | % nfft = minimum of 256 and the length of the signal; 17 | % Notes: 18 | % B = STFT(A,NFFT,dM,dN,WINTYPE) calculates the STFT 19 | % for the signal in vector A. The signal is split into 20 | % overlapping segments, each of which are windowed and then 21 | % Fourier transformed to produce an estimate of the 22 | % short-term frequency content of the signal. 23 | 24 | % Copyright (c) 2000. Dr Israel Cohen. 25 | % All rights reserved. Created 17/12/00. 26 | % ***************************************************************@ 27 | 28 | % Changed by Yuval to use Kaiser window with parameter beta. 29 | 30 | x = x(:); % make a column vector for ease later 31 | nx = length(x); 32 | if nargin == 1 33 | nfft = min(nx,256); 34 | end 35 | if nargin < 3 36 | dM = 0.5*nfft; 37 | dN = 1; 38 | end 39 | %if nargin < 5 40 | % wintype = 'Hanning'; 41 | %end 42 | 43 | %if exist(wintype) 44 | % wins=eval([lower(wintype),sprintf('(%g)',nfft)]); 45 | %else 46 | % error(['Undefined window type: ',wintype]) 47 | %end 48 | 49 | wins= kaiser(nfft, beta); 50 | 51 | % find analysis window for the above synthesis window 52 | win=biorwin(wins,dM,dN); 53 | 54 | % figure out number of columns for offsetting the signal 55 | % this may truncate the last portion of the signal since we'd 56 | % rather not append zeros unnecessarily - also makes the fancy 57 | % indexing that follows more difficult. 58 | ncol = fix((nx-nfft)/dM+1); 59 | y = zeros(nfft,ncol); 60 | 61 | % now stuff x into columns of y with the proper offset 62 | % should be able to do this with fancy indexing! 63 | colindex = 1 + (0:(ncol-1))*dM; 64 | rowindex = (1:nfft)'; 65 | y(:) = x(rowindex(:,ones(1,ncol))+colindex(ones(nfft,1),:)-1); 66 | 67 | % Apply the window to the array of offset signal segments. 68 | y(:) = win(:,ones(1,ncol)).*y; 69 | 70 | % now fft y which does the columns 71 | N = nfft/dN; 72 | for k=1:dN-1 73 | y(1:N,:) = y(1:N,:) + y((1:N)+k*N,:); 74 | end 75 | y = y(1:N,:); 76 | y = fft(y); 77 | if ~any(any(imag(x))) 78 | y = y(1:N/2+1,:); 79 | end 80 | % take abs, and use image to display results 81 | if nargout == 0 82 | imagesc(abs(y));axis xy 83 | else 84 | Y = y; 85 | end 86 | -------------------------------------------------------------------------------- /vars.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IsraelCohenLab/MultichannelAcousticEchoCancellation/31f8551f49ea8e856c2e40fff158a26abd6292f8/vars.mat --------------------------------------------------------------------------------