├── .gitignore ├── Auxiliary ├── compdist.m ├── generate_data.m ├── generate_sie.m ├── plot_J.m ├── plot_filter.m ├── plot_npm.m ├── plot_time.m ├── rdp.m └── ula_pos.m ├── Documentation ├── BSIE_Toolbox.pdf ├── BSIE_Toolbox.tex └── Figs │ └── pdf │ ├── clusteringExamples.pdf │ ├── cs.pdf │ ├── ls.pdf │ ├── mcflms_npm.pdf │ ├── mcflms_td.pdf │ ├── mclms_J.pdf │ ├── mclms_npm.pdf │ ├── mclms_td.pdf │ ├── mcn_J.pdf │ ├── mcn_npm.pdf │ ├── mcn_td.pdf │ ├── nmcflms_J.pdf │ ├── nmcflms_npm.pdf │ ├── nmcflms_speech_fd.pdf │ ├── nmcflms_speech_mic.pdf │ ├── nmcflms_speech_npm.pdf │ ├── nmcflms_speech_td.pdf │ ├── nmcflms_td.pdf │ ├── nmcmdflms.pdf │ ├── room.pdf │ ├── structure.pdf │ ├── system.pdf │ ├── tmp │ ├── wls.pdf │ ├── wls_iterative.pdf │ └── wls_iterative_J.pdf ├── LICENSE ├── README.md ├── Test ├── test_channel_shortening.m ├── test_edc.m ├── test_gmc.m ├── test_lsinvfilt.m ├── test_mcflms.m ├── test_mcflms_speech.m ├── test_mclms.m ├── test_mclms_cmpl.m ├── test_mclms_simple.m ├── test_mcn.m ├── test_mcss.m ├── test_nmcflms.m ├── test_nmcflms_sc.m ├── test_nmcflms_speech.m ├── test_nmcmdflms.m ├── test_nmcmdflms_comp.m ├── test_rmcls.m ├── test_rnmcflms_speech.m ├── test_spcc.m ├── test_wls.m └── test_wls_iterative.m ├── channel_shortening.m ├── contents.m ├── edc.m ├── gmc_st.m ├── init_mcflms.m ├── init_mclms.m ├── init_mcn.m ├── init_nmcflms.m ├── init_nmcflms_sc.m ├── init_nmcmdflms.m ├── init_rnmcflms.m ├── lsinvfilt.m ├── magnitude_deviation.m ├── mcflms.m ├── mclms.m ├── mcls.m ├── mcn.m ├── mcss.m ├── nmcflms.m ├── nmcflms_sc.m ├── nmcmdflms.m ├── npm.m ├── npm_ac.m ├── phase_deviation.m ├── rcic.m ├── rec.m ├── rmcls.m ├── rnmcflms.m ├── wls.m └── wls_iterative.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /Auxiliary/compdist.m: -------------------------------------------------------------------------------- 1 | function [IdxCm, chCm, dist]= compdist(zr,tol,opdist) 2 | 3 | % This function computes the distances between all the zeros for any 4 | % arbitrary number of channels 5 | % 6 | % Input zr: a N-by-M matrix where N= zeros of a transfer fn and 7 | % M= channels 8 | % 9 | % tol: specify the tolerance of the common zero. 10 | % opdist: output dist(y or n) 11 | % 12 | % Output dist: a 4D matrix containg the distances where 13 | % indices 1 and 2 contain all possible channels 14 | % indices 3 and 4 contain dist. of all possible zeros 15 | % of the tr. fn. 16 | % 17 | % IdxCm: a matrix containing the index of the zr mtx which are 18 | % common (total rows= toal common zeros, columns=2); 19 | % 20 | % chCm: a matrix containing the channels of the zr mtx which are 21 | % common (total rows= toal common zeros, columns=2); 22 | % 23 | % 24 | % E.g. dist(1,2,3,4) will return the distance between 3rd and 4th zero 25 | % of channel 1 and 2 respectively 26 | % 27 | % Method: This uses the relationship: (A-B)^2= A^2-2AB+B^2; 28 | % 29 | % Future versions: 30 | % - to increase efficiency, reduce the number of loops 31 | % from ch^2 to ch*(ch-1)/2 32 | % 33 | % History: 14th Feb 07 34 | % 16th Feb 07- Added common zeros extraction 35 | % 23th Feb 07- adjusted tolerance sensitivity 36 | % 21st May 07- changed order of comparison using struct prog 37 | % 23rd May 07- removed eps tolerence @ 80 38 | % 09th Jul 07- include dist output option 39 | % 40 | % Copyright (C) Imperial College London 2007-2010 41 | 42 | [len,TotCh] = size(zr); 43 | 44 | if lower(opdist)=='n' 45 | dist = zeros(len,len); 46 | ch1Bg = zeros(len,len); 47 | ch2Bg = zeros(len,len); 48 | 49 | 50 | IdxCm = []; 51 | chCm = []; 52 | 53 | for chA= 1:TotCh 54 | for chB= 1:TotCh 55 | 56 | ch1 = zr(:,chA); 57 | ch2 = zr(:,chB); 58 | 59 | ch1Bg = ch1*ones(1,len); 60 | ch2Bg = ones(len,1)*ch2.'; 61 | 62 | dist =... 63 | sqrt(abs(ch1Bg.^2-(2*ch1*ch2.')+ch2Bg.^2)); 64 | 65 | clear ch1Bg; 66 | clear ch2Bg; 67 | if chA 2 78 | tdoa = toa - min(toa); 79 | end 80 | 81 | % Truncate room impulse response 82 | h = h(1:L,:); 83 | 84 | if nargin > 4 && nargout > 1 85 | if nargin < 6 86 | SNR = 30; 87 | end 88 | 89 | % Generate source signal 90 | if ~exist('s','var') 91 | s = randn(N, 1); 92 | else 93 | if(length(s)==1) 94 | RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', s)); 95 | s = randn(N, 1); 96 | elseif(isempty(s)) 97 | s=randn(N,1); 98 | else 99 | N=length(s); 100 | end 101 | end 102 | 103 | % Calculate noisy sensor signals with correct SNR 104 | z = fftfilt(h, s); 105 | if isinf(SNR) 106 | x = z; 107 | else 108 | if (~exist('v','var')) 109 | v = randn(N,M); 110 | elseif(length(v)==1) 111 | RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', v)); 112 | v = randn(N, M); 113 | end 114 | v = sqrt(var(s)*norm(h(:),2).^2 / (10^(SNR/10)*M*mean(var(v)))).*v; 115 | x = z + v; 116 | end 117 | end 118 | 119 | % DEBUG 120 | % figure(100); 121 | % room_plot_all(src_pos',mic_pos',air.room_dim'); -------------------------------------------------------------------------------- /Auxiliary/generate_sie.m: -------------------------------------------------------------------------------- 1 | function ie = generate_sie(h, npm, mode, T60, fs) 2 | 3 | % This function generates system identification errors 4 | % 5 | % [ie] = generate_sie(h, npm, mode, T60, fs) 6 | % 7 | % Input Parameters: 8 | % h : system impulse responses 9 | % npm : desired NPM level in dB 10 | % mode : the shape of errors. Three options are 11 | % 'wgn' white Gaussian noise like errors; 12 | % 'prop' WGN but proportional to h; 13 | % 'damp' damping errors, damping factor same as h 14 | % T60 : the reverberation time of h, only needed for 15 | % generating damping errors 16 | % fs : sampling frequency, only needed for generating damping 17 | % errors (optional: default 8000) 18 | % 19 | % Output Parameters: 20 | % ie : the representation of identification errors 21 | % 22 | % Author : W. Zhang 23 | % 24 | % History: 2009-07-13 Initial version 25 | % 26 | % Copyright (C) Imperial College London 2009-2010 27 | 28 | [L M] = size(h); 29 | re = zeros(L, M); 30 | ie = zeros(L, M); 31 | 32 | if nargin == 3 && strcmp(mode, 'damp') 33 | error('T60 is required to generate damping errors'); 34 | else 35 | for m = 1:M 36 | switch mode 37 | case 'wgn' 38 | re(:,m) = randn(L,1); 39 | case 'prop' 40 | re(:,m) = randn(L,1) .* h(:,m); 41 | case 'damp' 42 | if nargin == 4 43 | fs = 8000; 44 | end 45 | alpha = 3*log(10)/T60/fs; 46 | re(:,m) = randn(L,1) .* exp(-alpha*(1:L))'; 47 | end 48 | ie(:,m) = re(:,m)-(re(:,m)'*h(:,m))/(h(:,m)'*h(:,m))*h(:,m); 49 | ie(:,m) = ie(:,m)/norm(ie(:,m))*norm(h(:,m))*10^(npm/20)/sqrt(1-10^(2*npm/20)); 50 | end 51 | end -------------------------------------------------------------------------------- /Auxiliary/plot_J.m: -------------------------------------------------------------------------------- 1 | function plot_J(J, fs, varargin) 2 | 3 | % Copyright (C) Imperial College London 2009-2010 4 | 5 | ax = 1/fs : 1/fs : length(J)/fs; 6 | plot(ax, 10*log10(J),varargin{:}); grid on; 7 | xlabel('Time (s)'); ylabel('J (dB)'); 8 | -------------------------------------------------------------------------------- /Auxiliary/plot_filter.m: -------------------------------------------------------------------------------- 1 | function plot_filter(h, h_hat) 2 | 3 | % Copyright (C) Imperial College London 2009-2010 4 | 5 | h_norm = h(:, 1)./max(abs(h(:, 1))); 6 | h_hat_norm = h_hat(:, 1)./max(abs(h_hat(:, 1))); 7 | 8 | stem(h_norm,'b'); 9 | hold on; 10 | stem(h_hat_norm, 'r'); 11 | grid on; 12 | hold off; 13 | xlabel('Time (samples)'); ylabel('Amplitude'); 14 | legend('h','h_{hat}'); 15 | axis tight; -------------------------------------------------------------------------------- /Auxiliary/plot_npm.m: -------------------------------------------------------------------------------- 1 | function phandle = plot_npm(npm_dB, fs, ns, varargin) 2 | 3 | % Copyright (C) Imperial College London 2009-2010 4 | 5 | if nargin < 3 6 | ns = 1; 7 | end 8 | 9 | ax = 1/fs : ns/fs : length(npm_dB)*ns/fs; 10 | phandle = plot(ax, npm_dB, varargin{:}); 11 | grid on; 12 | xlabel('Time (s)'); 13 | ylabel('NPM (dB)'); -------------------------------------------------------------------------------- /Auxiliary/plot_time.m: -------------------------------------------------------------------------------- 1 | function plot_time(x,fs,varargin) 2 | t = 0:1/fs:(length(x)-1)/fs; 3 | if nargin == 2 4 | plot(t,x); 5 | else 6 | plot(t,x,varargin{:}); 7 | end 8 | xlabel('Time (s)'); 9 | ylabel('Amplitude'); 10 | axis tight; -------------------------------------------------------------------------------- /Auxiliary/rdp.m: -------------------------------------------------------------------------------- 1 | function [h] = rdp(h_unc, toa) 2 | 3 | % This function removes the direct path propagation of 4 | % room impulse responses generated by image method 5 | % 6 | % [h, dl] = rdp(h_unc, tau, stat) 7 | % 8 | % Input Parameters: 9 | % h_unc : original room impulse responses 10 | % toa : shortest direct-path propagation time in 11 | % (fractional) samples 12 | % 13 | % Output Parameters: 14 | % h : updates room impulse responses 15 | % 16 | % Author : E.A.P. Habets 17 | % 18 | % History: 2009-07-11 Initial version by E.A.P. Habets 19 | % 2010-10-16 Automatically selects the microphone that is 20 | % closest to the source. 21 | % 2011-03-01 RIRs are now padded with zeros. 22 | % 23 | % Copyright (C) Imperial College London 2009-2011 24 | 25 | [L,M] = size(h_unc); 26 | 27 | h_tmp = zeros(L+ceil(toa),M); 28 | for m = 1:M 29 | h_tmp(:,m) = [h_unc(:, m); h_unc(end, m).*zeros(ceil(toa), 1)]; 30 | end 31 | 32 | NFFT = 2^nextpow2(size(h_tmp,1)); 33 | f = (0:fix(NFFT/2))/NFFT; 34 | H_unc = fft(h_tmp,NFFT); 35 | H = zeros(NFFT,M); 36 | for mm = 1:M 37 | E = exp(1i*2*pi*f*toa); 38 | H(:,mm) = H_unc(:,mm) .* [E conj(E(end-1:-1:2))].'; 39 | end 40 | h = real(ifft(H)); 41 | h = h(1:L,:); -------------------------------------------------------------------------------- /Auxiliary/ula_pos.m: -------------------------------------------------------------------------------- 1 | function micPos = ula_pos(micSpc,micNum,CenPos) 2 | 3 | % This function positions a ULA such that its centroid is positioned 4 | % at CenPos. 5 | % 6 | % micPos = ula_pos(micSpc,micHght,micNum,CenPos) 7 | % 8 | % Input Parameters: 9 | % micSpc : microphone spacing 10 | % micNum : number of microphones 11 | % CenPos : center position of the array 12 | % 13 | % Output parameters: 14 | % micPos : a 3-by-micNum vector containing mic positions 15 | % 16 | % Authors: A. Kong 17 | % 18 | % History: 2007 Inital version by A. Kong 19 | % 20 | % Copyright (C) Imperial College London 2007-2010 21 | 22 | linArray = 0:micSpc:micSpc*(micNum-1); % generate linear array 23 | arrayCen = linArray(end)/2; % find array centroid 24 | linArray = linArray-arrayCen; % center the array at origin 25 | micPos(1,:) = linArray+repmat(CenPos(1),1,micNum); 26 | micPos(2,:) = repmat(CenPos(2),1,micNum); 27 | micPos(3,:) = CenPos(3); 28 | -------------------------------------------------------------------------------- /Documentation/BSIE_Toolbox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/BSIE_Toolbox.pdf -------------------------------------------------------------------------------- /Documentation/BSIE_Toolbox.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/BSIE_Toolbox.tex -------------------------------------------------------------------------------- /Documentation/Figs/pdf/clusteringExamples.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/clusteringExamples.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/cs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/cs.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/ls.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/ls.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mcflms_npm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mcflms_npm.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mcflms_td.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mcflms_td.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mclms_J.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mclms_J.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mclms_npm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mclms_npm.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mclms_td.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mclms_td.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mcn_J.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mcn_J.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mcn_npm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mcn_npm.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/mcn_td.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/mcn_td.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_J.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_J.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_npm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_npm.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_speech_fd.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_speech_fd.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_speech_mic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_speech_mic.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_speech_npm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_speech_npm.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_speech_td.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_speech_td.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcflms_td.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcflms_td.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/nmcmdflms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/nmcmdflms.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/room.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/room.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/structure.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/structure.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/system.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/system.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/tmp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Documentation/Figs/pdf/wls.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/wls.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/wls_iterative.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/wls_iterative.pdf -------------------------------------------------------------------------------- /Documentation/Figs/pdf/wls_iterative_J.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickanaylor/BSIE_toolbox/309d3e7a52d25951a001143acce7c41b0d102a3a/Documentation/Figs/pdf/wls_iterative_J.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BSIE_toolbox 2 | Blind System Identification and Equalization Toolbox 3 | 4 | This is a pre-release version of our BSIE Toolbox. Please understand this is a work-in-progress. 5 | 6 | Authors: Emanuel A. P. Habets and Patrick A. Naylor 7 | 8 | All enquiries to p.naylor@imperial.ac.uk 9 | -------------------------------------------------------------------------------- /Test/test_channel_shortening.m: -------------------------------------------------------------------------------- 1 | % Run equalization algorithm: Channel_Shortening 2 | % This script runs the channel shortening algorithm 3 | % for equalization 4 | % 5 | % Authors: E.A.P. Habets 6 | % 7 | % History: 2009-07-11 Initial version 8 | % 9 | % Copyright (C) Imperial College London 2009-2010 10 | 11 | clc 12 | clear 13 | close all 14 | 15 | %% Initialization 16 | M = 2; % number of channels 17 | fs = 8e3; % sampling frequency 18 | L = 512; % channel length 19 | Li = L-1; 20 | Lw = 128; 21 | k = 0; 22 | iter = 600; 23 | a = 1.00145; 24 | w = [ones(k+1,1); a.^(1:L+Li-2-k)'-1]; 25 | 26 | % Generate AIRs 27 | air.c = 342; % speed of sound 28 | air.T60 = 0.3; % reverberation time 29 | air.room_dim = [10; 10; 3]; % room dimension 30 | air.mic_spacing = 0.2; % microphone spacing (m) 31 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 32 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 33 | h = generate_data(M, L, fs, air); 34 | 35 | % Truncate and normalize room impulse response 36 | h = h(1:L,:)./h(1,1); 37 | 38 | % Add identification errors, desired NPM = -30 dB 39 | ie = generate_sie(h,-30,'prop'); 40 | h_tilde = h + ie; 41 | 42 | %% Load room impulse responses 43 | % load ../Data/ht_3_C; 44 | % h = -ht(91:91+L-1,1:M)./ht(91,1); 45 | % clear ht; 46 | 47 | %% Compute equalization system using CS algorithm 48 | g = channel_shortening(h_tilde, Li, Lw, k); 49 | 50 | %% Compute equalized response 51 | er = zeros(L+Li-1,1); 52 | for m = 1:M 53 | er = er + conv(h(:,m), g(:,m)); 54 | end 55 | 56 | %% Plot results 57 | figure(1); 58 | plot([[h(:,1) ; zeros(Li-1,1)] er]); 59 | title('Impulse Responses'); 60 | xlabel('Time (samples)'); 61 | ylabel('Amplitude'); 62 | legend('First channel','Equalized'); -------------------------------------------------------------------------------- /Test/test_edc.m: -------------------------------------------------------------------------------- 1 | % Runs energy decay curve (EDC) and obtains derived measures. 2 | % 3 | % Authors: M. R. P. Thomas 4 | % 5 | % History: 2010-11-29 Initial version 6 | % 7 | % Copyright (C) Imperial College London 2009-2010 8 | 9 | clc 10 | clear 11 | close all 12 | 13 | %% Initialization 14 | M = 1; % number of channels 15 | fs = 8e3; % sampling frequency 16 | L = 2048; % channel length 17 | 18 | % Generate AIRs 19 | air.c = 342; % speed of sound 20 | air.T60 = 0.3; % reverberation time 21 | air.room_dim = [10; 10; 3]; % room dimension 22 | air.mic_spacing = 0.2; % microphone spacing (m) 23 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 24 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 25 | h = generate_data(M, L, fs, air); 26 | 27 | mymeas = {'T30','C50','D50'}; 28 | [decay, meas] = edc(h,fs,mymeas); 29 | 30 | t=1000*(0:1/fs:(length(decay)-1)/fs); 31 | plot(t,decay); 32 | xlabel('Time (ms)'); 33 | ylabel('EDC (dB)'); 34 | grid on; 35 | 36 | for ii=1:length(mymeas) 37 | fprintf('%s: %f\n',mymeas{ii},meas(ii)); 38 | end -------------------------------------------------------------------------------- /Test/test_gmc.m: -------------------------------------------------------------------------------- 1 | % Runs the GMC_ST algorithms to find 2 | % the number of near-common zeros 3 | % 4 | % References: 5 | % [1] J. Allen and D. Berkley, "Image method for 6 | % efficiently simulating small room acoustics", 7 | % JASA, 1979. 8 | % 9 | % Authors: E.A.P. Habets 10 | % 11 | % History: 2009-07-14 Initial version 12 | % 13 | % Copyright (C) Imperial College London 2009-2010 14 | 15 | clc; 16 | clear; 17 | close all; 18 | 19 | %% Initialization 20 | M = 2; % number of channels 21 | fs = 8e3; % sampling frequency 22 | L = 512; % channel length 23 | tol = 0.005; % tolerance 24 | 25 | % Generate AIRs 26 | air.c = 342; % speed of sound 27 | air.T60 = 0.3; % reverberation time 28 | air.room_dim = [5; 6; 3]; % room dimension 29 | air.mic_spacing = 0.2; % microphone spacing (m) 30 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 31 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 32 | h = generate_data(M, L, fs, air); 33 | 34 | % Find zeros of the acoustic impulse responses 35 | for ii=1:M; 36 | zr(:, ii) = roots(h(:, ii)); 37 | end 38 | 39 | % Find number of near-common zeros using GMC-DC 40 | % display(sprintf('\nRunning GMC-DC...')) 41 | % ZeroMtx = gmc_dc(zr, tol); 42 | % display(sprintf('GMC-DC: %d\n', size(ZeroMtx, 1))); 43 | % clear ZeroMtx; 44 | 45 | % Find clusters of near-common zeros using GMC-ST 46 | fprintf('Running GMC-ST...\n') 47 | [ClustMtx, ClustMem, ClustNum] = gmc_st(zr, tol); 48 | fprintf('GMC-ST: %d\n',ClustNum); -------------------------------------------------------------------------------- /Test/test_lsinvfilt.m: -------------------------------------------------------------------------------- 1 | % Run equalization algorithm: LS 2 | % This script runs the least squares (LS) 3 | % algorithm for equalization. 4 | % 5 | % Authors: E.A.P. Habets 6 | % 7 | % History: 2009-07-11 Initial version 8 | % 9 | % Copyright (C) Imperial College London 2009-2010 10 | 11 | clc 12 | clear 13 | close all 14 | 15 | %% Initialization 16 | M = 2; % number of channels 17 | fs = 8e3; % sampling frequency 18 | L = 128; % channel length 19 | Li = L-1; 20 | k = 0; 21 | 22 | % Generate AIRs 23 | air.c = 342; % speed of sound 24 | air.T60 = 0.3; % reverberation time 25 | air.room_dim = [10; 10; 3]; % room dimension 26 | air.mic_spacing = 0.2; % microphone spacing (m) 27 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 28 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 29 | h = generate_data(M, L, fs, air); 30 | 31 | % Truncate and normalize room impulse response 32 | h = h(1:L,:)./h(1,1); 33 | 34 | % Add identification errors, desired NPM = -30 dB 35 | ie = generate_sie(h,-30,'prop'); 36 | h_tilde = h + ie; 37 | 38 | %% Load room impulse responses 39 | % load ../Data/ht_3_C; 40 | % h = -ht(91:91+L-1,1:M)./ht(91,1); 41 | % clear ht; 42 | 43 | %% Compute equalization system using MINT (Li=L-1) 44 | g = lsinvfilt(h_tilde, Li, k); 45 | 46 | %% Compute equalized response 47 | er = zeros(L+Li-1,1); 48 | for m = 1:M 49 | er = er + conv(h(:,m), g(:,m)); 50 | end 51 | 52 | %% Plot results 53 | figure(1); 54 | plot([[h(:,1) ; zeros(Li-1,1)] er]); 55 | title('Impulse Responses'); 56 | xlabel('Time (samples)'); 57 | ylabel('Amplitude'); 58 | legend('First channel','Equalized channel'); -------------------------------------------------------------------------------- /Test/test_mcflms.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCFLMS 2 | % This script runs the MCFLMS algorithm for 3 | % blind system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Frequency-Domain 10 | % adaptive approaches to blind multi-channel 11 | % identification," IEEE Trans. Sig. Process., 12 | % Vol. 51, No. 1, Jan 2003. 13 | % 14 | % Authors: E.A.P. Habets 15 | % 16 | % History: 2009-07-10 Initial version 17 | % 18 | % Copyright (C) Imperial College London 2009-2010 19 | 20 | clc; 21 | clear; 22 | close all; 23 | 24 | %% Initialization 25 | M = 5; % number of channels 26 | fs = 8e3; % sampling frequency 27 | L = 128; % channel length 28 | F = 2*L; % frame lenght 29 | SNR = 40; % signal to noise ratio (in dB) 30 | N = 5*fs; % data length (samples) 31 | s_seed = 1; % seed for generating source signal 32 | v_seed = 50;% seed for generating noise signal 33 | mu = 0.2; % step-size 34 | 35 | % Generate sensor signals and AIRs 36 | air.c = 342; % speed of sound 37 | air.T60 = 0.3; % reverberation time 38 | air.room_dim = [5; 6; 3]; % room dimension 39 | air.mic_spacing = 0.2; % microphone spacing (m) 40 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 41 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 42 | [h, x] = generate_data(M, L, fs, air, N, SNR, s_seed, v_seed); 43 | 44 | % Initialize MCLMS 45 | [h_hat] = init_mcflms(L, M); 46 | ns = F-L+1; % number of new samples per iteration 47 | B = fix(N/ns); % number of input blocks of length L 48 | npm_dB = zeros(B,1); 49 | 50 | %% Processing Loop: run MCFLMS [2] 51 | wbar = waitbar(0,'MCFLMS'); 52 | ss_cntr = {'fixed','vss','rvss'}; 53 | h_hat = repmat(h_hat,[1 1 length(ss_cntr)]); 54 | for bb = 1 : B 55 | waitbar(bb/B); 56 | if bb == 1 57 | xm = [zeros(F-ns,M); x(1:ns,:)]; 58 | else 59 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 60 | end 61 | for tt = 1 : length(ss_cntr) 62 | [h_hat(:,:,tt)] = mcflms(xm, h_hat(:,:,tt), mu, ss_cntr{tt}); 63 | npm_dB(bb,tt) = 20*log10(npm(h, h_hat(:,:,tt))); 64 | end 65 | end 66 | close(wbar); 67 | 68 | %% Plot results 69 | % NPM 70 | figure(1); 71 | phandle = plot_npm(npm_dB, fs, ns, '-o', 'MarkerIndices',1:floor(length(npm_dB)/20):length(npm_dB)); 72 | legend(['MCFLMS' strcat(ss_cntr(2:end),'-MCFLMS')]); 73 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 74 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 75 | 76 | % Time-domain coefficients 77 | figure(2); plot_filter(h, h_hat(:,:,1)); -------------------------------------------------------------------------------- /Test/test_mcflms_speech.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCFLMS 2 | % This script runs MCFLMS algorithm for blind 3 | % system identification, the acoustic source is 4 | % a male speaker 5 | % 6 | % References: 7 | % [1] J. Allen and D. Berkley, "Image method for 8 | % efficiently simulating small room acoustics", 9 | % JASA, 1979. 10 | % [2] Y. Huang and J. Benesty, "Frequency-Domain 11 | % adaptive approaches to blind multi-channel 12 | % identification," IEEE Trans. Sig. Process., 13 | % Vol. 51, No. 1, Jan 2003. 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2009-07-10 Initial version 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 4; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 256; % channel length 29 | F = 2*L; % frame-length 30 | SNR = 50; % signal to noise ratio (in dB) 31 | mu = 0.005; % step-size 32 | 33 | % Generate AIRs 34 | air.c = 342; % speed of sound 35 | air.T60 = 0.3; % reverberation time 36 | air.room_dim = [5; 6; 3]; % room dimension 37 | air.mic_spacing = 0.2; % microphone spacing (m) 38 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 39 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 40 | h = generate_data(M, L, fs, air); 41 | 42 | % Load source signal 43 | N = 18*fs; % Simulation time in seconds 44 | [s, fs_wav] = audioread([datapath 'male_english_8k.wav']); 45 | if fs_wav ~= fs 46 | error('Incorrect sample frequency.'); 47 | end 48 | s = s(1:N); 49 | % Add small amount of noise to source signal to improve stability 50 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',1)); 51 | va = randn(size(s,1), 1); 52 | va = sqrt(var(s)/(10^(40/10)*mean(var(va)))) .* va; 53 | s = s + va; 54 | s = 0.9 * s' / max(abs(s)); 55 | 56 | % Calculate noisy sensor signals with correct SNR 57 | z = fftfilt(h, s); 58 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',50)); 59 | v = randn(N, M); % Generate additive noise 60 | v = sqrt(var(s)*norm(h(:),2).^2/(10^(SNR/10)*M*mean(var(v)))) .* v; 61 | x = z + v; 62 | 63 | % Initialize MCLMS 64 | [h_hat] = init_mcflms(L, M); 65 | ns = L/8; % number of new samples per iteration 66 | B = fix(N/ns); % number of input blocks of length L 67 | npm_dB = zeros(B,1); 68 | 69 | %% Processing Loop: run MCFLMS [2] 70 | wbar = waitbar(0,'MCFLMS'); 71 | for bb = 1 : B 72 | waitbar(bb/B); 73 | if bb == 1 74 | xm = [zeros(F-ns,M); x(1:ns,:)]; 75 | else 76 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 77 | end 78 | [h_hat, P_k_avg] = mcflms(xm, h_hat, mu, 'rvss'); 79 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 80 | end 81 | close(wbar); 82 | 83 | %% Plot results 84 | % NPM 85 | figure(1); plot_npm(npm_dB, fs, ns); 86 | legend('RVSS-MCFLMS'); 87 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 88 | ', SNR= ', num2str(SNR), ', M= ', num2str(M)]); 89 | 90 | % Filter coeff. 91 | figure(2); plot_filter(h,h_hat); 92 | 93 | % Frequency-domain 94 | figure(3); 95 | H = fft(h(:,1)./norm(h(:,1)),L); 96 | H_hat = fft(h_hat(:,1)./norm(h_hat(:,1)),L); 97 | plot(20*log10(abs(H(1:end/2+1)))); hold on; 98 | plot(20*log10(abs(H_hat(1:end/2+1))), 'r'); grid on; hold off; 99 | xlabel('Frequency bins'); 100 | ylabel('Magnitude (dB)'); 101 | legend('h','h_{hat}'); 102 | axis tight; 103 | 104 | % First microphone signal 105 | figure(4); 106 | plot_time(x(:,1), fs); 107 | -------------------------------------------------------------------------------- /Test/test_mclms.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCLMS 2 | % This script runs the MCLMS algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Adaptive multi- 10 | % channel mean square and Newton algorithms 11 | % for blind channel identification", 12 | % Signal Process., vol. 83, no. 8, 13 | % pp. 1127-1138, Aug 2002. 14 | % 15 | % Authors: S. Lin, E.A.P. Habets 16 | % 17 | % History: 2009-06-25 Initial version by SL 18 | % 2009-07-10 Major changes by EH 19 | % 20 | % Copyright (C) Imperial College London 2009-2010 21 | 22 | clc; 23 | clear; 24 | close all; 25 | 26 | %% Initialization 27 | M = 5; % number of channels 28 | fs = 8e3; % sampling frequency 29 | L = 128; % channel length 30 | SNR = 30; % signal to noise ratio (dB) 31 | N = 4*fs; % data length (samples) 32 | s_seed = 1; % seed for generating source signal 33 | v_seed = 50;% seed for generating noise signal 34 | mu = .8; % step-size 35 | 36 | % Generate sensor signals and AIRs 37 | air.c = 342; % speed of sound 38 | air.T60 = 0.3; % reverberation time 39 | air.room_dim = [5; 6; 3]; % room dimension 40 | air.mic_spacing = 0.2; % microphone spacing (m) 41 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 42 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 43 | [h, x] = generate_data(M, L, fs, air, N, SNR, s_seed, v_seed); 44 | 45 | % Initialize MCLMS 46 | [xin, h_hat] = init_mclms(L, M); 47 | npm_dB = zeros(N,1); 48 | J = zeros(N,1); 49 | 50 | %% Processing Loop: run MCLMS [2] 51 | wbar = waitbar(0,'MCLMS'); 52 | ss_cntr = {'fixed','vss'}; 53 | h_hat = repmat(h_hat,[1 1 length(ss_cntr)]); 54 | for nn = 1 : N 55 | waitbar(nn/N); 56 | xin = [x(nn, :); xin(1 : L-1, :)]; 57 | for tt = 1 : length(ss_cntr) 58 | [h_hat(:,:,tt), J(nn,tt)] = mclms(xin, h_hat(:,:,tt), mu, ss_cntr{tt}); 59 | npm_dB(nn,tt) = 20*log10(npm(h, h_hat(:,:,tt))); 60 | end 61 | end 62 | close(wbar); 63 | 64 | %% Plot results 65 | figure(1); 66 | phandle = plot_npm(npm_dB, fs, 1, '-o', 'MarkerIndices',1:floor(length(npm_dB)/20):length(npm_dB)); 67 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 68 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 69 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 70 | 71 | figure(2); plot_J(J, fs); % cost function 72 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 73 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 74 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 75 | 76 | figure(3); plot_filter(h, h_hat(:,:,2)) % filter coeff. -------------------------------------------------------------------------------- /Test/test_mclms_cmpl.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCLMS 2 | % This script runs the MCLMS algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Adaptive multi- 10 | % channel mean square and Newton algorithms 11 | % for blind channel identification", 12 | % Signal Process., vol. 83, no. 8, 13 | % pp. 1127-1138, Aug 2002. 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2009-08-24 Initial version by EH 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 3; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 1; % channel length 29 | SNR = 40; % signal to noise ratio (dB) 30 | N = 0.2*fs; % data length (samples) 31 | mu = .1; % step-size 32 | 33 | % Generate sensor signals and AIRs 34 | s = randn(1,N) + 1i*randn(1,N); 35 | h(:,1) = 1 * exp(1i*pi/2); 36 | h(:,2) = 1 * exp(1i*0); 37 | h(:,3) = 1 * exp(1i*2*pi/3); 38 | for m = 1 : M 39 | x(:,m) = filter(h(:,m),1,s); 40 | end 41 | 42 | % Initialize MCLMS 43 | [xin, h_hat] = init_mclms(L, M); 44 | npm_dB = zeros(N,1); 45 | J = zeros(N,1); 46 | 47 | %% Processing Loop: run MCLMS [2] 48 | wbar = waitbar(0,'MCLMS'); 49 | ss_cntr = {'fixed'}; 50 | h_hat = repmat(h_hat,[1 1 length(ss_cntr)]); 51 | for nn = 1 : N 52 | waitbar(nn/N); 53 | xin = [x(nn, :); xin(1 : L-1, :)]; 54 | for tt = 1 : length(ss_cntr) 55 | [h_hat(:,:,tt), J(nn,tt)] = mclms(xin, h_hat(:,:,tt), mu, ss_cntr{tt}); 56 | npm_dB(nn,tt) = 20*log10(npm(h, h_hat(:,:,tt))); 57 | end 58 | end 59 | close(wbar); 60 | 61 | %% Plot results 62 | figure(1); 63 | phandle = plot_npm(npm_dB, fs, 1, '-o', 'MarkerIndices',1:floor(length(npm_dB)/20):length(npm_dB)); 64 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 65 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 66 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 67 | 68 | figure(2); plot_J(J, fs); % cost function 69 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 70 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 71 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 72 | 73 | figure(3); 74 | roots_h = roots(h(1,:)); 75 | roots_h_hat = roots(h_hat(1,:)); 76 | zplane(roots_h); 77 | hold on; 78 | plot(real(roots_h),imag(roots_h),'bo'); 79 | plot(real(roots_h_hat),imag(roots_h_hat),'rs'); 80 | hold off; 81 | axis(2*[-1 1 -1 1]); 82 | grid on; 83 | legend('True zeros','Estimated zeros') 84 | 85 | % display([roots_h.' ; roots_h_hat.']); -------------------------------------------------------------------------------- /Test/test_mclms_simple.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCLMS 2 | % This script runs the MCLMS algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Adaptive multi- 10 | % channel mean square and Newton algorithms 11 | % for blind channel identification", 12 | % Signal Process., vol. 83, no. 8, 13 | % pp. 1127-1138, Aug 2002. 14 | % 15 | % Authors: S. Lin, E.A.P. Habets 16 | % 17 | % History: 2009-09-02 Initial version by EH 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 3; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 3; % channel length 29 | SNR = [30 30 20]; % signal to noise ratio (dB) 30 | N = .5*fs; % data length (samples) 31 | mu = .4; % step-size 32 | 33 | %% Generate simple impulse responses 34 | theta = pi/10; 35 | phi = pi/10; % Ill Conditioned System 36 | % phi = 2*pi/3; % Well Conditioned System 37 | 38 | h(:,1) = [1 -2*cos(theta) 1]'; 39 | h(:,2) = [1 -2*cos(theta+phi) 1]'; 40 | h(:,3) = [1 -2*cos(theta+2*phi) 1]'; 41 | 42 | %% Generate signals 43 | s = randi([0,1],[1,N]); % Generate D length of either 0 or 1. 44 | s = s - mean(s); 45 | for i = 1:M 46 | x(:,i) = filter(h(:,i),1,s); 47 | x(:,i) = awgn(x(:,i),SNR(i)); 48 | end 49 | 50 | %% Initialize MCLMS 51 | % global R_hat; 52 | % R_hat = zeros(L*M,L*M); 53 | % for tf=1:N-L+1 54 | % xin = x(tf:tf+L-1,:); 55 | % R_hat = 0.98 * R_hat + (1-0.98) * xin(:)*xin(:)'; 56 | % end 57 | [xin, h_hat] = init_mclms(L, M); 58 | npm_dB = zeros(N,1); 59 | J = zeros(N,1); 60 | 61 | %% Processing Loop: run MCLMS [2] 62 | wbar = waitbar(0,'MCLMS'); 63 | ss_cntr = {'fixed','vss-unconstrained','vss'}; 64 | h_hat = repmat(h_hat,[1 1 length(ss_cntr)]); 65 | for nn = 1 : N 66 | waitbar(nn/N); 67 | xin = [x(nn, :); xin(1 : L-1, :)]; 68 | for tt = 1 : length(ss_cntr) 69 | if tt == 1 70 | [h_hat(:,:,tt), J(nn,tt)] = mclms(xin, h_hat(:,:,tt), mu/10, ss_cntr{tt}); 71 | else 72 | [h_hat(:,:,tt), J(nn,tt)] = mclms(xin, h_hat(:,:,tt), mu, ss_cntr{tt}); 73 | end 74 | npm_dB(nn,tt) = 20*log10(npm(h, h_hat(:,:,tt))); 75 | end 76 | end 77 | close(wbar); 78 | 79 | %% Plot results 80 | figure(1); 81 | phandle = plot_npm(npm_dB, fs, 1, '-o', 'MarkerIndices',1:floor(length(npm_dB)/20):length(npm_dB)); 82 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 83 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 84 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 85 | 86 | figure(2); plot_J(J, fs); % cost function 87 | legend(['MCLMS' strcat(ss_cntr(2:end),'-MCLMS')]); 88 | title(['L= ',num2str(L), ', \mu= ',num2str(mu), ... 89 | ', SNR= ',num2str(SNR), ', M= ', num2str(M)]); 90 | 91 | figure(3); plot_filter(h, h_hat(:,:,3)) % filter coeff. -------------------------------------------------------------------------------- /Test/test_mcn.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: MCN 2 | % This script runs the MCN algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Adaptive multi- 10 | % channel mean square and Newton algorithms 11 | % for blind channel identification", 12 | % Signal Process., vol. 83, no. 8, 13 | % pp. 1127-1138, Aug 2002. 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2009-07-10 Initial version 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 5; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 16; % channel length 29 | SNR = 40; % signal to noise ratio (in dB) 30 | N = 0.2*fs; % data length (samples) 31 | s_seed = 1; % seed for generating source signal 32 | v_seed = 50;% seed for generating noise signal 33 | rho = 0.98; % step-size 34 | lambda = 0.99; % forgetting-factor 35 | 36 | % Generate sensor signals and AIRs 37 | air.c = 342; % speed of sound 38 | air.T60 = 0.3; % reverberation time 39 | air.room_dim = [5; 6; 3]; % room dimension 40 | air.mic_spacing = 0.2; % microphone spacing (m) 41 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 42 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 43 | [h, x] = generate_data(M, L, fs, air, N, SNR, s_seed, v_seed); 44 | 45 | % Initialize MCLMS 46 | [xin, h_hat, R_hat] = init_mcn(L, M, [x(1,:) ; ... 47 | zeros(L-1,M)]); 48 | npm_dB = zeros(N, 1); 49 | N = size(x, 1); 50 | J = zeros(N, 1); 51 | 52 | %% Processing Loop: run MCN [2] 53 | wbar = waitbar(0,'MCN'); 54 | for nn = 1 : N 55 | waitbar(nn/N); 56 | xin = [x(nn, :) ; xin(1 : L-1, :)]; 57 | [h_hat, R_hat, J(nn)] = mcn(xin, h_hat,... 58 | R_hat, rho, lambda); 59 | npm_dB(nn) = 20*log10(npm(h, h_hat)); 60 | end 61 | close(wbar); 62 | 63 | %% Plot results 64 | figure(1); plot_npm(npm_dB, fs); % NPM 65 | legend('MCN'); 66 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 67 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 68 | num2str(SNR), ', M= ', num2str(M)]); 69 | 70 | figure(2); plot_J(J, fs); % cost function 71 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 72 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 73 | num2str(SNR), ', M= ', num2str(M)]); 74 | 75 | figure(3); plot_filter(h,h_hat); % filter coeff. 76 | -------------------------------------------------------------------------------- /Test/test_mcss.m: -------------------------------------------------------------------------------- 1 | % Run subspace BSI algorithm: MCSS 2 | % This script runs the MCSS algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % 10 | % Authors: E.A.P. Habets 11 | % 12 | % History: 2010-04-15 Initial version by EH 13 | % 14 | % Copyright (C) Imperial College London 2010 15 | 16 | clear; 17 | close all; 18 | 19 | %% Initialization 20 | M = 4; % number of channels 21 | fs = 8e3; % sampling frequency 22 | L = 64; % channel length 23 | SNR = 50; % signal to noise ratio (dB) 24 | N = 2*fs; % data length (samples) 25 | 26 | % Generate sensor signals and AIRs 27 | air.c = 342; % speed of sound 28 | air.T60 = 0.2; % reverberation time 29 | air.room_dim = [5; 6; 3]; % room dimension 30 | air.mic_spacing = 0.2; % microphone spacing (m) 31 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 32 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 33 | h = generate_data(M, L, fs, air, N, SNR); 34 | 35 | % theta = pi/10; % IC 36 | % phi = pi/10; % IC 37 | % theta = pi/10; % WC 38 | % phi = 2*pi/3; % WC 39 | % h(:,1) = [1 -2*cos(theta) 1]'; 40 | % h(:,2) = [1 -2*cos(theta+phi) 1]'; 41 | % h(:,3) = [1 -2*cos(theta+2*phi) 1]'; 42 | 43 | % RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', 3)); 44 | % h = randn(L,M); 45 | % h = h ./ norm(h,2); 46 | 47 | %% Generate signals 48 | RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', 1)); 49 | s = randi(2,1,N); % Generate N length of either 0 or 1. 50 | s = s - mean(s); 51 | for i = 1:M 52 | x(:,i) = filter(h(:,i),1,s); 53 | end 54 | 55 | %% Add noise 56 | for i = 1:M 57 | x(:,i) = awgn(x(:,i),SNR); 58 | end 59 | 60 | %% Processing Loop: run MCLS 61 | % methods = {'Moulines'}; 62 | methods = {'Moulines','Moulines_constraint'}; 63 | npm_dB = zeros(length(methods),2); 64 | % h_hat = zeros(L,M,length(methods)); 65 | D = 0; % Over-estimate with D coefficients 66 | for mm = 1:length(methods) 67 | % Overestimate but given the correct channel order 68 | % h_hat(:,:,mm) = mcss(x,L+2,L,methods{mm}); 69 | 70 | % Overestimate and given the incorrect channel order 71 | h_hat(:,:,mm) = mcss(x,L+D,L+D,methods{mm}); 72 | 73 | npm_dB(mm,1) = 20*log10(npm(h, h_hat(:,:,mm))); 74 | npm_dB(mm,2) = 20*log10(npm_ac(h, h_hat(:,:,mm))); 75 | end 76 | 77 | %% Plot results 78 | fprintf('NPM\n'); 79 | for mm = 1:length(methods) 80 | fprintf([methods{mm} ' : %.2f / %.2f dB\n'], npm_dB(mm,:)); 81 | end 82 | 83 | NFFT=2^nextpow2(L+1); 84 | figure(2); 85 | Ptmp=20*log10(abs(fft(h(:,1),NFFT))); 86 | plot(Ptmp(1:NFFT/2+1)-mean(Ptmp),'g'); 87 | hold on; 88 | Ptmp = 20*log10(abs(fft(h_hat(:,1,1),NFFT))); 89 | plot(Ptmp(1:NFFT/2+1)-mean(Ptmp),':r'); 90 | Ptmp = 20*log10(abs(fft(h_hat(:,1,2),NFFT))); 91 | plot(Ptmp(1:NFFT/2+1)-mean(Ptmp),'b'); 92 | hold off; grid on; 93 | legend('True','Moulines','Habets') 94 | xlabel('Frequency'); 95 | ylabel('Energy (dB)'); 96 | 97 | figure;plot([[zeros(D,1) ; h(:,1)] h_hat(:,1,1) -h_hat(:,1,2)]); -------------------------------------------------------------------------------- /Test/test_nmcflms.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: NMCFLMS 2 | % This script runs the NMCFLMS algorithm for 3 | % blind system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Frequency-Domain 10 | % adaptive approaches to blind multi-channel 11 | % identification," IEEE Trans. Sig. Process., 12 | % Vol. 51, No. 1, Jan 2003. 13 | % 14 | % Authors: E.A.P. Habets 15 | % 16 | % History: 2009-07-10 Initial version 17 | % 18 | % Copyright (C) Imperial College London 2009-2010 19 | 20 | clc; 21 | clear; 22 | close all; 23 | 24 | %% Initialization 25 | M = 5; % number of channels 26 | fs = 8e3; % sampling frequency 27 | L = 128; % channel length 28 | F = 2*L; % frame lenght 29 | SNR = 40; % signal to noise ratio (in dB) 30 | s_seed = 1; % seed for generating source signal 31 | v_seed = 50; % seed for generating noise signal 32 | N = 5*fs; % data length (samples) 33 | rho = 0.8; % step-size 34 | lambda = 0.98; % forgetting-factor 35 | 36 | % Generate sensor signals and AIRs 37 | air.c = 342; % speed of sound 38 | air.T60 = 0.3; % reverberation time 39 | air.room_dim = [5; 6; 3]; % room dimension 40 | air.mic_spacing = 0.2; % microphone spacing (m) 41 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 42 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 43 | [h, x] = generate_data(M, L, fs, air, N, SNR, s_seed, v_seed); 44 | 45 | % Initialize NMCFLMS 46 | [h_hat, P_k_avg] = init_nmcflms(L, F, M, x(1:F,:)); 47 | ns = F-L+1; 48 | B = fix(N/ns); % number of input blocks of length L 49 | J = zeros(N,1); 50 | npm_dB = zeros(B,1); 51 | 52 | Xm = fft(x(1:F,:),F); 53 | P_x = conj(Xm).*Xm; 54 | delta = (M-1)*mean(mean(P_x)); 55 | 56 | %% Processing Loop: run NMCFLMS [2] 57 | wbar = waitbar(0,'NMCFLMS'); 58 | for bb = 1 : B 59 | waitbar(bb/B); 60 | if bb == 1 61 | xm = [zeros(F-ns,M); x(1:ns,:)]; 62 | else 63 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 64 | end 65 | [h_hat, P_k_avg, J_tmp] = nmcflms(xm, h_hat,... 66 | P_k_avg, rho, lambda, delta); 67 | J((bb-1)*ns+1:(bb)*ns) = J_tmp(F-L-ns+2:end); 68 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 69 | end 70 | close(wbar); 71 | 72 | %% Plot results 73 | figure(1); plot_npm(npm_dB, fs, ns); % NPM 74 | legend('NMCFLMS'); 75 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 76 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 77 | num2str(SNR), ', M= ', num2str(M)]); 78 | 79 | figure(2); plot_J(J, fs); % cost function 80 | legend('NMCFLMS'); 81 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 82 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 83 | num2str(SNR), ', M= ', num2str(M)]); 84 | 85 | figure(3); plot_filter(h,h_hat); % filter coeff. -------------------------------------------------------------------------------- /Test/test_nmcflms_sc.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: NMCFLMS_SC 2 | % This script runs the NMCFLMS algorithm for 3 | % blind system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] N. D. Gaubitch, Md. K. Hasan and P. A. Naylor, "Noise Robust 10 | % Adaptive Blind Channel Identification Using Spectral Constraints", 11 | % Proc. IEEE Int. Conf. on Acoust. Speech and Signal Processing 12 | % (ICASSP), Toulouse, France, May 2006. 13 | % 14 | % Authors: E.A.P. Habets 15 | % 16 | % History: 2010-03-27 Initial version 17 | % 18 | % Copyright (C) Imperial College London 2010 19 | 20 | clc; 21 | clear; 22 | close all; 23 | 24 | %% Initialization 25 | M = 5; % number of channels 26 | fs = 8e3; % sampling frequency 27 | L = 128; % channel length 28 | F = 2*L; % frame lenght 29 | SNR = 20; % signal to noise ratio (in dB) 30 | N = 50*fs; % data length (samples) 31 | rho = 0.8; % step-size 32 | lambda = 0.8; % forgetting-factor 33 | 34 | % Generate sensor signals and AIRs 35 | air.c = 342; % speed of sound 36 | air.T60 = 0.3; % reverberation time 37 | air.room_dim = [5; 6; 3]; % room dimension 38 | air.mic_spacing = 0.2; % microphone spacing (m) 39 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 40 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 41 | [h, x] = generate_data(M, L, fs, air, N, SNR); 42 | 43 | x = [zeros(L,M); x]; 44 | 45 | % Initialize MCLMS_SC 46 | [h_hat(:,:,1), P_k_avg(:,:,1)] = init_nmcflms(L, F, M, x(1:F,:)); 47 | [h_hat(:,:,2), P_k_avg(:,:,2), Pn] = init_nmcflms_sc(L, F, M, x(1:F,:)); 48 | ns = F-L+1; 49 | B = fix(N/ns); % number of input blocks of length ns 50 | J = zeros(N,1); 51 | npm_dB = zeros(B,1); 52 | 53 | Xm = fft(x(1:F,:),F); 54 | P_x = conj(Xm).*Xm; 55 | delta = (M-1)*mean(mean(P_x)); 56 | %delta = sum(sum(P_x))/F*(M-1)/M/(10^(SNR/10)); 57 | 58 | %% Processing Loop: run NMCFLMS_SC 59 | wbar = waitbar(0,'NMCFLMS with and without SC'); 60 | for bb = 1 : B 61 | waitbar(bb/B); 62 | xm = x((bb-1)*L+1:(bb+1)*L,:); 63 | 64 | [h_hat(:,:,1), P_k_avg(:,:,1), J_tmp] = nmcflms(xm, h_hat(:,:,1),... 65 | P_k_avg(:,:,1), rho, lambda, delta); 66 | J((bb-1)*ns+1:(bb)*ns,1) = J_tmp(F-L-ns+2:end); 67 | npm_dB(bb,1) = 20*log10(npm(h, h_hat(:,:,1))); 68 | 69 | [h_hat(:,:,2), P_k_avg(:,:,2), Pn, J_tmp] = nmcflms_sc(xm, h_hat(:,:,2),... 70 | P_k_avg(:,:,2), Pn, rho, lambda, delta); 71 | J((bb-1)*ns+1:(bb)*ns,2) = J_tmp(F-L-ns+2:end); 72 | npm_dB(bb,2) = 20*log10(npm(h, h_hat(:,:,2))); 73 | end 74 | close(wbar); 75 | 76 | %% Plot results 77 | figure(1); plot_npm(npm_dB, fs, ns); % NPM 78 | legend('NMCFLMS','NMCFLMS-SC'); 79 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 80 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 81 | num2str(SNR), ', M= ', num2str(M)]); 82 | 83 | figure(2); plot_J(J, fs); % cost function 84 | legend('NMCFLMS','NMCFLMS-SC'); 85 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 86 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 87 | num2str(SNR), ', M= ', num2str(M)]); 88 | 89 | figure(3); plot_filter(h,h_hat(:,:,2)); % filter coeff. -------------------------------------------------------------------------------- /Test/test_nmcflms_speech.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: NMCFLMS 2 | % This script runs NMCFLMS algorithm for blind 3 | % system identification, the acoustic source is 4 | % a male speaker 5 | % 6 | % References: 7 | % [1] J. Allen and D. Berkley, "Image method for 8 | % efficiently simulating small room acoustics", 9 | % JASA, 1979. 10 | % [2] Y. Huang and J. Benesty, "Frequency-Domain 11 | % adaptive approaches to blind multi-channel 12 | % identification," IEEE Trans. Sig. Process., 13 | % Vol. 51, No. 1, Jan 2003. 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2009-07-10 Initial version 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 4; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 256; % channel length 29 | F = 2*L; % frame-length 30 | SNR = 50; % signal to noise ratio (in dB) 31 | rho = 0.2; % step-size 32 | lambda = 0.98; % forgetting-factor 33 | 34 | % Generate AIRs 35 | air.c = 342; % speed of sound 36 | air.T60 = 0.3; % reverberation time 37 | air.room_dim = [5; 6; 3]; % room dimension 38 | air.mic_spacing = 0.2; % microphone spacing (m) 39 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 40 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 41 | h = generate_data(M, L, fs, air); 42 | 43 | % Load source signal 44 | N = 18*fs; % Simulation time in seconds 45 | [s, fs_wav] = audioread([datapath 'male_english_8k.wav']); 46 | if fs_wav ~= fs 47 | error('Incorrect sample frequency.'); 48 | end 49 | s = s(1:N); 50 | % Add small amount of noise to source signal to improve stability 51 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',1)); 52 | va = randn(size(s,1), 1); 53 | va = sqrt(var(s)/(10^(40/10)*mean(var(va)))) .* va; 54 | s = s + va; 55 | s = 0.9 * s' / max(abs(s)); 56 | 57 | % Calculate noisy sensor signals with correct SNR 58 | z = fftfilt(h, s); 59 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',50)); 60 | v = randn(N, M); % Generate additive noise 61 | v = sqrt(var(s)*norm(h(:),2).^2/(10^(SNR/10)*M*mean(var(v)))) .* v; 62 | x = z + v; 63 | 64 | % Initialize MCLMS 65 | [h_hat, P_k_avg] = init_nmcflms(L, F, M, x(1:F,:)); 66 | ns = L/8; % number of new samples per iteration 67 | B = fix(N/ns); % number of input blocks of length L 68 | npm_dB = zeros(B,1); 69 | 70 | %% Processing Loop: run NMCFLMS [2] 71 | wbar = waitbar(0,'NMCFLMS'); 72 | for bb = 1 : B 73 | waitbar(bb/B); 74 | if bb == 1 75 | xm = [zeros(F-ns,M); x(1:ns,:)]; 76 | else 77 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 78 | end 79 | 80 | Xm = fft(xm,F); 81 | P_x = conj(Xm).*Xm; 82 | delta = (M-1)*mean(mean(P_x)); 83 | 84 | [h_hat, P_k_avg] = nmcflms(xm, h_hat, P_k_avg,... 85 | rho, lambda, delta); 86 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 87 | end 88 | close(wbar); 89 | 90 | %% Plot results 91 | % NPM 92 | figure(1); plot_npm(npm_dB, fs, ns); 93 | legend('NMCFLMS'); 94 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 95 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 96 | num2str(SNR), ', M= ', num2str(M)]); 97 | 98 | % Filter coeff. 99 | figure(2); plot_filter(h,h_hat); 100 | 101 | % Frequency-domain 102 | figure(3); 103 | H = fft(h(:,1)./norm(h(:,1)),L); 104 | H_hat = fft(h_hat(:,1)./norm(h_hat(:,1)),L); 105 | plot(20*log10(abs(H(1:end/2+1)))); hold on; 106 | plot(20*log10(abs(H_hat(1:end/2+1))), 'r'); grid on; hold off; 107 | xlabel('Frequency bins'); 108 | ylabel('Magnitude (dB)'); 109 | legend('h','h_{hat}'); 110 | axis tight; 111 | 112 | % First microphone signal 113 | figure(4); 114 | plot_time(x(:,1), fs); -------------------------------------------------------------------------------- /Test/test_nmcmdflms.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: NMCMDFLMS 2 | % This script runs the NMCMDFLMS algorithm [2] for 3 | % blind system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] R. Ahmad, A. W. H. Khong, and P. Naylor, "Proportionate frequency 10 | % domain adaptive algorithms for blind channel identification," in 11 | % Proc. ICASSP, Toulouse, France, May 2006, vol. 5, pp. 29-32. 12 | % 13 | % Authors: E.A.P. Habets 14 | % 15 | % History: 2011-03-01 Initial version 16 | % 17 | % Copyright (C) Imperial College London 2011 18 | 19 | clc; 20 | clear; 21 | close all; 22 | 23 | %% Initialization 24 | Mch = 5; % number of channels 25 | fs = 8e3; % sampling frequency 26 | L = 128; % channel length 27 | F = 2*L; % frame lenght 28 | SNR = 40; % signal to noise ratio (in dB) 29 | TimeSec = 10; % duration (seconds) 30 | Ldata = TimeSec*fs; % data length (samples) 31 | rho = 0.6; 32 | Mks = 0:2; % determines the number of partitions to consider 33 | lstyle = {'-','--',':'}; 34 | 35 | % Generate sensor signals and AIRs 36 | air.c = 342; % speed of sound 37 | air.T60 = 0.3; % reverberation time 38 | air.room_dim = [5; 6; 3]; % room dimension 39 | air.mic_spacing = 0.2; % microphone spacing (m) 40 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 41 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 42 | [h, x] = generate_data(Mch, L, fs, air, Ldata, SNR); 43 | 44 | %% Process 45 | for Mk_idx = 1:length(Mks) 46 | Ms = 2^Mks(Mk_idx); 47 | Ns = 2*L/Ms; 48 | npm_dB_all = []; 49 | 50 | for rho_idx = 1:length(rho) 51 | % Initialize NMCMDFLMS 52 | [shMDF h_hat] = init_nmcmdflms(L, Ms, Mch, x); 53 | 54 | ns = Ns/2; % number of new samples per iteration 55 | B = fix(Ldata/ns); % number of input blocks of length L 56 | npm_dB = zeros(B,1); 57 | 58 | % Processing Loop: run NMCMDFLMS 59 | wbar = waitbar(0,'NMCMDFLMS'); 60 | 61 | for bb = 1 : B 62 | waitbar(bb/B); 63 | 64 | if bb == 1 65 | xm = [zeros(ns,Mch); x(1:ns,:)]; 66 | else 67 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 68 | end 69 | 70 | [shMDF, h_hat] = nmcmdflms(shMDF, xm, rho(rho_idx)); 71 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 72 | end 73 | npm_dB_all = [npm_dB_all, npm_dB]; 74 | close(wbar) 75 | end 76 | 77 | NN = length(npm_dB); 78 | xscale = 1:NN; 79 | tsec = Ldata/fs; 80 | xscale = xscale/NN*tsec; 81 | 82 | figure(1); 83 | hold on; 84 | plot(xscale,npm_dB_all,lstyle{Mk_idx}); 85 | end 86 | 87 | %% Markup plot 88 | leg = []; 89 | for Mk_idx = 1:length(Mks) 90 | rho_str = num2str(rho.'); 91 | for kk = 1:size(rho_str,1) 92 | leg = [leg ; ['NMCMDFLMS \rho = ', rho_str(kk,:), ', Ms = ', num2str(2^Mks(Mk_idx))]]; 93 | end 94 | end 95 | grid on; 96 | axis([0 TimeSec -25 0]) 97 | legend(leg) 98 | hold off; 99 | xlabel('Time (s)'); 100 | ylabel('NPM (dB)'); -------------------------------------------------------------------------------- /Test/test_nmcmdflms_comp.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: NMCMDFLMS 2 | % This script runs the NMCMDFLMS algorithm [2] for 3 | % blind system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] R. Ahmad, A. W. H. Khong, and P. Naylor, "Proportionate frequency 10 | % domain adaptive algorithms for blind channel identification," in 11 | % Proc. ICASSP, Toulouse, France, May 2006, vol. 5, pp. 29-32. 12 | % 13 | % Authors: E.A.P. Habets 14 | % 15 | % History: 2011-03-01 Initial version 16 | % 17 | % Copyright (C) Imperial College London 2011 18 | 19 | clc; 20 | clear; 21 | close all; 22 | 23 | %% Initialization 24 | Mch = 5; % number of channels 25 | fs = 8e3; % sampling frequency 26 | L = 128; % channel length 27 | F = 2*L; % frame lenght 28 | SNR = 40; % signal to noise ratio (in dB) 29 | TimeSec = 10; % Duration (seconds) 30 | Ldata = TimeSec*fs; % data length (samples) 31 | rho = [0.6 ; 0.6]; % step-size 32 | lambda = []; 33 | delta = []; 34 | 35 | % Generate sensor signals and AIRs 36 | air.c = 342; % speed of sound 37 | air.T60 = 0.3; % reverberation time 38 | air.room_dim = [5; 6; 3]; % room dimension 39 | air.mic_spacing = 0.2; % microphone spacing (m) 40 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 41 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 42 | [h, x] = generate_data(Mch, L, fs, air, Ldata, SNR); 43 | 44 | %% Process 45 | for Mk = 2 46 | Ms = 2^Mk; 47 | Ns = 2*L/Ms; 48 | npm_dB_NMCMDFLMS_all = []; 49 | npm_dB_NMCFLMS_all = []; 50 | 51 | for rho_idx = 1:size(rho,2) 52 | % Initialize NMCMDFLMS 53 | [shMDF h_hat] = init_nmcmdflms(L, Ms, Mch, x); 54 | 55 | ns = Ns/2; % number of new samples per iteration 56 | B = fix(Ldata/ns); % number of input blocks of length L 57 | npm_dB = zeros(B,1); 58 | 59 | % Processing Loop: run NMCMDFLMS 60 | wbar = waitbar(0,'NMCMDFLMS'); 61 | 62 | for bb = 1 : B 63 | waitbar(bb/B); 64 | 65 | if bb == 1 66 | xm = [zeros(ns,Mch); x(1:ns,:)]; 67 | else 68 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 69 | end 70 | 71 | shMDF.bb = bb; 72 | shMDF.normVal = 1; 73 | [shMDF, h_hat, J_tmp] = nmcmdflms(shMDF, xm, rho(1,rho_idx), lambda, delta); 74 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 75 | end 76 | npm_dB_NMCMDFLMS_all = [npm_dB_NMCMDFLMS_all; npm_dB]; 77 | close(wbar) 78 | end 79 | end 80 | 81 | for rho_idx = 1:size(rho,2) 82 | % Initialize NMCFLMS 83 | [h_hat, P_k_avg] = init_nmcflms(L, F, Mch, x(1:F,:)); 84 | 85 | ns = F-L; 86 | B = fix(Ldata/ns); % number of input blocks of length L 87 | J = zeros(Ldata,1); 88 | npm_dB = zeros(B,1); 89 | 90 | % Processing Loop: run NMCFLMS 91 | wbar = waitbar(0,'NMCFLMS'); 92 | for bb = 1 : B 93 | waitbar(bb/B); 94 | if bb == 1 95 | xm = [zeros(F-ns,Mch); x(1:ns,:)]; 96 | else 97 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 98 | end 99 | [h_hat, P_k_avg, J_tmp] = nmcflms(xm, h_hat,... 100 | P_k_avg, rho(2,rho_idx), lambda, delta); 101 | J((bb-1)*ns+1:(bb)*ns) = J_tmp(F-L-ns+2:end); 102 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 103 | end 104 | npm_dB_NMCFLMS_all = [npm_dB_NMCFLMS_all; npm_dB]; 105 | close(wbar); 106 | end 107 | 108 | %% Plot results 109 | tsec = Ldata/fs; 110 | 111 | figure(1); 112 | hold on 113 | xscale = (1:length(npm_dB_NMCFLMS_all))/length(npm_dB_NMCFLMS_all)*tsec; 114 | plot(xscale,npm_dB_NMCFLMS_all,'b-'); 115 | xscale = (1:length(npm_dB_NMCMDFLMS_all))/length(npm_dB_NMCMDFLMS_all)*tsec; 116 | plot(xscale,npm_dB_NMCMDFLMS_all,'r--'); 117 | hold off; 118 | rho_str = num2str(rho.'); 119 | legend('NMCFLMS','NMCMDFLMS Ms=4'); 120 | grid on; 121 | xlabel('Time (s)'); 122 | ylabel('NPM (dB)'); -------------------------------------------------------------------------------- /Test/test_rmcls.m: -------------------------------------------------------------------------------- 1 | % Run equalization algorithm: rmcls 2 | % This script runs the RMCLS algorithm for equalization 3 | % 4 | % Authors: M. R. P. Thomas 5 | % 6 | % History: 2011-01-24 Initial version 7 | % 8 | % Copyright (C) Imperial College London 2009-2011 9 | 10 | clc 11 | clear 12 | close all 13 | 14 | %% Initialization 15 | M = 2; % number of channels 16 | fs = 8e3; % sampling frequency 17 | L = 512; % channel length 18 | Li = L-1; 19 | Lw = 128; 20 | k = 0; 21 | tau = 0; 22 | iter = 600; 23 | a = 1.00145; 24 | w = [ones(k+1,1); a.^(1:L+Li-2-k)'-1]; 25 | 26 | % Generate AIRs 27 | air.c = 342; % speed of sound 28 | air.T60 = 0.3; % reverberation time 29 | air.room_dim = [10; 10; 3]; % room dimension 30 | air.mic_spacing = 0.2; % microphone spacing (m) 31 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 32 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 33 | h = generate_data(M, L, fs, air); 34 | 35 | % Truncate and normalize room impulse response 36 | h = h(1:L,:)./h(1,1); 37 | 38 | % Add identification errors, desired NPM = -30 dB 39 | ie = generate_sie(h,-30,'prop'); 40 | h_tilde = h + ie; 41 | 42 | %% Load room impulse responses 43 | % load ../Data/ht_3_C; 44 | % h = -ht(91:91+L-1,1:M)./ht(91,1); 45 | % clear ht; 46 | 47 | %% Compute equalization system using CS algorithm 48 | g = rmcls(h_tilde, Li, Lw, tau); 49 | 50 | %% Compute equalized response 51 | er = zeros(L+Li-1,1); 52 | for m = 1:M 53 | er = er + conv(h(:,m), g(:,m)); 54 | end 55 | 56 | %% Plot results 57 | figure(1); 58 | plot([[h(:,1) ; zeros(Li-1,1)] er]); 59 | title('Impulse Responses'); 60 | xlabel('Time (samples)'); 61 | ylabel('Amplitude'); 62 | legend('First channel','Equalized'); -------------------------------------------------------------------------------- /Test/test_rnmcflms_speech.m: -------------------------------------------------------------------------------- 1 | % Run adaptive BSI algorithm: RNMCFLMS 2 | % This script runs the RNMCFLMS algorithm for blind 3 | % system identification, the acoustic source is 4 | % a male speaker 5 | % 6 | % References: 7 | % [1] J. Allen and D. Berkley, "Image method for 8 | % efficiently simulating small room acoustics", 9 | % JASA, 1979. 10 | % [2] Y. Huang and J. Benesty, "Frequency-Domain 11 | % adaptive approaches to blind multi-channel 12 | % identification," IEEE Trans. Sig. Process., 13 | % Vol. 51, No. 1, Jan 2003. 14 | % [3] M. Haque and M. Hasan, "Noise robust multi- 15 | % channel frequency-domain LMS algorithms 16 | % for blind channel identification," IEEE Signal 17 | % Process. Lett., vol. 15, pp. 305-308, 2008. 18 | % 19 | % Authors: E.A.P. Habets 20 | % 21 | % History: 2009-07-10 Initial version 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | clc; 26 | clear; 27 | close all; 28 | 29 | %% Initialization 30 | M = 4; % number of channels 31 | fs = 8e3; % sampling frequency 32 | L = 256; % channel length 33 | F = 2*L; % frame-length 34 | SNR = 50; % signal to noise ratio (in dB) 35 | rho = 0.2; % step-size 36 | lambda = 0.98; % forgetting-factor 37 | 38 | % Generate AIRs 39 | air.c = 342; % speed of sound 40 | air.T60 = 0.3; % reverberation time 41 | air.room_dim = [5; 6; 3]; % room dimension 42 | air.mic_spacing = 0.2; % microphone spacing (m) 43 | air.src_pos = [100*pi/180 2*pi/180 2]; % source location 44 | air.cen_pos = [2.5; 2; 1.6]; % centre pos. of the array 45 | h = generate_data(M, L, fs, air); 46 | 47 | % Load source signal 48 | N = 18*fs; % Simulation time in seconds 49 | [s, fs_wav] = audioread([datapath 'male_english_8k.wav']); 50 | if fs_wav ~= fs 51 | error('Incorrect sample frequency.'); 52 | end 53 | s = s(1:N); 54 | % Add small amount of noise to source signal to improve stability 55 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',1)); 56 | va = randn(size(s,1), 1); 57 | va = sqrt(var(s)/(10^(40/10)*mean(var(va)))) .* va; 58 | s = s + va; 59 | s = 0.9 * s' / max(abs(s)); 60 | 61 | % Calculate noisy sensor signals with correct SNR 62 | z = fftfilt(h, s); 63 | RandStream.setGlobalStream(RandStream('mt19937ar','Seed',50)); 64 | v = randn(N, M); % Generate additive noise 65 | v = sqrt(var(s)*norm(h(:),2).^2/(10^(SNR/10)*M*mean(var(v)))) .* v; 66 | x = z + v; 67 | 68 | % Initialize RNMCFLMS 69 | [h_hat, P_k_avg] = init_nmcflms(L, F, M, x(1:F,:)); 70 | ns = L/8; % number of new samples per iteration 71 | B = fix(N/ns); % number of input blocks of length L 72 | npm_dB = zeros(B,1); 73 | 74 | %% Processing Loop: run RNMCFLMS [2,3] 75 | wbar = waitbar(0,'RNMCFLMS'); 76 | for bb = 1 : B 77 | waitbar(bb/B); 78 | if bb == 1 79 | xm = [zeros(F-ns,M); x(1:ns,:)]; 80 | else 81 | xm = [xm(ns+1:end,:); x((bb-1)*ns+1:bb*ns,:)]; 82 | end 83 | 84 | Xm = fft(xm,F); 85 | P_x = conj(Xm).*Xm; 86 | delta = (M-1)*mean(mean(P_x)); 87 | 88 | [h_hat, P_k_avg] = rnmcflms(xm, h_hat, P_k_avg,... 89 | rho, lambda, delta); 90 | npm_dB(bb) = 20*log10(npm(h, h_hat)); 91 | end 92 | close(wbar); 93 | 94 | %% Plot results 95 | % NPM 96 | figure(1); plot_npm(npm_dB, fs, ns); 97 | legend('RNMCFLMS'); 98 | title(['L= ',num2str(L), ', \rho= ',num2str(rho), ... 99 | ', \lambda= ',num2str(lambda), ', SNR= ', ... 100 | num2str(SNR), ', M= ', num2str(M)]); 101 | 102 | % Filter coeff. 103 | figure(2); plot_filter(h,h_hat); 104 | 105 | % Magnitude response 106 | figure(3); 107 | freqs = (0:(fs/2)/(L/2):(fs/2))/1000; 108 | H = fft(h(:,1)./norm(h(:,1)),L); 109 | H_hat = fft(h_hat(:,1)./norm(h_hat(:,1)),L); 110 | plot(freqs,20*log10(abs(H(1:end/2+1)))); hold on; 111 | plot(freqs,20*log10(abs(H_hat(1:end/2+1))), 'r'); grid on; hold off; 112 | xlabel('Frequency (kHz)'); 113 | ylabel('Magnitude (dB)'); 114 | legend('h','h_{hat}'); 115 | axis tight; 116 | 117 | % First microphone signal 118 | figure(4); 119 | plot_time(x(:,1), fs); -------------------------------------------------------------------------------- /Test/test_spcc.m: -------------------------------------------------------------------------------- 1 | % Run subspace BSI algorithm: MCLS 2 | % This script runs the MCLS algorithm for blind 3 | % system identification 4 | % 5 | % References: 6 | % [1] J. Allen and D. Berkley, "Image method for 7 | % efficiently simulating small room acoustics", 8 | % JASA, 1979. 9 | % [2] Y. Huang and J. Benesty, "Adaptive multi- 10 | % channel mean square and Newton algorithms 11 | % for blind channel identification", 12 | % Signal Process., vol. 83, no. 8, 13 | % pp. 1127-1138, Aug 2002. 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2010-03-23 Initial version by EH 18 | % 19 | % Copyright (C) Imperial College London 2010 20 | 21 | clc; 22 | clear; 23 | close all; 24 | 25 | %% Initialization 26 | M = 3; % number of channels 27 | fs = 8e3; % sampling frequency 28 | L = 3; % channel length 29 | N = 2*fs; % data length (samples) 30 | N_ittr = 10; % number of itterations 31 | SNR = 30; 32 | 33 | %% Generate impulse responses 34 | % theta = pi/10; % Ill Conditioned System 35 | % phi = pi/10; % Ill Conditioned System 36 | theta = pi/10; % Well Conditioned System 37 | phi = 2*pi/3; % Well Conditioned System 38 | h(:,1) = [1 -2*cos(theta) 1]'; 39 | h(:,2) = [1 -2*cos(theta+phi) 1]'; 40 | h(:,3) = [1 -2*cos(theta+2*phi) 1]'; 41 | 42 | %% Generate signals 43 | RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', 1)); 44 | s = randi(2,1,N); % Generate N length of either 0 or 1. 45 | s = s - mean(s); 46 | for i = 1:M 47 | x(:,i) = filter(h(:,i),1,s); 48 | end 49 | 50 | %% Add noise 51 | SNR_M = SNR + [0 0 -15]; 52 | for i = 1:M 53 | x(:,i) = awgn(x(:,i),SNR_M(i)); 54 | end 55 | 56 | %% Processing Loop: run MCLS 57 | [h_hat(:,:,1), R_hat(:,:,1)] = mcls(x,L,'recursive_alt'); 58 | npm_dB(1) = 20*log10(npm(h, h_hat(:,:,1))); 59 | 60 | for ittr = 2 : N_ittr 61 | [h_hat(:,:,ittr),R_hat(:,:,ittr)] = mcls(x,L,'spcc',h_hat(:,:,ittr-1)); 62 | npm_dB(ittr) = 20*log10(npm(h, h_hat(:,:,ittr))); 63 | end 64 | 65 | %% Plot results 66 | figure(1); 67 | plot(npm_dB,'b-o'); 68 | grid on; 69 | xlabel('Itterations'); 70 | ylabel('NPM (dB)') -------------------------------------------------------------------------------- /Test/test_wls.m: -------------------------------------------------------------------------------- 1 | % Run equalization algorithm: WLS 2 | % This script runs the weighted least squares (WLS) 3 | % algorithm for equalization. 4 | % 5 | % Authors: E.A.P. Habets 6 | % 7 | % History: 2009-07-11 Initial version 8 | % 9 | % Copyright (C) Imperial College London 2009-2010 10 | 11 | clc 12 | clear 13 | close all 14 | 15 | %% Initialization 16 | M = 2; % number of channels 17 | fs = 8e3; % sampling frequency 18 | L = 512; % channel length 19 | Li = L-1; 20 | k = 0; 21 | a = 1.00145; 22 | w = [ones(k+1,1); a.^(1:L+Li-2-k)'-1]; 23 | 24 | % Generate AIRs 25 | air.c = 342; % speed of sound 26 | air.T60 = 0.3; % reverberation time 27 | air.room_dim = [10; 10; 3]; % room dimension 28 | air.mic_spacing = 0.2; % microphone spacing (m) 29 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 30 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 31 | h = generate_data(M, L, fs, air); 32 | 33 | % Truncate and normalize room impulse response 34 | h = h(1:L,:)./h(1,1); 35 | 36 | % Add identification errors, desired NPM = -30 dB 37 | ie = generate_sie(h,-30,'prop'); 38 | h_tilde = h + ie; 39 | 40 | % Check the NPM level for h_tilde 41 | fprintf('NPM for h_tilde: %d dB\n\n',20*log10(npm(h,h_tilde))); 42 | 43 | %% Load room impulse responses 44 | % load ../Data/ht_3_C; 45 | % h = -ht(91:91+L-1,1:M)./ht(91,1); 46 | % clear ht; 47 | 48 | %% Compute equalization system using MINT (Li=L-1) 49 | g = wls(h_tilde, Li, k, w); 50 | 51 | %% Compute equalized response 52 | er = zeros(L+Li-1,1); 53 | for m = 1:M 54 | er = er + conv(h(:,m), g(:,m)); 55 | end 56 | 57 | %% Plot results 58 | figure(1); 59 | plot([[h(:,1) ; zeros(Li-1,1)] er]); 60 | title('Impulse Responses'); 61 | xlabel('Time (samples)'); 62 | ylabel('Amplitude'); 63 | legend('First channel','Equalized channel'); 64 | 65 | figure(2) 66 | subplot(211); 67 | [md, md_all] = magnitude_deviation(er); 68 | plot(md_all); 69 | axis tight; 70 | grid on; 71 | title('Magnitude Distortion'); 72 | xlabel('Frequency bins'); 73 | ylabel('Distortion (dB)'); 74 | 75 | figure(2) 76 | subplot(212); 77 | [pd, pd_all] = phase_deviation(er); 78 | plot(pd_all); 79 | axis tight; 80 | grid on; 81 | title('Phase Distortion'); 82 | xlabel('Phase (rad)'); 83 | ylabel('Distrotion (dB)'); -------------------------------------------------------------------------------- /Test/test_wls_iterative.m: -------------------------------------------------------------------------------- 1 | % Run equalization algorithm: WLS_iterative 2 | % This script runs the iterative weighted 3 | % least squares (LS) algorithm for equalization. 4 | % 5 | % Authors: E.A.P. Habets 6 | % 7 | % History: 2009-07-11 Initial version 8 | % 9 | % Copyright (C) Imperial College London 2009-2010 10 | 11 | clc 12 | clear 13 | close all 14 | 15 | %% Initialization 16 | M = 2; % number of channels 17 | fs = 8e3; % sampling frequency 18 | L = 512; % channel length 19 | Li = L-1; % equalizer length 20 | k = 0; % delay 21 | iter = 600; % number of iterations 22 | a = 1.00145; % weight parameter 23 | w = [ones(k+1,1); a.^(1:L+Li-2-k)'-1]; % weighting 24 | 25 | % Generate AIRs 26 | air.c = 342; % speed of sound 27 | air.T60 = 0.3; % reverberation time 28 | air.room_dim = [10; 10; 3]; % room dimension 29 | air.mic_spacing = 0.2; % microphone spacing (m) 30 | air.src_pos = [100*pi/180 2*pi/180 3]; % source location 31 | air.cen_pos = [5; 4; 1.6]; % centre pos. of the array 32 | h = generate_data(M, L, fs, air); 33 | 34 | % Truncate and normalize room impulse response 35 | h = h(1:L,:)./h(1,1); 36 | 37 | % Add identification errors, desired NPM = -30 dB 38 | ie = generate_sie(h,-30,'prop'); 39 | h_tilde = h + ie; 40 | 41 | %% Load room impulse responses 42 | % load ../Data/ht_3_C; 43 | % h = -ht(91:91+L-1,1:M)./ht(91,1); 44 | % clear ht; 45 | 46 | %% Compute equalization system using iterative WLS 47 | [g, J] = wls_iterative(h_tilde, Li, k, iter, w); 48 | 49 | %% Compute equalized response 50 | er = zeros(L+Li-1,1); 51 | for m = 1:M 52 | er = er + conv(h(:,m), g(:,m)); 53 | end 54 | 55 | %% Plot results 56 | figure(1); 57 | plot([[h(:,1) ; zeros(Li-1,1)] er]); 58 | title('Impulse Responses'); 59 | xlabel('Time (samples)'); 60 | ylabel('Amplitude'); 61 | legend('First channel','Equalized channel'); 62 | 63 | figure(2); 64 | plot(10*log10(J)); 65 | title('Cost function J(n)'); 66 | xlabel('Time (iteration)'); 67 | ylabel('J(n) (dB)'); -------------------------------------------------------------------------------- /channel_shortening.m: -------------------------------------------------------------------------------- 1 | function [g] = channel_shortening(h_hat, Li, Lw, k) 2 | 3 | % Channel shortening for acoustic system equalization 4 | % 5 | % [g] = channel_shortening(h_hat, Li, Lw, k) 6 | % 7 | % Input Parameters [size]: 8 | % h_hat : M impulse responses of length L [L x M] 9 | % Li : length of the equalization filters 10 | % Lw : length of the shortened impulse response 11 | % k : delay of the target response 12 | % 13 | % Output parameters [size]: 14 | % g : equalization filters [Li x M] 15 | % 16 | % Reference: 17 | % [1] 18 | % 19 | % Authors: W. Zhang 20 | % 21 | % History: 2009-07-06 - Initial version by W. Zhang 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | % Initialization 26 | [L M]= size(h_hat); 27 | H = zeros(L+Li-1,M*Li); 28 | for ii = 1:M 29 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(h_hat(:,ii),Li); 30 | end 31 | 32 | % Compute equalization system 33 | wd = [zeros(k,1); ones(Lw,1); zeros(L+Li-Lw-k-1,1)]; 34 | wu = [ones(k,1); zeros(Lw,1); ones(L+Li-Lw-k-1,1)]; 35 | Wd = repmat(wd, 1, M*Li); 36 | Wu = repmat(wu, 1, M*Li); 37 | Bd = Wd.*H; 38 | Au = Wu.*H; 39 | clear wd wu Wd Wu; 40 | 41 | B = Bd'*Bd; 42 | A = Au'*Au; 43 | clear Bd Au 44 | 45 | [V,D] = eig(B, A); 46 | ev = diag(D); 47 | clear D; 48 | 49 | % Find solution that produces minimum 2-norm 50 | if(any(isinf(ev))) 51 | Vinf=V(:,isinf(ev)); 52 | evall=H*Vinf; 53 | [~,I]=min(sqrt(sum(evall.^2,1))); 54 | gv=Vinf(:,I); 55 | else 56 | [mev indmev] = max(ev); 57 | gv = V(:, indmev); 58 | end 59 | g = reshape(gv, Li, M); -------------------------------------------------------------------------------- /contents.m: -------------------------------------------------------------------------------- 1 | % BSIE: Blind System Identification and Equalization Toolbox 2 | % 3 | % Initialize Blind Adaptive System Identification 4 | % init_mclms - Initialize Multichannel Least Mean Squares 5 | % init_mcn - Initialize Multichannel Newton 6 | % init_mcflms - Initialize Multichannel Frequency Domain LMS 7 | % init_nmcflms - Initialize Normalized MCFLMS 8 | % init_nmcflms_sc - Initialize Normalized MCFLMS with Spectral Constraint 9 | % init_nmcmdflms - Initialize Normalized Multichannel MDF LMS 10 | % init_rnmcflms - Initialize Robust NMCFLMS 11 | % 12 | % Blind System Identification 13 | % mcss - Multichannel Subspace Algorithm 14 | % 15 | % Blind Adaptive System Identification 16 | % mclms - Multichannel Least Mean Squares Algorithm 17 | % mcn - Multichannel Newton Algorithm 18 | % mcflms - Multichannel Frequency Domain LMS Algorithm 19 | % nmcflms - Normalized MCFLMS Algorithm 20 | % nmcflms_sc - Normalized MCFLMS with Spectral Constraint Algorithm 21 | % nmcmdflms - Normalized Multichannel MDF LMS Algorithm 22 | % rnmcflms - Robust NMCFLMS Algorithm 23 | % 24 | % System Equalization 25 | % lsinvfilt - Compute Least Squares Inverse Filter 26 | % wls - Compute Weighted LS Filter 27 | % wls_iterative - Compute Iterative Weighted LS Filter 28 | % channel_shortening - Compute Channel Shortening Filter 29 | % rmcls - Compute Relaxed Multichannel LS Filter 30 | % rcic - Compute RMCLS Filter with Constrained Initial Coefficients 31 | % rec - Compute RMCLS Filter with Envelope Constraint 32 | % 33 | % Performance Evaluation and Analyses 34 | % edc - Compute Energy Decay Curve 35 | % npm - Normalized Projection Misalignment 36 | % npm_ac - NPM with Alignment Correction 37 | % magnitude_deviation - Compute Magnitude Deviation 38 | % phase_deviation - Compute Phase Distortion 39 | % gmc_st - Generalized Multichannel Clustering 40 | % 41 | % Auxiliary Functions 42 | % generate_data - Generate Sensor Data 43 | % generate_sie - Generate System Identification Errors 44 | % rdp - Remove Direct-Path Propagation 45 | % ula_pos - Sensor Positions of a Uniform Linear Array 46 | % 47 | % Copyright (C) Imperial College London 2009-2011 48 | % 49 | % BSIE is a MATLAB toolbox for blind SIMO identification and equalization 50 | % 51 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 52 | % This program is free software; you can redistribute it and/or modify 53 | % it under the terms of the GNU General Public License as published by 54 | % the Free Software Foundation; either version 2 of the License, or 55 | % (at your option) any later version. 56 | % 57 | % This program is distributed in the hope that it will be useful, 58 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 59 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 60 | % GNU General Public License for more details. 61 | % 62 | % You can obtain a copy of the GNU General Public License from 63 | % ftp://prep.ai.mit.edu/pub/gnu/COPYING-2.0 or by writing to 64 | % Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA. 65 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -------------------------------------------------------------------------------- /edc.m: -------------------------------------------------------------------------------- 1 | function [decay, varargout] = edc(h, fs, varargin) 2 | % Calculate the energy decay curve and derived measures for an 3 | % impulse response according to [1] 4 | % 5 | % [decay,...] = edc(h,fs,...) 6 | % 7 | % Inputs: 8 | % h Lx1 vector containing the room impulse response 9 | % fs [Optional] Sampling frequency (Hz) - required for meas 10 | % meas [Optional] Any number of strings containing 11 | % 'Txx': Reverberation time (ms) 12 | % 'Cxx': Clarity index (early-to-late ratio) (dB) 13 | % 'Dxx': Deutlichkeit (early-to-total sound energy) (dB) 14 | % where xx specifies the argument in dB for 'Txx' and in ms 15 | % for 'Cxx' and 'Dxx'. Meas can also contain cell arrays. 16 | % 17 | % Outputs: 18 | % decay Lx1 normalized energy decay curve in dB 19 | % meas Measures in order of input argument 20 | % 21 | % Examples: 22 | % edc(h); 23 | % decay = edc(h); 24 | % [decay T60 C80 D50] = edc(h,8000,'T60','C80','D50'); 25 | % [decay manymeas T60]= edc(h,8000,{'C50, 'D50'},'T60'); 26 | % 27 | % Notes: 28 | % If no outputs are specified, EDC is plotted. 29 | % 30 | % To do: 31 | % Txx estimation could be better calculated with a linear fit. 32 | % 33 | % Authors: M. R. P. Thomas, N. D. Gaubitch 34 | % 35 | % History: 26 Feb 2004 Initial version by N. D. Gaubitch 36 | % 21 Sep 2010 Measures added by M. R. P. Thomas 37 | % 38 | % References: 39 | % [1] M.R. Schroeder, "New Method of Measuring Reverberation Time," 40 | % J. Acoust. Soc. Am., vol. 37 pp 409-412, 1965. 41 | % 42 | % Copyright (C) Imperial College London 2004-2010 43 | 44 | % Calculate EDC 45 | h = flipud(h(:).^2); 46 | decaylin = flipud(cumsum(h)); 47 | decaylin=decaylin/decaylin(1); 48 | decay = 10*log10(decaylin); 49 | 50 | % Call meas function 51 | for ii=1:length(varargin) 52 | if(iscell(varargin{ii})) 53 | cellsize=size(varargin{ii}); 54 | varargout{ii}=cellfun(@procmeas,repmat({decaylin},cellsize),repmat({fs},cellsize),varargin{ii}); 55 | else 56 | varargout{ii}=procmeas(decaylin,fs,varargin{ii}); 57 | end 58 | end 59 | 60 | % Plot if no output specified 61 | if(nargout==0) 62 | if(nargin>1) 63 | t=1000*(0:1/fs:(length(decay)-1)/fs); 64 | plot(t,decay); 65 | xlabel('Time (ms)'); 66 | else 67 | plot(decay); 68 | xlabel('Time (samples)'); 69 | end 70 | ylabel('EDC (dB)'); 71 | grid on; 72 | end 73 | 74 | function meas = procmeas(decaylin,fs,meastype) 75 | measarg = str2double(meastype(2:end)); 76 | switch meastype(1) 77 | case 'T' 78 | [~,meas] = min(abs(10*log10(decaylin)+measarg)); 79 | meas=1000*meas/fs; 80 | case 'C' 81 | ne = round(fs*measarg/1000); 82 | meas=10*log10((decaylin(1)-decaylin(ne+2))/decaylin(ne+2)); 83 | case 'D' 84 | ne = round(fs*measarg/1000); 85 | meas=10*log10((decaylin(1)-decaylin(ne+2))/decaylin(1)); 86 | end 87 | -------------------------------------------------------------------------------- /gmc_st.m: -------------------------------------------------------------------------------- 1 | function [ClustMtx,ClustMem,ClustNum] = gmc_st(zr,tol) 2 | 3 | % This function attempts to cluster elements in the "zr" matrix given the 4 | % constriant that 5 | % a) each member within a cluster must come from an element in each column 6 | % of "zr" (i.e., number of members in a cluster = size(zr,2)), 7 | % b) that all the Euclidean distances between the members inside a cluster 8 | % must be less than or equal to "tol". 9 | % 10 | % Note that any member in a cluster can belong to other clusters 11 | % (one-to-many relationship). 12 | % 13 | % Input Parameters [size]: 14 | % zr : zeros of the channel impulse responses [L-1 x M] 15 | % tol : tolerence 16 | % 17 | % Output Parameters: 18 | % ClustMtx : a matrix containing number of clusters-by-cluster 19 | % members 20 | % 21 | % References: 22 | % [1] A. W. H. Khong, X. Lin, and P. A. Naylor, 23 | % "Algorithms for identifying clusters of near-common 24 | % zeros in multichannel blind system identification and 25 | % equalization," in Proc. IEEE Intl. Conf. Acoust., 26 | % Speech, Signal Processing (ICASSP), Las Vegas, USA, 27 | % Apr. 2008, pp. 389-392. 28 | % 29 | % Authors: A. Kong 30 | % 31 | % History: 2007-07-05 Initial version 32 | % 33 | % Copyright (C) Imperial College London 2009-2010 34 | 35 | [len, totCh] = size(zr); 36 | 37 | [pwIdxCm, pwChCm] = compdist(zr,tol,'n'); 38 | resultTst = chkpwChCm(pwChCm,totCh); 39 | 40 | if totCh==2; 41 | [pwIdxCm, pwChCm] = compdist(zr,tol,'n'); 42 | ClustMtx = pwIdxCm; 43 | else 44 | if isempty(pwIdxCm) 45 | disp('No clusters found: terminated by zero pairwise channels.'); 46 | ClustMtx = []; 47 | elseif (resultTst==1) 48 | [ClstrComb,MemLen] = GrpClstrComb(pwIdxCm, pwChCm); 49 | minMemLen = min(MemLen); 50 | minMemLenIdx = find(MemLen==minMemLen); 51 | minGpIdx = minMemLenIdx(1); 52 | sumchCombMtx = ChkChComb(ClstrComb,totCh); 53 | 54 | if sumchCombMtx==totCh*(totCh-1)/2; 55 | ClustMtx = getClusters(ClstrComb,minGpIdx,minMemLen,totCh,tol,zr); 56 | else 57 | disp('No clusters found: terminated by missing pairwise channels.'); 58 | ClustMtx = []; 59 | end 60 | elseif (resultTst==0); 61 | disp('No clusters found: terminated by missing pairwise channels.'); 62 | ClustMtx = []; 63 | end 64 | end 65 | 66 | ClustIdx = ClustMtx; 67 | ClustMem = getClustMem(zr,ClustIdx,totCh); 68 | ClustNum = size(ClustIdx,1); 69 | 70 | %-------------------------------------------------------------------------- 71 | function [ClstrComb,MemLen] = GrpClstrComb(pwIdxCm, pwChCm) 72 | % this function tabulates cluster pair matrix according to their pairwise 73 | % channels 74 | absdif = abs(pwChCm-circshift(pwChCm,1)); 75 | sumdif = sum(absdif'); 76 | chIdx = find(sumdif~=0); 77 | for i = 1:length(chIdx); 78 | ClstrComb.ChGp{i} = pwChCm(chIdx(i),:); 79 | end 80 | for i = 1: length(chIdx)-1; 81 | ClstrComb.MemGp{i} = pwIdxCm(chIdx(i):chIdx(i+1)-1,:); 82 | MemLen(i) = size(ClstrComb.MemGp{i},1); 83 | end 84 | ClstrComb.MemGp{i+1} = pwIdxCm(chIdx(end):size(pwIdxCm,1),:); 85 | MemLen(i+1) = size(ClstrComb.MemGp{i+1},1); 86 | 87 | %-------------------------------------------------------------------------- 88 | function out = ChkChComb(ClstrComb,totCh) 89 | % this function checks that all channels are paired. If "out" is not equal 90 | % to 0.5M(M-1), then no common zeros; 91 | chCombMtx = zeros(totCh,totCh); 92 | for i = 1:length(ClstrComb.ChGp); 93 | chCombMtx(ClstrComb.ChGp{i}(1),ClstrComb.ChGp{i}(2)) = 1; 94 | end 95 | out = sum(sum(chCombMtx)); 96 | 97 | %-------------------------------------------------------------------------- 98 | function ClustMtx = getClusters(ClstrComb,minGpIdx,minMemLen,totCh,tol,zr); 99 | % this function extracts out the clusters; 100 | ClustMtx = []; 101 | for i = 1:minMemLen 102 | seedMem = ClstrComb.MemGp{minGpIdx}(i,:); 103 | seedCh = ClstrComb.ChGp{minGpIdx}; 104 | ClustVec = updateClust(seedMem,seedCh,ClstrComb,totCh,tol,zr); % can be a vector or matrix (chared cluster) 105 | ClustMtx = [ClustMtx; ClustVec]; 106 | end 107 | 108 | %-------------------------------------------------------------------------- 109 | function ClustVecOut = updateClust(seedMem,seedCh,ClstrComb,totCh,tol,zr); 110 | % this is the main fn where clusters get expanded(shared), or gets 111 | % trimmed. 112 | ClustVec = zeros(1,totCh); 113 | ClustVec(seedCh) = seedMem; 114 | eptyCh = find(ClustVec==0); 115 | noneptyCh = find(ClustVec~=0); 116 | ClustVecOut = []; 117 | 118 | while ~isempty(eptyCh); 119 | eptyCh = find(ClustVec(1,:)==0); 120 | ChB = eptyCh(1); 121 | ChA = noneptyCh(1); 122 | 123 | memA = ClustVec(1,ChA); 124 | [actMem,chIx] = getActMem(ClstrComb,ChA,ChB); 125 | rww = find(actMem(:,chIx)==memA); 126 | chIy = swapIx(chIx); 127 | memB = actMem(rww,chIy); 128 | 129 | if isempty(memB); 130 | ClustVec(1,:)=[]; 131 | else 132 | ClustVecConc = repmat(ClustVec(1,:),size(memB,1)-1,1); 133 | ClustVec = [ClustVecConc;ClustVec]; 134 | ClustVec(1:size(memB,1),ChB) = memB; 135 | end 136 | 137 | if size(ClustVec,1)>=1; 138 | ClustVec = trimClustVec(ClustVec,tol,zr); 139 | end 140 | 141 | if size(ClustVec,1)>=1; 142 | numNZ = all(ClustVec'); 143 | NZid = find(numNZ==1); 144 | ClustVecOut = [ClustVecOut;ClustVec(NZid,:)]; 145 | ClustVec(NZid,:) = []; 146 | end 147 | 148 | if size(ClustVec,1)>=1; 149 | eptyCh = find(ClustVec(1,:)==0); 150 | else 151 | eptyCh = []; 152 | end 153 | 154 | end 155 | 156 | %-------------------------------------------------------------------------- 157 | function [actMem,chIx] = getActMem(ClstrComb,ChA,ChB) 158 | % this extracts out members of ChA and ChB 159 | for j=1:length(ClstrComb.ChGp); 160 | gt1 = (ClstrComb.ChGp{j}==[ChA ChB]); 161 | gt2 = (ClstrComb.ChGp{j}==[ChB ChA]); 162 | smtst1 = sum(gt1); 163 | smtst2 = sum(gt2); 164 | if (smtst1==2)||(smtst2==2); 165 | ot = j; 166 | chIx = find(ClstrComb.ChGp{j}==ChA); 167 | break; 168 | end 169 | end 170 | actMem = ClstrComb.MemGp{ot}; 171 | 172 | %-------------------------------------------------------------------------- 173 | function out = trimClustVec(ClustVec,tol,zr) 174 | % this function trims off ClustVec if any of the pairs are not within tol 175 | rwNum= size(ClustVec,1); 176 | out = []; 177 | for rr=1:rwNum; 178 | Clust = ClustVec(rr,:); 179 | nzrId = find(Clust~=0); 180 | nzrNum = length(nzrId); 181 | pp = NaN*ones(nzrNum,nzrNum); 182 | for ii=1:nzrNum; 183 | pp(ii,ii) = zr(Clust(nzrId(ii)),nzrId(ii)); 184 | end 185 | [A,C] = compdist(pp,tol,'n'); 186 | if size(A,1)==0.5*nzrNum*(nzrNum-1); 187 | out = [out;Clust]; 188 | end 189 | end 190 | 191 | %-------------------------------------------------------------------------- 192 | function chIy = swapIx(chIx) 193 | if chIx==2;chIy=1; 194 | else chIy=2; 195 | end 196 | 197 | %-------------------------------------------------------------------------- 198 | function ClustMem = getClustMem(zr,ClustIdx,totCh) 199 | ClustMem = ClustIdx.*0; 200 | 201 | for rw= 1: size(ClustIdx,1); 202 | ClustMem(rw,:) = diag(zr(ClustIdx(rw,:),1:totCh))'; 203 | end 204 | 205 | %-------------------------------------------------------------------------- 206 | function out=chkpwChCm(pwChCm,totCh) 207 | absdif = abs(pwChCm-circshift(pwChCm,1)); 208 | sumdif = sum(absdif'); 209 | chIdx = find(sumdif~=0); 210 | out = 0; 211 | if length(chIdx)==totCh*(totCh-1)/2; 212 | out=1; 213 | end -------------------------------------------------------------------------------- /init_mcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat] = init_mcflms(L, M, h_hat0) 2 | 3 | % This function initializes MCFLMS algorithm 4 | % 5 | % [h_hat] = init_mcflms(L, M, h_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % M : number of channels 10 | % h_hat0 : initial filter coef. vector (unit-norm constrained) [L x M] 11 | % 12 | % Output parameters [size]: 13 | % h_hat : initialized filter coef. matrix [L x M] 14 | % 15 | % Authors: E.A.P. Habets 16 | % 17 | % History: 2009-07-10 Initial version by E.A.P. Habets 18 | % 19 | % Copyright (C) Imperial College London 2009-2010 20 | 21 | narginchk(2,3); 22 | 23 | if nargin > 2 && ~isempty(h_hat0) 24 | if size(h_hat0,1) == L && size(h_hat0,2) == M 25 | h_hat = h_hat0; 26 | else 27 | error('hhat0 must be of size L times M.'); 28 | end 29 | else 30 | % Unit-norm initialization 31 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 32 | end; -------------------------------------------------------------------------------- /init_mclms.m: -------------------------------------------------------------------------------- 1 | function [xin, h_hat] = init_mclms(L, M, xin0, h_hat0) 2 | 3 | % This function initializes MCLMS algorithm 4 | % 5 | % [h_hat, xin] = init_mclms(L, N, M, h_hat0, xin0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % M : number of channels 10 | % xin0 : initial input matrix [L x M] 11 | % h_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 12 | % 13 | % Output parameters [size]: 14 | % xin : initialized signal matrix [L x M] 15 | % h_hat : initialized filter coef. matrix [L x M] 16 | % 17 | % Authors: E.A.P. Habets 18 | % 19 | % History: 2009-07-10 Initial version by E.A.P. Habets 20 | % 21 | % Copyright (C) Imperial College London 2009-2010 22 | 23 | narginchk(2,4); 24 | 25 | if nargin > 2 && ~isempty(xin0) 26 | if size(xin0,1) ~= L || size(xin0,2) ~= M 27 | error('xin0 must be of size N times M.'); 28 | end 29 | else 30 | xin = zeros(L,M); 31 | end; 32 | 33 | if nargin > 3 && ~isempty(h_hat0) 34 | if size(h_hat0,1) ~= L || size(h_hat0,2) ~= M 35 | error('h_hat0 must be of size L times M.'); 36 | end 37 | else 38 | % Unit-norm initialization 39 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 40 | end; -------------------------------------------------------------------------------- /init_mcn.m: -------------------------------------------------------------------------------- 1 | function [xin, h_hat, Rhat] = init_mcn(L, M, xin0, h_hat0) 2 | 3 | % This function initializes MCLMS algorithm 4 | % 5 | % [xin, h_hat, Rhat] = init_mcn(L, N, M, xin0, h_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % M : number of channels 10 | % xin0 : initial input matrix [L x M] 11 | % h_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 12 | % 13 | % Output parameters [size]: 14 | % xin : initialized input matrix [L x M] 15 | % h_hat : initialized filter coef. matrix [L x M] 16 | % Rhat : covariance matrix [M L x M L] 17 | % 18 | % Authors: E.A.P. Habets 19 | % 20 | % History: 2009-07-10 Initial version by E.A.P. Habets 21 | % 22 | % Copyright (C) Imperial College London 2009-2010 23 | 24 | narginchk(2,4); 25 | 26 | if nargin > 2 && ~isempty(xin0) 27 | if size(xin0,1) == L && size(xin0,2) == M 28 | xin = [xin0(1,:); zeros(L-1,M)]; 29 | Rhat = trace(xin0'*xin0)/L * eye(M*L); 30 | else 31 | error('xin0 must be of size L times M.'); 32 | end 33 | else 34 | xin = zeros(L,M); 35 | Rhat = eye(M*L); 36 | end; 37 | 38 | if nargin > 3 && ~isempty(h_hat0) 39 | if size(h_hat0,1) ~= L || size(h_hat0,2) ~= M 40 | error('h_hat0 must be of size L times M.'); 41 | end 42 | h_hat = h_hat0; 43 | else 44 | % Unit-norm initialization 45 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 46 | end; -------------------------------------------------------------------------------- /init_nmcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k] = init_nmcflms(L, F, M, xm0, h_hat0) 2 | 3 | % This function initializes NMCFLMS algorithm 4 | % 5 | % [h_hat, P_k] = init_nmcflms(L, F, M, xm0, h_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % F : frame length 10 | % M : number of channels 11 | % xm0 : initial input block used to calculate P_k [F x M] 12 | % h_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 13 | % 14 | % Output parameters [size]: 15 | % h_hat : initialized filter coef. matrix [L x M] 16 | % P_k : initialized PSDs [F x M] 17 | % 18 | % Authors: E.A.P. Habets 19 | % 20 | % History: 2009-07-10 Initial version by E.A.P. Habets 21 | % 2010-03-27 Fixed initialization of P_k 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | narginchk(3,5); 26 | 27 | if nargin > 3 && ~isempty(xm0) 28 | if size(xm0,1) == F && size(xm0,2) == M 29 | Xm = fft(xm0,F); 30 | P_x = conj(Xm).*Xm; 31 | P_k = sum(P_x,2)*ones(1,M)-P_x; 32 | else 33 | error('xin0 must be of size F times M.'); 34 | end 35 | else 36 | P_k = zeros(F,M); 37 | end; 38 | 39 | if nargin > 4 && ~isempty(h_hat0) 40 | if size(h_hat0,1) == L && size(h_hat0,2) == M 41 | h_hat = h_hat0; 42 | else 43 | error('h_hat0 must be of size L times M.'); 44 | end 45 | else 46 | % Unit-norm initialization 47 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 48 | end; -------------------------------------------------------------------------------- /init_nmcflms_sc.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k, Pn] = init_nmcflms_sc(L, F, M, xm0, h_hat0) 2 | 3 | % This function initializes NMCFLMS_SC algorithm 4 | % 5 | % [h_hat, P_k, Pn] = init_nmcflms_sc(L, F, M, xm0, h_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % F : frame length 10 | % M : number of channels 11 | % xm0 : initial input block used to calculate P_k [F x M] 12 | % h_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 13 | % 14 | % Output parameters [size]: 15 | % h_hat : initialized filter coef. matrix [L x M] 16 | % P_k : initialized PSDs [F x M] 17 | % Pn : initialized P_n [F x M] 18 | % 19 | % Authors: E.A.P. Habets 20 | % 21 | % History: 2010-03-27 Initial version by E.A.P. Habets 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | narginchk(3,5); 26 | 27 | if nargin > 3 && ~isempty(xm0) 28 | if size(xm0,1) == F && size(xm0,2) == M 29 | Xm = fft(xm0,F); 30 | P_x = conj(Xm).*Xm; 31 | P_k = sum(P_x,2)*ones(1,M)-P_x; 32 | else 33 | error('xin0 must be of size F times M.'); 34 | end 35 | else 36 | P_k = zeros(F,M); 37 | end; 38 | 39 | if nargin > 4 && ~isempty(h_hat0) 40 | if size(h_hat0,1) == L && size(h_hat0,2) == M 41 | h_hat = h_hat0; 42 | else 43 | error('h_hat0 must be of size L times M.'); 44 | end 45 | else 46 | % Unit-norm initialization 47 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 48 | end; 49 | 50 | Pn = zeros(F,M); -------------------------------------------------------------------------------- /init_nmcmdflms.m: -------------------------------------------------------------------------------- 1 | function [shMDF H_hat] = init_nmcmdflms(L, Ms, Mch, xm0, H_hat0) 2 | 3 | % This function initializes NMCMDFLMS algorithm 4 | % 5 | % [shMDF H_hat] = init_nmcmdflms(L, Ms, M, H_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : total filter length 9 | % Ms : number of MDF segments 10 | % Mch : number of channels 11 | % xm0 : input data 12 | % H_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 13 | % 14 | % Output parameters [size]: 15 | % shMDF : MDF data structure 16 | % H_hat : initialized filter coef. matrix [L x M] 17 | % 18 | % Authors: B. Castro and E.A.P. Habets 19 | % 20 | % History: 2011-03-01 Initial version 21 | % 22 | % Copyright (C) Bar-Ilan University 2011 23 | 24 | narginchk(2,5); 25 | 26 | if rem(2*L,Ms) ~= 0 27 | error('Segment length (2*L/Ms) needs to be an integer number.'); 28 | end 29 | Ns = 2*L/Ms; % segment length 30 | 31 | if nargin > 5 && ~isempty(H_hat0) 32 | if size(H_hat0,1) == L && size(H_hat0,2) == Mch 33 | H_hat = H_hat0; 34 | else 35 | error('hhat0 must be of size L times Mch.'); 36 | end 37 | else 38 | % Unit-norm initialization 39 | H_hat = [ones(1,Mch) ; zeros(L-1,Mch)]/sqrt(Mch); 40 | end; 41 | 42 | H1 = zeros(Ns , Mch , Ms); 43 | for nn = 1:Mch 44 | hh1 = reshape(H_hat(:,nn),Ns/2,Ms); % rearange H_hat in blocks 45 | H1(:,nn,:) = fft(hh1,Ns);% padding each block 46 | end 47 | 48 | % Define shMDF data structure 49 | shMDF.Ns = Ns; 50 | shMDF.Ms = Ms; 51 | shMDF.Mch = Mch; 52 | shMDF.H_hat = H1; 53 | shMDF.Xm = zeros(Ns, Mch, Ms); % Data buffer with overlap 54 | 55 | % Initialization of shMDF.St 56 | Xm = fft(xm0,shMDF.Ns); 57 | P_x = conj(Xm).*Xm; 58 | P_k = sum(P_x,2)*ones(1,Mch)-P_x; 59 | shMDF.P_k_avg = P_k; -------------------------------------------------------------------------------- /init_rnmcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k] = init_rnmcflms(L, F, M, xm0, h_hat0) 2 | 3 | % This function initializes RMCFLMS algorithm 4 | % 5 | % [h_hat, P_k] = init_rmcflms(L, F, M, xm0, h_hat0) 6 | % 7 | % Input Parameters [size]: 8 | % L : filter length 9 | % F : frame length 10 | % M : number of channels 11 | % xm0 : initial input block used to calculate P_k [F x M] 12 | % h_hat0 : initial filter coef. matrix (unit-norm constrained) [L x M] 13 | % 14 | % Output parameters [size]: 15 | % h_hat : initialized filter coef. matrix [L x M] 16 | % P_k : initialized PSDs [F x M] 17 | % 18 | % Authors: E.A.P. Habets 19 | % 20 | % History: 2009-07-10 Initial version by E.A.P. Habets 21 | % 2010-03-27 Fixed initialization of P_k 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | narginchk(3,5); 26 | 27 | if nargin > 3 && ~isempty(xm0) 28 | if size(xm0,1) == F && size(xm0,2) == M 29 | Xm = fft(xm0,F); 30 | P_x = conj(Xm).*Xm; 31 | P_k = sum(P_x,2)*ones(1,M)-P_x; 32 | else 33 | error('xin0 must be of size F times M.'); 34 | end 35 | else 36 | P_k = zeros(F,M); 37 | end; 38 | 39 | if nargin > 4 && ~isempty(h_hat0) 40 | if size(h_hat0,1) == L && size(h_hat0,2) == M 41 | h_hat = h_hat0; 42 | else 43 | error('h_hat0 must be of size L times M.'); 44 | end 45 | else 46 | % Unit-norm initialization 47 | h_hat = [ones(1,M) ; zeros(L-1,M)]/sqrt(M); 48 | end; -------------------------------------------------------------------------------- /lsinvfilt.m: -------------------------------------------------------------------------------- 1 | function [g] = lsinvfilt(h_hat, Li, k) 2 | 3 | % LS equalization system design for both single and 4 | % multichannel acoustic systems. 5 | % 6 | % [g] = lsinvfilt(h_hat, Li, k) 7 | % 8 | % Input Parameters [size]: 9 | % h_hat : M impulse responses of length L [L x M] 10 | % Li : length of the equalization filters 11 | % k : delay of the target response 12 | % 13 | % Output parameters [size]: 14 | % g : equalization filters [Li x M] 15 | % 16 | % Remarks: 17 | % When Li = L-1 we obtain the MINT solution as proposed in [1]. 18 | % 19 | % Reference: 20 | % [1] M. Miyoshi .etc, "Inverse filtering of room acoustics", 21 | % IEEE Trans. ASSP, vol. 36, 1988. 22 | % 23 | % [2] Y.Huang, J. Benesty and J. Chen, "A Blind Channel Identification-Based 24 | % Two-Stage Approach to Separation and Dereverberation of Speech 25 | % Signals in a Reverberant Environment," IEEE Trans. Speech Audio 26 | % Processing, vol. 13, no. 5 pp. 882-895, 2005. 27 | % 28 | % Authors: W. Zhang 29 | % 30 | % History: 2009-07-06 - Initial version by W. Zhang 31 | % 32 | % Copyright (C) Imperial College London 2009-2010 33 | 34 | [L, M] = size(h_hat); 35 | 36 | % Define target impulse response 37 | d = [zeros(k,1); 1; zeros(L+Li-k-2,1)]; 38 | 39 | % H is the matrix in Equation (11a,11b) in [1] 40 | %fprintf('Generating convmtx\n'); 41 | %tic; 42 | H = zeros(L+Li-1,M*Li); 43 | %H2=[]; 44 | for ii = 1:M 45 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(h_hat(:,ii),Li); 46 | %H2=[H2 myconvmtx(h_hat(:,ii),Li)]; 47 | end 48 | %toc; 49 | 50 | % Compute inverse 51 | 52 | % if(size(H,1)==size(H,2)) 53 | % % fprintf('Computing MINT inverse LU'); 54 | % % tic; 55 | % % [F.L F.U p]=lu(H,'vector'); % Slow bit (need to exploit block toeplitz) 56 | % % F.p=sparse(1:length(p),p,1); 57 | % % opL.LT=true; 58 | % % opU.UT=true; 59 | % % g=reshape(linsolve(F.U,linsolve(F.L,F.p*d,opL),opU),Li,M); 60 | % % g=reshape(inverse(H)*d,Li,M); 61 | % % toc 62 | % 63 | % fprintf('Computing MINT inverse with \\ \n'); 64 | % %tic 65 | % g = reshape(H\d, Li, M); 66 | % %toc 67 | % 68 | % %max(max(g2-g)) 69 | % else 70 | % fprintf('Computing MINT inverse with pinv(H) \n'); 71 | % 72 | % tic 73 | iH=pinv(H); 74 | g = reshape(iH*d, Li, M); 75 | % toc 76 | % end 77 | % 78 | % function M = myconvmtx(x,nh) 79 | % n = length(x); 80 | % M = sparse(bsxfun(@plus,(1:n)',0:(nh-1)), ... 81 | % repmat(1:nh,n,1),repmat(x,1,nh),n+nh-1,nh); 82 | -------------------------------------------------------------------------------- /magnitude_deviation.m: -------------------------------------------------------------------------------- 1 | function [emag emag_freq] = magnitude_deviation(heq, NFFT) 2 | 3 | % Magnitude distortion measure 4 | % 5 | % [emag emag_freq] = magnitude_deviation(heq, NFFT) 6 | % 7 | % Input Parameters: 8 | % heq : equalized impulse response 9 | % NFFT : length discrete Fourier transform 10 | % 11 | % Output Parameters: 12 | % emag : magnitude deviation 13 | % emag_freq : magnitude deviation per frequency 14 | % 15 | % Authors: N.D. Gaubitch, E.A.P. Habets 16 | % 17 | % History: 2006-09-15 Initial Version by N.D. Gaubitch 18 | % 2007-03-12 Minor changes by N.D. Gaubitch 19 | % 2009-07-10 NFFT option by E.A.P. Habets 20 | % 21 | % Copyright (C) Imperial College London 2006-2010 22 | 23 | % Initialization 24 | L = length(heq); 25 | if nargin == 1 26 | NFFT = 2^nextpow2(2*(L-1)); 27 | else 28 | if NFFT < 2*(L-1) 29 | warning('BSIE:magnitude_distortion','FFT length is too small!'); 30 | end 31 | end 32 | 33 | % Magnitude distortion 34 | Heq = fft(heq,NFFT); 35 | Hdb = mean(10*log10(abs(Heq(1:NFFT/2+1)))); 36 | emag = sqrt(mean((10*log10(abs(Heq(1:NFFT/2+1))) - Hdb).^2)); % RMS 37 | if nargout > 1 38 | emag_freq = 10*log10(abs(Heq(1:NFFT/2+1))) - Hdb; 39 | end -------------------------------------------------------------------------------- /mcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, J] = mcflms(xm, h_hat, mu, ss_cntr) 2 | 3 | % The blind Multichannel Frequency-domain LMS (MCFLMS) 4 | % 5 | % [h_hat, J] = mcflms(xm, h_hat, mu, ss_cntr) 6 | % 7 | % Input Parameters [size]: 8 | % xm : input matrix [F x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % mu : step size (optional: default mu=0.9) 11 | % ss_cntr : type of step-size control (optional: default 'fixed'): 12 | % 'fixed' - fixed with unit-norm-constrained; 13 | % 'vss' - variable step-size 14 | % 'rvss' - robust variable step-size 15 | % 16 | % Output Parameters: 17 | % h_hat : updated filter coef. matrix [L x M] 18 | % J : value of the cost function 19 | % 20 | % Remarks: 21 | % This algorithm is suitable for estimating IRs generated using the 22 | % method of images. 23 | % 24 | % For simulated IRs, leading zeros should be removed before employing 25 | % this algorithm, i.e., identify the first direct path and remove all 26 | % values before it and apply same process to other channels. 27 | % 28 | % References: 29 | % [1] Y. Huang and J. Benesty, "Frequency-Domain adaptive approaches to 30 | % blind multi-channel identification," IEEE Trans. Sig. Process. Vol. 51 31 | % No. 1, Jan 2003. 32 | % 33 | % Authors: N. D. Gaubitch, E.A.P. Habets 34 | % 35 | % History: 2006-03-29 Initial version by N. D. Gaubitch 36 | % 2009-07-11 Minor Changes by E.A.P. Habets 37 | % 38 | % Copyright (C) Imperial College London 2006-2010 39 | 40 | narginchk(2,4); 41 | 42 | % Initialization 43 | L = size(h_hat,1); 44 | F = size(xm,1); 45 | M = size(h_hat,2); 46 | U = zeros(F,M); 47 | J = zeros(F-L+1,1); 48 | e = zeros(F,M); % cross-relation error 49 | 50 | if nargin < 3 || isempty(mu) 51 | mu = 0.9; 52 | end 53 | if nargin < 4 54 | ss_cntr = 'fixed'; 55 | end 56 | 57 | h_hat_10 = fft(h_hat,F); 58 | Xm = fft(xm); 59 | 60 | % Calculate cross-relation error 61 | for kk = 1:M 62 | for ll = 1:M 63 | e(:,ll) = Xm(:,ll).*h_hat_10(:,kk)-Xm(:,kk).*h_hat_10(:,ll); 64 | end 65 | e = real(ifft(e)); 66 | e(1:L-1,:) = 0; 67 | J = J + 0.5*sum(abs(e(L:end,:)).^2, 2); 68 | e = fft(e); 69 | U(:,kk) = sum(conj(Xm).*e,2); 70 | end 71 | 72 | % Update and constrain h_hat 73 | switch lower(ss_cntr) 74 | case 'fixed' 75 | h_hat_1x = h_hat_10 - mu*U; 76 | h_hat = real(ifft(h_hat_1x)); 77 | h_hat = h_hat(1:L,:); 78 | h_hat = h_hat/norm(h_hat(:)); 79 | 80 | case 'vss' 81 | mu_optimal = h_hat_10(:)' * U(:) ./ norm(U(:),2).^2; 82 | h_hat_1x = h_hat_10 - mu_optimal*U; 83 | h_hat = real(ifft(h_hat_1x)); 84 | h_hat = h_hat(1:L,:); 85 | h_hat = h_hat/norm(h_hat(:)); 86 | 87 | case 'rvss' 88 | DJ_p = 2./abs(h_hat_10).^2 .* h_hat_10; 89 | beta = abs(DJ_p(:)' * U(:) ./ norm(DJ_p(:),2).^2); 90 | mu_optimal = h_hat_10(:)' * U(:) ./ norm(U(:),2).^2; 91 | h_hat_1x = h_hat_10 - mu_optimal*U + mu_optimal*beta*DJ_p; % update 92 | h_hat = real(ifft(h_hat_1x)); 93 | h_hat = h_hat(1:L,:); 94 | h_hat = h_hat/norm(h_hat(:)); 95 | 96 | otherwise 97 | error('Unknown step-size control type.'); 98 | end -------------------------------------------------------------------------------- /mclms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, J] = mclms(xin, h_hat, mu, ss_cntr) 2 | 3 | % A time-domain Multi-channel LMS for blind channel identification [1] 4 | % 5 | % [h_hat, J] = mclms(xin, h_hat, mu, ss_cntr) 6 | % 7 | % Input Parameters [size]: 8 | % xin : input vector [N x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % mu : step-size 11 | % ss_cntr : type of step-size control (optional: default 'fixed'): 12 | % 'fixed' - fixed with unit-norm-constrained; 13 | % 'vss-unconstrained' - variable step-size; 14 | % 'vss' - variable step-size 15 | % 16 | % Output parameters [size]: 17 | % h_hat : updated filter coef. matrix [L x M] 18 | % J : value of cost function 19 | % 20 | % References: 21 | % [1] Y. Huang and J. Benesty, "Adaptive multi-channel mean square and 22 | % Newton algorithms for blind channel identification", Signal Process., 23 | % vol. 83, no. 8, pp. 1127-1138, Aug 2002 24 | % 25 | % Authors: N.D. Gaubitch, E.A.P. Habets 26 | % 27 | % History: 2004-11-02 - Initial version by NG 28 | % 2009-07-11 - Added various step-size control types by EH 29 | % 2009-08-24 - For real and complex input vectors by EH 30 | % Does not work with vss-normlized and vss! 31 | % 32 | % Copyright (C) Imperial College London 2004-2010 33 | 34 | narginchk(3,4); 35 | 36 | if nargin < 4 37 | ss_cntr = 'fixed'; 38 | end 39 | 40 | e = xin.'*h_hat; % cross-relation error 41 | e = e-e.'; 42 | 43 | % Note that norm(h_hat,2).^2 = 1 44 | J = 0.5*(e(:)'*e(:)); % cost function 45 | 46 | switch lower(ss_cntr) 47 | case 'fixed' 48 | DJ = 2*(conj(xin)*e-J*h_hat); 49 | h_hat = h_hat - mu*DJ; % update 50 | h_hat = h_hat/norm(h_hat(:)); % constrain 51 | 52 | case 'vss-unconstrained' 53 | DJ = 2*(conj(xin)*e); 54 | mu_optimal = h_hat(:).' * DJ(:) / norm(DJ(:),2).^2; 55 | h_hat = h_hat - mu_optimal*DJ; % update 56 | 57 | case 'vss' 58 | DJ = 2*(conj(xin)*e); 59 | mu_optimal = h_hat(:).' * DJ(:) / norm(DJ(:),2).^2; 60 | h_hat = h_hat - mu_optimal*DJ; % update 61 | h_hat = h_hat/norm(h_hat(:)); % constrain 62 | 63 | otherwise 64 | error('Unknown step-size control type.'); 65 | end -------------------------------------------------------------------------------- /mcls.m: -------------------------------------------------------------------------------- 1 | function [h_hat, R_hat] = mcls(x,L,method,h_hat) 2 | 3 | % Multichannel LS cross-relation algorithms for blind SIMO system identification 4 | % 5 | % [h_hat, R_hat, J] = mcls(x,L,method,h_hat) 6 | % 7 | % Input parameters: 8 | % xin : input matrix [N x M] 9 | % L : channel length 10 | % method : {'recursive','xu','minimum','minimum_unbiased','spcc'} 11 | % h_hat : updated filter coef. matrix [L x M] (only for SPCC) 12 | % 13 | % Outputs parameters: 14 | % h_hat : updated filter coef. matrix [L x M] 15 | % R_hat : covariance matrix [M L x M L] 16 | % 17 | % Authors: E.A.P. Habets 18 | % 19 | % History: 2010-03-05 Initial version by E.A.P. Habets 20 | % 21 | % Copyright (C) Imperial College London 2010 22 | 23 | narginchk(2,4); 24 | 25 | if ~exist('method','var'); 26 | method = 'xu'; 27 | end 28 | 29 | if strcmp(method,'recursive') 30 | lambda = 1; 31 | end 32 | 33 | M = size(x,2); 34 | N = size(x,1); 35 | 36 | switch lower(method); 37 | case 'recursive' 38 | R_hat = zeros(M*L,M*L); 39 | for nn = L : N 40 | xin = x(nn:-1:nn-L+1,:); 41 | R_tilde = -xin(:)*xin(:)'; 42 | Rr = xin*xin'; 43 | for jj = 1:M 44 | row = (jj-1)*L+1:jj*L; 45 | for ii = 1:M 46 | col = (ii-1)*L+1:ii*L; 47 | R_tilde(row,col) = R_tilde(row,col)'; 48 | end 49 | R_tilde(row,row) = R_tilde(row,row) + Rr; 50 | end 51 | R_hat = lambda * R_hat + R_tilde; 52 | end 53 | 54 | R_hat = R_hat./((N-L)*(M-1)); 55 | 56 | case 'recursive_alt' % Test by EH 57 | R = zeros(M*L,M*L); 58 | for nn = L : N 59 | xin = x(nn:-1:nn-L+1,:); 60 | R_tilde = xin(:)*xin(:)'; 61 | for jj = 1:M 62 | row = (jj-1)*L+1:jj*L; 63 | for ii = 1:M 64 | col = (ii-1)*L+1:ii*L; 65 | R_tilde(row,col) = R_tilde(row,col)'; 66 | end 67 | end 68 | R = R + R_tilde; 69 | end 70 | 71 | D = zeros(L*M,L*M); 72 | for ii = 1:M 73 | row = (ii-1)*L+1:ii*L; 74 | for nn = [1:ii-1 ii+1:M] 75 | idx = (nn-1)*L+1:nn*L; 76 | D(row,row) = D(row,row) + R(idx,idx); 77 | end 78 | end 79 | 80 | R_hat = zeros(L*M,L*M); 81 | for ii = 1:M 82 | row = (ii-1)*L+1:ii*L; 83 | for jj = 1:M 84 | col = (jj-1)*L+1:jj*L; 85 | if ii==jj 86 | R_hat(row,col) = D(row,col); 87 | else 88 | R_hat(row,col) = -R(row,col); 89 | end 90 | end 91 | end 92 | 93 | case 'xu' 94 | X = []; 95 | for ii = 1:M-1 96 | X_left = []; 97 | for ll = ii+1:M 98 | X_tmp = convmtx(x(:,ll),L); 99 | X_left = [X_left ; X_tmp(L:N-L+1,:)]; 100 | end 101 | X_tmp = convmtx(x(:,ii),L); 102 | X_right = repblkdiag(-X_tmp(L:N-L+1,:),M-ii); 103 | X = [ X ; zeros((N-2*L+2)*(M-ii),L*(ii-1)) X_left X_right]; 104 | end 105 | 106 | R_hat = X.'*X; 107 | R_hat = R_hat./((N-L)*(M-1)); 108 | 109 | case 'convmtx' % Not OK for small N! 110 | X = []; 111 | for ii = 1:M-1 112 | X_left = []; 113 | for ll = ii+1:M 114 | X_left = [X_left ; convmtx(x(:,ll),L)]; 115 | end 116 | X_right = repblkdiag(-convmtx(x(:,ii),L),M-ii); 117 | X = [ X ; zeros((N+L-1)*(M-ii),L*(ii-1)) X_left X_right]; 118 | end 119 | 120 | R_hat = X.'*X; 121 | R_hat = R_hat./((N-L)*(M-1)); 122 | 123 | case 'minimum' 124 | all_perm = nchoosek(1:M,2); 125 | [~,pos] = unique(all_perm(:,2)); 126 | 127 | % For nn=1 128 | X_1 = convmtx(x(:,1),L); 129 | X_2 = convmtx(x(:,2),L); 130 | X = [X_2(L:N-L+1,:) -X_1(L:N-L+1,:)]; 131 | 132 | % For 2<=nn<=length(pos) 133 | for nn = 2:length(pos) 134 | X_tmp = convmtx(x(:,all_perm(pos(nn),2)),L); 135 | X_left = [zeros(N-2*L+2,L*(all_perm(pos(nn),1)-1)) X_tmp(L:N-L+1,:)]; 136 | X_tmp = convmtx(x(:,all_perm(pos(nn),1)),L); 137 | X_right = -X_tmp(L:N-L+1,:); 138 | X = [X zeros(size(X,1),L); X_left X_right]; 139 | end 140 | 141 | R_hat = X.'*X; 142 | R_hat = R_hat./((N-L)*(M-1)); 143 | 144 | case 'minimum_unbiased' 145 | all_perm = nchoosek(1:M,2); 146 | all_perm = [all_perm ; M 1]; 147 | [~,pos] = unique(all_perm(:,2)); 148 | pos = sort(pos); 149 | 150 | % For nn=1 151 | X_1 = convmtx(x(:,1),L); 152 | X_2 = convmtx(x(:,2),L); 153 | X = [X_2(L:N-L+1,:) -X_1(L:N-L+1,:)]; 154 | 155 | % For 2<=nn<=lenght(pos)-1 156 | for nn = 2:length(pos)-1 157 | X_tmp = convmtx(x(:,all_perm(pos(nn),2)),L); 158 | X_left = [zeros(N-2*L+2,L*(all_perm(pos(nn),1)-1)) X_tmp(L:N-L+1,:)]; 159 | X_tmp = convmtx(x(:,all_perm(pos(nn),1)),L); 160 | X_right = -X_tmp(L:N-L+1,:); 161 | X = [X zeros(size(X,1),L); X_left X_right]; 162 | end 163 | 164 | % For nn==length(pos) 165 | nn = length(pos); 166 | X_tmp = convmtx(x(:,all_perm(pos(nn),1)),L); 167 | X_left = [X_tmp(L:N-L+1,:) zeros(N-2*L+2,L*(all_perm(pos(nn),1)-2))]; 168 | X_tmp = convmtx(x(:,all_perm(pos(nn),2)),L); 169 | X_right = -X_tmp(L:N-L+1,:); 170 | X = [X; X_left X_right]; 171 | 172 | R_hat = X.'*X; 173 | R_hat = R_hat./((N-L)*(M-1)); 174 | 175 | case 'spcc' 176 | R = zeros(L*M,L*M); 177 | for nn = L : N 178 | xin = x(nn:-1:nn-L+1,:); 179 | R_tilde = xin(:)*xin(:)'; 180 | for jj = 1:M 181 | row = (jj-1)*L+1:jj*L; 182 | for ii = 1:M 183 | col = (ii-1)*L+1:ii*L; 184 | R_tilde(row,col) = R_tilde(row,col)'; 185 | end 186 | end 187 | R = R + R_tilde; 188 | end 189 | 190 | alpha = zeros(M,M); 191 | beta = zeros(M,M); 192 | for ii=1:M 193 | row = (ii-1)*L+1:ii*L; 194 | for jj=1:M 195 | col = (jj-1)*L+1:jj*L; 196 | alpha(ii,jj) = (h_hat(:,ii).'*R(col,row)*h_hat(:,jj))/(h_hat(:,ii).'*R(col,col)*h_hat(:,ii)); 197 | beta(ii,jj) = alpha(ii,jj)/(h_hat(:,jj).'*R(row,row)*h_hat(:,jj)); 198 | end 199 | end 200 | 201 | D = zeros(L*M,L*M); 202 | for ii = 1:M 203 | row = (ii-1)*L+1:ii*L; 204 | for nn = [1:ii-1 ii+1:M] 205 | idx = (nn-1)*L+1:nn*L; 206 | D(row,row) = D(row,row) + alpha(ii,nn) * beta(ii,nn) * R(idx,idx); 207 | end 208 | end 209 | 210 | R_hat = zeros(L*M,L*M); 211 | for ii = 1:M 212 | row = (ii-1)*L+1:ii*L; 213 | for jj = 1:M 214 | col = (jj-1)*L+1:jj*L; 215 | if ii==jj 216 | R_hat(row,col) = D(row,col); 217 | else 218 | R_hat(row,col) = -beta(ii,jj) * R(row,col); 219 | end 220 | end 221 | end 222 | 223 | otherwise 224 | error('Unknown method.'); 225 | end 226 | 227 | [~,~,V] = svd(R_hat); 228 | h_hat = V(:,end) / norm(V(:,end)); 229 | h_hat = reshape(h_hat,L,M); 230 | 231 | % [V,DD] = eig(R_hat); 232 | % [~,pos] = min(diag(DD)); 233 | % h_hat = reshape(V(:,pos),L,M); 234 | % h_hat = h_hat./norm(h_hat); 235 | 236 | % figure(1);imagesc(20*log10(abs(X))) 237 | 238 | function B = repblkdiag(A,num) 239 | B = []; 240 | for l = 1:num 241 | B = blkdiag(B,A); 242 | end -------------------------------------------------------------------------------- /mcn.m: -------------------------------------------------------------------------------- 1 | function [h_hat, R_hat, J] = mcn(xin, h_hat, R_hat, rho, lamda) 2 | 3 | % Multi-channel Newton algorithm for blind channel identification [1] 4 | % 5 | % [h_hat, R_hat, J] = mcn(xin, h_hat, R_hat, rho, lamda) 6 | % 7 | % Input parameters: 8 | % xin : input matrix [L x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % R_hat : covariance matrix [M L x M L] 11 | % rho : step size (optional: default rho=0.95) 12 | % lamda : exponential forgetting factor (0 < lamda < 1) 13 | % (optional: default lamda=0.99) 14 | % 15 | % Outputs parameters: 16 | % h_hat : updated filter coef. matrix [L x M] 17 | % R_hat : covariance matrix [M L x M L] 18 | % J : value of cost function 19 | % 20 | % References: 21 | % [1] Y. Huang and J. Benesty, "Adaptive multi-channel mean square and 22 | % Newton algorithms for blind channel identification", Signal Process., 23 | % vol. 83, no. 8, pp. 1127-1138, Aug 2002 24 | % 25 | % Authors: N.D. Gaubitch, E.A.P. Habets 26 | % 27 | % History: 2003-05-15 Initial Version by N.D. Gaubitch 28 | % : 2004-10-18 Minor changes by N.D. Gaubitch 29 | % : 2009-07-10 Minor changes by E.A.P. Habets 30 | % 31 | % Copyright (C) Imperial College London 2003-2010 32 | 33 | narginchk(3,5); 34 | 35 | L = size(h_hat,1); 36 | M = size(xin,2); 37 | h_hat_ud = h_hat(:); 38 | if nargin < 4 39 | rho = 0.95; 40 | end 41 | if nargin < 5 42 | lamda = 0.99; 43 | end 44 | epsilon = 10^-8; 45 | 46 | R_tilde = -xin(:)*xin(:)'; 47 | Rr = xin*xin'; 48 | for jj = 1:M 49 | row = (jj-1)*L+1:jj*L; 50 | for ii = 1:M 51 | col = (ii-1)*L+1:ii*L; 52 | R_tilde(row,col) = R_tilde(row,col)'; 53 | end 54 | R_tilde(row,row) = R_tilde(row,row) + Rr; 55 | end 56 | R_hat = lamda*R_hat + R_tilde; 57 | 58 | H_mat = h_hat_ud*h_hat_ud'; 59 | W = R_hat - 2*H_mat*R_hat - 2*R_hat*H_mat; 60 | B = inv(W+epsilon*eye(M*L,M*L)./(1+epsilon)); 61 | 62 | E = xin'*h_hat; 63 | e = triu(E-E'); 64 | chi = e(:)'*e(:); 65 | h_hat_ud = h_hat_ud - rho*B*(R_tilde*h_hat_ud - chi*h_hat_ud); 66 | h_hat_ud = h_hat_ud/norm(h_hat_ud); 67 | J = chi/(h_hat_ud'*h_hat_ud); 68 | h_hat = reshape(h_hat_ud,L,M); -------------------------------------------------------------------------------- /mcss.m: -------------------------------------------------------------------------------- 1 | function [h_hat, R_hat] = mcss(x,L,Lc,method) 2 | 3 | % Multichannel subspace algorithms for blind SIMO system identification 4 | % 5 | % [h_hat, R_hat, J] = mcss(x,L,Lc,method) 6 | % 7 | % Input parameters: 8 | % xin : input matrix [N x M] 9 | % L : overestimated channel length (Note: Moulines uses N) 10 | % Lc : channel length (Note: Moulines uses M=Lc-1) 11 | % method : {'Moulines'} 12 | % 13 | % Outputs parameters: 14 | % h_hat : updated filter coef. matrix [L x M] 15 | % R_hat : covariance matrix [M L x M L] 16 | % 17 | % Authors: E.A.P. Habets 18 | % 19 | % History: 2010-04-15 Initial version by E.A.P. Habets 20 | % 21 | % Copyright (C) Imperial College London 2010 22 | 23 | narginchk(2,4); 24 | 25 | if ~exist('method','var'); 26 | method = 'moulines'; 27 | end 28 | 29 | M = size(x,2); 30 | N = size(x,1); 31 | 32 | switch lower(method); 33 | case 'moulines' 34 | R_hat = zeros(M*L,M*L); 35 | for nn = L : N 36 | xin = x(nn:-1:nn-L+1,:); 37 | Rr = xin(:)*xin(:)'; 38 | R_hat = R_hat + Rr; 39 | end 40 | R_hat = R_hat./((N-L)*M); 41 | 42 | [~,~,V] = svd(R_hat); 43 | 44 | V_null = V(:,L+Lc:end); 45 | 46 | for k = 1:size(V_null,2) % M*L-(Lc-1)-L 47 | Gi = MC_FilteringMatrix(V_null(:,k),L,Lc-1); 48 | if k ==1 49 | Q = Gi*Gi'; 50 | else 51 | Q = Q + Gi*Gi'; 52 | end 53 | end 54 | [~,~,V] = svd(Q); 55 | 56 | h_hat = reshape(V(:,end),Lc,M); 57 | h_hat = h_hat./norm(h_hat); 58 | 59 | case 'moulines_constraint' % Under construction... (EH) 60 | R_hat = zeros(M*L,M*L); 61 | for nn = L : N 62 | xin = x(nn:-1:nn-L+1,:); 63 | Rr = xin(:)*xin(:)'; 64 | R_hat = R_hat + Rr; 65 | end 66 | R_hat = R_hat./((N-L)*M); 67 | 68 | [~,~,V] = svd(R_hat); 69 | 70 | V_null = V(:,L+Lc:end); 71 | 72 | for k = 1:size(V_null,2) % M*L-(Lc-1)-L 73 | Gi = MC_FilteringMatrix(V_null(:,k),L,Lc-1); 74 | if k ==1 75 | Q = Gi*Gi'; 76 | else 77 | Q = Q + Gi*Gi'; 78 | end 79 | end 80 | [~,S,V] = svd(Q); 81 | 82 | K = diff(log(diag(S))); 83 | [~,pos_min] = min(K); 84 | % display([num2str(pos_min) '/' num2str(length(diag(S)))]); 85 | 86 | % Maximize passband engery! 87 | V_prime = V(:,pos_min+1:end); 88 | F = zeros(Lc,Lc); 89 | BP = 4; 90 | for k = BP:ceil(Lc/2+1)-BP 91 | f = exp(-1i*2*pi*(0:Lc-1)*k/Lc).'; 92 | F = F + f * f'; 93 | end 94 | B = repblkdiag(F,M); 95 | [~,~,V] = svd(V_prime' * B * V_prime); 96 | beta = V(1,:).'; 97 | 98 | if isreal(x) 99 | h_hat = real(reshape(V_prime*beta,Lc,M)); 100 | else 101 | h_hat = reshape(V_prime*beta,Lc,M); 102 | end 103 | h_hat = h_hat./norm(h_hat); 104 | 105 | otherwise 106 | error('Unknown method.'); 107 | end 108 | 109 | function B = repblkdiag(A,num) 110 | B = []; 111 | for l = 1:num 112 | B = blkdiag(B,A); 113 | end 114 | 115 | function [V_tot] = MC_FilteringMatrix(V, N, M) 116 | [LN,~] = size(V); 117 | L = LN/N; % Number of channels 118 | V_tot = []; 119 | for l = 0:L-1 120 | Vl = V(l*N+1:(l+1)*N).'; 121 | Vl_extent = [Vl , zeros(1,M)]; 122 | Vl_mat = toeplitz([Vl_extent(1),zeros(1,M)],Vl_extent); 123 | V_tot = [V_tot ; Vl_mat]; %#ok 124 | end -------------------------------------------------------------------------------- /nmcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k_avg, J] = nmcflms(xm, h_hat, P_k_avg, rho, lambda, delta) 2 | 3 | % The blind Normalized Multichannel Frequency-domain LMS (NMCFLMS) 4 | % 5 | % [h_hat, P_k_avg, J] = nmcflms(xm, h_hat, P_k_avg, rho, lambda, SNR) 6 | % 7 | % Input Parameters [size]: 8 | % xm : input matrix [F x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % P_k_avg : estimated PSD matrix [F x M] 11 | % rho : step size (optional: default rho=0.8) 12 | % lambda : forgetting factor (0 < lambda < 1) (optional) 13 | % delta : regularization (optional) 14 | % 15 | % Output Parameters: 16 | % h_hat : updated filter coef. matrix [L x M] 17 | % P_k_avg : updated PSD matrix [F x M] 18 | % J : cost function values [F-L+1 x 1] 19 | % 20 | % Remarks: 21 | % This algorithm is suitable for estimating IRs generated using the 22 | % method of images. 23 | % 24 | % For simulated IRs, leading zeros should be removed before employing 25 | % this algorithm, i.e., identify the first direct path and remove all 26 | % values before it and apply same process to other channels. In order 27 | % to keep IRs the same length, random coefficients with small values 28 | % can be appended at the tail part. 29 | % 30 | % References: 31 | % [1] Y. Huang and J. Benesty, "Frequency-Domain adaptive approaches to 32 | % blind multi-channel identification," IEEE Trans. Sig. Process. Vol. 51 33 | % No. 1, Jan 2003. 34 | % 35 | % Authors: N. D. Gaubitch, E.A.P. Habets 36 | % 37 | % History: 2006-03-29 Initial version by N. D. Gaubitch 38 | % 2009-07-11 Minor Changes by E.A.P. Habets 39 | % 40 | % Copyright (C) Imperial College London 2006-2010 41 | 42 | narginchk(3,6); 43 | 44 | % Initialization 45 | L = size(h_hat,1); 46 | F = size(xm,1); 47 | M = size(h_hat,2); 48 | U = zeros(F,M); 49 | J = zeros(F-L+1,1); 50 | e = zeros(F,M); % cross-relation error 51 | 52 | if nargin < 4 || isempty(rho) 53 | rho = 0.8; 54 | end 55 | if nargin < 5 || isempty(lambda) 56 | lambda = (1 - (1/(3*L)))^L; 57 | end 58 | 59 | h_hat_10 = fft(h_hat,F); 60 | Xm = fft(xm); 61 | P_x = conj(Xm).*Xm; 62 | P_k = sum(P_x,2)*ones(1,M)-P_x; 63 | P_k_avg = lambda*P_k_avg + (1-lambda)*P_k; 64 | 65 | if nargin < 6 || isempty(delta) 66 | delta = (M-1)*mean(mean(P_x)); 67 | % delta = sum(sum(P_x))/F*(M-1)/M/(10^(SNR/10)); % regularization 68 | end 69 | 70 | % Calculate cross-relation error 71 | for kk = 1:M 72 | for ll = 1:M 73 | e(:,ll) = Xm(:,ll).*h_hat_10(:,kk)-Xm(:,kk).*h_hat_10(:,ll); 74 | end 75 | e = real(ifft(e)); 76 | e(1:L-1,:) = 0; 77 | J = J + 0.5*sum(abs(e(L:end,:)).^2, 2); 78 | e = fft(e); 79 | U(:,kk) = sum(conj(Xm).*e,2); 80 | end 81 | 82 | % Update h_hat 83 | h_hat_10 = h_hat_10 - rho./(P_k_avg + delta).*U; 84 | h_hat = real(ifft(h_hat_10)); 85 | h_hat = h_hat(1:L,:); 86 | h_hat = h_hat/norm(h_hat(:)); -------------------------------------------------------------------------------- /nmcflms_sc.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k_avg, Pn, J] = nmcflms_sc(xm, h_hat, P_k_avg, Pn, rho, lambda, delta) 2 | 3 | % The blind Normalized Multichannel Frequency-domain LMS with Spectral Constraint (NMCFLMS_SC) 4 | % 5 | % [h_hat, P_k_avg, J] = nmcflms(xm, h_hat, P_k_avg, rho, lambda, SNR) 6 | % 7 | % Input Parameters [size]: 8 | % xm : input matrix [F x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % P_k_avg : estimated PSD matrix [F x M] 11 | % Pn : penality matrix [F x M] 12 | % rho : step size (optional: default rho=0.8) 13 | % lambda : exponential forgetting factor (0 < lambda < 1) (optional) 14 | % delta : regularization (optional) 15 | % 16 | % Output Parameters: 17 | % h_hat : updated filter coef. matrix [L x M] 18 | % P_k_avg : updated PSD matrix [F x M] 19 | % Pn : updated penality matrix [F x M] 20 | % J : cost function values [F-L+1 x 1] 21 | % 22 | % Remarks: 23 | % This algorithm is suitable for estimating IRs generated using the 24 | % method of images. 25 | % 26 | % For simulated IRs, leading zeros should be removed before employing 27 | % this algorithm, i.e., identify the first direct path and remove all 28 | % values before it and apply same process to other channels. 29 | % 30 | % References: 31 | % [1] N. D. Gaubitch, Md. K. Hasan and P. A. Naylor, "Noise Robust 32 | % Adaptive Blind Channel Identification Using Spectral 33 | % Constraints", Proc. IEEE Int. Conf. on Acoust. Speech and 34 | % Signal Processing (ICASSP), Toulouse, France, May 2006. 35 | % 36 | % Authors: N.D. Gaubitch and E.A.P. Habets 37 | % 38 | % History: 2010-03-27 Initial version by N.D. Gaubitch and E.A.P. Habets 39 | % 40 | % Copyright (C) Imperial College London 2010 41 | 42 | narginchk(4,7); 43 | 44 | % Initialization 45 | L = size(h_hat,1); 46 | F = size(xm,1); 47 | M = size(h_hat,2); 48 | U = zeros(F,M); 49 | J = zeros(F-L+1,1); 50 | e = zeros(F,M); % cross-relation error 51 | 52 | if nargin < 5 || isempty(rho) 53 | rho = 0.8; 54 | end 55 | if nargin < 6 || isempty(lambda) 56 | lambda = (1 - (1/(3*L)))^L; 57 | end 58 | 59 | h_hat_10 = fft(h_hat,F); 60 | Xm = fft(xm); 61 | P_x = conj(Xm).*Xm; 62 | P_k = sum(P_x,2)*ones(1,M)-P_x; 63 | P_k_avg = lambda*P_k_avg + (1-lambda)*P_k; 64 | 65 | if nargin < 7 || isempty(delta) 66 | delta = (M-1)*mean(mean(P_x)); 67 | % delta = sum(sum(P_x))/F*(M-1)/M/(10^(SNR/10)); % regularization 68 | end 69 | 70 | % Initialization spectral constraint 71 | wt = impz([1 -1],1,M*L); 72 | WT = abs(fft(wt)).^4; 73 | WT = WT/sum(WT); 74 | gamma = 0.5; 75 | beta = 0.0075; 76 | 77 | % Calculate cross-relation error 78 | for kk = 1:M 79 | for ll = 1:M 80 | e(:,ll) = Xm(:,ll).*h_hat_10(:,kk)-Xm(:,kk).*h_hat_10(:,ll); 81 | end 82 | e = real(ifft(e)); 83 | e(1:L-1,:) = 0; 84 | J = J + 0.5*sum(abs(e(L:end,:)).^2, 2); 85 | e = fft(e); 86 | U(:,kk) = sum(conj(Xm).*e,2); 87 | end 88 | 89 | % Update h_hat 90 | h_hat_10 = h_hat_10 - rho * (1./(P_k_avg + delta).*U + Pn); 91 | h_hat = real(ifft(h_hat_10)); 92 | h_hat = h_hat(1:L,:); 93 | h_hat = h_hat/norm(h_hat(:)); 94 | 95 | % Update Pn 96 | hhatv = h_hat(:); 97 | Hhatv = fft(hhatv,M*L); 98 | E = hhatv.'*hhatv; % Note: Result is approximatly one due to unit-norm constraint 99 | WH = WT.*Hhatv; 100 | Gh = M*L*real(ifft(WH)); 101 | ep = 1/(M*L)*hhatv.'*Gh - gamma*E; 102 | dep = reshape(Gh,L,M); 103 | Pn = 4*beta*conj(fft(ep*dep,F)); -------------------------------------------------------------------------------- /nmcmdflms.m: -------------------------------------------------------------------------------- 1 | function [shMDF, H_hat, e_iijj] = nmcmdflms(shMDF, xm, rho, lambda, delta) 2 | 3 | % The blind normalized multichannel MDF LMS (NMCMDFLMS) [1] 4 | % 5 | % [shMDF H_hat J] = mcmdflms(shMDF, xm, rho, lambda, delta) 6 | % 7 | % Input Parameters [size]: 8 | % shMDF : MDF structure 9 | % xm : input matrix [F x M] 10 | % H_hat : current filter coef. matrix [L x M] 11 | % rho : step size (optional: default rho=0.2) 12 | % lambda : exponential forgetting factor (0 < lambda < 1) (optional) 13 | % delta : regularization (optional) 14 | % 15 | % Output Parameters: 16 | % shMDF : MDF structure 17 | % H_hat : updated filter coef. matrix [L x M] 18 | % J : cross-relation error [Ns x M x M] 19 | % 20 | % shMDF structure: 21 | % H_hat : MDF representation of H_hat (MC) 22 | % Xm : MDF representation of x - with overlapping (MC) 23 | % Ms : number of MDF segments (blocks). 24 | % Mch : number of channels 25 | % Nm : segment length 26 | % 27 | % Remarks: 28 | % This algorithm is suitable for estimating IRs generated using the 29 | % method of images. 30 | % 31 | % For simulated IRs, leading zeros should be removed before employing 32 | % this algorithm, i.e., identify the first direct path and remove all 33 | % values before it and apply same process to other channels. 34 | % 35 | % References: 36 | % [1] R. Ahmad, A. W. H. Khong, and P. Naylor, "Proportionate frequency 37 | % domain adaptive algorithms for blind channel identification," in 38 | % Proc. ICASSP, Toulouse, France, May 2006, vol. 5, pp. 29-32. 39 | % 40 | % Authors: B. Castro, S. Gannot and E.A.P. Habets 41 | % 42 | % History: 2011-03-01 Initial version 43 | % 44 | % Copyright (C) Bar-Ilan University 2011 45 | 46 | % Initialization 47 | F = size(xm,1); 48 | U = zeros(F,shMDF.Mch,shMDF.Ms); 49 | 50 | H_hat_10 = shMDF.H_hat; 51 | 52 | if nargin < 3 || isempty(rho) 53 | rho = 0.2; 54 | end 55 | if nargin < 4 || isempty(lambda) 56 | lambda = (1-1/(3*shMDF.Ns*shMDF.Ms/2))^(shMDF.Ns/2); 57 | end 58 | 59 | Xm = fft(xm); 60 | shMDF.Xm(:,:,2:end) = shMDF.Xm(:,:,1:end-1); 61 | shMDF.Xm(:,:,1) = Xm; 62 | 63 | % Calculate cross-relation error 64 | e_iijj = zeros(shMDF.Ns,shMDF.Mch,shMDF.Mch); 65 | 66 | % Calculate current error 67 | for ii = 1:shMDF.Mch % for each channel 68 | for jj = 1:shMDF.Mch % CR with other channel 69 | for kk = 1:shMDF.Ms 70 | Eij = shMDF.Xm(:,ii,kk).*H_hat_10(:,jj,kk)- ... 71 | shMDF.Xm(:,jj,kk).*H_hat_10(:,ii,kk); 72 | e_iijj(:,ii,jj) = e_iijj(:,ii,jj) - Eij; 73 | end 74 | eij = real(ifft(e_iijj(:,ii,jj))); 75 | eij(1:shMDF.Ns/2,:) = 0; 76 | e_iijj(:,ii,jj) = fft(eij); 77 | end 78 | end 79 | 80 | % Update normalization diagonal matrix 81 | P_x = conj(Xm(:,:,1)).*Xm(:,:,1); 82 | P_k = sum(P_x,2)*ones(1,shMDF.Mch)-P_x; 83 | shMDF.P_k_avg = lambda*shMDF.P_k_avg + (1-lambda)*P_k; 84 | 85 | if nargin < 5 || isempty(delta) 86 | delta = (shMDF.Mch-1)*mean(mean(P_x)); 87 | end 88 | 89 | % Update filter 90 | for ii = 1:shMDF.Mch % for each channel 91 | for kk = 1:shMDF.Ms 92 | grad_temp = zeros(shMDF.Ns,1); 93 | for jj = 1:shMDF.Mch 94 | ttt = conj(shMDF.Xm(:,jj,kk)) .* (e_iijj(:,ii,jj)); 95 | grad_temp = grad_temp + ttt; 96 | end 97 | grad_temp = (1./(shMDF.P_k_avg(:,ii) + delta)).*grad_temp; 98 | grad_temp = real(ifft(grad_temp)); 99 | TU = grad_temp(1:end/2,:,:); 100 | U(:,ii, kk) = fft([TU; zeros(size(TU))]); 101 | end 102 | end 103 | 104 | H_hat_1x = H_hat_10 - rho * U; 105 | 106 | shMDF.H_hat = H_hat_1x; 107 | 108 | % Normalization in time domain - to avoid trivial solution 109 | % Firstly, calculate time domain filter from the MDF representation 110 | % Secondly, transform the normalized time domain filter back to the MDF 111 | 112 | shMDF_tmp = shMDF; % temporary structure 113 | [shMDF_tmp y_out normVal] = MDFconvCh(shMDF_tmp); 114 | H_hat = y_out/normVal; 115 | shMDF.normVal = normVal; 116 | H1 = zeros(shMDF_tmp.Ns , shMDF_tmp.Mch , shMDF_tmp.Ms); 117 | for nn = 1:shMDF_tmp.Mch 118 | hh1 = reshape(H_hat(:,nn),shMDF_tmp.Ns/2,shMDF_tmp.Ms); 119 | H = fft(hh1,shMDF_tmp.Ns); 120 | H1(:,nn,:) = H; 121 | end 122 | shMDF.H_hat = H1; 123 | 124 | function [sMDF y_out normVal] = MDFconvCh(sMDF) 125 | Ns = sMDF.Ns; 126 | Ms = sMDF.Ms; 127 | y_out = []; 128 | x1 = [zeros(sMDF.Ns/2,1);1;zeros(Ns*Ms/2,1)]; 129 | sMDF.Xm = 0*sMDF.Xm; 130 | B = floor(length(x1)/(Ns/2)); 131 | Ls = Ns/2; 132 | for nn = 0:B-2 133 | x_s = x1(nn*Ls +1:nn*Ls + Ns); 134 | x_s = repmat(x_s,1,sMDF.Mch); 135 | 136 | [sMDF y_tmp] = MDFconv(sMDF,x_s); 137 | y_out = [y_out; y_tmp]; 138 | end 139 | normVal = norm(y_out(:)); 140 | 141 | function [sMDF y] = MDFconv(sMDF,xnew) 142 | sMDF.Xm(:,:,2:end) = sMDF.Xm(:,:,1:end-1); 143 | sMDF.Xm(:,:,1) = fft(xnew); 144 | Y = zeros(sMDF.Ns,sMDF.Mch); 145 | for kk = 1:sMDF.Ms 146 | Y = Y + sMDF.Xm(:,:,kk).*sMDF.H_hat(:,:,kk); 147 | end 148 | yy = real(ifft(Y)); 149 | y = yy(end/2+1:end,:); -------------------------------------------------------------------------------- /npm.m: -------------------------------------------------------------------------------- 1 | function [npm_val] = npm(h, hhat) 2 | 3 | % Normalized Projection Misalignment 4 | % 5 | % [npm_val] = npm(h, hhat) 6 | % 7 | % Input Parameters [size]: 8 | % h : true impulse responses [L x M] 9 | % hhat : estimated impulse responses [L x M] 10 | % 11 | % Output Parameter: 12 | % npm_val : Normalize Projection Misalignment 13 | % 14 | % References: 15 | % [1] D. R. Morgan, J. Benesty and M. M. Sondhi, "On the evaluation of 16 | % estimated impulse responses," IEEE Signal Processing Lett., Vol. 5, No. 17 | % 7, pp. 174-176, Jul 1998. 18 | % 19 | % [2] Y. Huang and J. Benesty, "Frequency-Domain adaptive approaches to 20 | % blind multi-channel identification," IEEE Trans. Sig. Process. Vol. 51 21 | % No. 1, pp. 11-24, Jan 2003. 22 | % 23 | % Authors: N.D. Gaubitch and E.A.P. Habets 24 | % 25 | % History: 2004-04-26 - Initial version by NG 26 | % 2009-10-28 - reshape when the size of h_hat differs from h 27 | % 28 | % Copyright (C) Imperial College London 2004-2010 29 | 30 | if size(hhat,1) <= size(h,1) 31 | hv = reshape(h(1:size(hhat,1),:),[],1); 32 | hhatv = hhat(:); 33 | else 34 | % hv = h(:); 35 | % hhatv = reshape(hhat(1:size(h,1),:),[],1); 36 | h = [h ; zeros(size(hhat,1)-size(h,1),size(h,2))]; 37 | hv = h(:); 38 | hhatv = hhat(:); 39 | end 40 | 41 | epsilon = hv-((hv.'*hhatv)/(hhatv.'*hhatv))*hhatv; 42 | npm_val = norm(epsilon)/norm(hv); -------------------------------------------------------------------------------- /npm_ac.m: -------------------------------------------------------------------------------- 1 | function [npm_val] = npm_ac(h, hhat) 2 | 3 | % Normalized Projection Misalignment with Alignment Correction 4 | % 5 | % [npm_val] = npm_ac(h, hhat) 6 | % 7 | % Input Parameters [size]: 8 | % h : true impulse responses [L x M] 9 | % hhat : estimated impulse responses [L x M] 10 | % 11 | % Output Parameter: 12 | % npm_val : Normalize Projection Misalignment 13 | % 14 | % References: 15 | % [1] D. R. Morgan, J. Benesty and M. M. Sondhi, "On the evaluation of 16 | % estimated impulse responses," IEEE Signal Processing Lett., Vol. 5, No. 17 | % 7, pp. 174-176, Jul 1998. 18 | % 19 | % Authors: E.A.P. Habets 20 | % 21 | % History: 2010-04-16 - added alignment correction to npm.m (EH) 22 | % 23 | % Copyright (C) Imperial College London 2010 24 | 25 | if size(hhat,1) <= size(h,1) 26 | hv = reshape(h(1:size(hhat,1),:),[],1); 27 | hhatv = hhat(:); 28 | else 29 | % hv = h(:); 30 | % hhatv = reshape(hhat(1:size(h,1),:),[],1); 31 | h = [h ; zeros(size(hhat,1)-size(h,1),size(h,2))]; 32 | hv = h(:); 33 | hhatv = hhat(:); 34 | end 35 | 36 | hhatv_sc = sign((hv.'*hhatv)/(hhatv.'*hhatv))*hhat(:); 37 | hhat_sc = reshape(hhatv_sc,size(hhat,1),size(hhat,2)); 38 | 39 | % Correct possible phase shift! 40 | L = max(size(hhat,1),size(h,1)); 41 | NFFT=2^(nextpow2(L)+1); 42 | H = fft(h,NFFT); 43 | Hhat = fft(hhat_sc,NFFT); 44 | binFreq = ((mod(((0:NFFT-1)+floor(NFFT/2)), NFFT)-floor(NFFT/2))/NFFT).'; 45 | u = Hhat .* conj(H); 46 | if mod(NFFT, 2) == 0 47 | u(length(u)/2+1,:) = 0; 48 | end 49 | Xcor = abs(ifft(u)); 50 | intDelay = find(Xcor==max(max(Xcor))); 51 | intDelay = intDelay(1)-1; 52 | rotN = repmat(exp(1i*2*pi*intDelay .* binFreq),1,size(h,2)); 53 | uDelayPhase = repmat(-2*pi*binFreq,1,size(h,2)); 54 | u = u .* rotN; 55 | weight = abs(u); 56 | uDelayPhase = uDelayPhase .* weight; 57 | weighted_angle_u = angle(u).* weight; 58 | % Note: fracDelay minimizes norm(uDelayPhase(:)*fracDelay - weighted_angle_u(:),2) 59 | fracDelay = pinv(uDelayPhase(:))*weighted_angle_u(:); 60 | Hhat = Hhat .* repmat(exp(1i*2*pi*(intDelay+fracDelay).*binFreq),1,size(h,2)); 61 | hhat_new = real(ifft(Hhat)); 62 | hhat = hhat_new(1:size(hhat,1),:); 63 | hhatv = hhat(:); 64 | 65 | % display(['Delay:' num2str(intDelay+fracDelay)]); 66 | % H_angle = unwrap(angle(H(1:NFFT/2+1,:))); 67 | % Hhat_angle = unwrap(angle(Hhat(1:NFFT/2+1,:))); 68 | % Hhat_angle_new = unwrap(angle(Hhat(1:NFFT/2+1,:))); 69 | % figure(10);plot([(H_angle(1:NFFT/2+1,2)) (Hhat_angle(1:NFFT/2+1,2)) (Hhat_angle_new(1:NFFT/2+1,2))]); 70 | 71 | epsilon = hv-((hv.'*hhatv)/(hhatv.'*hhatv))*hhatv; 72 | npm_val = norm(epsilon)/norm(hv); 73 | 74 | %figure(100); 75 | %plot([hv ((hv.'*hhatv)/(hhatv.'*hhatv))*hhatv]); -------------------------------------------------------------------------------- /phase_deviation.m: -------------------------------------------------------------------------------- 1 | function [epha epha_freq] = phase_deviation(heq, NFFT) 2 | 3 | % Phase distortion measure 4 | % 5 | % [epha epha_freq] = phase_deviation(heq, NFFT) 6 | % 7 | % Input Parameters: 8 | % heq : equalized impulse response 9 | % NFFT : length discrete Fourier transform 10 | % 11 | % Output Parameters: 12 | % epha : phase deviation 13 | % epha_freq : phase deviation per frequency 14 | % 15 | % Authors: N.D. Gaubitch, E.A.P. Habets 16 | % 17 | % History: 2006-09-15 Initial Version by N.D. Gaubitch 18 | % 2007-03-12 Minor changes by N.D. Gaubitch 19 | % 2009-07-10 NFFT option by E.A.P. Habets 20 | % 21 | % Copyright (C) Imperial College London 2006-2010 22 | 23 | % Initialization 24 | L = length(heq); 25 | if nargin == 1 26 | NFFT = 2^nextpow2(2*(L-1)); 27 | else 28 | if NFFT < 2*(L-1) 29 | warning('BSIE:phase_distortion','FFT length is too small!'); 30 | end 31 | end 32 | 33 | % Phase distortion 34 | Heq = fft(heq,NFFT); 35 | xdat = (0:NFFT/2).'; 36 | Hang = unwrap(angle(Heq(1:NFFT/2+1))); 37 | gamma = polyfit(xdat,Hang,1); 38 | Hlin = gamma(1)*xdat + gamma(2); 39 | epha = sqrt(mean((Hang-Hlin).^2)); % RMS 40 | 41 | if nargout > 1 42 | epha_freq = Hang-Hlin; 43 | end -------------------------------------------------------------------------------- /rcic.m: -------------------------------------------------------------------------------- 1 | function g = rcic(hHat, Li, Lw, Lws, tau, desiredEq) 2 | % rcic RMCLS with constrained initial coefficients 3 | % 4 | % USAGE: 5 | % g = rcic(hHat, Li, Lw, Lws, tau, desiredEq) 6 | % 7 | % INPUT: 8 | % hHat : M impulse responses of length L [L x M] 9 | % Li : length of filter 10 | % Lw : length to channel shorten the EIR to 11 | % Lws : length of initial taps to constrain 12 | % tau : delay of the target response 13 | % desiredEq : desired equalized response (optional) 14 | % 15 | % OUTPUT: 16 | % g : equalizing filter 17 | % 18 | % REFERENCES: 19 | % 20 | % AUTHOR : Felicia Lim 21 | %************************************************************************** 22 | 23 | %% Initialization 24 | if (nargin == 5) 25 | % Choose the first estimated channel by default 26 | desiredEq = hHat(:,1); 27 | end 28 | 29 | [L, M] = size(hHat); 30 | 31 | %% Define the desired target response 32 | d = [zeros(tau,1); desiredEq(1:Lws); zeros(L+Li-Lws-tau-1,1)]; 33 | 34 | 35 | %% Calculate the convolution matrix 36 | H = zeros(L+Li-1,M*Li); 37 | for ii = 1:M 38 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(hHat(:,ii),Li); 39 | end 40 | 41 | 42 | %% Define the relaxation window 43 | if (Lw > 0) 44 | w = [ones(tau,1); ones(Lws,1); zeros(Lw-Lws,1); ones(L+Li-1-Lw-tau,1)]; 45 | else 46 | w = ones(tau+L+Li-1,1); 47 | end 48 | 49 | W = repmat(w,1,M*Li); 50 | 51 | %% Find the equalizing filters 52 | iH = pinv(W.*H); 53 | g = reshape(iH*(w.*d),Li,M); 54 | 55 | end 56 | 57 | -------------------------------------------------------------------------------- /rec.m: -------------------------------------------------------------------------------- 1 | function [g] = rec(hHat, Li, Lw, Lcit, tau, fs, t60) 2 | % RMCLS with envelope constraint 3 | % 4 | % g = rec(hHat, Li, Lw, Lcit, tau, fs, t60) 5 | % 6 | % Input: 7 | % hHat : estimated AIR 8 | % Li : length of equalization filter 9 | % Lw : length of relaxation window 10 | % Lcit : sub-length of Lw to constrain to initial taps 11 | % tau : delay 12 | % fs : sampling frequency 13 | % t60 : reverberation time (secs) 14 | % 15 | % Output: 16 | % g : equalizing filters 17 | % 18 | % Authors: F. Lim, W. Zhang 19 | % 20 | % Copyright (C) Imperial College London 2009-2010 21 | 22 | [L, M] = size(hHat); 23 | 24 | % Tolerance for error between the mask and the EIR 25 | tol = 1e-3; 26 | 27 | % Convolution matrix 28 | H = zeros(L+Li-1,M*Li); 29 | for ii = 1:M 30 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(hHat(:,ii),Li); 31 | end 32 | 33 | % Define mask according to Polack's method 34 | if (Lcit > 0) 35 | n = Lcit:Lw-1; 36 | else 37 | n = 1:Lw; 38 | end 39 | alpha = 10^-(3/t60/fs); 40 | decurv_h = decacrv_v2(hHat(:,1)); 41 | beta = sqrt(decurv_h(Lw+1)*(1-alpha^2)/(alpha^(2*(tau+Lw))-alpha^(2*(tau+L)))); 42 | mask = beta*alpha.^n'; 43 | clear n; 44 | 45 | % Define target impulse response 46 | if (Lcit > 0) 47 | hHatInitTaps = hHat(tau+1:tau+Lcit,1); 48 | d = [zeros(tau,1); hHatInitTaps; zeros(L+Li-Lcit-tau-1,1)]; 49 | else 50 | d = [zeros(tau,1); 1; zeros(L+Li-tau-2,1)]; 51 | end 52 | 53 | % Define the weighting function 54 | if (Lcit > 0) 55 | w = [ones(tau,1); ones(Lcit,1); zeros(Lw-Lcit,1); ones(L+Li-1-Lw-tau,1)]; 56 | else 57 | % place one weight arbitrarily at the beginning to avoid the trivial solution. 58 | w = [ones(tau,1); 1; zeros(Lw-1,1); ones(L+Li-1-Lw-tau,1)]; 59 | end 60 | 61 | if (Lcit > 0) 62 | nr_weights_before = sum(w); 63 | else 64 | nr_weights_before = 0; 65 | end 66 | 67 | iterCount = 0; 68 | while (true) 69 | iterCount = iterCount + 1; 70 | display(sprintf(['Iteration: ',num2str(iterCount), ... 71 | ', Number of weights: ', num2str(sum(w))])); 72 | 73 | if (Lcit == 0 && iterCount == 2) 74 | w(tau+1) = 0; % reset to zero the initial weight placed to avoid the trivial solution 75 | end 76 | g = rmcls(H,w,d); 77 | 78 | eir = zeros(length(hHat)+Li-1,1); 79 | for m = 1:M 80 | eir = eir + conv(hHat(:,m), g(:,m)); 81 | end 82 | % Shape only the taps from Lcit+1:Lw 83 | eir = eir(tau+Lcit+1:tau+Lw); 84 | 85 | % update w 86 | wUpdated = false; 87 | while(sum(abs(eir)) > 0) 88 | [~,ind] = max(abs(eir)); 89 | if (abs(eir(ind)) - mask(ind) > tol) 90 | % when updating w and d, compensate for the tau+Lcit taps not 91 | % considered in the comparison against the mask 92 | if (w(ind+tau+Lcit) == 0) 93 | w(ind+tau+Lcit) = 1; 94 | wUpdated = true; 95 | si = sign(eir(ind)); 96 | d(ind+tau+Lcit) = si.*mask(ind); 97 | end 98 | end 99 | eir(ind) = 0; 100 | end 101 | 102 | 103 | if (~wUpdated) 104 | display(sprintf('w not updated')); 105 | break; 106 | end 107 | end 108 | 109 | nr_weights_after = sum(w); 110 | total_nr_weights = nr_weights_after - nr_weights_before; 111 | total_unconstr_weights = length(w) - sum(w); 112 | 113 | function g = rmcls(H,w,d) 114 | W = repmat(w,1,M*Li); 115 | iH = pinv(W.*H); 116 | g = reshape(iH*(w.*d), Li, M); 117 | end 118 | 119 | function decurv = decacrv_v2(h) 120 | % decay curve computing 121 | [Ld,Md] = size(h); 122 | bsmatrx = triu(ones(Ld,Ld),0); 123 | decurv = zeros(Ld, Md); 124 | for md = 1:Md 125 | h(:,md) = h(:,md)/h(1,1); 126 | decurv(:,md) = bsmatrx * h(:,md).^2; 127 | end 128 | end 129 | 130 | end -------------------------------------------------------------------------------- /rmcls.m: -------------------------------------------------------------------------------- 1 | function [g] = rmcls(h_hat, Li, Lw, k) 2 | 3 | % RMCLS equalization system design. 4 | % 5 | % [g] = wls(h_hat, Li, Lw, k) 6 | % 7 | % Input Parameters [size]: 8 | % h_hat : M impulse responses of length L [L x M] 9 | % Li : length of the equalization filters 10 | % Lw : length of relaxed window 11 | % k : delay of the target response 12 | % 13 | % Output parameters [size]: 14 | % g : equalization filters [Li x M] 15 | % 16 | % Authors: W. Zhang 17 | % 18 | % Copyright (C) Imperial College London 2009-2010 19 | 20 | [L, M] = size(h_hat); 21 | 22 | % Define target impulse response 23 | d = [zeros(k,1); 1; zeros(L+Li-k-2,1)]; 24 | 25 | w = [ones(k,1); 1; zeros(Lw-1,1); ones(L+Li-1-Lw-k,1)]; 26 | 27 | % H is the matrix in Equation (11a,11b) in [1] 28 | H = zeros(L+Li-1,M*Li); 29 | for ii = 1:M 30 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(h_hat(:,ii),Li); 31 | end 32 | 33 | W = repmat(w,1,M*Li); 34 | 35 | iH = pinv(W.*H); 36 | g = reshape(iH*(w.*d), Li, M); 37 | 38 | % tic 39 | % % Inspired by Factorize 40 | % [F.L F.U p]=lu(W.*H,'vector'); % Slow bit (need to exploit block toeplitz) 41 | % F.p=sparse(1:length(p),p,1); 42 | % opL.LT=true; 43 | % opU.UT=true; 44 | % g=reshape(linsolve(F.U,linsolve(F.L,F.p*(w.*d),opL),opU),Li,M); 45 | % toc -------------------------------------------------------------------------------- /rnmcflms.m: -------------------------------------------------------------------------------- 1 | function [h_hat, P_k_avg, J] = rnmcflms(xm, h_hat, P_k_avg, rho, lambda, delta) 2 | 3 | % The blind Robust Normalized Multichannel Frequency-domain LMS (RNMCFLMS) 4 | % 5 | % [h_hat, P_k_avg, J] = nmcflms(xm, h_hat, P_k_avg, rho, lambda, SNR) 6 | % 7 | % Input Parameters [size]: 8 | % xm : input matrix [F x M] 9 | % h_hat : current filter coef. matrix [L x M] 10 | % P_k_avg : estimated PSD matrix [F x M] 11 | % rho : step size (optional: default rho=0.8) 12 | % lambda : exponential forgetting factor 13 | % (0 < lambda < 1) (optional) 14 | % delta : regularization (optional) 15 | % 16 | % Output Parameters: 17 | % h_hat : updated filter coef. matrix [L x M] 18 | % P_k_avg : updated PSD matrix [F x M] 19 | % J : cost function values [F-L+1 x 1] 20 | % 21 | % References: 22 | % [1] Y. Huang and J. Benesty, "Frequency-Domain adaptive approaches to 23 | % blind multi-channel identification," IEEE Trans. Sig. Process. 24 | % vol. 51 no. 1, Jan 2003. 25 | % [2] M. Haque and M. Hasan, "Noise robust multichannel 26 | % frequency-domain LMS algorithms for blind channel 27 | % identification," IEEE Signal Process. Lett., vol. 15, 28 | % pp. 305-308, 2008. 29 | % 30 | % Authors: E.A.P. Habets 31 | % 32 | % History: 2009-08-05 Initial version by E.A.P. Habets 33 | % 34 | % Copyright (C) Imperial College London 2009-2010 35 | 36 | narginchk(3,6); 37 | 38 | % Initialization 39 | L = size(h_hat,1); 40 | F = size(xm,1); 41 | M = size(h_hat,2); 42 | U = zeros(F,M); 43 | J = zeros(F-L+1,1); 44 | e = zeros(F,M); % cross-relation error 45 | 46 | if nargin < 4 || isempty(rho) 47 | rho = 0.8; 48 | end 49 | if nargin < 5 || isempty(lambda) 50 | lambda = (1 - (1/(3*L)))^L; 51 | end 52 | 53 | h_hat_10 = fft(h_hat,F); 54 | Xm = fft(xm); 55 | P_x = conj(Xm).*Xm; 56 | P_k = sum(P_x,2)*ones(1,M)-P_x; 57 | P_k_avg = lambda*P_k_avg + (1-lambda)*P_k; 58 | 59 | if nargin < 6 || isempty(delta) 60 | delta = (M-1) * mean(mean(P_x)); 61 | % delta = sum(sum(P_x))/F*(M-1)/M/(10^(SNR/10)); % regularization 62 | end 63 | 64 | % Calculate cross-relation error 65 | for kk = 1:M 66 | for ll = 1:M 67 | e(:,ll) = Xm(:,ll).*h_hat_10(:,kk)-Xm(:,kk).*h_hat_10(:,ll); 68 | end 69 | e = real(ifft(e)); 70 | e(1:L-1,:) = 0; 71 | J = J + 0.5*sum(abs(e(L:end,:)).^2, 2); 72 | e = fft(e); 73 | U(:,kk) = sum(conj(Xm).*e,2); 74 | end 75 | 76 | % Update h_hat 77 | DJ_p = 2./abs(h_hat_10).^2 .* h_hat_10; 78 | DJ_f = U./(P_k_avg+delta); 79 | beta = abs(DJ_p(:)' * DJ_f(:) ./ norm(DJ_p(:),2).^2); 80 | h_hat_10 = h_hat_10 - rho*DJ_f + rho*beta*DJ_p; 81 | h_hat = real(ifft(h_hat_10)); 82 | h_hat = h_hat(1:L,:); 83 | h_hat = h_hat/norm(h_hat(:)); -------------------------------------------------------------------------------- /wls.m: -------------------------------------------------------------------------------- 1 | function [g] = wls(h_hat, Li, k, w) 2 | 3 | % Weighted LS equalization system design for both single and 4 | % multichannel acoustic systems. 5 | % 6 | % [g] = wls(h_hat, Li, k, w) 7 | % 8 | % Input Parameters [size]: 9 | % h_hat : M impulse responses of length L [L x M] 10 | % Li : length of the equalization filters 11 | % k : delay of the target response 12 | % w : weighting function [L+Li-1 x 1] (optional) 13 | % 14 | % Output parameters [size]: 15 | % g : equalization filters [Li x M] 16 | % 17 | % Reference: 18 | % [1] M. Miyoshi .etc, "Inverse filtering of room acoustics", 19 | % IEEE Trans. ASSP, vol. 36, 1988. 20 | % 21 | % [2] Y.Huang, J. Benesty and J. Chen, "A Blind Channel Identification-Based 22 | % Two-Stage Approach to Separation and Dereverberation of Speech 23 | % Signals in a Reverberant Environment," IEEE Trans. Speech Audio 24 | % Processing, vol. 13, no. 5 pp. 882-895, 2005. 25 | % 26 | % Authors: W. Zhang 27 | % 28 | % History: 2009-07-06 - Initial version by W. Zhang 29 | % 30 | % Copyright (C) Imperial College London 2009-2010 31 | 32 | [L, M] = size(h_hat); 33 | 34 | % Define target impulse response 35 | d = [zeros(k,1); 1; zeros(L+Li-k-2,1)]; 36 | 37 | % H is the matrix in Equation (11a,11b) in [1] 38 | H = zeros(L+Li-1,M*Li); 39 | for ii = 1:M 40 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(h_hat(:,ii),Li); 41 | end 42 | 43 | % Compute inverse 44 | if nargin == 3 45 | iH = pinv(H); 46 | g = reshape(iH*d, Li, M); 47 | else 48 | W = repmat(w,1,M*Li); 49 | iH = pinv(W.*H); 50 | g = reshape(iH*(w.*d), Li, M); 51 | end -------------------------------------------------------------------------------- /wls_iterative.m: -------------------------------------------------------------------------------- 1 | function [g, J] = wls_iterative(h_hat, Li, k, iter, w) 2 | 3 | % Iterative weighted LS equalization system design using conjugate 4 | % gradient method. 5 | % 6 | % [g, J] = wls_iterative(h_hat, Li, k, iter, w) 7 | % 8 | % Input Parameters [size]: 9 | % h_hat : M impulse responses of length L [L x M] 10 | % Li : length of the equalization filters 11 | % k : delay of the target response 12 | % iter : number of iterations 13 | % w : weighting function [L+Li-1 x 1] (optional) 14 | % 15 | % Output parameters [size]: 16 | % g : equalization filters [Li x M] 17 | % J : cost function at each iteration 18 | % 19 | % Authors: W. Zhang 20 | % 21 | % History: 2009-07-06 - Initial version by W. Zhang 22 | % 23 | % Copyright (C) Imperial College London 2009-2010 24 | 25 | % Initialization 26 | [L, M] = size(h_hat); 27 | H = zeros(L+Li-1,M*Li); 28 | for ii = 1:M 29 | H(:,(ii-1)*Li+1:ii*Li) = convmtx(h_hat(:,ii),Li); 30 | end 31 | d = [zeros(k,1); 1; zeros(L+Li-k-2,1)]; 32 | 33 | if nargin == 4 34 | w = ones(L+Li-1,1); 35 | end 36 | W = repmat(w,1,M*Li); 37 | T = W.*H; 38 | clear W; 39 | F = T'*T; 40 | md = T'*(w.*d); 41 | clear T; 42 | 43 | J = zeros(iter,1); 44 | 45 | % Iterations 46 | gv = zeros(M*Li,1); 47 | r0 = md - F*gv; 48 | p1 = r0; 49 | v = F*p1; 50 | mu = r0'*r0/(p1'*v); 51 | gv = gv + mu*p1; 52 | r1 = r0 - mu*v; 53 | J(1) = norm(w.*(H*gv-d))^2; 54 | for j = 2:iter 55 | beta = r1'*r1/(r0'*r0); 56 | p2 = r1 + beta*p1; 57 | v = F*p2; 58 | mu = r1'*r1/(p2'*v); 59 | gv = gv + mu*p2; 60 | r0 = r1; 61 | r1 = r1 - mu*v; 62 | p1 = p2; 63 | J(j) = norm(w.*(H*gv-d))^2; 64 | end 65 | g = reshape(gv, Li, M); --------------------------------------------------------------------------------