diff m-toolbox/classes/+utils/@math/rootmusic.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/+utils/@math/rootmusic.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,194 @@
+function [w_i,powers,w_mse,p_mse] = rootmusic(x,p,varargin)
+%ROOTMUSIC   Computes the frequencies and powers of sinusoids via the
+%            Root MUSIC algorithm.
+%   W = ROOTMUSIC(X,P) returns the vector of frequencies W of the complex
+%   sinusoids contained in signal vector X.  W is in units of rad/sample.
+%   P is the number of complex sinusoids in X. If X is a data matrix,
+%   each row is interpreted as a separate sensor measurement or trial.
+%   In this case, X must have a number of columns larger than P.  You can
+%   use the function CORRMTX to generate data matrices to be used here.  
+%
+%   W = ROOTMUSIC(R,P,'corr') returns the vector of frequencies W, for a
+%   signal whose correlation matrix estimate is given by the positive
+%   definite matrix R. Exact conjugate-symmetry of R is ensured by forming
+%   (R+R')/2 inside the function. The number of rows or columns of R must
+%   be greater than P.
+%
+%   If P is a two element vector, P(2) is used as a cutoff for signal and
+%   noise subspace separation.  All eigenvalues greater than P(2) times
+%   the smallest eigenvalue are designated as signal eigenvalues.  In 
+%   this case, the signal subspace dimension is at most P(1).
+%
+%   F = ROOTMUSIC(...,Fs) uses the sampling frequency Fs in the computation
+%   and returns the vector of frequencies, F, in Hz.
+%
+%   [W,POW] = ROOTMUSIC(...) returns in addition a vector POW containing the
+%   estimates of the powers of the sinusoids in X.
+%
+%   EXAMPLES:
+%      s1 = RandStream.create('mrg32k3a');
+%      n=0:99;   
+%      s=exp(i*pi/2*n)+2*exp(i*pi/4*n)+exp(i*pi/3*n)+randn(s1,1,100);  
+%      X=corrmtx(s,12,'mod'); % Estimate the correlation matrix using
+%                             % the modified covariance method.
+%      [W,P] = rootmusic(X,3);         
+%   
+%   See also ROOTEIG, PMUSIC, PEIG, PMTM, PBURG, PWELCH, CORRMTX, SPECTRUM.
+
+%   Reference: Stoica, P. and R. Moses, INTRODUCTION TO SPECTRAL ANALYSIS,
+%              Prentice-Hall, 1997.
+
+%   Author(s): R. Losada
+%   Copyright 1988-2008 The MathWorks, Inc.
+%   $Revision: 1.1 $  $Date: 2010/02/18 11:16:00 $
+
+%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Added function to compute approx. MSE for the case of a unique sinusoid
+%  
+%  REFERENCES: Rao, B. Performance Analysis of Root-Music
+%             IEEE Trans. Acoust. Speech and Sig. Proc. 37, 1989
+%
+%  VERSION:     $Id: rootmusic.m,v 1.1 2010/02/18 11:16:00 miquel Exp $
+% 
+%  M Nofrarias 12/02/2010
+%
+
+error(nargchk(2,5,nargin,'struct'));
+
+xIsReal = isreal(x);
+
+% Check for an even number of complex sinusoids if data is real
+if xIsReal && rem(p,2),
+	error(generatemsgid('InvalidDimensions'),'Real signals require an even number p of complex sinusoids.');
+end
+
+nfft = []; % Root Music doesn't use nfft, but the parser needs it
+varargin = {nfft,varargin{:}};
+
+[md,msg] = utils.math.music(x,p,varargin{:});
+if ~isempty(msg), error(generatemsgid('SigErr'),msg); end
+
+% Find the Complex Sinusoid Frequencies
+w_i = compute_freqs(md.noise_eigenvects,md.p_eff,md.EVFlag,md.eigenvals);
+
+% Estimate the noise variance as the average of the noise subspace eigenvalues
+sigma_w = sum(md.eigenvals(md.p_eff+1:end))./size(md.noise_eigenvects,2);
+
+% Estimate the power of the sinusoids
+[powers] = compute_power(md.signal_eigenvects,md.eigenvals,w_i,md.p_eff,sigma_w,xIsReal);
+
+% Compute MSE
+[w_mse,p_mse] = compute_mse(sigma_w,powers,length(x));
+
+% Convert the estimated frequencies to Hz if Fs was specified
+if ~isempty(md.Fs),
+   w_i = w_i*md.Fs./(2*pi);
+   w_mse = w_mse*(md.Fs./(2*pi))^2;
+end
+
+%---------------------------------------------------------------------------------------------
+function w_i = compute_freqs(noise_eigenvects,p_eff,EVFlag,eigenvals)
+%Compute the frequencies via the roots of the polynomial formed with the noise eigenvectors
+%
+%   Inputs:
+%
+%     noise_eigenvects - a matrix whose columns are the noise subspace eigenvectors
+%     p_eff            - signal subspace dimension
+%     EVFlag           - a flag indicating of the eigenvector methos should be used
+%     eigenvals        - a vector with all the correlation matrix eigenvalues. 
+%                        However, we use only the noise eigenvalues as weights 
+%                        in the eigenvector method.
+%
+%   Outputs:
+%
+%     w_i - frequencies of the complex sinusoids
+
+
+% compute weights
+if EVFlag,
+   % Eigenvector method, use eigenvalues as weights
+   weights = eigenvals(end-size(noise_eigenvects,2)+1:end); % Use the noise subspace eigenvalues
+else
+   weights = ones(1,size(noise_eigenvects,2));
+end
+
+% Form a polynomial D, consisting of a sum of polynomials given by the product of
+% the noise subspace eigenvectors and the reversed and conjugated version.
+D = 0;
+for i = 1:length(weights),
+   D = D + conv(noise_eigenvects(:,i),conj(flipud(noise_eigenvects(:,i))))./weights(i);
+end
+
+roots_D = roots(D);
+% Because D is formed from the product of a polynomial and its conjugated and reversed version,
+% every root of D inside the unit circle, will have a "reflected" version outside the unit circle.
+% We choose to use the ones inside the unit circle, because the distance from them to the unit
+% circle will be smaller than the corresponding distance for the "reflected" root.
+roots_D1 = roots_D(abs(roots_D) < 1);
+
+% Sort the roots from closest to furthest from the unit circle
+[not_used,indx] = sort(abs(abs(roots_D1)-1)); %#ok
+sorted_roots = roots_D1(indx);
+
+% Use the first p_eff roots to determine the frequencies
+w_i = angle(sorted_roots(1:p_eff));
+
+%-----------------------------------------------------------------------------------------------
+function [powers] = compute_power(signal_eigenvects,eigenvals,w_i,p_eff,sigma_w,xIsReal)
+%COMPUTE_POWER   Solves the system of linear eqs. to calculate the power of the sinusoids.
+%
+%   Inputs:
+%
+%     signal_eigenvects - the matrix whose columns are the signal subspace eigenvectors
+%     eigenvals         - a vector containing all eigenvalues of the correlation matrix
+%     w_i               - a vector of frequency estimates of the sinusoids
+%     p_eff             - the dimension of the signal subspace
+%     sigma_w           - the estimate of the variance of the white noise
+%     xIsReal           - a flag indicating wether we have real or complex sinusoids
+%
+%   Outputs:
+%
+%     powers - a vector that contains the power of each sinusoid
+
+%This is just the solution of a linear system of eqs, Ax=b
+
+% For real sinusoids, the system of eqs. has half the number of unknowns
+if xIsReal,
+   w_i = reshape(w_i,2,length(w_i)./2);
+   w_i = w_i(1,:); % Use only the positive freqs.
+   w_i = w_i(:);
+   p_eff = p_eff./2;
+end
+
+% Form the A matrix
+if length(w_i) == 1,
+   % FREQZ does not compute the gain at a single frequency, handle this separately
+   A = polyval(signal_eigenvects(:,1),exp(1i*w_i));
+else
+   for n = 1:p_eff,
+      A(:,n) = freqz(signal_eigenvects(:,n),1,w_i);
+   end
+end
+
+A = abs(A.').^2;
+
+% Form the b vector
+b = eigenvals(1:p_eff) - sigma_w;
+
+% The powers are simply the solution to the set of eqs.
+powers = A\b;
+
+%--------------------------------------------------------------------------
+function [w_mse,p_mse] = compute_mse(sigma_w,powers,N)
+% implements eq.30 in Reference   
+
+  L = 1; % one element array
+  
+  p_mse =   12    *   (sigma_w/(powers*N*L^2));
+  % first term of eq.30 in paper is to pass from frequency to DOA
+  % this sigma_w^2 could be wrong
+  w_mse = 12/(2*L)*   (sigma_w^2/(powers*N*L^2)); 
+
+% [EOF] rootmusic.m
+