Mercurial > hg > ltpda
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 +